0

在用 C 语言设计游戏实体系统时,我尝试了一种“equals-free”初始化方法。我很惊讶地看到一个 linter 告诉我在我的 init 函数结束时存在内存泄漏,并且我的变量ent从未在以下代码中初始化。事实证明是正确的,因为我遇到了“总线错误”:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int x;
    int y;
} entity_t;

void entity_init(entity_t* ent, int _x, int _y)
{
    ent = malloc(sizeof(*ent));
    ent->x = _x;
    ent->y = _y;
}

int main(void)
{
    entity_t* ent;
    entity_init(ent, 10, 24);
    printf("Entity: x%d y%d", ent->x, ent->y);
    return 0;
}

认为上面的代码会做的是将我提供的空ent指针作为参数,告诉它指向一些新分配的内存,然后填充该内存,一切都会好起来的。我不知道导致“总线错误”的真正原因是什么,我是否遗漏了一些关于指针和 malloc 的关键信息?

隐约记得之前在一些 C 代码中看到过与此非常相似的东西(equals-free struct 初始化),如果在 C 中可能发生这样的事情,我强烈希望使用类似于此(损坏的)代码的 equals-free 初始化样式.

4

2 回答 2

4

malloc调用移到初始化函数之外:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int x;
    int y;
} entity_t;

void entity_init(entity_t* ent, int _x, int _y)
{
    ent->x = _x;
    ent->y = _y;
}

int main(void)
{
    entity_t* ent;
    if(NULL==(ent = malloc(sizeof(*ent))))
        return 1;
    entity_init(ent, 10, 24);
    printf("Entity: x%d y%d", ent->x, ent->y);
    return 0;
}

您正在将指向已分配块的指针分配给局部变量(ent)。这不能影响entin main

如果您想保留mallocin entity_init,您应该使用双指针,但您还应该更改签名以允许一种方式来表示malloc失败entity_init

int entity_init(entity_t **ent, int _x, int _y)
{
    if(NULL==(*ent = malloc(sizeof(**ent))))
        return -1;
    (*ent)->x = _x;
    (*ent)->y = _y;
}

int main(void)
{
    entity_t* ent;
    if(0>entity_init(&ent, 10, 24))
        return 1;
    printf("Entity: x%d y%d", ent->x, ent->y);
    return 0;
}

更常见的模式是:

entity_t *entity_new(int _x, int _y)
{
    entity_t *ent = malloc(sizeof(*ent));
    if (NULL==ent) 
        return NULL;
    ent->x = _x;
    ent->y = _y;
    return ent;
}

int main(void)
{
    entity_t* ent;
    if(NULL==(ent=entity_new(10,24)))
        return 1;
    printf("Entity: x%d y%d", ent->x, ent->y);
    return 0;
}
于 2017-11-29T22:40:05.380 回答
1

如果必须在entity_init()函数内分配,则需要返回指向分配的指针,或者通过创建ent指向指针的指针来添加间接层entity_t。在发布的代码中,withinentity_init() ent是传递给函数的指针的副本。对该指针所做的任何更改,例如将内存分配的地址分配给指针,都不会从调用函数中看到,因为该副本将在函数返回后不复存在。

另外,请注意,您需要检查从返回的值malloc()以确保分配成功。如果成功,函数可以继续初始化过程;如果不是,ent可以保留一个空指针,应该在调用函数中检查:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int x;
    int y;
} entity_t;

void entity_init(entity_t **ent, int _x, int _y)
{
    *ent = malloc(sizeof **ent);
    if (*ent) {
        (*ent)->x = _x;
        (*ent)->y = _y;
    }
}

int main(void)
{
    entity_t *ent;
    entity_init(&ent, 10, 24);

    if (ent == NULL) {
        fprintf(stderr, "Allocation failure in entity_init()\n");
        exit(EXIT_FAILURE);
    }

    printf("Entity: x%d y%d\n", ent->x, ent->y);

    return 0;
}

程序输出:

Entity: x10 y24
于 2017-11-29T22:51:26.210 回答