В первой главе этого туториала мы рассматривали функции на следующих уроках:
Урок №12. Функции и оператор возврата return
Урок №13. Параметры и аргументы функций
Урок №19. Прототип функции и Предварительное объявление
Урок №20. Многофайловые программы
Перед тем как продолжить, вы должны быть знакомы с концепциями, обсуждаемыми на этих уроках.
Параметры vs. Аргументы
На следующих трех уроках мы поговорим о параметрах и аргументах, поэтому давайте вкратце вспомним их определения.
Параметр функции (или «формальный параметр») — это переменная, создаваемая в объявлении функции:
1 2 3 4 5 |
void boo(int x); // объявление (прототип функции). x - это параметр void boo(int x) // определение (также объявление). x - это параметр { } |
Аргумент (или «фактический параметр») — это значение, которое передает в функцию вызывающий объект (caller):
1 2 |
boo(7); // 7 - это аргумент, который передается в параметр x boo(y+1); // выражение y+1 - это аргумент, который передается в параметр x |
Когда функция вызывается, все параметры функции создаются как переменные, а значения аргументов копируются в параметры. Например:
1 2 3 4 5 |
void boo(int x, int y) { } boo(4, 5); |
При вызове функции boo() с аргументами 4
и 5
, создаются параметры x
и y
функции boo() и им присваиваются соответствующие значения: 4
и 5
. Результатом будет x = 4
и y = 5
.
Примечание: В примере, приведенном выше, порядок обработки параметров в функции boo() будет справа налево, т.е. сначала создастся переменная y
и ей присвоится значение 5
, а затем уже создастся переменная x
и ей присвоится значение 4
. Порядок, в котором инициализируются параметры в круглых скобках функции, определяет каждый компилятор отдельно, так как С++ явно не указывает этот порядок обработки. С параметрами-переменными это не столь важно и критично, но если вы будете использовать в качестве параметров функции вызовы других функций (что является плохой практикой и не рекомендуется к использованию), то результат может быть неожиданным.
Рассмотрим следующую программу:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <iostream> int prinX() { std::cout << "x = 4\n"; return 0; } int prinY() { std::cout << "y = 5\n"; return 0; } void prinAll(int a, int b) {} int main() { prinAll(prinX(), prinY()); // в качестве параметров функции используются вызовы функций X() и Y() return 0; } |
Результат выполнения программы:
y = 5
x = 4
Хотя параметры не объявлены внутри блока функции, они имеют локальную область видимости. Это означает, что они создаются при вызове функции и уничтожаются, когда блок функции завершается:
1 2 3 |
void boo(int x, int y) // x и y создаются здесь { } // x и y уничтожаются здесь |
Существует 3 основных способа передачи аргументов в функцию:
передача по значению;
передача по ссылке;
передача по адресу.
Мы рассмотрим каждый из этих способов по порядку.
Я бы еще уточнил, что передавать результат выполнения функций в качестве аргумента вполне безопасно в случае, если у этих функций нет побочных эффектов… Или эти побочные эффекты полностью независимы.
Просто хочу уточнить, что здесь описано не совсем верно. Функция считывает параметры в обратном порядке (по крайней мере в Visual Studio 2017).
И если для переменных это не критически важно, то при передаче функции в качестве аргумента (такое конечно лучше не творить, но все же) могут возникнуть ошибки, например:
выводом будет:
y = 5
x = 4
Вы правы. С++ явно не указывает порядок инициализации параметров в функции и уже каждый компилятор сам решает в каком порядке ему их инициализировать. Статью обновил.