История вопроса
Оператор return появился в C для явного завершения работы функции и передачи результата вызвавшему коду. В ранних языках программирования не всегда присутствовала возможность возвращать значения, а механизм return позволил явно указывать результат вычислений. Это повысило выразительность и безопасность программ.
Проблема
Главная задача: корректно завершить функцию и, если нужно, вернуть значение, соответствующее определённому типу. Ошибки часто возникают из-за возвращения значения неправильного типа, указателей на несуществующие или локальные переменные, либо игнорирования возвращаемого значения вызывающей стороной.
Решение
Пример кода:
#include <stdio.h> struct Point { int x, y; }; struct Point make_point(int x, int y) { // возвращаем структуру (копия) struct Point p = {x, y}; return p; } int* dangerous() { int num = 42; return # // опасно: возвращаем адрес локальной переменной! } void do_nothing() { return; // корректно для функций типа void } int main() { struct Point p = make_point(3, 4); printf("%d %d ", p.x, p.y); int* ptr = dangerous(); // UB: ptr указывает на уничтоженную область }
Ключевые особенности:
Можно ли использовать return в функциях без значения (void)?
Ответ: Да, писать "return;" можно для функций void, но нельзя указывать выражение (return x;) для void-функции.
Что происходит при возврате массива из функции?
Ответ: В C нельзя вернуть массив напрямую. Можно вернуть только указатель (например, на статический массив), но чаще следует возвращать указатель и размер или использовать динамически выделенный массив.
int* make_arr() { static int arr[5] = {1,2,3,4,5}; return arr; // статический массив живёт после выхода из функции }
Почему опасно возвращать указатель на локальную переменную?
Ответ: После выхода из функции память под локальную переменную освобождается (стековая область). Использование возвращённого указателя ведёт к неопределённому поведению.
Негативный кейс
Функция возвращает указатель на локальную переменную, вызывающий получает "мусор", непредсказуемое поведение и редкие плавающие баги.
Плюсы:
Минусы:
Позитивный кейс
Использование возвращаемой структуры (копируется по значению) или возврат указателя на статическую/динамическую память:
Плюсы:
Минусы: