在很长一段时间的休息之后,我重新访问了C语言,并且一直在专门利用可增长数组来帮助我回到手动内存管理。我使用的修改代码来自埃克塞特大学,并归功于埃克塞特大学)。
我试图在一个结构体中从一个(在这种情况下是整数)数组中释放单独分配的元素,但我在这样做时遇到了麻烦。
首先,我创建了一个结构体来保存一个整数数组、当前元素的数量和缓冲区大小,以跟踪已分配的内存。
typedef struct int_array
{
int *values;
int numValues;
int bufferLen;
} IntArray;
然后使用以下命令创建初始结构体:
IntArray *new_int_array(void)
{
IntArray *intArr;
intArr = calloc(1, sizeof *intArr);
intArr->bufferLen = intArr->numValues = 0;
intArr->values = NULL;
return intArr;
}
最后,向数组中添加元素:
void add_element_to_array(IntArray *intArr, int
values)
{
// Check to see if array extension needed
if (intArr->numValues == intArr->bufferLen) {
intArr->bufferLen += GROWBY; // #define GROWBY 16
intArr->values = realloc
(intArr->values, intArr->bufferLen *
sizeof intArr->values);
}
intArr->values[intArr->numValues] =
values;
intArr->numValues++;
}
我习惯了释放一个单malloc/callloc数组,但是从我所读到的循环遍历所有元素并释放每个元素(每个分配一个自由)将是正确的方式,但我似乎不能得到它的权利。我正在调用一个辅助函数来释放内存:
void free_struct(IntArray *intArr)
{
for(int i = 0; i < intArr->bufferLen; i++){
free(intArr->values[i]);
}
}
我可以粘贴我在玩上面的free_struct函数时得到的许多错误,但我将永远在这里。它们的范围从期望void *到无效类型参数,到双自由度和其他。
编辑:我没有提到我所面临的最大问题,根据Valgrind的说法,那就是内存泄漏。被接受的答案解决了这个问题,因为正确地解引用intArr->values
允许我释放相同的intArr->values
,然后释放intArr
本身。
这段代码在添加
时出现了一个问题if (intArr->numValues == intArr->bufferLen) {
intArr->bufferLen += GROWBY; // #define GROWBY 16
intArr->values = realloc
(intArr->values, intArr->bufferLen *
sizeof intArr->values);
}
这是解决问题的方法:
if( arr->nVal == arr->bufLen) {
arr->bufLen += GROWBY; // #define GROWBY 16
arr->vals = realloc( arr->vals, arr->bufLen * sizeof *arr->vals );
// NOTICE ^
}
OP代码在表达式的sizeof
项中缺少解引用星号。
请注意,当涉及的语句没有分布在多行源代码中时,这是多么容易阅读。我建议使用有意义但简短的变量名。源代码需要是"可扫描的",而不是"在冬天的晚上在火炉旁可读的"。
注意,元素的大小是整数的大小,而不是指针的大小。当存储的整数变为存储的结构体时,这一点将变得非常重要。
当alloc
家族在任务中失败时,通常没有其他选择,只能优雅地退出。使用NULL指针继续处理(直到崩溃)是不合适的。
if( arr->nVal == arr->bufLen) {
arr->bufLen += GROWBY; // #define GROWBY 16
arr->vals = realloc( arr->vals, arr->bufLen * sizeof *arr->vals );
if( arr->vals == NULL ) {
fprintf( stderr, "realloc() failuren" );
exit( 1 );
}
}
现在这个问题已经解决了,'free() '问题应该更容易理解了。
指向数组的指针指向一个连续的内存块。你只需要一个free( arr->vals );
来释放整个块。
当这个以GROWBY
的增量"增长"数组时,你可能想要尝试删除一个随机元素(包括将数组中的后续元素向上移动;见memmove()
),甚至收缩数组(再次realloc()
),当有SHRINKBY
未使用的元素在数组的底部…
编辑:
由于calloc()
保证分配的字节将被设置为0,因此:
IntArray *new_int_array(void)
{
IntArray *intArr;
intArr = calloc(1, sizeof *intArr);
intArr->bufferLen = intArr->numValues = 0;
intArr->values = NULL;
return intArr;
}
可以简化为:
IntArray *new_int_array(void)
{
IntArray *arr = calloc(1, sizeof *arr);
if( arr == NULL ) {
fprintf( stderr, "calloc() failedn" );
exit( 1 );
}
return arr;
}