return в C: что делает оператор и как работает

return в C: что делает оператор и как работает Полезное

Оператор return в C — это инструкция, которая немедленно завершает выполнение текущей функции и передает управление обратно в точку вызова, а при наличии выражения — еще и возвращает его значение. Ниже разберем, что именно возвращает return, как он работает в обычной и в void-функции, зачем нужен ранний выход и чем return отличается от break, continue и exit.

Материал рассчитан на тех, кто начинает писать на C. Все примеры — готовые программы, которые можно скопировать и скомпилировать (например, gcc file.c -o prog && ./prog).

Что возвращает return

return отдает одно значение в ту функцию, которая вызвала текущую. Тип этого значения приводится к типу, объявленному у функции. Если функция объявлена как int, вернется целое; если как double — дробное.

Приведение делается автоматически и может терять данные. Внутри функции с типом int запись return 3.9; вернет 3 — дробная часть отбрасывается. Внутри функции с типом double запись return 3; вернет 3.0.

Важно: в C возврат идет по значению — наружу уходит копия. Чтобы вернуть много данных или большой массив, обычно возвращают структуру или указатель, а не копируют все поэлементно.

Если функция должна вернуть значение (тип не void), но управление дошло до закрывающей скобки без return, возвращаемое значение не определено. Вызвавший код получит мусор, поэтому return в не-void функции обязателен на всех путях выполнения.

Синтаксис и как это работает

Форм записи две:

return выражение;   // завершить функцию и вернуть значение выражения
return;             // завершить функцию без возврата значения (только для void)

При обработке return происходит три вещи по порядку:

  1. Выполнение текущей функции прекращается сразу же.
  2. Значение выражения (если оно есть) приводится к типу возврата и передается в точку вызова.
  3. Управление возвращается в вызвавшую функцию, на место сразу после вызова.

Инструкции, написанные после сработавшего return, не выполняются — это недостижимый код. В одной функции может быть несколько return (например, в разных ветках if); сработает первый, до которого дойдет управление, остальные будут пропущены.

Отдельный случай — return в функции main. Он завершает программу и передает код в операционную систему: return 0; — признак успешного завершения, ненулевой код — признак ошибки. Начиная со стандарта C99, если управление доходит до конца main без return, компилятор сам подставляет return 0;.

Минимальный рабочий пример на C

Начнем с целой программы, которую можно запустить, а потом разберем ее по строкам.

#include <stdio.h>

// Возвращает наибольшее из двух целых
int max2(int a, int b) {
    if (a > b) {
        return a;   // ранний выход: до второго return дело не дойдет
    }
    return b;
}

int main(void) {
    int m = max2(7, 3);
    printf("max2(7, 3) = %d\n", m);
    return 0;       // 0 - код успешного завершения программы
}
// --- конец примера ---

Вывод в консоли:

max2(7, 3) = 7

Что здесь происходит по шагам:

  • max2 объявлена с типом int, значит обязана вернуть целое на любом пути.
  • При вызове max2(7, 3) условие a > b истинно, срабатывает return a; — функция немедленно завершается и отдает 7.
  • Второй return b; в этом вызове недостижим: до него управление не доходит.
  • Возвращенное значение записывается в переменную m, и printf печатает 7.
  • return 0; в main завершает программу с кодом успеха.

Вывод этого примера не зависит от компилятора и операционной системы — он определен только логикой кода.

return в void-функции: просто выход

Если функция объявлена как void, она ничего не возвращает. Здесь return не отдает значение — он лишь досрочно прекращает работу функции. Форма только одна: return; без выражения. Попытка написать return что-то; в void-функции — ошибка компиляции.

Такой return удобен для раннего выхода: проверяем условие в начале и, если делать нечего, выходим, не заходя в основной код.

#include <stdio.h>

// Печатает число, только если оно положительное
void print_if_positive(int x) {
    if (x <= 0) {
        return;   // ранний выход из void-функции: значение не возвращается
    }
    printf("положительное: %d\n", x);
}

int main(void) {
    print_if_positive(-5);   // условие сработало, функция вышла молча
    print_if_positive(42);   // напечатает строку
    return 0;
}
// --- конец примера ---

Вывод:

положительное: 42

Первый вызов ничего не печатает: x <= 0, сработал return;, и до printf управление не дошло. Такой прием (ранняя проверка и выход) называют охранным условием — он убирает лишнюю вложенность if и делает код плоским и читаемым.

