Когда я должен использовать malloc в C, а когда нет? - PullRequest
89 голосов
/ 26 декабря 2009

Я понимаю, как работает malloc (). У меня вопрос, я увижу такие вещи:

#define A_MEGABYTE (1024 * 1024)

char *some_memory;
size_t size_to_allocate = A_MEGABYTE;
some_memory = (char *)malloc(size_to_allocate);
sprintf(some_memory, "Hello World");
printf("%s\n", some_memory);
free(some_memory);

Ради краткости я не включил проверку ошибок. У меня вопрос, не могли бы вы просто сделать выше, инициализируя указатель на некоторое статическое хранилище в памяти? возможно:

char *some_memory = "Hello World";

В какой момент вам действительно нужно выделять память самостоятельно вместо того, чтобы объявлять / инициализировать значения, которые нужно сохранить?

Ответы [ 6 ]

128 голосов
/ 26 декабря 2009
char *some_memory = "Hello World";

создает указатель на строковую константу. Это означает, что строка «Hello World» будет где-то в доступной только для чтения части памяти, и у вас просто есть указатель на нее. Вы можете использовать строку только для чтения. Вы не можете вносить в него изменения. Пример:

some_memory[0] = 'h';

просит неприятностей.

С другой стороны

some_memory = (char *)malloc(size_to_allocate);

выделяет массив символов (переменную) и указывает some_memory на эту выделенную память. Теперь этот массив как для чтения, так и для записи. Теперь вы можете сделать:

some_memory[0] = 'h';

и содержимое массива меняется на "Hello World"

35 голосов
/ 26 декабря 2009

В этом конкретном примере malloc бесполезен.

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

Вторичной причиной является то, что у C нет возможности узнать, достаточно ли места в стеке для выделения. Если ваш код должен быть на 100% надежным, безопаснее использовать malloc, потому что тогда ваш код может узнать, что выделение не выполнено, и обработать его.

15 голосов
/ 26 декабря 2009

malloc - замечательный инструмент для выделения, перераспределения и освобождения памяти во время выполнения по сравнению со статическими объявлениями, такими как пример hello world, которые обрабатываются во время компиляции и поэтому не могут быть изменены по размеру.

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

Конечно, в тривиальном примере, подобном тому, который вы привели, malloc не является волшебным «правильным инструментом для правильной работы», но для более сложных случаев (например, создание массива произвольного размера во время выполнения) это Единственный путь.

6 голосов
/ 24 апреля 2016

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


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

int do_something() {
    uint8_t* someMemory = (uint8_t*)malloc(1024);

    // Do some stuff

    if ( /* some error occured */ ) return -1;

    // Do some other stuff

    free(someMemory);
    return result;
}

Вы видите, что не так с этим кодом? Между malloc и free существует условный оператор возврата. Сначала это может показаться нормальным, но подумайте об этом. Если есть ошибка, вы вернетесь без освобождения выделенной памяти. Это распространенный источник утечек памяти.

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

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

6 голосов
/ 26 декабря 2009
char *some_memory = "Hello World";
sprintf(some_memory, "Goodbye...");

недопустимо, строковые литералы const.

Это выделит 12-байтовый массив символов в стеке или глобально (в зависимости от того, где он объявлен).

char some_memory[] = "Hello World";

Если вы хотите оставить место для дальнейших манипуляций, вы можете указать, что размер массива должен быть больше. (Пожалуйста, не кладите в стек 1 МБ.)

#define LINE_LEN 80

char some_memory[LINE_LEN] = "Hello World";
strcpy(some_memory, "Goodbye, sad world...");
printf("%s\n", some_memory);
5 голосов
/ 26 декабря 2009

Одна из причин, когда необходимо выделить память, - это если вы хотите изменить ее во время выполнения. В этом случае можно использовать malloc или буфер в стеке. Простой пример назначения «Hello World» указателю определяет память, которую «обычно» нельзя изменить во время выполнения.

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