Вход/Регистрация
Linux программирование в примерах
вернуться

Роббинс Арнольд

Шрифт:

coordinates = realloc(coordinates, new_amount);

Это плохо по следующей причине. Когда

realloc
возвращает
NULL
, первоначальный указатель все еще действителен; можно безопасно продолжить использовать эту память. Но если вы повторно используете ту же самую переменную и
realloc
возвращает
NULL
, вы теряете указатель на первоначальную память. Эту память больше нельзя использовать. Что еще важнее, эту память невозможно освободить! Это создает утечку памяти, которую нужно избежать.

Для версии

realloc
в стандартном С есть некоторые особые случаи: когда аргумент
ptr
равен
NULL
,
realloc
действует подобно
malloc
и выделяет свежий блок памяти. Когда аргумент
size
равен 0,
realloc
действует подобно
free
и освобождает память, на которую указывает
ptr
. Поскольку (а) это может сбивать с толку и (б) более старые системы не реализуют эту возможность, мы рекомендуем использовать
malloc
, когда вы имеете в виду
malloc
, и
free
, когда вы имеете в виду
free
.

Вот другой довольно тонкий момент [42] . Рассмотрим процедуру, которая содержит статический указатель на динамически выделяемые данные, которые время от времени должны расти. Процедура может содержать также автоматические (т.е. локальные) указатели на эти данные. (Для краткости, мы опустим проверки ошибок. В коде продукта не делайте этого.) Например:

void manage_table(void) {

 static struct table *table;

 struct table *cur, *p;

42

Он получен от реальной практики работы с

gawk
— Примеч. автора.

 int i;

 size_t count;

 ...

 table =

(struct table*)malloc(count * sizeof(struct table));

 /* заполнить таблицу */

 cur = &table[i]; /* указатель на 1-й элемент */

 ...

 cur->i = j; /* использование указателя */

 ...

 if (/* некоторое условие */) {

/* нужно увеличить таблицу */

count += count/2;

p =

(struct table*)realloc(table, count * sizeof(struct table));

table = p;

 }

 cur->i = j; /* ПРОБЛЕМА 1: обновление элемента таблицы */

 other_routine; /* ПРОБЛЕМА 2: см. текст */

 cur->j = k; /* ПРОБЛЕМА 2: см. текст */

 ...

}

Это выглядит просто;

manage_table
размешает данные, использует их, изменяет размер и т.д. Но есть кое-какие проблемы, которые не выходят за рамки страницы (или экрана), когда вы смотрите на этот код.

В строке, помеченной '

ПРОБЛЕМА 1
', указатель cur используется для обновления элемента таблицы. Однако,
cur
был инициализирован начальным значением
table
. Если некоторое условие верно и
realloc
вернула другой блок памяти,
cur
теперь указывает на первоначальный, освобожденный участок памяти! Каждый раз, когда
table
меняется, нужно обновить также все указатели на этот участок памяти. Здесь после вызова
realloc
и переназначения
table
недостает строки '
cur = &table[i];
'.

Две строки, помеченные '

ПРОБЛЕМА 2
', еще более тонкие. В частности, предположим, что
other_routine
делает рекурсивный вызов
manage_table
. Переменная
table
снова может быть изменена совершенно незаметно! После возвращения из
other_routine
значение cur может снова стать недействительным.

Можно подумать (что мы вначале и сделали), что единственным решением является знать это и добавить после вызова функции переназначение

cur
с соответствующим комментарием. Однако, Брайан Керниган (Brian Kernighan) любезно нас поправил. Если мы используем индексирование, проблема поддержки указателя даже не возникает:

table =

 (struct table*)malloc(count * sizeof(struct table));

...

/* заполнить таблицу */

...

table[i].i = j; /* Обновить член i-го элемента */

...

if (/* некоторое условие */) {

 /* нужно увеличить таблицу */

 count += count/2;

 p =

(struct table*)realloc(table, count * sizeof(struct table));

  • Читать дальше
  • 1
  • ...
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: