c-释放具有灵活数组成员的动态分配结构



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

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,这会导致内存泄漏。我为此目的构建数据的方式,或者我分配内存的方式,是否存在根本问题?

===注意===

我已经通过使用指针而不是显式声明的数组解决了这个问题。然而,我仍然有兴趣找到一个简洁的答案来解释为什么这不起作用。

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

示例:

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

正如您所看到的,一个malloc总是得到一个free。这是因为操作系统知道你分配了多少字节,它不在乎它是什么类型以及创建了多少实例。(注意:这就是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调用中仍然是空闲的。循环释放已分配的指针数据,相当于释放动态分配的2D数组。

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

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

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

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

相关内容

  • 没有找到相关文章

最新更新