Search code examples
cmallocdirent.h

Segfault/incompatible type error when attempting to create an array of directory structures


I'm using the dirent.h library to scan a directory for all the files it contains and store pointers to the resulting objects in an array. I've been following this old SO question describing the storage of structure pointers in arrays, but I'm running into issues during my implementation.

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>

int main(int argc, char **argv) 
{
    DIR *d = NULL;
    struct dirent *dir = NULL;
    struct dirent *d_array[50]; //big overkill array to avoid realloc
    size_t n = 0; //number of items

    d = opendir("scandir"); //name of directory to search
    if(d)
    { 
        while((dir = readdir(d))!=NULL) {
            //d_array[n] = malloc(sizeof(struct dirent));
            d_array[n++] = dir;
        }
        closedir(d);
    }
    for(size_t i = 0;i<n;i++) {
        printf(d_array[n]->d_name);
        free(d_array[n]);
    }
    free(d_array);
    return 0;
}

Running the above code results in a Segmentation fault: 11. I thought this was probably because I was properly allocating the memory for the structures (as seen in the commented out malloc), but including that gives the following error:

error: assigning to 'struct dirent *' from incompatible type
  'void *'

I don't understand why d_array[n] = malloc(sizeof(struct dirent)), which is verbatim from multiple posts about this topic, is having this incompatible type error. And if it's inappropriate to use, why am I getting a segfault?


Solution

  • Running the above code results in a Segmentation fault: 11.

    This could be because of

        printf(d_array[n]->d_name);
    

    or

        free(d_array[n]);
    

    , because n is the number of directory entries, and d_array[n] is uninitialized. (You appear to have meant d_array[i]) Note, too, that you should not attempt to free the pointer returned by readdir(), as it does not belong to you. The documentation specifically says that you should not attempt to free it. That would potentially apply in the version in which you just assign the pointer itself to the array.

    It could also be because of

    free(d_array);
    

    , since d_array itself is not dynamically allocated. You could reasonably hope that your compiler would warn about that one. Mine does.

    I don't understand why d_array[n] = malloc(sizeof(struct dirent)), which is verbatim from multiple posts about this topic, is having this incompatible type error.

    That would be because your compiler is non-conforming. Perhaps you are using a C++ compiler instead of a C compiler -- these are not interchangeable. That statement is perfectly valid C, given the declarations that are in scope where it appears in your code.

    Addendum: As for what you actually should do, if you are going to dynamically allocate memory for the elements of d_array to point to (and you should, if you use an array of pointers at all) then you need to copy the pointed-to struct dirent structures into the allocated space, not assign the returned pointers directly to the array. That would be

        *d_array[i] = *dir;
    

    as Paul Ogilvie first pointed out in a now-deleted answer.