Почему безопаснее использовать sizeof (* pointer) в malloc

Дано

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

Чтобы распределить новую структуру,

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

безопаснее, чем

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

Зачем? Я думал, что они одинаковы.

Всего 4 ответа


Это безопаснее, потому что вам не нужно дважды упоминать имя типа и не нужно создавать правильное написание для «разыменованной» версии типа. Например, вам не нужно «считать звезды» в

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

Сравните это с основанным на типе sizeof в

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

где вы тоже убедитесь, что вы использовали правильное количество * под sizeof .

Чтобы переключиться на другой тип, вам нужно изменить только одно место (объявление p ) вместо двух. И люди, которые имеют привычку использовать результат malloc должны поменяться тремя местами.

В более общем смысле, имеет смысл придерживаться следующего принципа: имена типов принадлежат декларациям и больше нигде. Фактические утверждения должны быть независимыми от типа. Им следует избегать упоминания каких-либо имен типов или использования любых других специфических для типов функций.

Последнее означает: избегайте ненужных приведений. Избегайте ненужного специфичного для типа константного синтаксиса (например, 0.0 или 0L где достаточно простого 0 ). Избегайте упоминания имен типов под sizeof . И так далее.


Потому что если в какой-то более поздний момент времени p будет указывать на другой тип структуры, тогда ваш оператор выделения памяти, использующий malloc , не должен изменяться, он все равно выделяет достаточно памяти, необходимой для нового типа . Это обеспечивает:

  • Вам не нужно изменять оператор выделения памяти каждый раз, когда вы меняете тип, для которого он выделяет память.
  • Ваш код более надежен и менее подвержен ошибкам вручную.

В целом, всегда полезно не полагаться на конкретные типы, и первая форма просто делает это, не кодируя тип жестко.


Это удобно, потому что вы можете преобразовать это:

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() и все готово! Компилятор позаботится об этом за вас.


Это не влияет непосредственно на безопасность, но можно утверждать, что это может предотвратить ошибку в будущих версиях. С другой стороны, легко забыть это маленькое * . Как насчет того, чтобы сделать его типом, это, конечно, чище.

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

Тогда вы можете сделать это:

node_t *p = malloc(sizeof(node_t));

Есть идеи?

10000