Przekazywanie parametrów do funkcji przez wartość i przez referencję

Parametry funkcji są danymi, które otrzymuje ona w wywołaniu z programu głównego. Najczęściej są to dane niezbędne do wyznaczenia wyniku działania funkcji. Na przykład funkcja obliczająca pole powierzchni poniższej figury SF:

musi obliczyć pole koła SO i pole kwadratu SK, a wtedy:

Zatem do wyznaczenia pola musimy znać wartość średnicy koła d i boku kwadratu a. Ponieważ jednak kwadrat jest wpisany w koło, to jego bok a zależy od średnicy opisującego koła d. Zwróć uwagę na rysunek figury. Na pewno zauważysz, iż boki a tworzą kąty proste - bo to jest kwadrat. Natomiast średnica koła d jest przekątną kwadratu. Skoro tak, to z tw. Pitagorasa otrzymujemy:

Związek ten łączy ze sobą wielkości a i d. Jeśli znamy jedną z nich, to wyznaczymy drugą i bez problemu obliczymy pole figury w obu przypadkach:

Znane d:

 

Znane a:

// Obliczanie pola koła z wyłączeniem
// wpisanego weń kwadratu
//-----------------------------------

#include <iostream>
#include <iomanip>

using namespace std;

const double PI = 3.1415926535;

// Funkcja oblicza pole figury
// jeśli dana jest średnica d
//----------------------------
double SF(double d)
{
  return (PI/4 - 0.5) * d * d;       
}

main()
{
  double d;
  
  cout << "Pole koła bez wpisanego kwadratu\n\n"
          "Podaj srednice d = ";
  cin >> d;
  
  cout << setprecision(4) << fixed
       << endl
       << "Pole figury wynosi "
       << SF(d) << endl << endl;
       
  system("PAUSE");
}
// Obliczanie pola koła z wyłączeniem
// wpisanego weń kwadratu
//-----------------------------------

#include <iostream>
#include <iomanip>

using namespace std;

const double PI = 3.1415926535;

// Funkcja oblicza pole figury
// jeśli dany jest bok a
//----------------------------
double SF(double a)
{
  return (PI/2 - 1) * a * a;       
}

main()
{
  double a;
  
  cout << "Pole koła bez wpisanego kwadratu\n\n"
          "Bok kwadratu a = ";
  cin >> a;
  
  cout << setprecision(4) << fixed
       << endl
       << "Pole figury wynosi "
       << SF(a) << endl << endl;
       
  system("PAUSE");
}

 

W powyższym przykładzie przekazujemy do funkcji parametr poprzez wartość. Ogólnie parametr przekazywany przez wartość jest zdefiniowany na liście parametrów jako:

 

..., typ nazwa, ...

 

Przy wywołaniu funkcji możemy w jego miejscu umieszczać wyrażenie, które komputer wylicza i wartość przekazuje do funkcji. Na przykład powyżej zdefiniowane funkcje SF() możemy wywoływać na wiele różnych sposobów:

Z otrzymanym parametrem funkcja może zrobić wszystko, co jest w języku C++ dozwolone. Na przykład może zmienić sobie jego wartość. Jednakże zmiana ta obowiązuje jedynie wewnątrz funkcji. Rozważmy prosty program:

#include <iostream>

using namespace std;

int f(int x)  // parametr jest wartością
{
  x += 15;
  cout << x << endl;
  return x;    
}

main()
{
  int x = 10;
  cout << x << endl;
  f(x);     // do funkcji przekazujemy wartość zmiennej x
  cout << x << endl << endl;
  system("PAUSE");
}
10
25
10
 

W programie głównym wywołujemy funkcję f() pomiędzy wyświetleniem zmiennej x. Jak widać, zmienna x zachowuje przez cały czas swoją wartość 10. Do funkcji f() została przekazana kopia tej wartości. Funkcja f() lokalnie zwiększyła tę kopię o 15 wyświetlając wynik 25. Zmiana lokalnej wartości parametrów nie wpłynęła na zmienną x w programie głównym. Parametr x posiada jedynie taką samą nazwę jak zmienna x w funkcji main, lecz nie jest nią.

Teraz zmienimy sposób przekazania parametru do funkcji. Zamiast przez wartość parametr przekażemy przez referencję - funkcja otrzyma adres zmiennej, którą umieścimy na liście parametrów funkcji w czasie jej wywołania. Dzięki adresowi funkcja uzyska dostęp do zmiennej i będzie mogła zmienić jej wartość. Jedyna zmiana polega na dodaniu pomiędzy typem a nazwą parametru znaku &:

#include <iostream>

using namespace std;

int f(int & x)  // parametr jest adresem zmiennej
{
  x += 15;
  cout << x << endl;
  return x;    
}

main()
{
  int x = 10;
  cout << x << endl;
  f(x);         // do funkcji przekazujemy adres zmiennej x
  cout << x << endl << endl;
  system("PAUSE");
}
10
25
25
 

Wynikiem działania tego programu jest:

Teraz wynik jest inny. Ponieważ funkcja f() otrzymała adres zmiennej, to mogła zmienić jej zawartość. Dlatego zmienna x w funkcji main() przyjęła wartość 25 po wykonaniu f(x).

 

Podsumowanie

Parametr przekazywany przez wartość

typ nazwa_funkcji(...,typ nazwa_parametru,...)
{
  funkcja ma dostęp tylko do kopii danych
}

Parametr przekazywany przez referencję

typ nazwa_funkcji(...,typ & nazwa_parametru,...)
{
  funkcja ma dostęp do danych
}

Do czego to nam jest potrzebne?

Przekazywanie parametrów przez wartość stosuje się wtedy, gdy funkcja ma na ich podstawie jedynie coś wyliczyć.

Przekazywanie parametrów przez referencję, czyli poprzez adres zmiennej stosujemy wtedy, gdy funkcja powinna coś w tej zmiennej umieścić, np. wynik obliczeń. W ten sposób pojedyncza funkcja może zwrócić wiele różnych wyników w kilku zmiennych, których adresy otrzymała na liście parametrów.

Referencja jest wygodna także wtedy, gdy przekazywany obiekt ma duży rozmiar. Przekazanie przez wartość zawsze wymaga tworzenia kopii obiektu, którą otrzymuje funkcja do swojej wyłącznej dyspozycji. Przy dużych obiektach prowadzi to do intensywnych operacji pamięciowych, spowalniając działanie programu. Referencja natomiast wymaga jedynie przesłania adresu obiektu - zwykle 4 bajty. Jest zatem bardzo szybka. Jednakże z uwagi na bezpośredni dostęp do obiektu, programista musi być bardzo ostrożny, aby przypadkowo nie zmienić danych, których funkcja zmieniać nie powinna.

Zadanie

Zaprojektuj funkcję, która zamienia zawartości dwóch zmiennych przekazanych jej przez referencję.

 



List do administratora Serwisu Edukacyjnego Nauczycieli I LO

Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:
Uwaga: ← tutaj wpisz wyraz  ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048

 

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień szeroko opisywanych w podręcznikach.



   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2017 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.