C 在结构上调用free会引发运行时错误

C 在结构上调用free会引发运行时错误,c,struct,function-pointers,free,C,Struct,Function Pointers,Free,我基于创建了一个简单的对象系统。然后,我决定通过添加一个函数来扩充代码,以便在怪物死亡时释放所有关于它的内存: void Monster_destroy(void *self) { Monster* monster=self; if(&(monster->proto)) free(&(monster->proto)); free(monster); } 我在这里使用的函数如下: int Monster_attack(void*

我基于创建了一个简单的对象系统。然后,我决定通过添加一个函数来扩充代码,以便在怪物死亡时释放所有关于它的内存:

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;
    }       
}
struct Monster
{
    Object proto;
    int hit_points;
};

typedef struct Monster Monster;
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;
void Monster_destroy(void *self)
{
  Monster* monster = self;
  if(&(monster->proto) != NULL)
    free(&(monster->proto));

  monster->proto = NULL;//Important
}
我得到以下错误:

==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== 
我有一个怪物看起来像这样的系统:

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;
    }       
}
struct Monster
{
    Object proto;
    int hit_points;
};

typedef struct Monster Monster;
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;
void Monster_destroy(void *self)
{
  Monster* monster = self;
  if(&(monster->proto) != NULL)
    free(&(monster->proto));

  monster->proto = NULL;//Important
}
对象
是一个如下所示的结构:

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;
    }       
}
struct Monster
{
    Object proto;
    int hit_points;
};

typedef struct Monster Monster;
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;
void Monster_destroy(void *self)
{
  Monster* monster = self;
  if(&(monster->proto) != NULL)
    free(&(monster->proto));

  monster->proto = NULL;//Important
}
这就是我现在使用“怪物”的方式:

 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;
}

struct Monster
中,
proto
不是动态分配的,因此您不必释放它

尝试不使用以下行:

if(&(monster->proto))
    free(&(monster->proto));
在函数
Monster\u destroy


请记住,只有在指针上使用过
malloc()
时,才在指针上使用
free()

struct Monster
中,proto是
对象
不是
对象*

所以在
Monster\u destroy()
函数中这样释放内存是无效的

if(&(monster->proto))
    free(&(monster->proto));
事实上,您没有专门为
proto
分配内存,因此不需要释放它


但是,如果为
proto->description
分配了内存,则需要使用
free(proto->description)
释放内存。我认为应该这样编写:

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;
    }       
}
struct Monster
{
    Object proto;
    int hit_points;
};

typedef struct Monster Monster;
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;
void Monster_destroy(void *self)
{
  Monster* monster = self;
  if(&(monster->proto) != NULL)
    free(&(monster->proto));

  monster->proto = NULL;//Important
}
上次对monster变量执行的释放是无用的(充其量),因为您正在将一个地址传递到堆栈中(当函数返回该地址时,会通过将sp寄存器移回自动删除该地址)


您应该只在动态分配的内存上使用free,就像您使用“malloc”或“new”创建的内存一样。

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

我认为最后这个free(monster)是没有用的,因为它只是堆栈上的一个指针(您没有在堆上分配它)。虽然您发布的代码的答案听起来是正确的,我想指出一个事实,Valgrind显示的调用堆栈与
怪物攻击
无关,尽管存在
房间攻击
。你确定你有正确的函数吗?哦,等等,我把Monster_destroy的调用从Monster_攻击改为Room_攻击,因为我想看看它是否在那里工作。因为
proto
不是动态分配的,所以你不能对它使用
free()
。因此,您的代码是错误的。在释放
description
后,如何将
proto
设置为
NULL
,正如上面的一个答案所述,当从类型“void*”分配给类型“Object”时,它会给我
不兼容的类型。