Ответ.
Динамические структуры данных в C (например, связанные списки, деревья) обычно реализуются вручную с использованием указателей и динамического выделения памяти (malloc, calloc, free).
Ключевые нюансы при реализации:
- Обязательно инициализируйте указатели: мусор в неинициализированных указателях приводит к утечкам или сегфолтам.
- Обрабатывайте ошибки выделения памяти: проверяйте результат malloc/calloc, иначе программа может работать с невалидным указателем.
- Корректно освобождайте память: не забывайте вызывать free для каждой аллоцированной структуры, чтобы не накапливались утечки.
- Избегайте висячих указателей (после free обнуляйте указатель).
Пример: создание и удаление простого односвязного списка
typedef struct Node {
int value;
struct Node* next;
} Node;
Node* create_node(int value) {
Node* n = malloc(sizeof(Node));
if (!n) return NULL;
n->value = value;
n->next = NULL;
return n;
}
void free_list(Node* head) {
while (head) {
Node* tmp = head;
head = head->next;
free(tmp);
}
}
Вопрос с подвохом.
Можно ли освобождать память узлов списка внутри цикла по нему, используя только текущий указатель?
Некорректно освобождать текущий узел без предварительного сохранения следующего! После вызова free память по адресу может быть переписана или возвращена ОС.
Правильный подход:
Node* curr = head;
while (curr) {
Node* next = curr->next;
free(curr);
curr = next;
}
Если не сохранить next — возникает обращение к уже освобождённой (и потенциально не вашей!) памяти.
История
Из-за забывания очистить весь список (free) при ошибочном завершении одной из операций работал автотест на 10000 операций добавления/удаления, из-за чего постепенно росло потребление памяти — профилировщик показал крупную утечку.
Разработчик хранил указатель на последний узел списка, но не обнулял его после удаления всех элементов, из-за чего в другой функции, ссылаясь на уже освобождённую память, получил трудноуловимый segfault.
При работе с деревьями забыли рекурсивно удалить все "поддеревья", освободив только корневой узел. Итог: из-за неполной очистки структура памяти оставалась грязной, приводя к периодическим сбоям.