Вопрос #1615376

Предоставлен кусок C-кода с указателями и выделением памяти, в котором проявляется утечка и возможная двойная free — найдите ошибки и перепишите фрагмент корректно с объяснением владения памятью и безопасных практик (используйте пример)

Ответы
1


Ниже — кратко и по делу: пример типичных ошибок (утечка и возможная двойная free), разбор и исправленный вариант с объяснением владения памятью и безопасных практик.
Ошибочный фрагмент (пример)
```c
int *f(void) {
int *a = malloc(sizeof(int) * 10); // выделили a
if (a == NULL) return NULL;
int *b = malloc(sizeof(int) * 5); // выделили b
if (b == NULL) return NULL; // утечка
a = b; // утечка
return a;
}
void g(void) {
int *x = f();
free(x);
free(x); // UB
}
```
Ошибки:
- При неудаче выделения `b` происходит `return NULL` без `free(a)` — утечка.
- Присваивание `a = b;` теряет указатель на ранее выделенную память, она не освобождена — утечка.
- В `g` дважды вызывается `free(x)` — двойное освобождение (undefined behavior).
- Нет явных правил владения: кто должен освобождать возвращённый указатель.
Исправленный, безопасный вариант и объяснение владения
```c
#include
int *f(void) {
int *a = malloc(sizeof(int) * 10); // выделяем буфер a
if (a == NULL) return NULL; // на ошибку внешнему коду возвращаем NULL
int *b = malloc(sizeof(int) * 5); // выделяем дополнительный буфер b
if (b == NULL) {
free(a); // освобождаем a перед выходом -> предотвращаем утечку
return NULL;
}
// Если функция возвращает b, то ответственность за free переходит к вызывающему.
// Освобождаем ненужную память a, если она больше не нужна:
free(a);
return b; // ownership: caller получает указатель и должен free()
}
void g(void) {
int *x = f();
if (x == NULL) {
// обработка ошибки
return;
}
// использовать x ...
free(x); // единственный free для выделенной памяти
x = NULL; // обнуляем, чтобы избегать повторного free
}
```
Безопасные практики (кратко):
- Документируйте владение: "функция возвращает malloc-память, caller обязан free()".
- При realloc используйте временный указатель:
```c
int *tmp = realloc(a, new_size);
if (tmp == NULL) {
// a всё ещё валиден — не теряем память
} else {
a = tmp;
}
```
- При ошибке освобождайте уже выделенные ресурсы перед возвратом.
- После `free(ptr); ptr = NULL;` — уменьшает риск двойного free.
- Используйте инструменты проверки (Valgrind, AddressSanitizer) и статический анализатор для обнаружения утечек/двойных free.
Кратко про владение: если функция выделяет память и возвращает указатель, она передаёт владение вызывающему; если функция принимает указатель и берёт на себя обязательство освобождения — это тоже должно быть явно задокументировано.

Минимум 10 символов
Прямой эфир