#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
int main(){
struct stat *something;
stat("/etc/profile", something);
printf("%d\n", something->st_gid);
free(something);
return 0;
}
$ ./a.out
Segmentation fault
I learned from this post that I need to allocate memory using malloc, so I changed it to as below, and it works:
- struct stat *something;
+ struct stat *something = malloc(sizeof(struct stat));
In a prior but related exercise, I did not use a malloc, and it had worked. I am lost! Why don't I need malloc for the line " *struct dirent b; " below?
Or, to rephrase, how can we know the payload is too much and to use malloc?
#include <stdio.h>
#include <dirent.h>
int main(int argc, char *argv[]){
if (argc != 2){
printf("Error. Syntax: ls <somefolder> \n");
return 1;
}
DIR *a = opendir(argv[1]) ;
if (a == NULL){
printf("error. cannot open %s\n", argv[1]);
return 1;
}
// - malloc question about this very next line
struct dirent *b;
while (( b = readdir(a)) != NULL){
printf("%s %lu\n", b->d_name, b->d_ino);
}
int closing = closedir(a);
printf("in closing, status is %d\n", closing);
return 0;
}
Newcomer to C, clueless too - please be gentle! :)
The problem with
struct stat *something;
stat("/etc/profile", something);
is that something
is an uninitialized pointer pointing to nowhere, this yields undefined behaviour as stat
would write something on an invalid address. With malloc
you allocated memory for it and passed a pointer to that allocated memory location to stat
and that's why it worked.
But you don't need to use malloc
for that, just don't declare something
as a pointer:
struct stat something;
stat("/etc/profile", &something); // <-- look at the usage of &
In stat
you should use the &
-operator which returns a pointer to something
.
In your other program
struct dirent *b;
while (( b = readdir(a)) != NULL)
readdir
returns a pointer to a valid location, the function itself took care of using a valid object and returning a pointer to it. However, you cannot do free(b)
:
RETURN VALUE
On success,
readdir()
returns a pointer to a dirent structure. (This structure may be statically allocated; do not attempt tofree(3)
it.)
readdir
returns a pointer to a struct dirent
. Doing: b = readdir(a)
overwrites the value b
with the new value returned by readdir
.
So of b
was previously initialized with allocated memory from a malloc
call, that value has been overwritten and you now likely have a memory leak.
You might wonder then whether you need to call free
on b
after the readdir
call. To answer that you have to consult your documentation. In this case, the answer is no .
From the documentation for readdir
:
On success, readdir() returns a pointer to a dirent structure. (This structure may be statically allocated; do not attempt to free(3) it.)
int main(){
struct stat *something;
stat("/etc/profile", something);
printf("%d\n", something->st_gid);
free(something);
return 0;
}
Above code has multiple issues,
something
which is not pointing to a valid location, and again using it as a buffer to store information return by stat()
. int stat(const char *pathname, struct stat *statbuf);
stat()
return information about a file, in the buffer pointed to by statbuf
, so your statbuf
(something) should be a valid buffer, with size enough to store information of file, ie size of struct stat
.
free(something);
from free() man page
if the argument passed to free() does not match a pointer earlier returned by a function in POSIX.1‐2008 that allocates memory as if by malloc(), or if the space has been deallocated by a call to free() or realloc(), the behavior is undefined.
Now coming to other code:
// - malloc question about this very next line
struct dirent *b;
while (( b = readdir(a)) != NULL){
printf("%s %lu\n", b->d_name, b->d_ino);
}
let's explore readdir()
a bit,
struct dirent *readdir(DIR *dirp); The readdir() function returns a pointer to a dirent structure representing the next directory entry in the directory stream pointed to by dirp. It returns NULL on reaching the end of the directory stream or if an error occurred.
You see readdir()
returns a pointer of struct dirent
type which makes b
in struct dirent *b
a valid pointer. That's why it worked.
Normally any pointers whether its a int *ptr
or char *ptr
or struct student *ptr
, it should have valid address
and valid address may be dynamically allocated address or address of some variable .
Case 1 : struct stat *something;
here something
is pointer of struct stat
type and its un-initialized.
when you do stat("/etc/profile", something);
you are trying to store /etc/profile
information into something
which is un-initialized. Instead of this you should store the information of /etc/profile
into address of something
or
struct stat info;
struct stat *something = &info;
stat("/etc/profile",something );
Case 2 : struct dirent *b;
b
is pointer of type struct dirent
, it should also have valid address. b = readdir(a);
readdir
return value is assigned to b
, so now you can perform b->d_name
etc.
From the manual page of readdir()
On success, readdir() returns a pointer to a dirent structure. (This structure may be statically allocated; do not attempt to free(3) it.)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.