Распределение переменных внутри динамически распределяемых структур
Предположим, у вас есть структура, которая содержит указатель на массив и его размер, например:
typedef struct {
int * array;
int arr_size;
}IntArray;
и хотите иметь это внутри другой структуры, это можно сделать двумя способами:
typedef struct{
IntArray ia;
//other variables
}Base1;
typedef struct{
IntArray * ia;
//other variables
}Base2;
Что происходит, когда я динамически выделяю Base1
а также Base2
(например Base1 b1 = (Base1 *)malloc(sizeof(Base1));
) и почему я должен выбрать один путь вместо другого?
2 ответа
Пространство вложенных структур существует как пространство в их родительской структуре, что означает, что им не нужно свое собственное выделение (но им все равно может потребоваться их собственная инициализация), тогда как поля структуры, которые являются указателями, должны быть как выделены, так и освобождены, когда родительский объект инициируется (это распространенная причина утечек памяти в C, потому что у него нет автоматических деструкторов объектов, как в C++). Хотя, используя указатель, вы можете указать на другой массив / объект, который может существовать в стеке (таким образом, избегая
malloc
/free
) но тогда вы можете столкнуться с ошибками времени жизни объекта в зависимости от разницы в области действия и времени жизни ваших объектов.Вложенные структуры существуют на месте, поэтому они не могут использоваться другими экземплярами. Это может быть или не быть идеальным (вы можете решить это с помощью шаблона в C++, в C вам придется согласиться на отвратительный макрос препроцессора).
Потому что динамически распределяемые объекты (такие как ваш массив и ваш
Base2
тип вложенныйia
член) существуют в разных местах в физической памяти, это означает, что ваш код не будет использовать пространственную локальность, которой могут воспользоваться кэши ЦП, и вы получите двойное разыменование указателя. Так что ваш код будет работать медленнее.
В любом случае: когда вы находитесь в C, вы должны стараться минимизировать использование указателей.
В основном вопрос такой же, как я должен выделить структуру или указатель на структуру? То есть:
IntArray myStruct;
или же
IntArray *myStructPtr;
Тот факт, что рассматриваемые переменные находятся внутри структуры, не имеет значения, вы можете выбрать любой из них.
И вы получаете к ним доступ таким же образом, как если бы они не были внутри другой структуры, после ссылки на поле внутри внешней структуры, конечно, так
Base1
содержит фактический IntArray
структура, чтобы вы
Base1 *b1 = malloc(sizeof(*b1));
b1->ia.array = malloc(yourSizeHere);
Base2
содержит указатель на IntArray
структура, так что вам нужно будет указать на существующий IntArray
struct или malloc() памяти для него, а затем получить к нему доступ в качестве указателя.
Base2 *b2 = malloc(sizeof(*b2));
b2->ia = malloc(sizeof(*(b2->ia)));
b2->ia->array = malloc(yourSizeHere);