释放分配的内存时堆损坏(C)

时间:2012-07-28 16:58:23

标签: c pointers malloc free heap-corruption

我正在动态分配内存以维护项目列表,但在尝试使用free()删除项目时,我收到内存堆损坏错误。我知道这在C ++(或java,或其他任何面向对象的语言)中要容易得多,但我必须在C中这样做(注意:C代码,但在Microsoft Visual Studio 2010中编译,以及因此是C ++编译器。)

以下是项目“看起来”的内容:

//item.h
typedef struct 
{
    char* titel;
    char* auteur;
    int jaar;
} Boek;

typedef struct
{
enum {BOEK, TIJDSCHRIFT} itemType;
    union {
        Boek* boek;
        Tijdschrift* tijdschrift;
    } itemData;
    struct Item* next;
} Item;

以下是创建/分配的方式。我还在使用strdupmalloc / strcpy之间切换以分配字符串,但这似乎没有任何影响。此外,我试图删除的项目是BOEK类型,TIJDSCHRIFT分配器/解除分配器的工作方式类似。

//item.c
Item* nieuwBoek(char* _titel, char* _auteur, int _jaar)
{
    Item* item = (Item*) malloc(sizeof(Item*));
    item->itemType=BOEK;
    item->itemData.boek=(Boek*) malloc(sizeof(Boek*));
    item->itemData.boek->titel=strdup(_titel);
    item->itemData.boek->auteur=strdup(_auteur);
    item->itemData.boek->jaar=_jaar;
    item->next=NULL;
    return item;
}

然后,另一个函数将返回的指针用于将其传递给列表中上一项的item->next

以下是我试图释放它的方式。我的理解是,在释放struct本身之前我必须释放已分配的字符串,但即使我只是调用free(item)(通过在deleteItem中注释掉其他代码或通过调用它来调用它)主要代码:free(nieuwBoek(...)我收到了堆损坏错误。

void deleteItem(Item* item)
{
    if (item->itemType==BOEK)
    {
        free(item->itemData.boek->titel); // When not running in debug-mode it crashes here.
        free(item->itemData.boek->auteur);
        free(item->itemData.boek); // When running in debug mode it crashes here.
    }
    /*else if... TIJDSCHRIFT deallocator here*/
    free(item); 
}

传递给deleteItem()的指针是指向项目的有效指针。它可能是令人难以置信的愚蠢我做错了/失踪,但我现在整天都难过这个问题,所以我要求你们帮忙。哦,并且在删除项目之前next->pointer设置为NULL,因此如果重要的话,它已经从列表中断开了。

3 个答案:

答案 0 :(得分:3)

Item* item = (Item*) malloc(sizeof(Item*));

您应该将sizeof更改为sizeof(Item)sizeof(*item)。否则你会分配足够的东西来保持一个指针,对你的结构来说还不够。

我个人更喜欢sizeof *item - 如果我改变它的类型,我只需要在一个地方做。


附注:

  • 腐败意味着什么:因为你分配给了很少的记忆,何时 你填写了你的结构字段搞砸了内部记账 malloc并且下一个操作检测到它
  • 虽然是个人偏好的问题,但您可能不应该归还malloc

答案 1 :(得分:2)

这:

Item* item = (Item*) malloc(sizeof(Item*));

仅为指针分配足够的空间。您希望为整个Item结构分配足够的空间:

Item* item = (Item*) malloc(sizeof(Item));

同样这个分配:

item->itemData.boek=(Boek*) malloc(sizeof(Boek*));

应该是:

item->itemData.boek=(Boek*) malloc(sizeof(Boek));

答案 2 :(得分:0)

晚会结束,但Valgrind会检测到这类问题。我有这个问题,它让我发疯,因为GCC允许程序运行,但VC2012每次都会崩溃。 Valgrind展示了以下内容:

    Invalid write of size 8
        at 0x10CC33: appendListItem (structMgmt.c:170)
        by 0x10BB6E: parse (parse.c:304)
        by 0x10A790: runParsingTests (CTSLicense.c:562)
        by 0x109B7F: main (CTSLicense.c:41)
    Address 0x5207748 is 0 bytes after a block of size 8 alloc'd
        at 0x4C2CB3F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
        by 0x10CC2A: appendListItem (structMgmt.c:169)
        by 0x10BB6E: parse (parse.c:304)
        by 0x10A790: runParsingTests (CTSLicense.c:562)
        by 0x109B7F: main (CTSLicense.c:41)

这非常令人困惑(我已经知道C为2周了)。我不小心为指针而不是结构使用了malloc。现在我的程序在GCC和VC2012中运行没有任何问题。

使用Microsoft的pageheap检测工具对查找问题的根本原因并不是很有帮助。它确实告诉我存在堆损坏而不是显示的其他愚蠢错误,但不是问题的根源。

Microsoft's heap detection tool

Hints to using valgrind to find this problem