Linux программирование в примерах | страница 57



Вдобавок, можно изменять размер динамически выделенной области памяти. Хотя можно сократить размер блока памяти, обычно его увеличивают. Изменение размера осуществляется с помощью >realloc(). Продолжая пример с >coordinates, типичный код выглядит следующим образом:

>int new_count;

>size_t new_amount;

>struct coord *newcoords; /* установить, например: */

>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, первоначальный указатель все еще действителен; можно безопасно продолжить использовать эту память. Но если вы повторно используете ту же самую переменную и