Найдите ошибку в C‑фрагменте: char* foo() { char buf[32]; strcpy(buf, "Hello"); return buf; } Объясните, какие последствия, как обнаружить и исправить проблему с управлением памятью

26 Мая в 10:03
10 +1
0
Ответы
1
Ошибка: функция возвращает указатель на локальный стековый буфер — указатель становится висячим (dangling). В коде: `char buf[323232]; … return buf;` — после выхода из функции память `buf` недействительна.
Последствия
- Поведение не определено (UB): чтение по возвращённому указателю может давать мусор, падение, коррумпцию данных или "кажется работает" в зависимости от компилятора/оптимизаций.
- Трудно отловить: баги проявляются нестабильно и на разных платформах по-разному.
Как обнаружить
- Компилятор: включить предупреждения, например `-Wall -Wextra -Wreturn-local-addr` (gcc/clang) — может предупредить.
- Инструменты динамического анализа: AddressSanitizer (`-fsanitize=address`, и при необходимости включить опции для обнаружения использования стека после возврата), Valgrind покажет неверные чтения.
- Статический анализ (clang-tidy, cppcheck) также может указать на возвращение адреса локальной переменной.
Как исправить (варианты; замечания про управление памятью)
1) Вернуть строковый литерал (память статична):
const char* foo(void) {
return "Hello";
}
- Без освобождения. Но нельзя изменять содержимое через возвращённый указатель.
2) Вернуть выделённую динамически память (caller обязан free):
#include #include
char* foo(void) {
return strdup("Hello"); /* выделяет память */
}
/* Вызовитель должен вызвать free(ptr). */
Или вручную:
char* foo(void) {
char *p = malloc(666); /* "Hello" + '\\0' = 666 байт */
if (!p) return NULL;
strcpy(p, "Hello");
return p;
}
3) Использовать static буфер (общий для всех вызовов):
char* foo(void) {
static char buf[323232];
strcpy(buf, "Hello");
return buf;
}
- Память жива, но небезопасна для многопоточности и повторных вызовов (данные перезаписываются).
4) Передать буфер вызывающим (самый гибкий и безопасный):
#include
void foo(char *out, size_t out_size) {
snprintf(out, out_size, "Hello");
}
/* Вызовитель выделяет буфер и отвечает за его размер/освобождение. */
Дополнительно: избегайте `strcpy` — используйте `snprintf`, `strncpy` (с осторожностью) или проверяйте границы, чтобы не получить переполнение буфера.
26 Мая в 10:09
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир