malloc для структуры и указателя в C
предположим, я хочу определить структуру, представляющую длину вектора и его значения как:
struct Vector{
double* x;
int n;
};
Теперь предположим, что я хочу определить вектор y и выделить для него память.
struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector));
мой поиск по интернету показывает, что я должен выделить память для x отдельно.
y->x = (double*)malloc(10*sizeof(double));
но, похоже, что я выделяю память для y - >x дважды, один при выделении памяти для y, а другой при выделении памяти для y - >x, и это кажется пустая трата памяти.
Это очень ценится, если дайте мне знать, что компилятор действительно делает и что было бы правильным способом
инициализируйте и y, и y - >x.
спасибо заранее.
7 ответов:
Нет, ты не выделение памяти для
y->xдва раза.вместо этого вы выделяете память для структуры (которая включает указатель) плюс что-то для этого указателя, чтобы указать.
подумайте об этом так:
1 2 +-----+ +------+ y------>| x------>| *x | | n | +------+ +-----+так что вам действительно нужны два распределения (
1и2) для хранения всего.кроме того, ваш тип должен быть
struct Vector *yтак как это указатель, и вы никогда не должны приведите возвращаемое значение отmallocв C, так как он может скрыть определенные проблемы, которые вы не хотите скрывать - C вполне способен неявно преобразоватьvoid*возвращает значение для любого другого указателя.и, конечно, вы, вероятно, хотите инкапсулировать создание этих векторов, чтобы сделать управление ими проще, например, с помощью:
struct Vector { double *data; // no place for x and n in readable code :-) size_t size; }; struct Vector *newVector (size_t sz) { // Try to allocate vector structure. struct Vector *retVal = malloc (sizeof (struct Vector)); if (retVal == NULL) return NULL; // Try to allocate vector data, free structure if fail. retVal->data = malloc (sz * sizeof (double)); if (retVal->data == NULL) { free (retVal); return NULL; } // Set size and return. retVal->size = sz; return retVal; } void delVector (struct Vector *vector) { // Can safely assume vector is NULL or fully built. if (vector != NULL) { free (vector->data); free (vector); } }инкапсулируя создание таким образом, вы гарантируете, что векторы либо полностью построены, либо не построены вообще - нет никаких шансов из них наполовину построены. Это также позволяет полностью изменить базовые структуры данных в будущем, не затрагивая клиентов (например, если вы хотите сделать их разреженными массивами, чтобы обменять пространство на скорость).
в первый раз вы выделяете память для
Vector, Что означает, что переменныеx,n.xпока не указывает ни на что полезное.вот почему второе распределение также необходимо.
несколько пунктов
struct Vector y = (struct Vector*)malloc(sizeof(struct Vector));не такон должен быть!--1--> С
yдержит указатель наstruct Vector.1-й
malloc()только выделяет память, достаточную для хранения векторной структуры (которая является указателем на double + int)2-й
malloc()на самом деле выделить память для хранения 10 двойной.
в принципе вы все делаете правильно. Для того, что вы хотите вам нужно два
malloc()s.просто некоторые комментарии:
struct Vector y = (struct Vector*)malloc(sizeof(struct Vector)); y->x = (double*)malloc(10*sizeof(double));должно быть
struct Vector *y = malloc(sizeof *y); /* Note the pointer */ y->x = calloc(10, sizeof *y->x);в первой строке вы выделяете память для векторного объекта.
malloc()возвращает указатель на выделенную память, поэтому y должен быть векторным указателем. Во второй строке вы выделяете память для массива из 10 дублей.в C вам не нужны явные приведения, и писать
sizeof *yвместо изsizeof(struct Vector)лучше для безопасности типа, и кроме того, это экономит на наборе текста.вы можете изменить структуру и сделать один
malloc()вот так:struct Vector{ int n; double x[]; }; struct Vector *y = malloc(sizeof *y + 10 * sizeof(double));
когда вы выделяете память для
struct Vectorвы просто выделяете память для указателяx, т. е. для пространства, где будет размещено его значение, содержащее адрес. Так что таким образом вы не выделяете память для блока, на которомy.xссылка.
первый malloc выделяет память для структуры, включая память для x (указатель на double). Второй malloc выделяет память для двойного значения wtich X указывает.
вы могли бы сделать это в одном malloc, выделив для вектора и массива одновременно. Например:
struct Vector y = (struct Vector*)malloc(sizeof(struct Vector) + 10*sizeof(double)); y->x = (double*)((char*)y + sizeof(struct Vector)); y->n = 10;это выделяет вектор 'y', а затем делает y->x указывают на дополнительные выделенные данные сразу после векторной структуры (но в том же блоке памяти).
если требуется изменить размер вектора, вы должны сделать это с двумя выделениями, как рекомендуется. Затем внутренний массив y - >x можно будет изменить, сохранив векторную структуру 'y' нетронутый.
Comments