为什么此 C 结构初始化代码会产生总线错误?
Why does this C struct initialization code produce a bus error?
在用 C 语言设计游戏实体系统时,我尝试了一种 "equals-free" 初始化方法。我很惊讶地看到 linter 告诉我在我的 init 函数末尾存在内存泄漏,并且我的变量 ent
从未在以下代码中初始化。结果是对的,因为我得到了 "bus error":
#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
指针作为参数提供,告诉它指向一些新分配的内存,并且然后填写那个记忆,一切都会好起来的。我不知道导致 "bus error" 的真正原因是什么,我是否遗漏了一些关于指针和 malloc 的关键信息?
我 模糊地 记得在一些 C 代码中看到过与此非常相似的东西(无等式结构初始化),我强烈希望使用无等式初始化样式类似于这个(损坏的)代码 if 这样的事情在 C 中是可能的。
将 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)。这不会影响 main
中的 ent
。
如果您想将 malloc
保留在 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;
}
如果必须在 entity_init()
函数内进行分配,则需要 return 指向分配的指针,或者通过使 ent
指向指针的指针来添加一个间接层至 entity_t
。在发布的代码中,entity_init()
ent
中是传递给函数的指针的 copy。对该指针所做的任何更改,例如将内存分配的地址分配给该指针,对于调用函数都是不可见的,因为该副本将在函数 returns.
之后不复存在。
另请注意,您需要检查从 malloc()
编辑的值 return 以确保分配成功。如果成功,该函数可以继续初始化过程;如果不是,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
在用 C 语言设计游戏实体系统时,我尝试了一种 "equals-free" 初始化方法。我很惊讶地看到 linter 告诉我在我的 init 函数末尾存在内存泄漏,并且我的变量 ent
从未在以下代码中初始化。结果是对的,因为我得到了 "bus error":
#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
指针作为参数提供,告诉它指向一些新分配的内存,并且然后填写那个记忆,一切都会好起来的。我不知道导致 "bus error" 的真正原因是什么,我是否遗漏了一些关于指针和 malloc 的关键信息?
我 模糊地 记得在一些 C 代码中看到过与此非常相似的东西(无等式结构初始化),我强烈希望使用无等式初始化样式类似于这个(损坏的)代码 if 这样的事情在 C 中是可能的。
将 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)。这不会影响 main
中的 ent
。
如果您想将 malloc
保留在 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;
}
如果必须在 entity_init()
函数内进行分配,则需要 return 指向分配的指针,或者通过使 ent
指向指针的指针来添加一个间接层至 entity_t
。在发布的代码中,entity_init()
ent
中是传递给函数的指针的 copy。对该指针所做的任何更改,例如将内存分配的地址分配给该指针,对于调用函数都是不可见的,因为该副本将在函数 returns.
另请注意,您需要检查从 malloc()
编辑的值 return 以确保分配成功。如果成功,该函数可以继续初始化过程;如果不是,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