2014-05-03 1 views
0

J имеют код, отображающий имя (это char []/string) каталогов или файлов в данной директории. Я хочу динамически поместить эти имена в массив. В таблице print1 отображаются правильные значения (имя каталогов или файлов), которые повторяются. Но в другой таблице печати3 отображаются неправильные значения. Может ли кто-нибудь помочь мне в этом? Это проблема с памятью или чем-то еще?Как добавить динамическую строку в массив с помощью C

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; 

}

+0

Просьба представить полностью воспроизводимый пример, включая скомпилируемый код и минимальный набор имен файлов, который показывает проблему. – merlin2011

ответ

0

Указатель, возвращаемый readdir() указывает на статически размещенную структуру, так что вы не должны сохранять ссылки на него после выполнения последующих вызовов, так как каждый раз, когда вы звоните readdir() снова это будет просто получить перезаписаны ,

Вы хотите изменить:

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

к чему-то вроде:

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

сделать копию того, что он указывает на, а не просто пытается сохранить указатель. Не забудьте позвонить free(), когда вы закончите с этим, так как strdup()malloc() s память для вас.

Альтернативой является использование readdir_r(), который использует структуру, выделенную вызывающим, но для того, что вы делаете это, вероятно, не нужно, поскольку вы просто хотите сохранить имя.

Как всегда, не отбрасывают возвращения из malloc() в С.

strlen(strArray) является неправильным, так как strArray не является строкой, и strlen() работает только для строк. Вы уже используете переменную count, чтобы отслеживать ее длину, поэтому просто используйте это. Весь этот блок:

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]); 

является очевидным кандидатом для цикла, и может быть заменен:

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

или:

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

, так как вы установите последний элемент NULL.

Вот фиксированная версия:

#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; 
} 

и выходы:

[email protected]:~/Documents/src/scratch/dir_test$ ls 
README  ls1   ls1.c  nothing.txt 
[email protected]:~/Documents/src/scratch/dir_test$ ./ls1 
Table1: ls1 
Count: 1 

Table1: README 
Count: 2 

Table3: ls1 
Table3: README 
Number of elements: 2 

[email protected]:~/Documents/src/scratch/dir_test$ 
+0

Что я могу получить размер массива, который возвращается функцией do_ls? Когда я вызываю char ** strArray = (char **) do_ls («C:/PAP»); – user3245771

+0

Вы можете просмотреть его и подсчитать до тех пор, пока не найдете 'NULL'. Это именно то, что делает 'free_ls_array()', за исключением того, что оно фактически не подсчитывается. –

1

Вот альтернативный способ, как вырастить динамически выделенный массив:

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); 
    } 
+0

Поблагодарите evrybody за помощью. – user3245771