Урок 12. Функции и return

  Юрий Ворон  | 

    | 

  Обновлено 3 Ноя 2018  | 

 36841

 ǀ   17 

Функция – это последовательность стейтментов, выполняющих определенное задание. Вы уже знаете, что каждая программа должна иметь функцию main() (с которой она и начинает своё выполнение). Тем не менее, большинство программ используют и много других функций.

Часто, ваши программы должны будут прерывать то, что они делают, чтобы выполнить что-то другое. Вы делаете это в реальной жизни всё время. Например, вы читаете книгу и вспомнили, что нужно сделать телефонный звонок. Вы оставляете закладку в своей книге, звоните и когда уже поговорили, возвращаетесь к той странице, на которой остановились.

Программы в C++ работают также. Иногда, когда программа выполняет код, она может столкнуться с вызовом функции (function call). Вызов функции – это выражение, которое указывает процессору прервать текущую функцию и выполнить другую. Процессор «оставляет закладку» в текущей точке выполнения, а затем вызывает (выполняет) определенную функцию. Когда выполнение вызываемой функции завершается, процессор возвращается к месту, где «осталась закладка» и возобновляет выполнение.

Функция, в которой находится вызов — называется caller, а функция, которую вызывают – callee (либо «вызываемая функция»).



Ниже приведен пример программы с вызовом функции:

Результат выполнения программы выше:

Starting main()
In doPrint()
Ending main()

Эта программа начинает выполнение с функции main() и первая строка выводит текст Starting main(). Вторая строка вызывает функцию doPrint(). На этом этапе выполнение инструкций в main() приостанавливается и процессор переходит к doPrint(). Первая (и единственная) строка в doPrint() выводит текст In doPrint(). Когда doPrint() завершает выполнение, caller (main ()) возобновляет выполнение с места остановки. Следовательно, следующая инструкция – вывод строки Ending main().

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

Правило: Не забывайте указывать скобки () при вызове функции.

Возвращаемые значения

Когда функция main() завершает своё выполнение, то она возвращает целочисленное значение обратно в операционную систему, используя стейтмент return.

Функции, которые вы пишете, также могут возвращать значения. Для этого нужно установить тип возвращаемого значения (или тип возврата). Он указывается при объявлении функции, перед её именем. Обратите внимание, тип возврата не указывает, какое конкретно значение будет возвращаться. Он указывает только, какого типа будет это значение.

Затем внутри вызываемой функции мы используем оператор return, чтобы указать, какое конкретно значение будет возвращаться в caller. Это значение, возвращаемое функцией, называется возвращаемым значением.

Рассмотрим простую функцию, которая возвращает целочисленное значение:

В первом вызове функции return7() функция возвращает значение 7 обратно в caller, которое затем передается в std::cout для вывода.

Во втором вызове функции return7() функция снова возвращает значение 7 обратно в caller. Выражение 7+3 производит значение 10. Значение 10 передается в std::cout для вывода.

В третьем вызове функции return7() функция возвращает значение 7 обратно в caller. Однако main() ничего не делает с возвращаемым значением, поэтому ничего и не происходит (возвращаемое значение игнорируется).

Примечание: Возвращаемые значения не будут выведены, если caller не отправит их в std::cout. В последнем вызове функции значение не отправляется в std::cout, поэтому ничего и не происходит.



Возвращаемые значения типа void

Функции могут и не возвращать значения. Чтобы сообщить компилятору, что функция не возвращает значение — нужно использовать тип возврата void. Посмотрим еще раз на функцию doPrint() из примера выше:

Эта функция имеет тип возврата void, который означает, что функция не возвращает значение обратно в caller. Поскольку значение не возвращается, то и оператор возврата (return) не требуется.

Вот еще один пример функции с типом возврата void:

В первом вызове функции returnNothing() выводится «Hey!», а затем ничего не возвращается обратно в caller. Точка выполнения возвращается в main(), и программа продолжает своё выполнение.

Второй вызов функции returnNothing() даже не скомпилируется. Функция returnNothing() имеет тип возврата void, который означает, что функция не возвращает значение. Однако main() пытается отправить это значение (которое не возвращается) в std::cout для вывода. std::cout не может обработать этот случай, так как значения не вывод не предоставлено. Следовательно, компилятор выдаст ошибку. Вам нужно будет закомментировать эту строку, чтобы компиляция прошла успешно.

Возврат в main

