C程序中的“double free or corruption (!prev)”错误

36
运行c程序时,我遇到了以下错误:
*** glibc detected *** ./a.out: double free or corruption (!prev): 0x080b8008 ***

我认为这是由于程序结束时调用了free(),但我无法确定在此之前malloc分配的内存被释放了。以下是代码:

#include <stdio.h>
#include <stdlib.h> //malloc
#include <math.h>  //sine

#define TIME 255
#define HARM 32

int main (void) {
    double sineRads;
    double sine;
    int tcount = 0;
    int hcount = 0;
    /* allocate some heap memory for the large array of waveform data */
    double *ptr = malloc(sizeof(double *) * TIME);
    if (NULL == ptr) {
        printf("ERROR: couldn't allocate waveform memory!\n");
    } else {
        /*evaluate and add harmonic amplitudes for each time step */
        for(tcount = 0; tcount <= TIME; tcount++){
            for(hcount = 0; hcount <= HARM; hcount++){
                sineRads = ((double)tcount / (double)TIME) * (2*M_PI); //angular frequency
                sineRads *= (hcount + 1); //scale frequency by harmonic number
                sine = sin(sineRads); 
                *(ptr+tcount) += sine; //add to other results for this time step
            }
        }
        free(ptr);
        ptr = NULL;     
    }
    return 0;
}

这是使用以下内容编译的:

gcc -Wall -g -lm test.c

Valgrind:

valgrind --leak-check=yes ./a.out

提供:

    ==3028== Memcheck, a memory error detector
==3028== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==3028== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==3028== Command: ./a.out
==3028== 
==3028== Invalid read of size 8
==3028==    at 0x8048580: main (test.c:25)
==3028==  Address 0x41ca420 is 1,016 bytes inside a block of size 1,020 alloc'd
==3028==    at 0x4024F20: malloc (vg_replace_malloc.c:236)
==3028==    by 0x80484F8: main (test.c:15)
==3028== 
==3028== Invalid write of size 8
==3028==    at 0x8048586: main (test.c:25)
==3028==  Address 0x41ca420 is 1,016 bytes inside a block of size 1,020 alloc'd
==3028==    at 0x4024F20: malloc (vg_replace_malloc.c:236)
==3028==    by 0x80484F8: main (test.c:15)
==3028== 
==3028== 
==3028== HEAP SUMMARY:
==3028==     in use at exit: 0 bytes in 0 blocks
==3028==   total heap usage: 1 allocs, 1 frees, 1,020 bytes allocated
==3028== 
==3028== All heap blocks were freed -- no leaks are possible
==3028== 
==3028== For counts of detected and suppressed errors, rerun with: -v
==3028== ERROR SUMMARY: 8514 errors from 2 contexts (suppressed: 14 from 7)

我对不自动管理内存的语言没有太多经验(因此这个c练习是为了学习一些知识),但我卡住了。任何帮助都将不胜感激。

这段代码应该是合成器中的一部分。在这方面它确实有效,并且给出了存储在ptr中的正确输出。

谢谢。

4个回答

29
double *ptr = malloc(sizeof(double *) * TIME);
/* ... */
for(tcount = 0; tcount <= TIME; tcount++)
                         ^^
  • 您超出了数组边界。请将 <= 更改为 < 或分配 SIZE + 1 个元素。
  • 您的 malloc 错误,应该使用 sizeof(double) 而不是 sizeof(double *)
  • 正如ouah所评论的那样,虽然与您的破坏问题没有直接关联,但您正在使用未初始化的 *(ptr+tcount)

  • 作为风格提示,您可以使用 ptr[tcount] 而不是 *(ptr + tcount)
  • 由于您已经知道 SIZE,因此您实际上不需要进行 malloc + free

2
同样的表达式 *(ptr+tcount) += sine;,但是该数组从未初始化过。 - ouah
2
@ouah 好判断。这个程序比瑞士奶酪还要多漏洞。 - cnicutar
瑞士奶酪真的很复杂!感谢您的帮助。看起来我还有很长的路要走才能真正掌握指针和动态内存分配。 - user1640921

7

修改这一行

double *ptr = malloc(sizeof(double *) * TIME);

为了

double *ptr = malloc(sizeof(double) * TIME);

4

1 - 你的malloc()函数有误。
2 - 你正在超出已分配内存的边界。
3 - 你应该初始化你已分配的内存。

下面是需要进行更改的程序。我已经编译和运行它,没有任何错误或警告。

#include <stdio.h>
#include <stdlib.h> //malloc
#include <math.h>  //sine
#include <string.h>

#define TIME 255
#define HARM 32

int main (void) {
    double sineRads;
    double sine;
    int tcount = 0;
    int hcount = 0;
    /* allocate some heap memory for the large array of waveform data */
    double *ptr = malloc(sizeof(double) * TIME);
     //memset( ptr, 0x00, sizeof(double) * TIME);  may not always set double to 0
    for( tcount = 0; tcount < TIME; tcount++ )
    {
         ptr[tcount] = 0; 
    }

    tcount = 0;
    if (NULL == ptr) {
        printf("ERROR: couldn't allocate waveform memory!\n");
    } else {
        /*evaluate and add harmonic amplitudes for each time step */
        for(tcount = 0; tcount < TIME; tcount++){
            for(hcount = 0; hcount <= HARM; hcount++){
                sineRads = ((double)tcount / (double)TIME) * (2*M_PI); //angular frequency
                sineRads *= (hcount + 1); //scale frequency by harmonic number
                sine = sin(sineRads); 
                ptr[tcount] += sine; //add to other results for this time step
            }
        }
        free(ptr);
        ptr = NULL;     
    }
    return 0;
}

1
关于 memset:所有位都是0并不一定意味着存储的双精度值为0。 - cnicutar
@cnicutar 这是因为浮点变量的表示是实现定义的吗? - Chimera
这是因为并不保证所有浮点数格式都将0表示为所有位都为0。 - cnicutar

3
我猜测错误出现在malloc调用中,但我没有检查所有的代码。你需要替换掉代码中的
 double *ptr = malloc(sizeof(double*) * TIME);

对于

 double *ptr = malloc(sizeof(double) * TIME);

因为你想要给一个双精度浮点数分配空间(而不是指向双精度浮点数的指针的大小)。


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