Что правильно при выделении памяти для структуры в C - PullRequest
1 голос
/ 10 сентября 2011

Предполагая, что у нас есть простая структура, такая как:

typedef struct
{
    int d1;
    int d2;
    float f1;
}Type;

Что правильно при выделении памяти для нового экземпляра:

Это:

// sizeof *t == sizeof(Type) ( gcc prints 12 bytes)
Type *t = malloc(sizeof *t); 

или

// sizeof pointer always == 4 (in my case also on gcc)
Type *t = malloc(sizeof(t)); 

Что правильно?

Ответы [ 6 ]

4 голосов
/ 10 сентября 2011

Это правильный путь:

Type *t = malloc(sizeof *t); 

Почему это правильно?

Потому что вы правильно распределили размер, достаточный для размещения структуры. *t указывает на тип Type.


Это неверный способ:

Type *t = malloc(sizeof(t)); 

Почему это неверно?

sizeof(t) возвращает размер указателя, а не фактический тип (т. Е. Не размер структуры).
Вы должны выделить достаточно большой размер, чтобы вместить структуру, а не размер, равный указателю на структуру.

Обратите внимание, что размер указателя, указывающего на Любой тип , одинаков в системе.


Почему первый подход лучше?
При первом подходе, когда вы изменяете Type, malloc автоматически меняет размер на правильное значение, вам не нужно делать это явно, в отличие от других способов.

Кроме того, важной частью написания вызова malloc является поиск правильного размера, который необходимо передать. Лучший способ сделать это - не смотреть куда-либо (потому что именно тогда мы совершаем ошибку), а только в левой части этого оператора malloc. Так как в этом случае это t, следовательно, правильный размер будет sizeof(*t).

Как стандартизировать использование malloc?

При вышеупомянутом правильном подходе есть одна проблема, скажем, если мы хотим malloc сказать 30 elements. Тогда наше malloc выражение становится:

t = (T *) malloc(30 * sizeof (*T));

Это не предпочтительный способ записи выражения malloc, потому что можно ошибиться, введя число 30 в параметре malloc. Что бы мы хотели - независимо от количества требуемых элементов, параметр malloc всегда должен быть стандартным sizeof(*x) или чем-то подобным.

Итак, вот подход с примером:

Предположим, у нас есть указатель p, указывающий на одномерный массив size 20, каждый элемент которого равен struct node. Декларация будет:

 struct node (*p) [20];   

Теперь, если мы хотим malloc 20 elements из stuct node и хотим, чтобы указатель p содержал адрес возврата malloc, тогда мы имеем

p = (data-type of p) malloc (size of 20 elements of struct node); 

Чтобы найти тип данных p, для приведения мы просто убираем имя переменной или заменяем p пробелом. Итак, теперь у нас есть

p = (struct node (*)[20] ) malloc(size of 20 elements of struct node);

Мы не можем ошибаться, потому что компилятор будет жаловаться, если мы ошибаемся. Наконец-то размер! Мы просто делаем стандартный способ, который мы описали, то есть

p =  (struct node (*)[20] ) malloc(sizeof (*p));

И мы закончили!

2 голосов
/ 10 сентября 2011
Type *t = malloc(sizeof *t); 

Это правильный способ выделить объем памяти, необходимый для нового экземпляра.

Type *t = malloc(sizeof (t)); 

Это выделит достаточно памяти только для указателя, а не для экземпляра.

1 голос
/ 10 сентября 2011

это:

Type *t = malloc(sizeof(*t));

Вы выделяете память для структуры, а не для указателя.

1 голос
/ 10 сентября 2011

sizeof(*t), потому что t имеет тип Type*, поэтому *t указывает на что-то типа Type.

Но я бы предложил использовать это вместо этого, потому что он более читабелени менее подвержен ошибкам:

Type *t = malloc(sizeof(Type));
0 голосов
/ 10 сентября 2011

Первое правильно.Второй не будет выделять достаточно памяти, потому что t имеет размер указателя.Еще лучше

Type *t = malloc(sizeof(Type));
0 голосов
/ 10 сентября 2011

Предпочтительно: Type * t = malloc(sizeof(Type));

Возможно, sizeof *t также работает и позволяет вам изменять фактический тип *t, не требуя изменения двух отдельных местоположений, но используя тип, а не выражение в начальном распределении, и делает его более читабельным и выразительным. .. это субъективно, хотя Если вы хотите оставить свои параметры открытыми для изменения типа, я бы лично предпочел добавить это изменение в typedef, а не в объявление / инициализацию переменной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...