You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言自定义动态数组内存异常问题:多数组交替添加元素时出错

C语言自定义动态数组内存异常问题:多数组交替添加元素时出错

哥们,我一眼就看出你的问题核心了——realloc扩容后没有同步更新外部的数组指针!这直接导致了野指针访问,进而出现诡异的内存错误。

问题根源分析

你的动态数组设计思路是对的:把元数据(长度、步长、容量)存在用户可见指针的前面,用户拿到的指针直接指向数据区。但在_arr_add函数里,当需要扩容调用realloc时,会出现一个关键问题:
realloc可能会把整个内存块(元数据+数据区)移动到新的内存地址,这时候你手里的raw指针已经指向新地址了,但用户传入的arr指针(也就是用户代码里的arr1、arr2)还是指向旧的内存地址——而旧地址已经被realloc释放或复用了。

当你单独操作一个数组时,有时候realloc会直接在原地址后追加空间(不需要移动),所以看起来没问题,但这是运气好的未定义行为;而交替操作两个数组时,内存分配更复杂,realloc移动了其中一个数组的内存,导致另一个数组的元数据被覆盖,就出现了你看到的诡异LENGTH值(1544099056),后续的memcpy也会因为野指针踩内存导致程序崩溃。

另外还有个小问题:你用%d打印size_t类型的变量,这会导致类型不匹配,也是出现奇怪数字的原因之一,size_t应该用%zu格式符。

解决方案

要让_arr_add能更新用户手里的数组指针,必须把函数参数改成指针的指针(void**),这样扩容后就能把新的指针地址同步回用户的变量里。

修改后的代码片段

  1. 先修改_arr_add的函数定义:
void _arr_add(void **arr, void *num) {
    // 从用户传入的指针(现在是指针的指针)获取元数据起始地址
    size_t *raw = ((size_t *)*arr) - NUM_PROPERTIES;
    // 用%zu打印size_t类型,避免类型不匹配
    printf("LENGTH: %zu\n", raw[LENGTH]);

    if (raw[LENGTH] == raw[CAPACITY]) {
        raw[CAPACITY] *= 2;
        size_t *new_raw = realloc(raw, sizeof(size_t) * NUM_PROPERTIES + raw[CAPACITY] * raw[STRIDE]);
        if (new_raw == NULL) {
            fprintf(stderr, "Error reallocating memory in _arr_add()\n");
            exit(1);
        }
        raw = new_raw;
        // 关键:更新外部的数组指针,指向新的数据区起始地址
        *arr = (void *)(raw + NUM_PROPERTIES);
    }

    // 转成char*做指针运算(C标准不允许void*直接加减)
    memcpy((char*)*arr + raw[LENGTH] * raw[STRIDE], num, raw[STRIDE]);
    raw[LENGTH]++;
}
  1. 同步修改arr_add宏,传入数组指针的地址:
#define arr_add(arr, num) _arr_add(&arr, &num)

验证效果

修改后,当你交替给arr1和arr2添加元素时,每次realloc都会自动更新用户手里的数组指针,不会再出现野指针访问的情况,LENGTH值会正常递增,程序也能稳定运行。

备注:内容来源于stack exchange,提问作者champson1864

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 08:53:09