Чем return отличается от break, continue и exit

Эти операторы часто путают, потому что все они меняют обычный ход выполнения. Но действуют они на разных уровнях: return — на уровне функции, break и continue — на уровне цикла, exit — на уровне всей программы.

Оператор Что делает Где применяется Куда уходит управление
return завершает текущую функцию, отдает значение в точку вызова в любой функции в вызвавшую функцию
break прерывает ближайший цикл или switch внутри for/while/do-while/switch на строку после цикла или switch
continue пропускает остаток текущей итерации внутри цикла к проверке условия цикла (следующая итерация)
exit немедленно завершает всю программу где угодно, нужен #include <stdlib.h> в операционную систему

Практический ориентир: break и continue управляют одним циклом и не выходят из функции; return выходит из функции целиком (и из цикла заодно, если был внутри него); exit(код) не возвращает управление никуда внутри программы — процесс завершается. В main запись return 0; по эффекту близка к exit(0).

Частые ошибки

Разберем три типовые ошибки в формате «неверный код -> результат -> как исправить».

1. return без значения в не-void функции.

int get_answer(void) {
    return;   // функция объявлена int, а значение не отдано
}

Результат при сборке gcc -Wall:

warning: 'return' with no value, in function returning non-void [-Wreturn-type]

Исправление — вернуть значение нужного типа: return 42;. На части компиляторов (например, Clang) это не предупреждение, а ошибка компиляции — сборка не пройдет, пока функция не вернет значение.

2. Пропущенный return в не-void функции.

int square(int x) {
    int r = x * x;
    // забыли вернуть r
}

Результат gcc -Wall:

warning: control reaches end of non-void function [-Wreturn-type]

Вызвавший код получит непредсказуемое значение. Исправление — добавить return r; в конце.

3. Недостижимый код после return.

int f(void) {
    return 1;
    printf("сюда управление не дойдет\n");   // мертвый код
}

Строка после return 1; не выполнится никогда: return уже завершил функцию. Компилятор может пропустить это молча (clang с флагом -Wunreachable-code предупредит). Исправление — убрать мертвый код или перенести нужные действия до return.

Выводы

  • return немедленно завершает функцию и передает управление в точку вызова; код после сработавшего return не выполняется.
  • В не-void функции return обязан вернуть значение на каждом пути; иначе вызвавший получит неопределенный результат.
  • Возвращаемое значение приводится к типу функции, поэтому int-функция обрежет дробную часть, а double-функция превратит целое в дробное.
  • В void-функции return не возвращает значение, а просто досрочно выходит; это удобный ранний выход через охранное условие.
  • return, break, continue и exit работают на разных уровнях: функция, цикл, цикл, программа — их нельзя заменять друг другом.
  • В main return передает код завершения в операционную систему: 0 — успех, ненулевой — ошибка.

Где применяется / связь с практикой

Возврат значений — основа любой программы на C: функции получают данные, обрабатывают и отдают результат через return, а main через него сообщает системе код завершения. Без уверенного понимания return сложно писать функции, разбивать программу на части и обрабатывать ошибки.

Освойте тему на практике

Отработать это на практике, с проверкой преподавателя, можно на курсе C++ для начинающих: там разбираются функции, возврат значений, работа с памятью и синтаксис, общий у C и C++. Посмотреть формат занятий и задать вопросы преподавателю можно на бесплатных вебинарах — это открытые уроки без оплаты.

Смежные темы: Язык C: области применения, Условный оператор IF: принципы работы, C++: описание языка и его основы.

FAQ

Сколько return может быть в одной функции?
Сколько угодно — например, свой return в каждой ветке if. Сработает первый, до которого дойдет управление, остальные будут пропущены.

Обязателен ли return 0; в конце main в современном C?
Нет. По стандарту C99 и новее, если управление доходит до конца main без return, компилятор сам подставляет возврат 0. Явный return 0; все же полезен для читаемости.

return копирует значение или отдает ссылку на переменную функции?
В C возврат идет по значению — наружу уходит копия, а локальные переменные функции уже уничтожены. Возвращать адрес локальной переменной нельзя; чтобы отдать много данных, возвращают структуру или указатель на память, живущую дольше вызова.

OTUS Журнал
Бесплатные открытые уроки (поп-ап)