`./a.out' 中的错误:free():释放动态分配的二维结构数组时无效的下一个大小(正常)
Error in `./a.out': free(): invalid next size (normal) while freeing dynamically allocated 2D array of struct
基本上,我正在使用 calloc() 创建结构的二维数组。然后我利用那个数组并释放分配的 space,同时释放它我得到 "double free or corruption (!prev)"。代码是用C语言写的。
代码:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <fcntl.h>
#include <malloc.h>
#include <unistd.h>
#include <string.h>
#include <float.h>
typedef struct complex_num{
double real;
double imag;
}comp;
void transpose(comp *arr, int height, int width);
void change(comp *arr, int width);
void main(){
int width = 64, height = 64;
int len = width;
comp *fft[len];
for(int i=0; i<len; i++){
fft[i] = (comp *)calloc(len, sizeof(comp));
}
for (int scan=0;scan<height;scan++){
for (int pix=0;pix<width;pix++){
fft[scan][pix].real = 1.0;
fft[scan][pix].imag = 0.0;
}
change(&fft[scan][0], len);
}
transpose(&fft[0][0], len, len);
for(int i=0;i<len;i++){
change(&fft[i][0], len);
}
transpose(&fft[0][0], len, len);
for(int i=0;i<len;i++){
free(fft[i]);
}
}
void transpose(comp *arr, int height, int width){
comp var;
for(int i=0;i<height;i++){
for(int j=0;j<width;j++){
if(j>i){
var = *((arr + (i*width)) + j);
*((arr + i*width) + j) = *((arr + j*width) + i);
*((arr + j*width) + i) = var;
}
}
}
}
void change(comp *arr, int width){
for(int i=0; i<width; i++){
(arr + i)->real = 5.0;
(arr + i)->imag = 6.9;
}
}
错误信息:
*** Error in `./a.out': double free or corruption (!prev): 0x0000000002095010 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f05108a77e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f05108b037a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f05108b453c]
./a.out[0x400880]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f0510850830]
./a.out[0x400509]
======= Memory map: ========
00400000-00401000 r-xp 00000000 00:00 467935 /path/to/a.out
00600000-00601000 r--p 00000000 00:00 467935 /path/to/a.out
00601000-00602000 rw-p 00001000 00:00 467935 /path/to/a.out
02095000-020b6000 rw-p 00000000 00:00 0 [heap]
7f050c000000-7f050c021000 rw-p 00000000 00:00 0
7f050c021000-7f0510000000 ---p 00000000 00:00 0
7f0510610000-7f0510626000 r-xp 00000000 00:00 360788 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f0510626000-7f0510825000 ---p 00000016 00:00 360788 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f0510825000-7f0510826000 rw-p 00015000 00:00 360788 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f0510830000-7f05109f0000 r-xp 00000000 00:00 360750 /lib/x86_64-linux-gnu/libc-2.23.so
7f05109f0000-7f05109f9000 ---p 001c0000 00:00 360750 /lib/x86_64-linux-gnu/libc-2.23.so
7f05109f9000-7f0510bf0000 ---p 000001c9 00:00 360750 /lib/x86_64-linux-gnu/libc-2.23.so
7f0510bf0000-7f0510bf4000 r--p 001c0000 00:00 360750 /lib/x86_64-linux-gnu/libc-2.23.so
7f0510bf4000-7f0510bf6000 rw-p 001c4000 00:00 360750 /lib/x86_64-linux-gnu/libc-2.23.so
7f0510bf6000-7f0510bfa000 rw-p 00000000 00:00 0
7f0510c00000-7f0510c25000 r-xp 00000000 00:00 360690 /lib/x86_64-linux-gnu/ld-2.23.so
7f0510c25000-7f0510c26000 r-xp 00025000 00:00 360690 /lib/x86_64-linux-gnu/ld-2.23.so
7f0510e25000-7f0510e26000 r--p 00025000 00:00 360690 /lib/x86_64-linux-gnu/ld-2.23.so
7f0510e26000-7f0510e27000 rw-p 00026000 00:00 360690 /lib/x86_64-linux-gnu/ld-2.23.so
7f0510e27000-7f0510e28000 rw-p 00000000 00:00 0
7f0510e30000-7f0510e31000 rw-p 00000000 00:00 0
7f0510e40000-7f0510e41000 rw-p 00000000 00:00 0
7f0510e50000-7f0510e51000 rw-p 00000000 00:00 0
7f0510e60000-7f0510e61000 rw-p 00000000 00:00 0
7fffc47c7000-7fffc4fc7000 rw-p 00000000 00:00 0 [stack]
7fffc5242000-7fffc5243000 r-xp 00000000 00:00 0 [vdso]
中止(核心已转储)
我正在使用 GCC 5.4.0 版编译我的代码。我不明白错误信息,也不知道如何调试。我应该怎么做才能释放指针数组?
transpose
公然访问数组边界之外的元素。
fft
in main
是一个指针数组。每个指针都被初始化为指向一块动态分配的内存(通过calloc
)。
记忆中是这样的:
0 1 63
fft: 0 [ 0x0000a000 ] ----> [ real; imag | real; imag | ... | real; imag ]
1 [ 0x0000ff08 ] ----> [ real; imag | real; imag | ... | real; imag ]
.
.
.
63 [ 0x0001041c ] ----> [ real; imag | real; imag | ... | real; imag ]
fft
有64个元素,每个元素都是一个指针。在此示例中,fft[0]
的值为 0x0000a000
,在该地址处还有另一个 64 元素数组(由 calloc
创建),它存储类型为 comp
的值(其中是一个 2 元素结构)。
因此 *fft[0]
是第一个 comp
结构(在地址 0x0000a000
),*fft[1]
是第二个 comp
结构(在地址 0x0000a010
), *fft[2]
是第三个 comp
结构(在地址 0x0000a020
处)等。每个 comp
结构占用 16 个字节,因此地址增加 16 (0x10) . fft[0]
、fft[0][63]
的最后一个元素位于地址 0x0000a3f0
。
fft[1]
是第二个指针,指向第二个(不相关的)内存块(也是由 calloc
创建的)。在此示例中,comp
的实例位于地址 0x0000ff08
、0x0000ff18
、0x0000ff28
等
fft
直到 fft[63]
的所有元素都会发生同样的事情。在此示例中,comp
个实例 fft[63][0]
、fft[63][1]
、fft[63][2]
等位于地址 0x0001041c
、0x0001042c
、0x0001043c
等
现在考虑一下 transpose
的作用。它是这样调用的:
transpose(&fft[0][0], len, len);
它像这样访问内存:
*((arr + (i*width)) + j)
这里arr
是第一个参数;它的值为 &fft[0][0]
,与 fft[0]
相同,在我们的示例中为 0x0000a000
.
width
是 64。i
和 j
介于 0 和 63 之间,具体取决于我们所处的循环迭代。假设它们在 63。
那么i*width
就是63*64
就是4032
,而arr + 4032
就是指向数组第4033个元素的指针。可是等等!没有这样的元素; arr
只有 64 个元素。
我们现在位于内存地址 0x00019c00
,它远远超出了 fft[0]
的范围(回想一下它的元素只能到达地址 0x000a3f0
)。
但我们还没有完成:我们向这个指针添加 j
(63),得到 0x00019ff0
。这个指针就是我们用 *
.
取消引用的指针
如果我们使用数组表示法编写此操作,它看起来会像
arr[i*width + j]
这更明显地表明我们正在访问 64 元素数组的元素 4095。
transpose
甚至写入这个地址:
*((arr + i*width) + j) = ...
这会修改不属于您的程序的内存,从而破坏 malloc
/ calloc
/ free
使用的内部数据结构。这就是错误消息 double free or corruption
的意思:您的代码损坏了 free
所需的数据,这可以通过释放同一个指针两次 ("double free") 或仅写入超过数组的末尾(如代码中所示)。
要修复您的代码,请将 transpose
更改为
void transpose(comp **arr, int height, int width) {
for (int i = 0 ; i < height; i++) {
for (int j=0; j < width; j++) {
if (j > i) {
comp var = arr[i][j];
arr[i][j] = arr[j][i];
arr[j][i] = var;
}
}
}
}
并将其命名为
transpose(fft, len, len);
这样您不仅可以传递第一个子数组的地址,还可以传递中间指针数组的地址(这反过来让您可以访问 64 个子数组中的任何一个)。
基本上,我正在使用 calloc() 创建结构的二维数组。然后我利用那个数组并释放分配的 space,同时释放它我得到 "double free or corruption (!prev)"。代码是用C语言写的。
代码:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <fcntl.h>
#include <malloc.h>
#include <unistd.h>
#include <string.h>
#include <float.h>
typedef struct complex_num{
double real;
double imag;
}comp;
void transpose(comp *arr, int height, int width);
void change(comp *arr, int width);
void main(){
int width = 64, height = 64;
int len = width;
comp *fft[len];
for(int i=0; i<len; i++){
fft[i] = (comp *)calloc(len, sizeof(comp));
}
for (int scan=0;scan<height;scan++){
for (int pix=0;pix<width;pix++){
fft[scan][pix].real = 1.0;
fft[scan][pix].imag = 0.0;
}
change(&fft[scan][0], len);
}
transpose(&fft[0][0], len, len);
for(int i=0;i<len;i++){
change(&fft[i][0], len);
}
transpose(&fft[0][0], len, len);
for(int i=0;i<len;i++){
free(fft[i]);
}
}
void transpose(comp *arr, int height, int width){
comp var;
for(int i=0;i<height;i++){
for(int j=0;j<width;j++){
if(j>i){
var = *((arr + (i*width)) + j);
*((arr + i*width) + j) = *((arr + j*width) + i);
*((arr + j*width) + i) = var;
}
}
}
}
void change(comp *arr, int width){
for(int i=0; i<width; i++){
(arr + i)->real = 5.0;
(arr + i)->imag = 6.9;
}
}
错误信息:
*** Error in `./a.out': double free or corruption (!prev): 0x0000000002095010 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f05108a77e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f05108b037a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f05108b453c]
./a.out[0x400880]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f0510850830]
./a.out[0x400509]
======= Memory map: ========
00400000-00401000 r-xp 00000000 00:00 467935 /path/to/a.out
00600000-00601000 r--p 00000000 00:00 467935 /path/to/a.out
00601000-00602000 rw-p 00001000 00:00 467935 /path/to/a.out
02095000-020b6000 rw-p 00000000 00:00 0 [heap]
7f050c000000-7f050c021000 rw-p 00000000 00:00 0
7f050c021000-7f0510000000 ---p 00000000 00:00 0
7f0510610000-7f0510626000 r-xp 00000000 00:00 360788 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f0510626000-7f0510825000 ---p 00000016 00:00 360788 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f0510825000-7f0510826000 rw-p 00015000 00:00 360788 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f0510830000-7f05109f0000 r-xp 00000000 00:00 360750 /lib/x86_64-linux-gnu/libc-2.23.so
7f05109f0000-7f05109f9000 ---p 001c0000 00:00 360750 /lib/x86_64-linux-gnu/libc-2.23.so
7f05109f9000-7f0510bf0000 ---p 000001c9 00:00 360750 /lib/x86_64-linux-gnu/libc-2.23.so
7f0510bf0000-7f0510bf4000 r--p 001c0000 00:00 360750 /lib/x86_64-linux-gnu/libc-2.23.so
7f0510bf4000-7f0510bf6000 rw-p 001c4000 00:00 360750 /lib/x86_64-linux-gnu/libc-2.23.so
7f0510bf6000-7f0510bfa000 rw-p 00000000 00:00 0
7f0510c00000-7f0510c25000 r-xp 00000000 00:00 360690 /lib/x86_64-linux-gnu/ld-2.23.so
7f0510c25000-7f0510c26000 r-xp 00025000 00:00 360690 /lib/x86_64-linux-gnu/ld-2.23.so
7f0510e25000-7f0510e26000 r--p 00025000 00:00 360690 /lib/x86_64-linux-gnu/ld-2.23.so
7f0510e26000-7f0510e27000 rw-p 00026000 00:00 360690 /lib/x86_64-linux-gnu/ld-2.23.so
7f0510e27000-7f0510e28000 rw-p 00000000 00:00 0
7f0510e30000-7f0510e31000 rw-p 00000000 00:00 0
7f0510e40000-7f0510e41000 rw-p 00000000 00:00 0
7f0510e50000-7f0510e51000 rw-p 00000000 00:00 0
7f0510e60000-7f0510e61000 rw-p 00000000 00:00 0
7fffc47c7000-7fffc4fc7000 rw-p 00000000 00:00 0 [stack]
7fffc5242000-7fffc5243000 r-xp 00000000 00:00 0 [vdso]
中止(核心已转储)
我正在使用 GCC 5.4.0 版编译我的代码。我不明白错误信息,也不知道如何调试。我应该怎么做才能释放指针数组?
transpose
公然访问数组边界之外的元素。
fft
in main
是一个指针数组。每个指针都被初始化为指向一块动态分配的内存(通过calloc
)。
记忆中是这样的:
0 1 63
fft: 0 [ 0x0000a000 ] ----> [ real; imag | real; imag | ... | real; imag ]
1 [ 0x0000ff08 ] ----> [ real; imag | real; imag | ... | real; imag ]
.
.
.
63 [ 0x0001041c ] ----> [ real; imag | real; imag | ... | real; imag ]
fft
有64个元素,每个元素都是一个指针。在此示例中,fft[0]
的值为 0x0000a000
,在该地址处还有另一个 64 元素数组(由 calloc
创建),它存储类型为 comp
的值(其中是一个 2 元素结构)。
因此 *fft[0]
是第一个 comp
结构(在地址 0x0000a000
),*fft[1]
是第二个 comp
结构(在地址 0x0000a010
), *fft[2]
是第三个 comp
结构(在地址 0x0000a020
处)等。每个 comp
结构占用 16 个字节,因此地址增加 16 (0x10) . fft[0]
、fft[0][63]
的最后一个元素位于地址 0x0000a3f0
。
fft[1]
是第二个指针,指向第二个(不相关的)内存块(也是由 calloc
创建的)。在此示例中,comp
的实例位于地址 0x0000ff08
、0x0000ff18
、0x0000ff28
等
fft
直到 fft[63]
的所有元素都会发生同样的事情。在此示例中,comp
个实例 fft[63][0]
、fft[63][1]
、fft[63][2]
等位于地址 0x0001041c
、0x0001042c
、0x0001043c
等
现在考虑一下 transpose
的作用。它是这样调用的:
transpose(&fft[0][0], len, len);
它像这样访问内存:
*((arr + (i*width)) + j)
这里arr
是第一个参数;它的值为 &fft[0][0]
,与 fft[0]
相同,在我们的示例中为 0x0000a000
.
width
是 64。i
和 j
介于 0 和 63 之间,具体取决于我们所处的循环迭代。假设它们在 63。
那么i*width
就是63*64
就是4032
,而arr + 4032
就是指向数组第4033个元素的指针。可是等等!没有这样的元素; arr
只有 64 个元素。
我们现在位于内存地址 0x00019c00
,它远远超出了 fft[0]
的范围(回想一下它的元素只能到达地址 0x000a3f0
)。
但我们还没有完成:我们向这个指针添加 j
(63),得到 0x00019ff0
。这个指针就是我们用 *
.
如果我们使用数组表示法编写此操作,它看起来会像
arr[i*width + j]
这更明显地表明我们正在访问 64 元素数组的元素 4095。
transpose
甚至写入这个地址:
*((arr + i*width) + j) = ...
这会修改不属于您的程序的内存,从而破坏 malloc
/ calloc
/ free
使用的内部数据结构。这就是错误消息 double free or corruption
的意思:您的代码损坏了 free
所需的数据,这可以通过释放同一个指针两次 ("double free") 或仅写入超过数组的末尾(如代码中所示)。
要修复您的代码,请将 transpose
更改为
void transpose(comp **arr, int height, int width) {
for (int i = 0 ; i < height; i++) {
for (int j=0; j < width; j++) {
if (j > i) {
comp var = arr[i][j];
arr[i][j] = arr[j][i];
arr[j][i] = var;
}
}
}
}
并将其命名为
transpose(fft, len, len);
这样您不仅可以传递第一个子数组的地址,还可以传递中间指针数组的地址(这反过来让您可以访问 64 个子数组中的任何一个)。