【问题标题】:Freeing Dynamically Allocated Struct with Flexible Array Member使用灵活的数组成员释放动态分配的结构
【发布时间】:2012-11-03 16:54:15
【问题描述】:

我有一个定义如下的数据结构:

struct varr {
    int n; //length of data array
    double data[];
};

数据数组的初始大小必须为 1,但允许增加。

struct varr * 分配空间时,我使用

struct varr *p = malloc(sizeof(struct varr) + sizeof(double));

在重新分配空间以增加我使用的数据数组的大小时

p = realloc(p, sizeof(struct varr) + p->n * sizeof(double));//p->n having already been set

我的问题是“我应该如何释放分配给这个结构的内存?”

我尝试了一个简单的free(p);,但根据 memcheck,这会导致内存泄漏。我为此目的构建数据的方式或分配内存的方式是否存在根本性问题?

==注意==

我通过使用指针而不是显式声明的数组解决了这个问题。但是,我仍然对为什么这不起作用的简明答案感兴趣。

【问题讨论】:

  • @KerrekSB 抱歉 - 这是一个错字。我实际上并没有使用 sizeof(sizeof())。我会编辑。
  • struct polystruct varr是什么关系?
  • varr::n 应该是size_t
  • @KeithRandall:也是一个错字。 KerrekSB 是的 - 但这是 C,而不是 C++
  • @PWhite:如果您正在泄漏内存,您一定是做错了其他事情(例如,如果 realloc 像 Kerreb SB 指出的那样失败,则破坏 p)。您不需要做任何特别的事情来释放涉及灵活数组成员的内存。 malloc/free 完全不知道您使用内存的目的。

标签: c malloc dynamic-allocation


【解决方案1】:

您可能知道,每次调用malloc 都会让操作系统给您一些内存并记住它的大小和属性。因此,如果您调用free,您可以清除数组或指针。

例子:

char* array = malloc(16 * sizeof(char));
char* single = malloc(sizeof(char));

free(array);
free(single);

如您所见,您总是会得到一个free 换一个malloc。那是因为操作系统知道你分配了多少字节,它不关心它是什么类型以及创建了多少个实例。 (注意:这就是 C++ 中 deletedelete[] 之间存在差异的原因,因为应用程序需要知道要运行哪些析构函数,清理的控制权不仅仅留给操作系统......)

从这里开始,我们可以假设,如果我们使用单个 malloc 将结构分配为一个块,则可以使用单个 free 调用来释放它。

这个例子对我有用,没有任何泄漏:

#include <stdlib.h>

typedef struct Array_t
{
    int Length;
    double Data[];
} Array;

Array* create_array(int length)
{
    Array* array = malloc(sizeof(Array) + length * sizeof(double));
    if (array != NULL)
        array->Length = length;

    return array;
}

void delete_array(Array* array)
{
    free(array);
}

int main()
{
    Array* array = create_array(100);
    if (array == NULL)
        return EXIT_FAILURE;

    for (int i = 0; i < array->Length; ++i)
    {
        array->Data[i] = 1.7 * (i + 3);
    }

    delete_array(array);

    return EXIT_SUCCESS;
}

当然,如果你遇到像 John Findlay 这样更复杂的例子

struct SomeStruct
{
    int Size;
    int* ArrayOfPointers[];
}

您仍然可以在一个 malloc 中创建此结构,例如

// *s* contains an array of 14 int pointers (int*)
struct SomeStruct* s = malloc(sizeof(SomeStruct) + 14 * sizeof(int*));
s->Size = 14;

核心问题是虽然int* ArrayOfPointers是一个指针数组,所以要正确初始化它,你还需要

// each of the *s*'s int pointers is actually a decayed array of 25 ints
for (int i = 0; i < s->Size; ++i)
    s->ArrayOfPointers[i] = malloc(25 * sizeof(int));

释放时:

for (int i = 0; i < s->Size; ++i)
    free(s->ArrayOfPointers[i]);

free(s);

但关键是带有 FAM 的结构仍然在一个 free 调用中被释放。循环正在释放分配的指针数据,相当于释放一个动态分配的二维数组。

【讨论】:

  • 这篇文章已经快三年了。
  • 但是我遇到了这个问题,并没有在任何地方找到解决方案/解释。
  • 我认为最初的问题归结为 3 年前我是一个相当差的 C 程序员。但这是最清楚地解释了问题和解决方案的答案,并且本着作为社区 wiki 改进堆栈溢出的精神,我已将接受的答案切换到此。
【解决方案2】:

我昨晚遇到了同样的问题。经过几个小时的谷歌搜索后,我在教程中找到了这个非常简单但聪明的答案:

void free_struct( THESTRUCT * ts )
{
// free all memory accoiated with our structure
if(ts){
    for(int i = 0; i<ts->count; i++)
        free(ts->str[i]);
    free(ts);
    }
}

http://www.johnfindlay.plus.com/lcc-win32/Tuts/FlexArrs.htm

【讨论】:

    【解决方案3】:

    这看起来完全不对。我认为应该是这样的:

    // step 1: Allocate n items:
    
    struct varr * p = malloc(sizeof *p + n * sizeof(double));
    if (p) { p->n = n; }
    

    // step 2: Reallocate to hold m items:
    
    struct varr * tmp = realloc(p, sizeof *tmp + m * sizeof(double));
    if (tmp) { p = tmp;  p->n = m; }
    

    完成后,别忘了说free(p);

    【讨论】:

    • 这会导致我的程序中断 - 给我一分钟,我会给你更多信息。
    • 抱歉,“一分钟”变成了一个小时 - 出现了看似与此代码无关的奇怪错误。无论如何,这并没有解决问题。我的内存泄漏比以前多。
    • 我现在会接受你的回答,即使它不能解决问题,因为它指出了一些原始代码做错的事情。
    猜你喜欢
    • 2012-09-22
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-25
    • 2011-03-04
    • 1970-01-01
    • 2020-04-13
    相关资源
    最近更新 更多