How to properly use scandir() in c?

若如初见. 提交于 2020-01-01 03:43:31

问题


I am trying to store list of files in a char** variable.

scandir() finishes properly but I get a segmentation fault when trying to print the char**.

Here's the code:

int main()
{
    char** fileList;
    int noOfFiles;
    char* path = ".";
    makeList(&fileList, &noOfFiles, path); 
    return 0;
}

void makeList(char ***fileList, int* noOfFiles, char* path){
    struct dirent **fileListTemp;
    *noOfFiles = scandir(path, &fileListTemp, NULL, alphasort);
    int i;
    fileList = (char***)malloc(sizeof(char***));
    *fileList = (char**)malloc(*noOfFiles * sizeof(char*));
    printf("total: %d files\n",*noOfFiles);
    for(i = 0; i < *noOfFiles; i++){
        *fileList[i] = (char*)malloc(strlen(fileListTemp[i] -> d_name) *sizeof(char));
        strcpy(*fileList[i], fileListTemp[i] -> d_name);
        printf("%s\n",*fileList[i]);
    }
    return;
}

This gives a segmentation fault after printing 2 file names.

output:

total: 27 files.

..

.j.v

Segmentation fault (core dumped)


回答1:


The function scandir() allocates the memory for you.

You do not need to allocate ANY memory. You DO need to free the memory returned to you by scandir().

Your code calls: *noOfFiles = scandir(path, &fileListTemp, NULL, alphasort);

On return, noOfFiles will contain the number of directory entries in the path directory, and fileListTemp will point to an allocated array of pointers to allocated strings each of which points to an allocated block containing the null-terminated name of a file.

If your directory contains the files "FirstFile.txt", "AnotherFile.txt", "ThirdFile.txt", for example, with your call, upon return from scandir(), noOfFiles will be set to 5 for the three files plus two more for the "." and ".." directory entries. THE ENTRIES WILL BE IN NO PARTICULAr ORDER IF YOU DO NOT PASS 'alphasort'. (Actually that's a little incorrect. They will be in the order of the directory filename entries which depends on the order in which the files were originally created.)

Because you passed 'alphasort' you should see the entries in the following order (I am explicitly showing the null-byte-string-terminator:

fileListTemp[0] == ".\0"
fileListTemp[1] == "..\0"
fileListTemp[2] == "AnotherFile.txt\0"
fileListTemp[3] == "FirstFile.txt\0"
fileListTemp[4] == "ThirdFile.txt\0"

So fileListTemp points to a block of allocated memory holding five (char *) pointers. Each of the five (char *) pointers points to a block of allocated memory containing a null-terminated directory entry name.

That is SIX blocks of allocated memory.

You can use this allocated memory until you are done with it, and then you call free() on EACH entry in the array followed by free() of the array itself.

You MUST free every entry as well as the array itself. They are all independently allocated blobs of memory.

When you are done with the list you should:

for (int i = 0; i < noOfFiles; i++)
  {
  free(fileListTemp[i];
  }

free(fileListTemp);



回答2:


This is an old question, but since I came upon it and it did not solve my question as effectively as the man page did, I am copying a code snippet from the man page as a new answer for the future.

  #include <dirent.h>

   int
   main(void)
   {
       struct dirent **namelist;
       int n;

       n = scandir(".", &namelist, NULL, alphasort);
       if (n < 0)
           perror("scandir");
       else {
           while (n--) {
               printf("%s\n", namelist[n]->d_name);
               free(namelist[n]);
           }
           free(namelist);
       }
   }



回答3:


modify the code, it works!

  #include <stdio.h>
  #include <sys/types.h>
  #include <sys/dir.h>
  #include <stdlib.h>
  #include <string.h>

  void makeList(char ***fileList, int* noOfFiles, char* path){
      struct dirent **fileListTemp;
      *noOfFiles = scandir(path, &fileListTemp, NULL, alphasort);
      int i;
      *fileList = (char**)malloc(*noOfFiles * sizeof(char*));
      printf("total: %d files\n",*noOfFiles);
      for(i = 0; i < *noOfFiles; i++){
          (*fileList)[i] = (char*)malloc(strlen(fileListTemp[i] -> d_name)+1);
          strcpy((*fileList)[i], fileListTemp[i] -> d_name);
          printf("%s\n",(*fileList)[i]);
      }   
      return;
  }

  int main()
  {
      char** fileList;
      int noOfFiles;
      char* path = ".";
      makeList(&fileList, &noOfFiles, path); 
      return 0;
  }

fileList is type of char ***, so *fileList is the fileList variable in main function.

*fileList = (char**)malloc(*noOfFiles * sizeof(char*));

with this statement, *fileList points to allocated memory of array of pointers.
if want to allocate memory for each pointer within the array, we need use (*fileList)[i], other than *fileList[i], the precedence of [] is higher than *.




回答4:


I am not sure this is the problem, but you have to allocate another byte for the null termination:

*fileList[i] = (char*)malloc(strlen(fileListTemp[i] -> d_name + 1) *sizeof(char));


来源:https://stackoverflow.com/questions/18402428/how-to-properly-use-scandir-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!