为什么在 malloc 中使用 sizeof(*pointer) 更安全

Why is it safer to use sizeof(*pointer) in malloc

提问人:Yu Hao 提问时间:6/23/2013 最后编辑:Yu Hao 更新时间:10/1/2021 访问量:40225

问:

鉴于

struct node
{
     int a;
     struct node * next;
};

要 malloc 一个新结构,

struct node *p = malloc(sizeof(*p));

struct node *p = malloc(sizeof(struct node));

为什么?我以为他们是一样的。

c 马洛克

评论

8赞 luser droog 6/23/2013
仅供参考,当与变量一起使用时,不需要分义:sizeofp = malloc(sizeof*p);
64赞 Tomer Arazy 6/23/2013
使用 parens 更具可读性
7赞 wildplasser 6/23/2013
@TomerArazy:我不敢苟同;使用 parens 的可读性较差。如果没有 parens,它就不能是类型名;缺乏 parens 有助于人类读者消除歧义。(小问题:此外,Parens 可能暗示 sizeof 是一个函数,但事实并非如此)
15赞 Eric Postpischil 6/23/2013
它没有括号但带有空格,更具可读性:.sizeof *p
10赞 Kaz 6/23/2013
使用parens或没有parens,它不会更具可读性。这些是意见,而不是事实。但事实上,parens 不是必需的,因为 sizeof 作为一元运算符应用于表达式。如果您并不总是对每个一元运算符都使用括号,为什么总是将它们与 sizeof 一起使用。

答:

23赞 Alok Save 6/23/2013 #1

因为如果在以后的某个时间点指向另一个结构类型,那么你的内存分配语句使用不必改变,它仍然会分配新类型所需的足够内存。它确保:pmalloc

  • 您不必在每次更改内存分配语句的类型时都修改内存分配语句。
  • 您的代码更可靠,更不容易出现手动错误。

一般来说,不依赖具体类型总是一个好的做法,第一种形式就是这样做的,它不对类型进行硬编码。

79赞 AnT stands with Russia 6/23/2013 #2

它更安全,因为您不必两次提及类型名称,也不必为该类型的“取消引用”版本构建正确的拼写。例如,您不必在

int *****p = malloc(100 * sizeof *p);

将其与基于类型的sizeof

int *****p = malloc(100 * sizeof(int ****));

您必须确保使用了正确数量的 under .*sizeof

为了切换到另一种类型,您只需要更改一个位置(声明 ),而不是两个。而有投法习惯的人,就要换三个地方。pmalloc

更一般地说,坚持以下准则很有意义:类型名称属于声明,而不是其他任何地方。实际语句应与类型无关。它们应尽可能避免提及任何类型名称或使用任何其他特定于类型的功能。

后者意味着:避免不必要的投射。避免不必要的特定于类型的常量语法(例如,或普通语法就足够了)。避免在 下提及类型名称。等等。0.00L0sizeof

评论

13赞 Eric Postpischil 6/23/2013
值得一提的是,当类型被改变时,在 p 的声明中改变它就足够了(没有必要在 中改变它)不仅意味着更少的工作,而且出错的机会也更少。因此,这有助于减少错误。malloc
0赞 Josh 12/20/2014
AndreyT,我明白你的意思了,抽象地说......但我敢打赌,在计算机的历史上,从来没有一个平台可以sizeof(int ****) != sizeof(int ***) :)
2赞 AnT stands with Russia 12/20/2014
@Josh:你基本上是说,每次你需要知道指针大小时,你都可以用.是的,它会起作用,但这样的事情应该会产生与无与伦比的左括号相同的未解决的紧张关系(xkcd.com/859sizeof(double *))
7赞 ruben2020 6/23/2013 #3

这很方便,因为您可以将其转换为:

struct node *p= malloc(sizeof(*p));

进入这个:

#define MALLOC(ptr)   (ptr) = malloc(sizeof(*(ptr) ))

struct node *p;
MALLOC(p);

或者,对于数组:

#define MALLOC_ARR(ptr, arrsize) \
       (ptr) = malloc(sizeof(*(ptr) ) * arrsize)

struct node *p;
MALLOC_ARR(p, 20);

为什么这是安全的?因为使用这些宏的用户不太可能犯 AndreyT 概述的错误,就像获取静态数组的大小一样。DIM()

#define DIM(arr)   ((sizeof(arr))/(sizeof(arr[0])))

这也更安全,因为用户不需要在多个地方使静态数组大小保持一致。在一个地方设置数组大小,然后只需使用 你就完成了!编译器会为您处理它。DIM()

评论

0赞 chux - Reinstate Monica 2/11/2021
通常宏参数应该有一个 ,所以 --> 。().... * arrsize)... * (arrsize))