Когда я должен использовать malloc для выделения памяти? - PullRequest
10 голосов
/ 04 июля 2010

1)
Для каких типов данных я должен выделять память с помощью malloc?

  • Для типов, подобных структурам, указателям, кроме основных типов данных, например, int
  • Для всех типов?

2)
Почему я могу запустить этот код?Почему он не падает?Я предположил, что сначала нужно выделить память для структуры.

#include <stdio.h>
#include <stdlib.h>

typedef unsigned int uint32;
typedef struct 
{
  int a;
  uint32* b;
}
foo;

int main(int argc, char* argv[])
{
 foo foo2;
 foo2.a = 3;
 foo2.b = (uint32*)malloc(sizeof(uint32));
 *foo2.b = 123;
}

Не лучше ли было бы использовать

foo* foo2 = malloc(sizeof(foo));

3) Как это сделать.b установлен?Ссылочная случайная память или NULL?

#include <stdio.h>
#include <stdlib.h>

typedef unsigned int uint32;
typedef struct 
{
  int a;
  uint32* b;
}
foo;

int main(int argc, char* argv[])
{
 foo foo2;
 foo2.a = 3;

}

Ответы [ 7 ]

18 голосов
/ 04 июля 2010

Все типы в C могут быть распределены либо динамически, автоматически (в стеке), либо статически.Проблема не в типе, а в желаемом времени жизни - вы используете malloc, когда хотите, чтобы объект существовал вне области действия функции, которая его создала, или когда вы заранее не знаете, какая вещь вам нужна.

9 голосов
/ 04 июля 2010

Изменить, чтобы ответить на ваши пронумерованные вопросы.

  1. Нет типов данных, которые вы должны выделить с помощью malloc. Только если вы хотите, чтобы тип указателя указывал на действительную память, вы должны использовать унарный оператор & (address-of) или malloc() или некоторую связанную функцию.

  2. В вашем коде нет ничего плохого - строка:

    foo foo2;
    

    Распределяет структуру в стеке - тогда все работает как обычно. Структуры в этом смысле ничем не отличаются от любой другой переменной. Не лучше и не хуже использовать автоматические переменные (распределение стека), глобальные переменные или malloc(), все они разные, с разной семантикой и разными причинами выбора.

  3. В вашем примере в # 3 значение foo2.b не определено. Любая автоматическая переменная имеет неопределенное и неопределенное значение, пока вы не инициализируете ее явно.

3 голосов
/ 04 июля 2010

Вы должны выделить malloc любую память, которой хотите управлять вручную, а не автоматически.Неважно, что там хранится: int или double или struct или что-то еще;malloc - это все о ручном управлении памятью.

Когда вы создаете переменную без malloc, она сохраняется в стеке , а когда она выходит из области видимости, ее память автоматическиутилизирован.Переменная выпадает из области видимости, когда переменная больше не доступна;например, когда блок или функция, в которой переменная была объявлена ​​в конце, заканчивается.

Когда вы выделяете память с помощью malloc, она сохраняется в heap , а malloc возвращает указатель наэта память.Эта память не будет восстановлена ​​до тех пор, пока вы не вызовете free для нее, независимо от того, останется ли указатель на нее доступным (если не осталось указателей на выделенную в куче память, это утечка памяти ).Это означает, что вы получаете возможность продолжать использовать память, выделенную вам после блока или функции, которая была выделена в конце, но, с другой стороны, теперь вы обязаны вручную освободить ее, когда закончите с ней.

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

2 голосов
/ 04 июля 2010

2) Почему я могу запустить этот код?Почему не происходит сбой?

Код никогда не ссылается на неопределенную память или NULL.Почему это потерпит крах?(У вас утечка памяти, как написано, но это, вероятно, потому, что вы показываете только часть кода, и в данной программе это не проблема в любом случае.)

Альтернативный код, который вы предлагаете, также будет работать, хотяпамять, возвращаемая из malloc, также неинициализирована по умолчанию.(Однажды я работал с пользовательским распределителем памяти, который по умолчанию заполнял возвращаемые блоки памяти ? символами. Все еще совершенно законно по правилам. Обратите внимание, что calloc возвращает указатель на инициализированную нулями память; используйте его, если вы этого хотите.)

3) Как установить foo.b?Является ли ссылка на случайную память или NULL?

Случайная память.Выделенные стека структуры не инициализированы для вас.

2 голосов
/ 04 июля 2010

foo foo2; автоматически распределяет структуру в стеке и автоматически освобождается при завершении функции включения (в данном случае main).

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

1 голос
/ 04 июля 2010

Память для экземпляра структуры ("foo2") будет выделена в стеке - нет необходимости выделять память для этого самостоятельно - если вы выделяете с помощью malloc, обязательно освободите память позднее.

1 голос
/ 04 июля 2010

Вы можете сделать это, но этого недостаточно.

Потому что второе поле - это указатель, который должен быть установлен на действительный адрес.Один из способов сделать это - выделить память (с помощью malloc).

К первому вопросу - используйте malloc, когда вы ДОЛЖНЫ управлять временем жизни объекта вручную.

Например, второй код можетпереписать так:

int main(int argc, char* argv[])
{
 foo foo2; uint32 b;
 foo2.a = 3;
 foo2.b = &b;
 *foo2.b = 123;
}

Это лучше, потому что время жизни такое же, а память теперь в стеке - и не требует освобождения.

...