Когда я должен использовать malloc для выделения памяти?

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

  • Для таких типов, как structs, указатели, кроме базовых типов данных, например 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) Как установить foo.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;

}

Ответ 1

Отредактируйте для ответа на нумерованные вопросы.

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

  • В коде нет ничего плохого: строка:

    foo foo2;
    

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

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

Ответ 2

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

Ответ 3

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

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

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

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

Ответ 4

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

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

Ответ 5

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

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

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

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

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

Ответ 6

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

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

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

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

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

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

Ответ 7

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