Теперь у вас есть понимание того, как работает функция main(). Когда программа выполняется, операционная система делает вызов функции main() и начинается её выполнение. Инструкции в main() выполняются последовательно. В конце main() возвращает целое значение (обычно 0) обратно в операционную систему. Поэтому main() объявляется как int main().

Почему нужно возвращать значение обратно в операционную систему? Возвращаемое значение в main() – это код состояния и он сообщает операционной системе успешно ли выполнена программа. Обычно, возвращаемое значение 0 (нуль) означает успех, а любое другое — ошибку.

Обратите внимание, по стандартам C++ функция main() должна возвращать целое число. Однако, если вы не укажете return в конце main(), то компилятор вернет 0 автоматически, если ошибок не будет. Но мы рекомендуем указывать return в main() и использовать тип возврата int для main().

Еще немного о возвращаемых значениях

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

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

Функция может возвращать только одно значение через return обратно в caller. Это может быть одно число (например, 5), значение переменной или выражения (которое производит одно значение). Или же определенное значение из набора возможных значений.

Но есть способы обойти правило возврата одного значения, возвращая таким образом сразу несколько значений, но об этом детальнее мы поговорим в главе 7.

Наконец, обратите внимание, функция может свободно определять, что означает её возвращаемое значение. Некоторые функции используют возвращаемые значения в качестве кодов состояния для указания результата выполнения (успешно или нет). Другие функции возвращают вычисленное или выбранное (из набора) значение. Еще другие функции ничего не возвращают. То, что функция возвращает, и значение этого значения — всё это определяется автором функции. Из-за большого разнообразия всего — было бы неплохо оставлять комментарии к собственным функциям, указывая не только, что они возвращают, но и что значат возвращаемые значения.

Повторное использование функций

Одну и ту же функцию можно вызывать несколько раз, что очень полезно.

Результат выполнения программы выше:

Enter an integer: 4
Enter an integer: 9
4 + 9 = 13

Здесь main() прерывается 2 раза. Обратите внимание, в обоих случаях, полученное значение, которое мы сохраняем в переменной x, передается обратно в main() с помощью return, а затем присваивается переменной a или b!

Также main() не является единственной функцией, которая может вызывать другие функции. Любая функция может вызвать любую другую функцию!

Результат выполнения программы выше:

Starting main()
O
K
Ending main()

Вложенные функции

В С++ функции не могут быть определены внутри других функций (быть вложенными). Следующая программа некорректна:

Правильно вот так:

Тест

Рассмотрите следующие программы и укажите, что они выводят, и какие из них не скомпилируются (и почему).

1.

Ответ 1

Результатом выполнения программы будет значение 13.

2.

Ответ 2

Эта программа не скомпилируется. Вложенные функции запрещены.

3.

Ответ 3

Эта программа скомпилируется, но не будет никакого вывода. Возвращаемые значения из функций не используются в main() и, таким образом, отбрасываются.

4.

Ответ 4

Эта программа не скомпилируется. Функция printO() возвращает void, который main() пытается отправить в std::cout. Это приведет к ошибке компиляции.

5.

Ответ 5

Эта программа выведет 6 дважды (в отдельных строках). Оба раза, когда вызывается функция getNumbers(), возвращается значение 6. Когда выполняется оператор return 6, то функция немедленно завершается и точка выполнения переходит в main(), return 8 никогда не выполняется.

6.

Ответ 6

Эта программа не скомпилируется, потому что функция имеет недопустимое имя.

7.

Ответ 7

Эта программа скомпилируется, но функция не будет вызываться, так как в вызове функции отсутствуют скобки. То, что выведется — зависит от компилятора.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (284 оценок, среднее: 4,83 из 5)
Загрузка...

