`./a.out'出错:free():释放动态分配的结构的二维数组时,下一个大小(正常)无效

问题描述 投票:1回答:1

基本上,我使用calloc()创建结构的2D数组。然后我利用那个阵列,我释放了分配的空间,同时释放它我得到“双重自由或腐败(!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编译我的代码。我不明白错误消息,不知道如何调试它。我应该怎么做才能释放指针数组?

c arrays struct free calloc
1个回答
3
投票

transpose公然访问数组边界之外的元素。

fft中的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的实例生活在地址0x0000ff080x0000ff180x0000ff28等。

同样的事情发生在fft的所有元素,直到fft[63]。在这个例子中,comp实例fft[63][0]fft[63][1]fft[63][2]等生活在地址0x0001041c0x0001042c0x0001043c等。

现在考虑一下transpose的作用。它被称为这样:

transpose(&fft[0][0], len, len);

它访问这样的内存:

*((arr + (i*width)) + j)

这里arr是第一个参数;它的值是&fft[0][0],它与fft[0]相同,在我们的例子中是0x0000a000

width是64.​​ ij介于0到63之间,具体取决于我们所处的循环迭代。让我们假设它们是63。

然后i*width63*644032,而arr + 4032是指向数组的4033rd元素的指针。可是等等!没有这样的元素; 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所需的数据,这可以通过释放相同的指针两次(“双重释放”)或者只是在数组末尾写入内存(如代码中所示) )。


要修复代码,请将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个子数组中的任何一个)。

© www.soinside.com 2019 - 2024. All rights reserved.