【问题标题】:How to create dynamic array of structs using realloc in function如何在函数中使用 realloc 创建结构的动态数组
【发布时间】:2019-05-23 01:44:29
【问题描述】:

我正在尝试使用 realloc 创建结构的动态数组(在本例中为图片)。我想在函数中做,但有一个问题: main 中的变量不会被这个函数改变。指针一定有问题,但我找不到。 PS:函数 UploadFile 工作正常。 有一个功能:

int AddPicture(struct Picture ***tab, int *PicCounter)
{
    struct Picture *temp;
    struct Picture pic;
    (*PicCounter)++;
    temp = realloc(*tab, (*PicCounter) *sizeof(*temp));
    if (temp != NULL)
    {
        UploadFile(&pic);
        **tab = temp;
        (*tab)[*PicCounter-1]->name = pic.name;
        (*tab)[*PicCounter-1]->type[0] = pic.type[0];
        (*tab)[*PicCounter-1]->type[1] = pic.type[1];
        (*tab)[*PicCounter-1]->width = pic.width;
        (*tab)[*PicCounter-1]->height = pic.height;
        (*tab)[*PicCounter-1]->scale = pic.scale;
        (*tab)[*PicCounter-1]->table = pic.table;
    }
    else {
        printf("Memory reallocation error");
        free(temp);
        return 1;
    }
return 0;
}

我在 main 中是这样称呼它的:

struct Picture *tabofpics;
int piccounter = 0;
tabofpics = malloc(1 * sizeof(*tabofpics));
AddPicture(&tabofpics,&piccounter);

感谢您的帮助。

编辑: 我试过 **tab 而不是 ***tab 并且 main 中的值是正确的,但它的行为就像内存没有正确重新分配,即使 realloc 不返回 NULL。

  int AddPicture(struct Picture **tab, int *PicCounter)
{
    struct Picture *temp;
    struct Picture pic;
    (*PicCounter)++;
    temp = realloc(*tab, (*PicCounter) * sizeof(*temp));
    if (temp != NULL)
    {
    UploadFile(&pic);
    *tab = temp;    
    tab[*PicCounter - 1]->name = pic.name;
    tab[*PicCounter - 1]->type[0] = pic.type[0];
    tab[*PicCounter - 1]->type[1] = pic.type[1];
    tab[*PicCounter - 1]->width = pic.width;
    tab[*PicCounter - 1]->height = pic.height;
    tab[*PicCounter - 1]->scale = pic.scale;
    tab[*PicCounter - 1]->table = pic.table;
}
else {
    printf("Memory reallocation error");
    free(*tab);
    return 1;
}
return 0;
}                                                                                                                             

我们的想法是在程序中放入任意数量的图片,对其进行一些操作然后离开。必须有功能可以在用户需要时添加和删除图片,但是当我第二次在参数中使用 **tab 调用函数时,我会得到访问冲突位置,所以正如我之前提到的,realloc 不能正常工作。

【问题讨论】:

  • 为什么tab 是三重指针?似乎双指针就足够了。特别是因为您根据Picture 的大小分配内存,而不是Picture *
  • 我认为编译器警告应该给出答案。而且似乎不知道要添加多少张图片,在这种情况下,也许链表会更好?每个节点都是关于你的图片的信息
  • struct Picture ***tab --> struct Picture **tab
  • @IgorZ 不要只是尝试解决问题。想一想,先试着理解底层的概念。检查我的答案。
  • @IharobAlAsimi,在分析时值得考虑考虑,但实际上它不是指数的,它是您使用的最大两倍...所以如果您正在处理 1gb 数据集您可能有一个 1gb 的缓冲区未使用,但在现代 VM 环境中这通常是可以的,比复制 .9gb 缓冲区 10 次要好得多

标签: c arrays struct realloc


【解决方案1】:

根据@Iharob 和@John 的回答,我能够编写一个工作函数:

 int AddPicture(struct Picture **tab, int *PicCounter)
{
struct Picture *temp;
(*PicCounter)++;
temp = realloc(*tab, (*PicCounter) * sizeof(*temp));
if (temp != NULL)
{
    struct Picture *pic;
    pic = malloc(sizeof(*pic));
    UploadFile(pic);
    *tab = temp;
    (*tab)[(*PicCounter)-1] = *pic;
    free(pic);
}
else {
    printf("Memory reallocation error");
    free(*tab);
    (*PicCounter)--;
    return 1;
}
return 0;
}

它并不完美,但可以正常工作。感谢您的帮助!

【讨论】:

  • 如果基于其他答案,请不要回答您自己的问题。接受你认为最有帮助的那个。如果它与已经提供的问题有很大不同,请仅回答您自己的问题。你的代码也有问题。如果你打电话给free(*tab),那么*PicCounter = 0 是必须的,因为现在你不能再访问tab 的内容了。而且代码中的间接级别仍然是错误的。如果它“有效”只是一个意外,所以请使用内存调试器或类似工具并检查您的代码是否错误。
