C语言三维数组malloc分配后free失败问题排查
三维数组内存分配后free失败的问题分析
我是一名C语言初学者,正在修改一个使用malloc分配多维数组的程序,需要将二维数组改为三维数组。我知道这并非处理多维数组的标准方式,但这是现有程序已采用的实现。修改后我发现数组可正常使用且所有内存分配均不为NULL,但free()函数执行失败,希望得到详细解释。
原始可运行代码
#include <stdio.h> #include <stdlib.h> double ***AllocArray3D(short ix, int iy, int iz){ double ***A3D; ix++; iy++; A3D = (double ***)malloc(ix * sizeof(double **)); int i, j; for (i = 0; i < ix; i++) { A3D[i] = (double **)malloc(iy * sizeof(double *)); for (j = 0; j < iy; j++) { A3D[i][j] = (double *)malloc(iz * sizeof(double)); if(!(j+1 < iy))printf("alloc i=%d,j=%d\n",i,j); //debug } } return A3D; } void FreeArray3D(double *** A3D, int ix, int iy){ ix++; iy++; int i, j; for (i = 0; i < ix; i++) { for (j = 0; j < iy; j++) { if(!(j+1 < iy)) printf("free i=%d,j=%d\n",i,j); //wenn das der letzte durchlauf ist printe free(A3D[i][j]); } free(A3D[i]); } free(A3D); } int main(){ int a=99, b=99; double *** A_xyz; A_xyz = AllocArray3D(a, b, 1309); FreeArray3D(A_xyz, a, b); return 0; }
两种导致free失败的修改情况
第一种修改后的函数
double ***AllocArray3D(short ix, int iy, int iz){ double ***A3D;//x++; iy++; A3D = (double ***)malloc(ix * sizeof(double **)); int i, j; for (i = 0; i < (ix+1); i++) { A3D[i] = (double **)malloc(iy * sizeof(double *)); for (j = 0; j < (iy+1); j++) { A3D[i][j] = (double *)malloc(iz * sizeof(double)); if(!(j+1 < iy))printf("alloc i=%d,j=%d\n",i,j); //debug } } return A3D; }
第二种修改后的函数(忘记注释掉ix++; iy++;)
double ***AllocArray3D(short ix, int iy, int iz){ double ***A3D; ix++; iy++; A3D = (double ***)malloc(ix * sizeof(double **)); int i, j; for (i = 0; i <= ix; i++) { A3D[i] = (double **)malloc(iy * sizeof(double *)); for (j = 0; j <= iy; j++) { A3D[i][j] = (double *)malloc(iz * sizeof(double)); if(!(j+1 < iy))printf("alloc i=%d,j=%d\n",i,j); //debug } } return A3D; }
问题根源:内存越界破坏堆结构
两种修改都存在堆内存越界访问的问题,这会破坏堆管理器维护的内存元数据,导致后续free操作失败:
第一种修改的问题
- 注释掉
ix++; iy++;后,malloc(ix * sizeof(double **))只分配了能容纳ix个double**指针的内存,合法下标范围是0到ix-1。 - 但循环条件写成
i < (ix+1),会让循环执行ix+1次,最终访问A3D[ix]——这已经超出了分配的内存范围。 - 越界写入
A3D[ix]会覆盖堆的关键管理信息,堆管理器在后续free时检测到结构异常,直接触发错误。
- 注释掉
第二种修改的问题
- 先执行了
ix++; iy++;,此时ix的值是传入参数+1,malloc(ix * sizeof(double **))分配的内存合法下标范围是0到ix-1。 - 但循环条件写成
i <= ix,会访问A3D[ix],超出分配范围;内层循环j <= iy同样会访问A3D[i][iy],超出每个A3D[i]分配的iy个double*的范围。 - 两层越界都会破坏堆元数据,导致free时堆校验失败。
- 先执行了
补充说明:为什么数组能正常使用?
越界访问的内存可能暂时属于进程地址空间且未被其他数据占用,所以程序在使用数组时不会立刻崩溃,但堆结构已经被悄悄破坏。当执行free时,堆管理器会检查内存块的完整性,此时就会发现异常并终止程序。
内容的提问来源于stack exchange,提问作者merlin
相关产品推荐
相关产品推荐

