如何释放结构体中的可增长(使用realloc)动态数组?

hmae6n7t  于 2022-12-22  发布在  其他
关注(0)|答案(1)|浏览(166)

在中断了很长一段时间后,我重新访问了C语言,并且一直在使用可增长数组来帮助我回到手动内存管理。我使用了University of Exeter中的修改代码。
我试图从结构体中的数组(在本例中为整数)中释放单独分配的元素,但是在这样做时遇到了麻烦。
首先,我创建一个结构体来保存一个整数数组、当前的元素数和缓冲区大小,以便跟踪分配的内存。

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/calloc数组,但是根据我所读到的,循环遍历所有元素并释放每个元素(每次分配释放一个元素)是正确的方法,但是我似乎不能正确地做到这一点,我调用一个helper函数来释放内存:

void free_struct(IntArray *intArr)
{
    for(int i = 0; i < intArr->bufferLen; i++){
        free(intArr->values[i]);
    }
}

我可以粘贴我在使用上面的free_struct函数时遇到的许多错误,但我会永远呆在这里,它们的范围从期待void * 到无效类型参数,到double frees和其他类似的错误。

**编辑:**我忽略了提到我所面临的最大问题,根据Valgrind的说法,这是一个内存泄漏。公认的答案解决了这个问题,因为正确地解引用intArr->values允许我释放相同的intArr->values,然后释放intArr本身。

1mrurvl1

1mrurvl11#

添加以下内容时此代码中存在问题:

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项中缺少解引用星号。
请注意,当一个 * involved * 语句没有分布在多行源代码中时,这是多么容易阅读。我建议使用有意义但简短的变量名。源代码需要是"可扫描的",而不是"在冬天晚上的炉火旁可读的"。
注意,元素的大小是整数的大小,而不是指针的大小。当存储的整数变成存储的结构体时,这一点就变得很重要了。
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() failure\n" );
        exit( 1 );
    }
}

既然已经澄清了这个问题,那么"free()"问题应该更容易理解了。
指向数组的一个指针指向一个连续的内存块。您只需要一个free( arr->vals );就可以释放整个内存块。
当数组以GROWBY为增量"增长"时,您可能希望尝试删除一个随机元素(包括在数组中向上移动后续元素;参见memmove()),甚至当数组底部有SHRINKBY个未使用的元素时缩小数组(再次为realloc())...

    • 编辑:**

由于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() failed\n" );
        exit( 1 );
    }
    return arr;
}

相关问题