Комментариев: 17

  1. Захар:

    // здраствуйте я правильно понял вопрос и выполнил задание ?

  2. Константин:

    Юра, в примере с printOK(), main(), выполняя код строку за строкой, видит printOK(), вызывает его и не дожидаясь ответа (т.к. он же void), продолжает свою работу, а тот в свою очередь также поступает с printO() и с printK() и все они параллельно работают или прерывают свое выполнение (а если так, то как они понимают где должна оказаться точка выполнения) и как возобновляют выполнение — ведь return-а у void-а нет
    Поясни, пожалуйста.

    1. Данила:

      вот как я понял там функциz возврата не нужна,так как функция вызывает другую функцию ,и так каждая функция по очереди . Это как раз пример как любая функция может дать вызов . Майн вызывает ПринтОК , функция ПринтОК ,в свою очередь (по запросу майн) вызывает уже две функции ПринтО и ПринтК. А Майн спокойно ждет ,когда эти две функции придут к ней по её вызовам.:D

  3. Ray:

    Доброго времени суток!

    Сайт наилучший, все очень доходчиво. Большое спасибо!

    Собрал примеры с нескольких уроков в одном примере и возникла пара вопросов:

    Компиляция выдает следующее:

    Starting main()
    Enter a number: 7
    Your number is: 7
    Inter an integer: 1
    Inter an integer: 2
    Inter an integer: 3
    Inter an integer: 4
    Inter an integer: 5
    2+3+4-5
    Ending main()
    Program ended with exit code: 0

    Вопрос: почему при компиляции, при многократном применении функции, возвращенных значений получается 5 (хотя переменных было 4:a,b,c,d ) ? и почему они начинаются со второго значения,т.е.2+3+4-5, а не 1+2+3-4 ?
    Заранее благодарен.

    1. Юрий Юрий:

      Так посмотрите сами у себя в функции main() код: что и за чем выполняется.

      Вы сначала вызываете doPrint — первое значение получаете (7). Затем вызываете getValueFromUsers — получаете второе значение (1). Затем инициализируете 4 переменные: a(2), b(3), c(4), d(5). Затем выполняете операции с 4 значениями: a + b + c — d. Второе значение getValueFromUsers (1) вы не присвоили никакой переменной в функции main(), только вывели в консоль, потому и значений 5. Почему вы добавляете 4 переменные и первое число 2, а не 1 — потому что отсчет начинается с переменной a(2).

    2. Максим:

      Почему я такой не доходчивый?! Я понимаю 50 на 50, но написать ничего не могу(

    3. Данила:

      у вас ,после допринт идет лишняя строка ,она обозначается как 1 ,её надо убрать и тогда 1 = а.

  4. Михаил:

    Привет)). Скажи пожалуйста я правильно понял, что если функция к примеру эта:

    инструкция return должна быть обязательно тоже х? Я просто к тому,что у тебя в примерах я заметил,что ты в return указываешь число,то в caller оно и возвращается.

    1. Юрий Юрий:

      Привет. Во всех функциях, кроме типа void, return должен возвращать значение указанного типа данных. Какое именно значение — не важно, главное, чтобы совпадал тип данных. В вашей функции кроме x, вы также можете просто записать:

      Ошибок от компилятора не будет. Но целесообразно возвращать x, так как вы используете функцию для получения значения.

  5. илья:

    странно, мне 10 лет но я что то понимаю

    1. Li4ik Li4ik:

      Ничего странного, если есть желание — будут возможности.

  6. beksheikh:

    Здравствуйте.скажите в институте учился и мне не говорили о ретурне.вместо этого использую getch(); подскажите в чем разница? Сначала добавляю библиотеку <conio.h> и потом в конце пишу гетч.и Второй вопрос.Как вы пишите std::cout(endl,cin) вместо этого научили писать в начале using namespace std; и потом вместо std::cout и тд пишу без стд.скажите как правильнее?)заранее Спасибо за ответ.С Уважением Beksheikh.

    1. Li4ik Li4ik:

      Привет.

      1. Функция getch() используется для захвата одного символа из консоли. Её вам говорили использовать в программах в самом конце, чтобы консольное окно не закрывалось сразу же после выполнения всех действий и чтобы вы успели увидеть результат. return же возвращает код состояния, в случае с return в функции main() — он возвращает 0, если всё произошло без ошибок, всё корректно и 1 (или любой другой символ ненулевой), если были обнаружены ошибки. Детальнее об этом говорится в этом же уроке.

      Функция main() должна возвращать значения, так как она типа int, а не void. return и getch выполняют разные задачи. return должен быть во всех функциях не void. getch() в конце можно прописывать, можно нет. Аналог ему:

      Если у вас консольное окно закрывается сразу же и вы не успеваете увидеть результат выполнения вашей программы — используйте либо getch();, либо system(«pause»);.

      2. Подробный ответ на второй ваш вопрос находится в уроке 24 и в уроке 54.

  7. nurdosramazan:

    Отличный сайт. Автору спасибо
    (даже адблок отключил ;))

    1. Li4ik Li4ik:

      Ахахах спасибо, учись на здоровье 🙂

  8. Алексей:

    Тут не хватает «{»
    У вас не поставлена=)

    1. Li4ik Li4ik:

      Спасибо, исправил.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

telegram канал
RAVESLI