Linux программирование в примерах | страница 59
>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));
> table = p;
>}
>table[i].i = j; /* ПРОБЛЕМА 1 устраняется */
>other_routine();
>/* Рекурсивный вызов, модифицирует таблицу */
>table[i].j = k; /* ПРОБЛЕМА 2 также устраняется */
Использование индексирования не решает проблему, если вы используете глобальную копию первоначального указателя на выделенные данные; в этом случае, вам все равно нужно побеспокоиться об обновлении своих глобальных структур после вызова >realloc()
.
ЗАМЕЧАНИЕ. Как и в случае с >malloc()
, когда вы увеличиваете размер памяти, вновь выделенная после >realloc()
память не инициализируется нулями. Вы сами при необходимости должны очистить память с помощью >memset()
, поскольку >realloc()
лишь выделяет новую память и больше ничего не делает.
3.2.1.5. Выделение с инициализацией нулями: >calloc()
Функция >calloc()
является простой оболочкой вокруг >malloc()
. Главным ее преимуществом является то, что она обнуляет динамически выделенную память. Она также вычисляет за вас размер памяти, принимая в качестве параметра число элементов и размер каждого элемента:
>coordinates = (struct coord*)calloc(count, sizeof(struct coord));
По крайней мере идейно, код >calloc()
довольно простой. Вот одна из возможных реализаций:
>void *calloc(size_t nmemb, size_t size) {
> void *p;
> size_t total;
> total = nmemb * size; /* Вычислить размер */
> p = malloc(total); /* Выделить память */
> if (p != NULL) /* Если это сработало - */
> memset(p, '\0', total); /* Заполнить ее нулями */
> return p; /* Возвращаемое значение NULL или указатель */
>}
Многие опытные программисты предпочитают использовать >calloc()
, поскольку в этом случае никогда не возникает вопросов по поводу вновь выделенной памяти.