При условии, что освобожденная память продолжает оставаться в адресном пространстве процесса, стоит обнулить ее перед освобождением. Например, такой способ может оказаться предпочтительным для программ с повышенными требованиями к безопасности.
Обсуждение ряда полезных инструментов для отладки динамической памяти см в разделе 15.5.2 «Отладчики выделения памяти».
3.2.1.4. Изменение размера:
realloc
Динамическая память имеет существенное преимущество перед статически объявленными массивами, поскольку это позволяет использовать столько памяти, сколько
нужно, и не больше. Не нужно объявлять глобальный, статический или локальный массив фиксированного размера и надеяться, что он: (а) достаточно большой и (б) не слишком большой. Вместо этого можно выделить ровно столько, сколько нужно, не больше и не меньше.
Вдобавок, можно изменять размер динамически выделенной области памяти. Хотя можно сократить размер блока памяти, обычно его увеличивают. Изменение размера осуществляется с помощью
new_count = count * 2; /* удвоить размер памяти */
new_amount = new_count * sizeof(struct coord);
newcoords =
(struct coord*)realloc(coordinates, new_amount);
if (newcoords == NULL) {
/* сообщить об ошибке, восстановить или прервать */
}
coordinates = newcoords;
/* продолжить использование coordinates ... */
Как и в случае с
malloc
, шаги стереотипны по природе и сходны по идее.
1. Вычислить новый выделяемый размер в байтах.
2. Вызвать
realloc
с оригинальным указателем, полученным от
malloc
(или от
calloc
или предыдущего вызова
realloc
) и с новым размером.
3. Привести тип и присвоить возвращенное
realloc
значение. Подробнее обсудим дальше.
4. Как и для
malloc
, проверить возвращенное значение, чтобы убедиться, что оно не равно NULL. Вызов любой функции выделения памяти может завершиться неудачей.
При увеличении размера блока памяти
realloc
часто выделяет новый блок нужного размера, копирует данные из старого блока в новый и возвращает указатель уже на новый блок. При сокращении размера блока данных
realloc
часто обновляет внутреннюю учетную информацию и возвращает тот же указатель. Это избавляет от необходимости копировать первоначальные данные. Однако, если это случится, не думайте, что можно использовать память за пределами нового размера!
В любом случае вы можете предположить, что если
realloc
не возвращает
NULL
, старые данные были скопированы для вас в новый участок памяти. Более того, старый указатель больше недействителен, как если бы вы вызвали
free
с ним, и использовать его больше не следует. Это верно для всех указателей на этот блок данных, а не только для того, который использовался при вызове
free
.
Возможно, вы заметили, что в нашем примере для указания на измененный блок памяти использовалась отдельная переменная. Можно было бы (хотя это плохая идея) использовать ту же самую переменную, как здесь:
coordinates = realloc(coordinates, new_amount);
Это плохо по следующей причине. Когда
realloc
возвращает
NULL
, первоначальный указатель все еще действителен; можно безопасно продолжить использовать эту память. Но если вы повторно используете ту же самую переменную и
realloc
возвращает
NULL
, вы теряете указатель на первоначальную память. Эту память больше нельзя использовать. Что еще важнее, эту память невозможно освободить! Это создает утечку памяти, которую нужно избежать.
Для версии
realloc
в стандартном С есть некоторые особые случаи: когда аргумент
ptr
равен
NULL
,
realloc
действует подобно
malloc
и выделяет свежий блок памяти. Когда аргумент
size
равен 0,
realloc
действует подобно
free
и освобождает память, на которую указывает
ptr
. Поскольку (а) это может сбивать с толку и (б) более старые системы не реализуют эту возможность, мы рекомендуем использовать
malloc
, когда вы имеете в виду
malloc
, и
free
, когда вы имеете в виду
free
.
Вот другой довольно тонкий момент [42] . Рассмотрим процедуру, которая содержит статический указатель на динамически выделяемые данные, которые время от времени должны расти. Процедура может содержать также автоматические (т.е. локальные) указатели на эти данные. (Для краткости, мы опустим проверки ошибок. В коде продукта не делайте этого.) Например: