§ 17. Массивы и структуры как параметры функций

17.1. Передача параметра по значению и по ссылке

По умолчанию аргументы функции в C++ передаются по значению. Когда аргумент передается по значению, то его значение копируется в параметр функции.

Рассмотрим пример 17.1. В первом вызове функции func аргументом является число 5. При вызове функции создается переменная k, значение 5 копируется в нее. Выполняются команды функции, работающие с этим значением. Затем, когда func завершит свою работу, переменная k  уничтожается.

Во втором вызове функции аргументом является переменная x со значением 2. При вызове переменная k создается снова, и значение 2 копируется в k. По завершении работы функции переменная k уничтожается.

В третьем вызове функции аргументом является выражение x + 3, которое сначала вычисляется (получаем 5), а затем это значение копируется в переменную k, которая уничтожается по завершении работы функции.

Поскольку функция работает с копией переданного значения, то исходное значение не может быть изменено функцией (пример 17.2). Значения переменных x и y, которые удвоились внутри функции, после ее вызова остались не измененными. Обратите внимание на переменную k, которая является параметром функции func, а также описана внутри main. Для компилятора это совершенно разные переменные. Во время работы функции func значение переменной k, объявленной в main, не известно.

Другим способом передачи значений параметров в функции может быть передача параметров по ссылке. Ссылка — тип переменной в C++, который работает как псевдоним другого объекта или значения. При объявлении ссылки используется знак амперсанд (&), который записывают между типом данных и именем ссылки.

Функция в примере 17.3 отличается от функции в примере 17.2 тем, что параметр k объявлен как ссылка.

При передаче параметра по ссылке не создается копия передаваемого объекта. Все действия происходят с тем объектом, на который указывает ссылка.

Разные способы передачи параметров имеют свои плюсы и минусы.

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

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

При передаче значения по ссылке возможен вызов функции, параметр которой еще не задан (пример 17.4). Значение параметра можно определить путем ввода с клавиатуры или из файла либо путем вычислений. Если формальный параметр объявлен как ссылка, то фактическим параметром может быть только переменная, описанная до вызова функции. 

Пример 17.1. Программа:

#include <iostream>

 

using namespace std;

 

void func(int k)

{

  k *= 2;

  cout << k << endl;

}

 

int main()

{

  func(5);

  int x = 2;

  func(x);

  func(+ 3);

  return 0;

}

Тестирование.

Пример 17.2. Программа:

#include <iostream>

 

using namespace std;

 

int func(int k)

{

  k *= 2;

  return k;

}

 

int main()

{

  int x = 1, y = 3;

  int k = func(x) + func(y);

  cout << x << " " << y;

  cout << " " << k << endl;

  return 0;

}

Тестирование.

Пример 17.3. Программа:

#include <iostream>

 

using namespace std;

 

int func(int &k)

{

  k *= 2;

  return k;

}

 

int main()

{

  int x = 1, y = 3;

  int k = func(x) + func(y);

  cout << x << " " << y;

  cout << " " << k << endl;

  return 0;

}

Тестирование.

При вызове func(x) параметр k становится псевдонимом переменной x. Таким образом, все, что описано для переменной k, будет происходить с переменной x. После завершения работы функции значение переменной x будет изменено (увеличится в 2 раза). Следующий вызов func(y) сделает параметр k псевдонимом переменной y, которая также изменит свое значение после выполнения функции.

Пример 17.4. Программа:

include <iostream>

 

using namespace std;

 

void vvod_chisla (int &x)

{

  cout << "vvedi chislo" << endl;

  cin >> x;

}

int main()

{

  int a, b, c;

  vvod_chisla(a);

  vvod_chisla(b);

  vvod_chisla(c);

  cout << "a = " << a ;

  cout << " b = " << b ;

  cout << " c = " << c << endl;

  return 0;

}

Тестирование.

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