Найдите и объясните ошибку в поведении этого C‑фрагмента, укажите возможные последствия на разных архитектурах и предложите безопасную альтернативу: char* greet() { char s[] = "Hello"; return s; }

2 Окт в 13:42
10 +2
0
Ответы
1

Ошибка: функция возвращает указатель на локальный массив s, размещённый в стеке. После выхода из функции память этого массива становится недействительной — доступ по возвращённому указателю приводит к неопределённому поведению (Undefined Behavior).

Почему это плохо (последствия):

На некоторых запусках и архитектурах вы можете «вдруг» увидеть» правильную строку — потому что содержимое стека ещё не перезаписано. Это вводит в заблуждение: программа «работает», пока не будет перезаписан стек.В других случаях доступ к уже освобождённой стековой памяти даст мусор, сбой (crash), зависимость от случайных данных, уязвимости безопасности (утечка памяти, возможность перезаписи).Разные архитектуры, ABI и уровни оптимизаций компилятора приводят к разным проявлениям: на x86 при слабой загрузке код может выглядеть корректно, на ARM/встроенных или при оптимизациях — сразу будут неправильные данные; инструменты вроде ASan/Valgrind обнаружат use-after-return.Компиляторы обычно предупреждают (флаг gcc/clang: -Wreturn-local-addr).

Безопасные альтернативы (выбирать по требованиям):

1) Вернуть указатель на строковый литерал (хранится в статическом сегменте, не модифицируйте его):
const char* greet(void) {
return "Hello";
}
Плюсы: очень просто; минус: нельзя изменять возвращённую строку.

2) Выделить память в куче и вернуть её (вызывающий должен освобождать):
char greet(void) {
char s = malloc(6); / 5 букв + '\0' /
if (!s) return NULL;
memcpy(s, "Hello", 6);
return s;
}
Использование: char *p = greet(); ... free(p);

3) Передать буфер вызывающим (лучше, если хотите избежать malloc):
void greet(char *buf, size_t bufsize) {
if (bufsize == 0) return;
strncpy(buf, "Hello", bufsize);
buf[bufsize-1] = '\0';
}

4) Сделать статический буфер (если разделяемое состояние и потокобезопасность не критичны):
char* greet(void) {
static char s[] = "Hello";
return s;
}
Минус: один и тот же буфер для всех вызовов, небезопасно при параллельном доступе или если строка модифицируется.

Резюме: текущий вариант возвращает указатель на память со временем жизни, чей срок закончился — это UB. Используйте строковый литерал (const char*), динамическую аллокацию или буфер, переданный вызывающим, в зависимости от требований.

2 Окт в 14:28
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир