Подтвердить что ты не робот

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

Учитывая

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

Ответ 2

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

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

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

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

Ответ 4

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

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

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

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