§ 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;

}

Тэсціраванне.

Значэнні пераменных да выкліку функцыі не вядомыя. Яны будуць вызначаны пры выкліку функцыі і змешчаны па адпаведных адрасах у памяці. Калі ў апісанні такой функцыі зняць спасылку, то пераменныя будуць вызначаны адвольнымі значэннямі.