Проверяйте каждый вызов malloc
или realloc
на предмет возвращенного нуля. Проверяйте realloc
даже в том случае, если вы уменьшаете размер блока; в системе, которая округляет размеры блока до степени двойки, realloc
может получить другой блок, если вы запрашиваете меньше памяти.
В Unix realloc
может разрушить блок памяти, если она возвращает ноль. GNU realloc
не содержит подобной ошибки: если она завершается неудачей, исходный блок остается без изменений. Считайте, что ошибка устранена. Если вы хотите запустить свою программу на Unix и хотите избежать потерь в этом случае, вы можете использовать GNU malloc
.
Вы должны считать, что free
изменяет содержимое освобожденного блока. Все, что вы хотите получить из блока, вы должны получать до вызова free
.
В этих трех коротких абзацах Ричард Столмен (Richard Stallman) выразил суть важных принципов управления динамической памятью с помощью malloc()
. Именно использование динамической памяти и принцип «никаких произвольных ограничений» делают программы GNU такими устойчивыми и более работоспособными по сравнению с их Unix-двойниками.
Мы хотим подчеркнуть, что стандарт С требует, чтобы realloc()
NULL
.
3.2.1.7. Использование персональных программ распределения
Набор функций с malloc()
является набором общего назначения по выделению памяти. Он должен быть способен обработать запросы на произвольно большие или маленькие размеры памяти и осуществлять все необходимые учетные действия при освобождении различных участков выделенной памяти. Если ваша программа выделяет значительную динамическую память, вы можете обнаружить, что она тратит большую часть своего времени в функциях malloc()
.
Вы можете написать malloc()
, а затем дробят их на маленькие кусочки по одному за раз. Эта методика особенно полезна, если вы выделяете множество отдельных экземпляров одной и той же сравнительно небольшой структуры.
Например, GNU awk (gawk) использует эту методику. Выдержка из файла awk.h
в дистрибутиве gawk
(слегка отредактировано, чтобы уместилось на странице):
#define getnode(n) if (nextfree) n = nextfree, \
nextfree = nextfree->nextp; else n = more_nodes()
#define freenode(n) ((n)->flags = 0, (n)->exec_count = 0,\
(n)->nextp = nextfree, nextfree = (n))
Переменная nextfree
указывает на связанный список структур NODE. Макрос getnode()
убирает из списка первую структуру, если она там есть. В противном случае она вызывает more_nodes()
, чтобы выделить новый список свободных структур NODE
. Макрос freenode()
освобождает структуру NODE
, помещая его в начало списка.
ЗАМЕЧАНИЕ. Первоначально при написании своего приложения делайте это простым способом: непосредственно используйте malloc()
и free()
. Написание собственного распределителя вы должны рассмотреть лишь в том и только в том случае, если профилирование вашей программы покажет, что она значительную часть времени проводит в функциях выделения памяти.
3.2.1.8. Пример: чтение строк произвольной длины
Поскольку это, в конце концов, readline()
из GNU Make 3.80 (ftp://ftp.gnu.org/gnu/make/make-3.80.tar.gz
). Ее можно найти в файле read.c
.