Можно подумать (что мы вначале и сделали), что единственным решением является знать это и добавить после вызова функции переназначение 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()
, поскольку в этом случае никогда не возникает вопросов по поводу вновь выделенной памяти.
Если вы знаете, что вам понадобится инициализированная нулями память, следует также использовать calloc()
, поскольку возможно, что память, возвращенная malloc()
, уже заполнена нулями. Хотя вы, программист, не можете этого знать, calloc()
может это знать и избежать лишнего вызова memset()
.
3.2.1.6. Подведение итогов из GNU Coding Standards
Чтобы подвести итоги, процитируем, что говорит об использовании процедур выделения памяти