문제

J have below a code which display the name (this is char[]/string) of directories or files in given directory. I want to put this names dynamically to array. In print table1 displays correct the values(name of directories or files) which are iterate. But in other print table3 displays incorrect values. Could anybody help me with that? Is this problem with memory or something else?

char** do_ls( char dirname[] ){
DIR *dir_ptr;
struct dirent *direntp;
char **strArray;
int count=0;
strArray = (char**)malloc(1 * sizeof(char*));
strArray[0] = NULL;

if ( ( dir_ptr = opendir( dirname ) ) == NULL )
    fprintf(stderr,"ls1: cannot open %s\n", dirname);
else {
    while ( ( direntp = readdir( dir_ptr ) ) != NULL ) {
        if(strchr(direntp->d_name, '.') == NULL) {

            strArray[count] = (char*)direntp->d_name;
            printf("\nTable1: %s \n", strArray[count]);
            count++;
            strArray = (char **)realloc(strArray, sizeof(char *) * (count + 1));
            printf("\nCount: %d \n", count);

        }
    }
    strArray[count] = NULL;  /* Terminate the array */
printf("\nTable3: %s \n", strArray[0]);
printf("\nTable3: %s \n", strArray[1]);
printf("\nTable3: %s \n", strArray[2]);
printf("\nTable4: %s \n", strArray[strlen(strArray)-1]);
printf("\nIndex: %d \n", strlen(strArray)-1);

    closedir(dir_ptr);
}



return strArray;

}

도움이 되었습니까?

해결책 2

The pointer returned by readdir() points to a statically allocated structure, so you should not retain references to it after making subsequent calls, since every time you call readdir() again it'll just get overwritten.

You'll want to change:

strArray[count] = (char*)direntp->d_name;

to something like:

strArray[count] = strdup(direntp->d_name);

to make a copy of what it points to, rather than just trying to retain the pointer. Don't forget to call free() when you're done with it, since strdup() malloc()s the memory for you.

An alternative is to use readdir_r() which uses a caller-allocated structure, but for what you're doing this is likely not necessary, since you just want to store the name.

As always, don't cast the return from malloc() in C.

strlen(strArray) is wrong, since strArray is not a string, and strlen() only works for strings. You already maintain a count variable to keep track of the length of it, so just use that. This whole block:

printf("\nTable3: %s \n", strArray[0]);
printf("\nTable3: %s \n", strArray[1]);
printf("\nTable3: %s \n", strArray[2]);
printf("\nTable4: %s \n", strArray[strlen(strArray)-1]);

is an obvious candidate for a loop, and can be replaced by:

for ( int s = 0; s < count; ++s ) {
    printf("\nTable3: %s \n", strArray[s]);
}

or:

int s = 0;
while ( strArray[s] ) {
    printf("\nTable3: %s \n", strArray[s++]);    
}

since you set the last element to NULL.

Here's a fixed version:

#define _POSIX_C_SOURCE 200809L

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

char ** do_ls(const char * const dirname) {
    DIR * dir_ptr;
    struct dirent * direntp;
    char ** strArray;
    size_t count = 0;

    if ( (strArray = malloc(sizeof(*strArray))) == NULL ) {
        fprintf(stderr, "ls1: couldn't allocate memory");
        exit(EXIT_FAILURE);
    }
    strArray[0] = NULL;

    if ( (dir_ptr = opendir(dirname)) == NULL ) {
        fprintf(stderr, "ls1: cannot open %s\n", dirname);
        exit(EXIT_FAILURE);
    }
    else {
        while ( (direntp = readdir(dir_ptr)) != NULL ) {
            if ( strchr(direntp->d_name, '.' ) == NULL ) {
                strArray[count] = strdup(direntp->d_name);
                if ( strArray[count] == NULL ) {
                    fprintf(stderr, "ls1: couldn't allocate memory");
                    exit(EXIT_FAILURE);
                }

                printf("Table1: %s\n", strArray[count++]);
                printf("Count: %zu\n\n", count);

                strArray = realloc(strArray, sizeof(*strArray) * (count + 1));
                if ( strArray == NULL ) {
                    fprintf(stderr, "ls1: couldn't reallocate memory");
                    exit(EXIT_FAILURE);
                }

                strArray[count] = NULL;
            }
        }

        for ( size_t s = 0; s < count; ++s ) {
            printf("Table3: %s\n", strArray[s]);
        }
        printf("Number of elements: %zu\n\n", count);

        closedir(dir_ptr);
    }

    return strArray;
}

void free_ls_array(char ** strArray) {
    size_t s = 0;
    while ( strArray[s] ) {
        free(strArray[s++]);
    }
    free(strArray);
}

int main(void) {
    char ** strArray = do_ls("./");
    free_ls_array(strArray);
    return 0;
}

and outputs:

paul@MacBook:~/Documents/src/scratch/dir_test$ ls
README      ls1         ls1.c       nothing.txt
paul@MacBook:~/Documents/src/scratch/dir_test$ ./ls1
Table1: ls1
Count: 1

Table1: README
Count: 2

Table3: ls1
Table3: README
Number of elements: 2

paul@MacBook:~/Documents/src/scratch/dir_test$ 

다른 팁

Here is an alternate method to how to grow a dynamically allocated array:

char **do_ls(
      const char *dirname
      ) 
   {
   DIR *dir_ptr = NULL;      /* A handle to iterate the specified directory. */
   int tmp;                  /* Used to iterate the array when printing it out. */

   char **strArray = NULL;   /* Array of string pointers for directory names. */
   int count=0;              /* Number of elements in the array */ 


   /* Open the specified directory. */
   dir_ptr = opendir(dirname);
   if(NULL == dir_ptr)
      {
      fprintf(stderr,"ls1: cannot open %s\n", dirname);
      goto CLEANUP;
      }

   /* Scan directory entries. */
   while((direntp = readdir( dir_ptr )))
      {
      struct dirent *direntp;   /* Pointer to a directory entry. */
      char **tmp;               /* Used to safely grow the array. */

      /* Ignore current & parent directories, and all files with an extension. */
      if(strchr(direntp->d_name, '.'))
         continue;

      /* Increase the size of the array. */
     tmp=realloc(strArray, count+1 * sizeof(*strArray));
     if(NULL == tmp)
         {
         fprintf(stderr, "realloc() failed.\n");
         goto CLEANUP;
         }
      strArray = tmp;

      /* Store directory entry name into new array slot. */
      strArray[count] = strdup(direntp->d_name);
      count++;
      }

   /* Print array entries. */
   for(tmp=0; tmp < count; ++tmp)
      printf("Slot #%d: %s\n", tmp, strArray[tmp]);

   /* Add a last "termination" entry to the array. */
   tmp=realloc(strArray, count+1 * sizeof(*strArray));
   if(NULL == tmp)
      {
      fprintf(stderr, "realloc() failed.\n");
      goto CLEANUP;
      }
   strArray = tmp;
   strArray[count] = NULL; 

CLEANUP:

   if(dir_ptr)
      closedir(dir_ptr);

   return(strArray);
   }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top