C语言二维动态数组调整大小问题:内存泄漏与访问错误
兄弟,我一看你这段代码就知道踩了几个C语言手动管理内存的经典坑,刚好我之前也遇到过类似的问题,给你拆解清楚:
1. 最致命的问题:参数传值导致外部指针没更新
你函数的参数是int **array,但C语言里参数是值传递——也就是说,函数里的array只是外部传入指针的一个副本。当你调用realloc(array, ...)的时候,修改的是这个副本的地址,而外部的原始指针根本没变化!
举个例子:外部原来的array指向0x1234,函数里的副本array被realloc改成0x5678,但外部的指针还是0x1234,这时候外部用array[i][j]访问的还是原来的旧内存,甚至可能已经被realloc回收了,自然会出问题。
解决方法:要么把参数改成指针的指针(int ***array),要么让函数返回新的指针。我更推荐后者,代码更清晰。
2. 明显的笔误:tomb[i]应该是array[i]
你的循环里写了realloc(tomb[i], ...),但函数里根本没有tomb这个参数啊!这明显是复制粘贴或者命名错误,应该改成array[i]。不然你操作的是完全无关的数组,原来的数组内存自然会泄漏,而且新数组的内容也会乱。
3. realloc的错误使用:直接赋值会导致内存泄漏
如果realloc失败,它会返回NULL。如果你直接写array = (int**)realloc(array, ...),一旦失败,原来的array指针就会被覆盖成NULL,原来的内存就再也找不到了,直接泄漏。
正确的做法是:先用临时变量接收realloc的结果,检查不为NULL再赋值给原指针。
4. 维度调整的逻辑混乱
看你的代码,newarraysize = WINDOWY/newsize,然后把每个一维数组的大小也改成newarraysize?这看起来逻辑有点奇怪——你是想把二维数组调整成newarraysize行,每行newarraysize个元素吗?如果是这样,那参数newsize的命名就很容易误导人,建议改成更清晰的名字,比如new_col_count或者直接计算目标行列数。
修正后的代码示例
我给你改了一版,解决了上面所有问题,你可以参考:
// 返回调整后的新指针,外部直接接收即可 int** resize(int **array, int new_rows, int old_rows, int new_cols, int old_cols) { // 先调整行指针数组的大小 int** temp_array = (int**)realloc(array, new_rows * sizeof(int*)); if (temp_array == NULL) { // realloc失败,返回原指针,避免内存丢失 fprintf(stderr, "Failed to reallocate row pointers\n"); return array; } array = temp_array; // 调整每行的元素大小 if (new_rows > old_rows) { // 如果行数增加,旧行调整大小,新行需要malloc for (int i = 0; i < old_rows; i++) { int* temp_row = (int*)realloc(array[i], new_cols * sizeof(int)); if (temp_row == NULL) { fprintf(stderr, "Failed to reallocate row %d\n", i); // 这里可以选择回滚已经分配的内存,避免泄漏 return array; } array[i] = temp_row; } // 为新增的行分配内存 for (int i = old_rows; i < new_rows; i++) { array[i] = (int*)malloc(new_cols * sizeof(int)); if (array[i] == NULL) { fprintf(stderr, "Failed to allocate new row %d\n", i); // 回滚:释放新增的行 for (int j = old_rows; j < i; j++) { free(array[j]); } return array; } // 可选:初始化新行的内容,比如设为0 memset(array[i], 0, new_cols * sizeof(int)); } } else { // 如果行数减少,只调整保留的行的大小,多余的行要free避免泄漏 for (int i = 0; i < new_rows; i++) { int* temp_row = (int*)realloc(array[i], new_cols * sizeof(int)); if (temp_row == NULL) { fprintf(stderr, "Failed to reallocate row %d\n", i); return array; } array[i] = temp_row; } // 释放多余的行 for (int i = new_rows; i < old_rows; i++) { free(array[i]); } } // 打印调试信息(可选) printf("\n"); for(int i=0;i<new_rows;i++) { for(int j=0;j<new_cols;j++) printf("[%d][%d]: %p ",i,j,&array[i][j]); printf("\n"); } return array; }
使用方式
外部调用的时候,要这样接收返回值:
// 假设原来的数组是array,行数old_rows,列数old_cols array = resize(array, new_rows, old_rows, new_cols, old_cols); if (array == NULL) { // 处理分配失败的情况 }
额外注意事项
- 如果你原来的二维数组是用
malloc分配的,最后一定要记得逐层释放:先循环释放每个array[i],再释放array本身。 - 尽量不要用魔法数字或者全局变量(比如
WINDOWY),最好作为参数传入,代码更健壮。 - 如果是C++环境,建议用
std::vector代替手动管理二维数组,完全不用操心内存泄漏和resize的问题。
内容的提问来源于stack exchange,提问作者hokkyo