【解决方案2】:

您的代码中的这两个摘录也许可以最好地概括核心问题:

    temp = realloc(*tab, (*PicCounter) *sizeof(*temp));

[...]

        **tab = temp;

您正在重新分配*tab 的值所指向的空间,但在成功时,您会将指向新空间的指针存储在**tab这是一个不同的位置。不管哪一个是指针的正确位置,组合肯定是错误的。

事实上,鉴于您调用函数的方式...

struct Picture *tabofpics;

[...]

AddPicture(&tabofpics,&piccounter);

...实际参数的类型是struct Picture **。这适合您的目的,因此您应该调整函数定义以匹配:

int AddPicture(struct Picture **tab, int *PicCounter)

。此外,您应该确保在包含AddPicture 定义的源文件和包含对该函数的调用的每个源文件中的#included 头文件中存在匹配的函数声明。再加上确保出现编译器警告,应该使编译器能够帮助您诊断此函数的定义和使用之间的不匹配。

完成此操作后,函数AddPicture() 中的表达式*tab 将引用与main() 中的表达式tabofpics(没有*)引用的相同对象。除了我在开头描述的不匹配之外,这似乎与您实际使用它的方式一致。

可以对您的代码提出其他合理的批评,但@Iharob 在他的回答中已经很好地解决了这些问题。

【讨论】:

    【解决方案3】:

    在我看来,你需要改进代码的逻辑,例如

    1. 暂时不要增加PicCounter
    2. 您的指针间接级别不匹配,在调用函数中您有struct Picture *,并且您将它作为struct Picture ** 传递给采用struct Picture *** 的函数。您应该对此进行推理,以及您真正想要的是什么。您似乎想要一个 struct Picture * 数组。

    风格,

    1. 不要将PicCounter 用于变量,使用number_of_pictures 或更合适的名称。
    2. 不要写1 * sizeof(...),它太明确了,你不需要这么多。

    工具,

    1. 启用编译器警告,以发现您在没有注意到的情况下犯的简单错误,或那些概念性缺陷,如代码中指针的不匹配间接。

    也就是说,我想你可能想写这个

    int
    AddPicture(struct Picture ***tab, int *counter)
    {
        struct Picture **array;   
        array = realloc(*tab, (*counter + 1) * sizeof(*array));
        if (array != NULL)
        {
            struct Picture *current;
            // We will avoid using the `tab' variable because it's
            // confusing, the only reason why it's a *** pointer is
            // to do this here, and below where we set it to `NULL'
            *tab = array;
            // We also need to allocate space for a new image to store
            // the results in.
            current = malloc(sizeof(*current));
            if (current == NULL)
                goto error;    
            // This is a guess, but isn't the code just initializing
            // the `pic' that you allocated on the stack?
            //
            // Well, the following is the same.
            //
            // Oh, and should we check for errors here?
            UploadFile(current);            
            // Now we can increase counterand update our array
            array[(*counter)++] = current;
            // We have succeded, so return 0
            return 0;
        }
    error:
        printf("Memory reallocation error");
        // Release memory allocated so far
        free(*tab);
        // Prevent dangling pointer
        *counter = 0;
        *tab = NULL;
        // A non zero value means, an error
        return 1;
    }
    

    调用函数应该是这样的

    struct Picture **tabofpics;
    int counter = 0;
    // `realloc' will take car of the allocation
    tabofpics = NULL;
    if (AddPicture(&tabofpics, &picounter) == 0)
        // Everything ok, picture added
    else
        // Error
    

    请小心*** 指针,它们会引起很多混乱。我必须思考四五次

    (*tab)[*counter] = current;
    

    在我看到它是正确的之前。所以我选择更改它,如您在代码中看到的那样。

    您的代码应尽可能具有描述性,而使用 *** 指针会导致错误的方向。

    【讨论】:

    • 你是三星级程序员吗?
    • @P__J__ 不,我不是,please check my comments in the question。但是一味的说三颗星是错的,就是错的。万物皆有其用。如果您小心的话,在这种情况下三颗星也不错。当您看到我保留了 3 颗星时,请在给出您的意见之前阅读代码。我认为这是故意的,OP只是没有正确使用它。
    • @P__J__ 我会重新检查,它可能是。这就是为什么他们如此不受欢迎的原因。感谢您的反馈。
    • @P__J__ 我发现了几个问题。请再次检查,如果仍然不好,请随时告诉我。这个网站上答案的健康对我来说真的很重要。谢谢。我不知道你是否熟悉,但对于某些标签来说,答案确实很糟糕,不像c 标签通常有很好的答案。
    猜你喜欢
    • 2015-02-13
    • 2020-11-20
    • 1970-01-01
    • 2017-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多