将realloc用于结构数组

时间:2014-06-01 17:35:54

标签: c memory struct realloc

我使用realloc来增加结构数组的内存量,而且它似乎根本没有增加。我已经阅读了与此相关的所有帖子,但我无法弄清楚我做错了什么。这是我的代码:

struct fileInfo {
char name[MAXNAMLEN];
struct stat stbuf;
};

...

 struct fileInfo * newFileInfoPtr;
 struct fileInfo * fileInfoPtr = (struct fileInfo *) realloc (NULL, sizeof (struct fileInfo));
    // loop through directory to find all filenames
    while ((direntPtr = readdir (dirFilePtr)) != NULL) {
        (void) strcpy (direntName, filename);
        (void) strcat (direntName, "/");
        (void) strcat (direntName, direntPtr->d_name);
        (void) strcat (direntName, "\0");
        // check for vaild file
        if (lstat (direntName, &st)) {
            if (errno) {
                (void) snprintf (buffer, BUFSIZ, STR_LSTAT_ERR);
                perror (buffer);
            }
            exit (EXIT_FAILURE);
        }

        // reallocate memory for new fileInfo struct
        newFileInfoPtr = (struct fileInfo *) realloc (fileInfoPtr, 
                                    (count+1) * sizeof (struct fileInfo));

        // check for allocation success and increase count
        if (newFileInfoPtr != NULL) {
            (void) memset (newFileInfoPtr->name, NULL, MAXNAMLEN);
            (void) strcpy (newFileInfoPtr->name, direntPtr->d_name);
            newFileInfoPtr->stbuf = st; 
            fileInfoPtr = newFileInfoPtr;
            count++;
        } else {
            if (errno) {
                (void) snprintf (buffer, BUFSIZ, STR_ALLOC_ERR);
                perror (buffer);
            }
            exit (EXIT_FAILURE);
        }
        ...

direntPtr是指向已打开目录的指针,我正在读取其中所有文件的名称。那部分是有效的,因为我可以打印出每个条目的名称。我的问题是我最终得到的最终结构数组。我理解realloc你根据旧数组分配内存,将返回值赋给新指针,用信息填充新指针,并将旧指针设置为新指针。但是,在完成循环之后,fileInfoPtr只是一个结构。我可以访问索引0处的字段,但之后它们都是空的。我打印出每个索引的内存地址,它们都是一样的...... 谢谢你的帮助

2 个答案:

答案 0 :(得分:2)

您的newFileInfoPtr指向新分配的数组的第一个条目。通过memsetstrcpy来电,您可以使用newFileInfoPtr->name进行操作,这会覆盖第一个条目的名称。你想要

(void) memset (newFileInfoPtr[count].name, NULL, MAXNAMLEN);
(void) strcpy (newFileInfoPtr[count].name, direntPtr->d_name);

访问索引count的最后一个条目(在递增之前)。

答案 1 :(得分:1)

你正在做一些正确的事情,并且realloc()会出错。

我认为正确的是:

newFileInfoPtr = (struct fileInfo *) realloc(fileInfoPtr, 
                                             (count+1) * sizeof (struct fileInfo));

这样可以确保在分配失败时不会丢失分配的空间。但是,每次重新分配都很昂贵;它可以导致二次行为。您应该每次分配两倍的条目,或者是该想法的次要变体。

但是,在检查非null之后,正确的后续步骤之一是:

fileInfoPtr = newFileInfoPtr;

您还需要将fileInfoPtr用作数组:

strcpy(FileInfoPtr[count].name, direntPtr->d_name);

我们可以就索引是count还是count ± 1进行协商;一般的想法是你需要使用struct fileInfo数组作为数组,而不是总是使用数组的第0个元素。

如果是我的代码,我可能会使用如下结构:

typedef strut fileInfo FileInfo;

size_t count = 0;
size_t avail = 0;

FileInfo *fileInfoPtr = 0;
// loop through directory to find all filenames
while ((direntPtr = readdir(dirFilePtr)) != NULL)
{
    snprintf(direntName, sizeof(direntName), "%s/%", filename, direntPtr->d_name);
    if (lstat(direntName, &st))
    {
        int errnum = errno;
        snprintf(buffer, sizeof(buffer), "Failed to lstat() %s (%d: %s)\n",
                 direntName, errnum, strerror(errnum));
        perror(buffer);
        exit(EXIT_FAILURE);
    }

    if (count >= avail)
    {
         size_t new_size = (avail + 1) * 2;
         FileInfo *np = realloc(fileInfoPtr, new_size);
         if (np == 0)
         {
             …handle error; release old fileInfoPtr…
             exit(EXIT_FAILURE);
         }
         avail = new_size;
         fileInfoPtr = np;
    }

    strcpy(fileInfoPtr[count].name, direntPtr->d_name);
    InfoPtr[count].stbuf = st;
    count++;
}

在循环结束时,count会告诉您阵列中正在使用的条目数,avail告诉您分配了多少条目。如果你担心太多的空间,你可以做一个最后的缩小realloc(),使阵列成为你需要的确切尺寸。实际上很少需要这样做。

请注意,memset()之前的strcpy()不是必需的。