C语言中使用malloc函数进行内存分配时出现了意料之外的结果。

7

我需要为4个指向浮点数(2D)的指针分配内存,这要在多次迭代(6次)中进行。但是在第二次迭代时,malloc为两个分配提供了相同的地址。代码:

int i=0, a=0;
for(i=0;i<6;i++)
{
    float** P_i=(float**) malloc(4*sizeof(float*));
    for(a=0;a<4;a++)    P_i[a]=(float*) calloc(4,sizeof(float));

    for(a=0;a<4;a++)    free(P_i[a]);
    free(P_i);
}

使用gdb进行调试:

(gdb) print i
$42 = 1
(gdb) set $pos=0
(gdb) print P_i[$pos++]
$51 = (float *) 0x804d500
(gdb) print P_i[$pos++]
$52 = (float *) 0x804d148
(gdb) print P_i[$pos++]
$53 = (float *) 0x804d4e8
(gdb) print P_i[$pos++]
$54 = (float *) 0x804d500

P_i[0]和P_i[3]指向同一个地址0x804d500,我找不到原因: /


3
C还是C++?使用malloc函数倾向于使用C语言,但转换它返回的void *指针则属于C++。如果你在使用C语言,请不要强制转换malloc函数返回的指针类型。 - Elias Van Ootegem
1
你使用的是哪个编译器?如果它在强制转换 malloc 返回值时出现问题,很可能你正在使用 C++ 编译器。 - Elias Van Ootegem
2
你在哪一行出错了? - molbdnilo
4
你能否在malloc和free循环之间添加一个for循环以打印地址,而不是使用gdb? - Radoslav Hristov
2
我的二维结构共享相同的地址,这需要在代码中显示出现,而不是调试器。发布导致问题的最小完整代码。也许早期的真实代码正在破坏内存,而你在这里看到的只是后果。 - chux - Reinstate Monica
显示剩余18条评论
2个回答

2

在第一个for循环(a=0;a<4;a++)和第二个(free之前)之间

我猜gdb会在循环的最后一次迭代之前中断,也就是在最后一个calloc()调用之前。如果是这种情况,那么P_i[3]将会有上一次迭代的地址。

顺便说一下,当一行代码有多个语句时,使用gdb会很困难。


中断点设置在两个for循环之间的空白行上,执行会在第二个for循环的指令处停止(但甚至不会开始循环)。我还没有完全掌握gdb!但到目前为止,我真的对它的灵活性印象深刻。 - DahoM
我怀疑这是最接近现实的。代码没有使用 P_i[3],而且可能已经进行了某些优化,导致断点不在源代码中出现的位置。 - chux - Reinstate Monica

1
有关信息不足,无法回答,但让我试试。
代码看起来没问题。我也无法重现你的问题。
你实际上不能在空行上设置断点。我猜这会使它停在一个带有free的行上。
我的猜测是,你的代码启用了优化,这可能重新排列了东西,确保你不确定执行已停止的位置。禁用优化并重新构建(在GCC上为-O0)。或者向我们展示反汇编(包括当前打印的PC)。
我的Ubuntu gcc运行(Ubuntu 4.8.4-2ubuntu1〜14.04.1)4.8.4使用-O0 -g构建,在free之前停在一行:

(gdb) 打印 i
$1 = 0
(gdb) 设定 $pos=0
(gdb) 打印 P_i[$pos++]
$2 = (float *) 0x602040
(gdb) 打印 P_i[$pos++]
$3 = (float *) 0x602060
(gdb) 打印 P_i[$pos++]
$4 = (float *) 0x602080
(gdb) 打印 P_i[$pos++]
$5 = (float *) 0x6020a0
(gdb) 回溯
#0 main () at malloc.c:12
(gdb) 列出
7 for(i=0;i<6;i++)
8 {
9 float** P_i=(float**) malloc(4*sizeof(float*));
10 for(a=0;a<4;a++) P_i[a]=(float*) calloc(4,sizeof(float));
11
12 for(a=0;a<4;a++) free(P_i[a]);

你的源代码是否存在问题,即使你单独构建它(不是较大程序的一部分)?你是否有自定义的calloc / malloc实现?"nm your-executable|grep calloc"显示什么?它应该像这样:

U calloc@@GLIBC_2.2.5


谢谢你的帮助。似乎在第一次迭代后出现了某个内存损坏问题。我正在调查并会尽快转发。 - DahoM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接