【问题标题】:How can I putting dynamically string into array using C如何使用 C 将动态字符串放入数组中
【发布时间】:2014-06-20 08:00:27
【问题描述】:

J 在下面有一个代码,它显示给定目录中目录或文件的名称(这是 char[]/string)。我想将这些名称动态地放入数组中。在打印表 1 中显示正确的值(目录或文件的名称)是迭代的​​。但在其他打印 table3 中显示不正确的值。有人可以帮我吗?这是内存问题还是其他问题?

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;

}

【问题讨论】:

  • 请提供一个完全可重现的示例,包括可编译的代码和显示问题的最少文件名集。

标签: c arrays memory-management dynamic-programming dir


【解决方案1】:

readdir() 返回的指针指向一个静态分配的结构,因此在进行后续调用后不应保留对它的引用,因为每次再次调用readdir() 时,它都会被覆盖。

你会想要改变:

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

类似于:

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

复制它所指向的内容,而不是仅仅试图保留指针。完成后不要忘记致电free(),因为strdup() malloc()s 是你的记忆。

另一种方法是使用readdir_r(),它使用调用者分配的结构,但对于您正在执行的操作,这可能不是必需的,因为您只想存储名称。

和往常一样,不要在 C 中从 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;
}

和输出:

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$ 

【讨论】:

  • 我可以获得什么函数do_ls返回的数组大小?当我调用 char ** strArray = (char **)do_ls("C:/PAP");
  • 您可以遍历它并计数,直到找到NULL。这正是free_ls_array() 所做的,只是它实际上并不算数。
【解决方案2】:

这里是如何增加动态分配的数组的另一种方法:

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

【讨论】:

  • 感谢大家的帮助。
猜你喜欢
  • 2022-01-05
  • 2013-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多