为什么这个C struct初始化代码会产生总线错误?

时间:2017-11-29 22:36:18

标签: c pointers struct malloc bus-error

在用C设计游戏实体系统时,我尝试了一个"等于免费的"初始化方法。我很惊讶地发现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指针作为参数,告诉它指向一些新分配的内存,然后填写那个内存一切都会好的。我不知道它真正做了什么导致了一个&#34;总线错误&#34;我是否遗漏了一些关于指针和malloc的批评?

依旧记得在某些C代码中看到与之前完全相似的东西(无等分结构初始化),我更倾向于使用类似于此的无等待初始化样式(破坏) )代码如果在C中可以做这样的事情。

3 个答案:

答案 0 :(得分: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)。这不会影响ent中的main

如果您希望将malloc保留在entity_init中,则应使用双指针,但您还应更改签名以允许从{malloc发出失败信号entity_init {1}}

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

答案 1 :(得分:1)

如果必须在entity_init()函数内进行分配,则需要返回指向分配的指针,或者通过使ent指向指向entity_t的指针来添加间接层。 。在发布的代码中,entity_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

答案 2 :(得分:-1)

正如Weather Vane指出的那样,malloc会覆盖你传入本地范围内函数的指针,但是指针是按值传递的,所以你不能把它取回来。从init返回后,内存将丢失。

尝试这样的事情:

#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(entity_t *));
    *(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;
}