malloc的不同方式之间的区别

时间:2015-02-26 19:29:45

标签: c malloc

struct node{
  int w;
  int x;
}
struct node *item;
  1. 请解释这些陈述之间的区别。
  2. 我在不需要malloc后读作类型转换。为什么会这样?

    1)item = malloc(sizeof(*item));

    2)item = malloc(sizeof(struct node));

    3)item = (struct node *) malloc(sizeof(struct node));

4 个答案:

答案 0 :(得分:2)

在这种特殊情况下,所有方法都会给出完全相同的结果。

1:

item = malloc(sizeof(*item));

*itemstruct node,因此sizeof(*item)将返回struct node的大小,该行将为单个节点分配内存。这有时优先于2),就好像你要将item重构为不同的类型一样,你不需要改变这一行。

2:

item = malloc(sizeof(struct node));

这一行相当不言自明。如前所述,如果item要更改类型,则需要更改此行,因为分配的内存量将不再正确(除非是纯粹的运气)。

3:

malloc会返回指向voidvoid *的指针。即使没有强制转换,它也会自动转换为正确的类型。事实上,有几个人(包括我自己)会建议你强烈不要使用类型转换器。有关详细信息,请阅读this question

的已接受答案

答案 1 :(得分:2)

让我们看看这些:

1) item = malloc(sizeof(*item));

上面的代码是C中的经典方法。使用calloc可能更安全,因为它将清除分配给所有位零的结构。如果稍后向结构添加字段并忘记在分配的每个实例中的malloc之后的代码中初始化,这将是一个有用的副作用。我会这么推荐:

1 preferred) item = calloc(1, sizeof(*item)); 

以下替代方案假设item是指向struct node的指针。当您第一次编写代码时可能会出现这种情况,如果您稍后更改item的类型,或者如果您将代码复制到item不同类型的其他位置并且您忘记了做出改变。

2) item = malloc(sizeof(struct node));

最后一个选项展示了另一个问题:

3) item = (struct node *) malloc(sizeof(struct node));

转换malloc的返回值的问题在其他地方已经有很多评论。它在C ++中是必要的,并且在C语言中被认为是无用的并且可能容易出错。在某种情况下它可能实际上有用的目的:

#define alloc_node()  ((struct node*)calloc(1, sizeof(node)))

item = alloc_node();

这里建议使用强制转换来检测错误类型的分配。如果item不是指向struct node的指针,编译器会抱怨并防止该错误。

总之,首选calloc优先于malloc,更喜欢sizeof(*item)优先于sizeof(node node)。如果上下文不允许使用sizeof(*dst),如上所述或在表达式或函数参数中,则使用强制转换。

答案 2 :(得分:2)

从功能上讲,这三者都是等价的。

在风格上,1是首选选项(至少由我和许多其他C程序员)。请注意,sizeof是一个运算符,而不是一个函数,只有在操作数是类型名称时才需要括号。所以你可以写sizeof *item而不是sizeof (*item) - 除了可读性之外,它们不会伤害任何东西。另请注意,sizeof不会尝试评估其参数(它不会尝试取消引用item);它所做的只是计算结果类型所需的字节数,它在编译时而不是运行时完成。

就C而言,你应该投射malloc的结果。从1989年的标准来看,它不再是必要的; malloc返回void *,可以将其分配给任何其他指针类型,而无需显式转换 1

根据C89标准,如果您忘记包含malloc或在范围内没有stdlib.h声明,那么投放malloc的结果可能会取消有用的诊断效果。 C89仍然允许隐式int声明;如果编译器在没有声明的情况下在代码中看到函数调用,则假定函数返回int值。如果你不使用强制转换,编译器会抱怨你试图为指针对象分配一个整数值。使用强制转换,编译器可以在没有诊断的情况下编译代码,但是您要将指针值转换为int并再次返回指针,这可能会也可能不起作用。

C99标准摆脱了隐式int声明,因此不再是问题;如果忘记加入stdlib.h,您是否会获得诊断。出于可读性和可维护性的原因,你仍然应该抛弃演员;它所做的就是添加无用的视觉混乱。如果您更改了目标的声明(从struct foo *struct bar *),那么您也必须更新演员阵容,这只是额外的工作,如果您忘了这样做然后它就是一个bug。无论您对item = malloc( sizeof *item )的类型做出哪些更改,item 总是做正确的事情而无需任何进一步的维护。

C ++,与C语言不同,具有不同的规则, not 允许您在没有显式强制转换的情况下将void *分配给另一个指针类型,因此将< / em>必须在这种情况下转换malloc的结果。如果您要从C迁移到C ++并且无法重做所有动态内存管理代码(这是唯一在C ++中使用malloc的借口,那么这是一个问题码)。当然,您应该在C ++中使用malloc / calloc / realloc;要么使用其中一个标准容器,要么使用new运算符。

<小时/> 1 - 在C89标准之前,malloccallocrealloc都返回char *,因此如果 ,则需要 目标是一种不同的指针类型。不幸的是,即使不再需要习惯,这种习惯仍然存在

答案 3 :(得分:1)

表单2很糟糕,因为您可能会意外分配错误的内存量。

表单1和表单3都允许程序员目视检查分配是否正确:

   item = malloc(sizeof(*item));
// ^^^^                 ^^^^^

   item = (struct node *) malloc(sizeof(struct node));
//        ^^^^^^^^^^^^^^^              ^^^^^^^^^^^^^

一旦您了解到varname应该使用*varname,或者(Typename *)应该使用(Typename),那么您更有可能快速检测到尺寸错误。

the main thread about this所述,在C89中,表格3是危险的,而表格1是安全的。在C99及更高版本中,该基本原理不太引人注目,但是Form 1具有更紧凑,并且需要更少维护的优点。如果item的类型被更改,那么任何Form 3行都将触发编译错误,而Form 1行只会自动使用更新后的类型。