在struct上调用free会引发运行时错误

时间:2013-12-13 08:28:18

标签: c struct function-pointers free

我已经创建了一个基于Simple Object System的简单对象系统。然后我决定通过添加一个函数来增加代码,以释放怪物死亡时的所有内存:

void Monster_destroy(void *self)
{
    Monster* monster=self;
    if(&(monster->proto))
        free(&(monster->proto));
    free(monster);
}

我在这里使用了这个函数:

int Monster_attack(void* self,int damage)
{
    Monster* monster=self;
    char* desc=monster->proto.description;
    printf("You attack %s!\n", desc);
    monster->hit_points-=damage;
    if(monster->hit_points>0)
    {
        printf("It is still alive\n");
        return 0;
    }
    else
    {
        printf("It is dead\n");
        monster->proto.destroy(monster);
        return 1;
    }       
}

我收到以下错误:

==4699== Invalid free() / delete / delete[] / realloc()
==4699==    at 0x4C2B83A: free (vg_replace_malloc.c:468)
==4699==    by 0x40080F: Monster_destroy (ex19.c:15)
==4699==    by 0x400A2C: Room_attack (ex19.c:96)
==4699==    by 0x400ACA: Map_attack (ex19.c:118)
==4699==    by 0x400E20: process_input (ex19.c:175)
==4699==    by 0x400F52: main (ex19.c:211)
==4699==  Address 0x51fd500 is 0 bytes inside a block of size 56 free'd
==4699==    at 0x4C2B83A: free (vg_replace_malloc.c:468)
==4699==    by 0x400803: Monster_destroy (ex19.c:14)
==4699==    by 0x400A2C: Room_attack (ex19.c:96)
==4699==    by 0x400ACA: Map_attack (ex19.c:118)
==4699==    by 0x400E20: process_input (ex19.c:175)
==4699==    by 0x400F52: main (ex19.c:211)
==4699== 

我有一个Monster看起来像这样的系统:

struct Monster
{
    Object proto;
    int hit_points;
};

typedef struct Monster Monster;

Object是一个如下所示的结构:

typedef struct
{
    char *description;
    int (*init)(void *self);
    void (*describe)(void* self);
    void (*destroy)(void* self);
    void* (*move)(void* self,Direction direction);
    int (*attack)(void* self,int damage);
}Object;

这就是我现在使用的'Monster_destroy:

 if(monster && monster->hit_points>0)
{
    monster->proto.attack(monster,damage);
    return 1;
}
else
{
           //dont even call Monster_attack because Monster has no hit_points
    printf("You flail at the air and hit nothing,Idiot\n");
    if(monster)
    monster->proto.destroy(monster);
    return 0;
}

4 个答案:

答案 0 :(得分:1)

struct Monster proto Object而非Object *

因此在Monster_destroy()函数中释放这样的内存是无效的。

if(&(monster->proto))
    free(&(monster->proto));

事实上,你没有专门为proto分配内存,所以你不需要释放它。

但是,如果为proto->description分配内存,则需要使用free(proto->description)释放内存。

答案 1 :(得分:0)

struct Monster中,proto未动态分配,因此您无需释放它。

尝试没有线条:

if(&(monster->proto))
    free(&(monster->proto));
函数Monster_destroy中的

请注意,只有在您使用free()之前,才在指针上使用malloc()

答案 2 :(得分:0)

我认为它应该简单地写成:

void Monster_destroy(void *self)
{
  Monster* monster = self;
  if(&(monster->proto) != NULL)
    free(&(monster->proto));

  monster->proto = NULL;//Important
}

你对monster变量的最后一次释放是没用的(充其量),因为你传递了一个位于堆栈中的地址(当函数返回时,通过移动sp寄存器自动删除该地址)。

你应该只在动态分配的内存上使用free,就像你用'malloc'或'new'创建的那样。

答案 3 :(得分:0)

声明变量时,它们从系统堆栈中获取内存。但是当你声明指针并分配内存时,它会从堆中分配。这就是为什么你可以使用从堆分配的free()释放内存(动态)。但是你不能尝试使用free来删除在堆栈中分配的内存。