Serwis Edukacyjny w I-LO w Tarnowie ![]() Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy Wałaszek |
©2023 mgr Jerzy Wałaszek |
Z jedną funkcją spotkaliśmy się już na samym początku nauki C++: main( ). Jest to funkcja główna, od której program rozpoczyna działanie, zatem musi wystąpić w każdym programie w C++.
Ogólna definicja funkcja funkcji jest następująca:
typ nazwa(parametry) { kod }
typ | – | określa typ wyniku zwracanego przez funkcję. |
nazwa | – | umożliwia wywoływanie funkcji. |
parametry | – | określają dane przekazywane do funkcji. |
kod | – | instrukcje wykonywane wewnątrz funkcji. |
Typ może być dowolnym typem danych języka C++, np. int, unsigned, float, double... Jeśli funkcja nie zwraca żadnej wartości, to ma specjalny typ void (pustka). O takiej funkcji mówimy, że jest procedurą.
Jeśli funkcja nie potrzebuje danych z programu, to nawiasy za nazwą zostawiamy puste (parametrami zajmujemy się dalej w tym rozdziale).
Funkcje definiujemy zwykle na początku programu.
Funkcję wywołujemy podając jej nazwę, nawiasy i ewentualne wartości parametrów w nawiasach za nazwą funkcji.
Poniższy przykład programu pokazuje sposób wywołania funkcji w programie.
// Funkcje //-------- #include <iostream> using namespace std; // Definicja funkcji //------------------ void piszABC() { cout << "ABC"; return; // Koniec działania funkcji } // Funkcja główna //--------------- int main() { setlocale(LC_ALL,""); int i; for(i = 0; i < 20; i++) piszABC(); cout << endl; for(i = 0; i < 10; i++) { piszABC(); cout << endl; } cout << endl; return 0; } |
ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC ABC ABC ABC ABC ABC ABC ABC ABC ABC ABC |
Przyjrzyjmy się dokładnie temu programowi. W programie zdefiniowana jest
funkcja
Funkcja
Program wykorzystuje tę funkcję w dwóch pętlach for. Pierwsza wykonuje
się 20 razy i w każdym obiegu wywołuje funkcję
Druga pętla for wykonuje się 10 razy i w każdym obiegu wywołuje
funkcję
Zwróć uwagę, iż funkcje pozwalają skrócić program i uczynić go bardziej przejrzystym. Jedną z metod programowania jest rozbicie problemu na prostsze podproblemy i każdy z tych podproblemów jest następnie rozwiązywany w osobnej funkcji (dalej w kursie omówimy tę metodę dokładnie).
Następny przykład programu zawiera funkcję zwracającą pewną wartość.
// Funkcje //-------- #include <iostream> #include <iomanip> using namespace std; // Definicja funkcji //------------------ double pi2() { const double PI = 3.14159265; return PI * PI; } int main() { setlocale(LC_ALL,""); cout << fixed << setprecision(5); int i; double x; x = 1; for(i = 2; i <= 20; i += 2) { x *= pi2(); cout << "PI^" << setw( 2) << i << " = " << setw(16) << x << endl; } cout << endl; return 0; } |
PI^ 2 =
9.86960 PI^ 4 = 97.40909 PI^ 6 = 961.38919 PI^ 8 = 9488.53093 PI^10 = 93648.04641 PI^12 = 924269.16885 PI^14 = 9122171.03582 PI^16 = 90032219.19690 PI^18 = 888582384.79490 PI^20 = 8769956595.65997 |
Analiza:
W programie zdefiniowana jest funkcja
Pętla for wyświetla parzyste potęgi liczby π. Jak to robi?
Wykorzystuje zmienną x do wyliczania potęg. Na początku do zmiennej x
wprowadzamy 1, po czym w każdym obiegu przemnażamy x przez wartość
zwracaną przez funkcję
Przed pierwszym obiegiem: | x ← 1 | ; x = 1 |
Obieg pierwszy, i = 2 | x ← 1 · π2 | ; x = π2 |
Obieg drugi, i = 4 | x ← π2 · π2 | ; x = π4 |
Obieg trzeci, i = 6 | x ← π4 · π2 | ; x = π6 |
Obieg czwarty, i = 8 | x ← π6 · π2 | ; x = π8 |
... | ... | ... |
Numery obiegów w zmiennej i tworzą ciąg kolejnych liczb parzystych 2 4 6 8 ... Numery te odpowiadają wykładnikowi potęgi liczby π w zmiennej x.
Ciekawsze rzeczy można uzyskać, przekazując do funkcji dane w postaci parametrów. Tym zajmuje się następny podrozdział.
Parametry są danymi przekazywanymi do funkcji w czasie jej wywołania. Parametry określamy w trakcie definiowania funkcji, podając dla każdego z nich typ oraz nazwę. Nazwa parametru jest lokalna, tzn. nie jest widoczna poza funkcją, powiemy o tym za chwilę. Definicja parametru jest podobna do definicji zmiennej:
typ_funkcji nazwa_funkcji(lista_parametrów) { kod_funkcji }
lista_parametrów: typ nazwa_1, typ nazwa_2, ... typ nazwa_n
typ | – | określa rodzaj danych przekazywanych w parametrze. Jest to normalny typ C++: int, unsigned, float, double... |
nazwa_i | – | umożliwia w funkcji odwoływanie się do określonego parametru |
Jeśli na liście jest więcej niż jeden parametr, to ich definicje rozdzielamy przecinkami. Każdy parametr musi posiadać swoją własną definicję. Tu jest różnica w stosunku do zmiennych:
Definicja trzech zmiennych typu int:
int a,b,c;
Definicja trzech parametrów typu int:
(int a, int b, int c)
Listy parametrów również nie kończymy średnikiem, tylko nawiasem zamykającym parametry funkcji. Każdy parametr może posiadać oddzielny typ w zależności od potrzeb danej funkcji:
(int a, double x, bool c)
Wartości parametrów określone zostają w momencie wywołania funkcji.
Poniższy przykład pokazuje tworzenie funkcji z parametrami oraz wykorzystanie jej w programie:
// Funkcje //-------- #include <iostream> #include <iomanip> using namespace std; // Średnia dwóch liczb //-------------------- double srednia(double a, double b) { return (a + b) / 2; } int main() { setlocale(LC_ALL,""); cout << fixed << setprecision(4); int i, x, y; cout << " x y | Średnia z x i y" << endl << "------+----------------" << endl; for(i = 0; i < 10; i++) { x = 20 - (i * 2); y = 3 + (i * 6); cout << setw(2) << x << setw(3) << y << " | " << setw(10) << srednia(x,y) << endl; } cout << endl; return 0; } |
x y | Średnia z x i y ------+---------------- 20 3 | 11.5000 18 9 | 13.5000 16 15 | 15.5000 14 21 | 17.5000 12 27 | 19.5000 10 33 | 21.5000 8 39 | 23.5000 6 45 | 25.5000 4 51 | 27.5000 2 57 | 29.5000 |
Przeanalizujmy ten program:
W programie mamy zdefiniowaną funkcję o nazwie srednia( ) (w nazwie funkcji nie mogą występować polskie litery, jeśli cię to denerwuje, używaj nazw angielskich: średnia = average). Funkcja zwraca wynik zmiennoprzecinkowy typu double. Funkcja zwracająca wynik musi posiadać w swoim kodzie instrukcję return, która kończy działanie funkcji i zwraca jako jej wynik wartość wyrażenia, które umieścimy za return. Funkcja posiada dwa parametry typu double: a i b. W parametrach tych kod wywołujący funkcję przekazuje do niej dane, które funkcja ma przetworzyć. Parametry te widzimy w wyrażeniu, którego wartość zwraca instrukcja return jako wartość funkcji.
// Średnia dwóch liczb //-------------------- double srednia(double a, double b) { return (a + b) / 2; }
Teraz przejdźmy do miejsca w programie, w którym funkcja jest wywoływana:
for(i = 0; i < 10; i++)
{
x = 20 - (i * 2);
y = 3 + (i * 6);
cout << setw(2) << x
<< setw(3) << y
<< " | "
<< setw(10) << srednia(x,y)
<< endl;
}
Funkcja srednia( ) jest wywoływana wewnątrz pętli for, która wykonuje 10 obiegów. W pętli wyliczamy dwie liczby x i y, następnie wyświetlamy wyliczone liczby x i y oraz wynik funkcji srednia( ), do której przekazano wartości liczb x i y. Wewnątrz funkcji liczby x i y trafiają odpowiednio do parametru a (x) i b (y). Następnie funkcja wykorzystuje te wartości do wyliczenia średniej i zwraca wynik. Wynik funkcji zostaje przekazany do strumienia cout.
Wewnątrz funkcji parametry można traktować jak zmienne. Parametry można dowolnie zmieniać i modyfikować w kodzie funkcji. Opisany sposób przekazywania danych do funkcji nosi nazwę przekazywania przez wartość. W miejsce parametru przy wywołaniu funkcji możemy wstawić dowolne wyrażenie. Komputer oblicza wartość tego wyrażenia i wynik umieszcza w odpowiednim parametrze. Następnie uruchomiony zostaje kod funkcji, która wykorzystuje parametr do swoich obliczeń.
// Zmienne lokalne
//----------------
#include <iostream>
using namespace std;
// Funkcja
//--------
void f(void) // (void) = brak parametrów
{
int a = 15;
cout << "W funkcji f() zmienna a = "
<< a << endl << endl;
}
int main()
{
cout << "W funkcji main() zmienna a = "
<< a << endl << endl;
return 0;
}
|
C:\lekcje\005\main.cpp In function 'int
main()': C:\lekcje\005\main.cpp 25 error: 'a' was not declared in this scope |
Otrzymasz komunikat o błędzie, który mówi, iż zmienna a w funkcji main( ) w wierszu 25 jest niezdefiniowana. O co tutaj chodzi? Zmienna a jest zdefiniowana wewnątrz bloku funkcji f( ) i jest dla niej lokalna, tzn. że nie jest widoczna poza blokiem tej funkcji. Z kolei w funkcji main( ) program odwołuje się do zmiennej a, której jednak nie zdefiniowano w main( ). Zmienna a w main( ) jest zupełnie inną zmienną, to tak jak uczniowie w dwóch różnych klasach mogą posiadać te same nazwiska i imiona, jednak są różnymi osobami. Uruchom następny program:
// Zmienne lokalne //---------------- #include <iostream> using namespace std; // Funkcja //-------- void f(void) // (void) = brak parametrów { int a = 15; // zmienna lokalna w f() cout << "W funkcji f() zmienna a = " << a << endl << endl; } int main() { double a = 3.1415; // zmienna lokalna w main() f(); cout << "W funkcji main() zmienna a = " << a << endl << endl; return 0; } |
W funkcji f() zmienna a = 15 W funkcji main() zmienna a = 3.1415 |
W obu funkcjach są zdefiniowane zmienne o nazwie a. W rzeczywistych programach należy raczej unikać takich rozwiązań, bo mogą być mylące, tu jednak utworzyliśmy te zmienne specjalnie, aby zademonstrować ich lokalność. Obie zmienne są różnymi zmiennymi. W funkcji f( ) zmienna lokalna a jest typu int i ma nadaną wartość 15. W funkcji main( ) zmienna lokalna a jest typu double i ma wartość 3.1415. Jak widać, obie zmienne są różne, mają tylko taką samą nazwę.
Wynika z tego pewien problem: co zrobić, jeśli chcemy, aby zmienna była widoczna i dostępna w całym programie? Rozwiązaniem są zmienne globalne. Takie zmienne definiujemy na początku programu przed funkcjami, w których mają być dostępne. Uruchom poniższy program:
// Zmienne lokalne //---------------- #include <iostream> using namespace std; // Zmienna globalna int a = 21; // Funkcja //-------- void f(void) { cout << "W funkcji f() zmienna a = " << a << endl << endl; } int main() { f(); cout << "W funkcji main() zmienna a = " << a << endl << endl; return 0; } |
W funkcji f() zmienna a = 21 W funkcji main() zmienna a = 21 |
Teraz nasza zmienna a jest dostępna w obu funkcjach i nie musimy jej w nich definiować. Zmienne globalne należy stosować ostrożnie, ponieważ mogą być zmieniane w dowolnym miejscu programu, czasem w sposób niezamierzony przez programistę. Stara maksyma programistów mówi, iż najlepszą liczbą zmiennych globalnych jest 0. Uruchom poniższy program:
// Zmienne lokalne //---------------- #include <iostream> using namespace std; // Zmienna globalna int a = 1; // Funkcje //-------- void f1(void) { cout << (++a) << " "; } void f2(void) { cout << (a *= 3) << " "; } void f3(void) { cout << (a -= 5) << " "; } int main() { int i; for(i = 0; i < 10; i++) { f1(); f2(); f3(); } cout << endl << endl; return 0; } |
2 6 1 2 6 1 2 6 1 2 6 1 2 6 1 2 6 1 2 6 1 2 6 1 2 6 1 2 6 1 |
Postaraj się przeanalizować działanie tego programu. Zmień wartość początkową zmiennej globalnej a na 2. Jak zmienią się wyniki?
Jeśli zmienna zostanie utworzona wewnątrz bloku, to będzie zmienną lokalną dla tego bloku. Odnosi się to w szczególności do instrukcji for. Wpisz do edytora poniższy program i spróbuj go skompilować:
// Zmienne lokalne
//----------------
#include <iostream>
using namespace std;
int main()
{
for(int i = 0; i < 10; i++)
cout << "Zmienna i w for = "
<< i << endl;
cout << endl
<< "Zmienna i poza for = "
<< i << endl << endl;
return 0;
}
|
Znów trzymasz informację o błędzie: zmienna i niezdefiniowana. O co tutaj chodzi? Zwróć uwagę, iż zmienna i została zdefiniowana wewnątrz instrukcji pętli for:
for(int i = 0; i < 10; i++)
Jest zatem zmienną lokalną tylko dla tej instrukcji. W zaznaczonej instrukcji, która jest poza pętlą for, program odwołuje się do zmiennej i, lecz nie ma do nie dostępu, ponieważ zmienna ta jest lokalna dla instrukcji for i tylko w niej jest dostępna.
Zmodyfikujmy nieco ten program:
// Zmienne lokalne //---------------- #include <iostream> using namespace std; int main() { float i = 2.73; cout << endl << "Zmienna i poza for = " << i << endl << endl; for(int i = 0; i < 10; i++) cout << "Zmienna i w for = " << i << endl; cout << endl << "Zmienna i poza for = " << i << endl << endl; return 0; } |
Zmienna i poza for = 2.73 Zmienna i w for = 0 Zmienna i w for = 1 Zmienna i w for = 2 Zmienna i w for = 3 Zmienna i w for = 4 Zmienna i w for = 5 Zmienna i w for = 6 Zmienna i w for = 7 Zmienna i w for = 8 Zmienna i w for = 9 Zmienna i poza for = 2.73 |
Na początku funkcji main została dodana definicja zmiennej i. Specjalnie zmieniony został typ tej zmiennej na float, aby pokazać, że jest to zupełnie inna zmienna od tej, którą zdefiniowano w instrukcji for. Zmienne te posiadają tylko tę samą nazwę. W pętli for zmienna lokalna i przebiega wartości od 0 do 9 i są to wartości całkowite. Zmienna i poza pętlą for przechowuje wartość zmiennoprzecinkową 2.73, której pętla for zupełnie nie zmienia.
Zapamiętaj, iż zmienna lokalna o tej samej nazwie, co zmienna zdefiniowana na wyższym poziomie zawsze przesłania tą drugą. W rzeczywistych programach należy raczej unikać takich sytuacji, ponieważ są mylące (dla programisty):
// Zmienne lokalne //---------------- #include <iostream> using namespace std; int main() { float i = 2.73; // Lokalna dla bloku main() { // Blok #1 int i = 15; // Lokalna dla bloku #1 { // Blok #2 double i = 3.1415; // Lokalna dla bloku #2 cout << i << endl; // Z bloku #2 } cout << i << endl; // Z bloku #1 } cout << i << endl; // Z bloku main() return 0; } |
3.1415 15 2.73 |
Ze zmiennymi lokalnymi i globalnymi wiąże się w języku C++ wiele różnych zagadnień, część z nich omówimy później, z resztą zapoznasz się na studiach informatycznych.
1GB = 230 bajtów = 1.073.741.824 bajtów
Programując w języku C++ nie musisz zwykle znać liczbowych adresów komórek pamięci, jednak powinieneś coś wiedzieć na ich temat. Kompilator dba o to, aby twój program umieszczał dane we właściwym miejscu pamięci, a następnie je z niego pobierał. Do tego celu wymyślono zmienne. Nazwa zmiennej informuje komputer o który obszar pamięci chodzi. Pod nazwą ukryty jest adres zmiennej w pamięci. Do wydobycia adresu z nazwy zmiennej mamy w C++ operator adresu &. Operator & w wyrażeniu umieszczamy przed nazwą zmiennej, której adres chcemy otrzymać. Uruchom poniższy program:
// Adres zmiennej //---------------- #include <iostream> using namespace std; int main() { setlocale(LC_ALL,""); double x = 12.56; cout << "Wartość x : " << x << endl << "Adres x : " << &x << endl << endl; return 0; } |
Wartość x : 12.56 Adres x : 0x61fe18 |
Strumień prezentuje adresy obiektów w pamięci w postaci liczby szesnastkowej. U ciebie adres 0x61fe18 może być inny - zależy to od zajętości pamięci, zwykle nie ma to znaczenia, ważne jest tylko to, iż mamy dostęp do adresu. Po co nam adres? W języku C++ możemy utworzyć zmienną do przechowania adresu zmiennej określonego typu. Taką zmienną nazywamy wskaźnikiem (ang. pointer). Wskaźnik definiujemy następująco:
typ * nazwa;
typ | : | określa typ danych, których adres przechowuje wskaźnik |
* | : | operator wskazania, informuje, że zmienna jest wskaźnikiem do danych, a nie danymi |
nazwa | : | nazwa wskaźnika |
Uruchom poniższy program:
// Adres zmiennej //---------------- #include <iostream> using namespace std; int main() { setlocale(LC_ALL,""); double x = 12.56; double *p = &x; // Tworzymy wskaźnik i wpisujemy // do niego adres zmiennej x cout << "Wartość x : " << x << endl << "Adres x : " << &x << endl << "Wskaźnik p : " << p << endl << endl; return 0; } |
Wartość x : 12.56 Adres x : 0x61fe10 Wskaźnik p : 0x61fe10 |
Zwróć uwagę na to, jak utworzono wskaźnik. Sama definicja wskaźnika tworzy jedynie zmienną do przechowywania adresu. Zmiennej należy przypisać odpowiedni adres, aby była użyteczna. Mając adres zmiennej, możemy uzyskać do niej dostęp przy pomocy operatora wskazania (*):
Jeśli p jest adresem zmiennej x, to *p jest wskazywaną przez p zmienną x. Uruchom poniższy program:
// Adres zmiennej //---------------- #include <iostream> using namespace std; int main() { setlocale(LC_ALL,""); double x; double *p = &x; // Tworzymy wskaźnik p i wpisujemy // do niego adres zmiennej x // Korzystając ze wskaźnika p nadajemy zmiennej x wartość *p = 16.3333; cout << "Wartość x = " << x << endl << endl; return 0; } |
Wartość x = 16.3333 |
W programie wpisaliśmy do zmiennej x wartość 16.3333 korzystając z adresu we wskaźniku p. Ponieważ wskaźnik jest zmienną, to zmiana adresu spowoduje, iż zacznie on wskazywać inny obiekt. Jednak musisz pamiętać, iż w języku C++ adresy mają typy i nie można normalnie do wskaźnika wpisać adresu innego typu, np. jeśli stworzyliśmy w programie wskaźnik do zmiennych typu double, to nie możemy przypisywać mu adresu zmiennej typu int. Dlaczego? Zmienne są umieszczane w pamięci obok siebie. Zmienna typu double zajmuje 8 bajtów pamięci, czyli tyle co 2 zmienne typu int. Wprowadzenie danych o długości 8 bajtów do danej o długości 4 bajtów mogłoby spowodować nadpisanie innej zmiennej, która w pamięci leży obok, co z kolei najprawdopodobniej doprowadziłoby do błędnego działania całego programu. Na szczęście kompilator C++ wykrywa takie błędy.
// Wskaźniki //---------------- #include <iostream> #include <iomanip> using namespace std; // Funkcja oblicza wynik dzielenia // całkowitoliczbowego oraz resztę // z tego dzielenia //-------------------------------- int divmod(int a, int b, int * p) { * p = a % b; return a / b; } int main() { setlocale(LC_ALL,""); for(int i = 0; i < 10; i++) { int x,y,r; x = (i + 4) * 20; y = (i + 2) * 3; cout << setw(3) << x << " /" << setw(3) << y << " =" << setw(3) << divmod(x,y,&r) << " i reszta" << setw(3) << r << endl; } cout << endl; return 0; } |
80 / 6 = 13 i reszta 2 100 / 9 = 11 i reszta 1 120 / 12 = 10 i reszta 0 140 / 15 = 9 i reszta 5 160 / 18 = 8 i reszta 16 180 / 21 = 8 i reszta 12 200 / 24 = 8 i reszta 8 220 / 27 = 8 i reszta 4 240 / 30 = 8 i reszta 0 260 / 33 = 7 i reszta 29 |
Przeanalizujmy ten program. Zaczynamy od funkcji:
int divmod(int a, int b, int * p) { * p = a % b; return a / b; }
Funkcja divmod( ) przyjmuje trzy parametry. Pierwsze dwa a i b są typu int. To normalne parametry, w których komputer umieści dane przy wywołaniu funkcji. Trzeci parametr p jest wskaźnikiem do danej typu int. W tym parametrze komputer umieści adres zmiennej typu int. Mając ten adres, funkcja uzyskuje dostęp do tej zmiennej poprzez operator wskazania * tak, jakby była ona zdefiniowana wewnątrz bloku funkcji.
W bloku funkcji wykonywane są dwie operacje. Pierwsza wylicza resztę z dzielenia a przez b i umieszcza ją w pamięci pod adresem wskazywanym przez wskaźnik p. Dzięki wskaźnikowi wynik ten zostanie zapamiętany poza funkcją i będzie go można wykorzystać. Druga operacja kończy działanie funkcji, zwracając jako jej wynik iloraz całkowity a przez b.
Teraz przejdźmy do funkcji main( ). Znajduje się tutaj pętla for. Przyjrzyjmy się jej bliżej:
for(int i = 0; i < 10; i++) { int x,y,r; x = (i + 4) * 20; y = (i + 2) * 3; cout << setw(3) << x << " /" << setw(3) << y << " =" << setw(3) << divmod(x,y,&r) << " i reszta" << setw(3) << r << endl; }
W pętli zdefiniowane są cztery zmienne lokalne typu int: i, x, y, r. Zmienna i służy do zliczania obiegów pętli oraz do tworzenia wartości x i y. Wartości te są przekazywane do funkcji divmod( ), która je dzieli i zwraca wynik, a resztę z dzielenia umieszcza w zmiennej r przekazanej do funkcji poprzez adres w trzecim argumencie. Instrukcja cout wyświetla w konsoli wartości x, y, x / y (wynik funkcji) oraz x % y (zwrócone przez funkcję w zmiennej r).
Przekazywanie adresu zmiennej w parametrze funkcji jest w języku C++ używane dosyć często, dlatego uproszczono ten proces przez wprowadzenie tzw. referencji. W parametrze funkcji umieszcza się przed nazwą parametru operator adresu &, który informuje kompilator, że dany parametr będzie zawierał adres zmiennej, a nie dane. W kodze funkcji odwołanie do tej zmiennej następuje poprzez nazwę parametru (bez operatora *). Również w wywołaniu w parametrze umieszcza się samą nazwę zmiennej bez operatora adresu &. Uruchom poniższy program:
// Referencja //----------- #include <iostream> #include <iomanip> using namespace std; // Funkcja oblicza wynik dzielenia // całkowitoliczbowego oraz resztę // z tego dzielenia //-------------------------------- int divmod(int a, int b, int & p) { p = a % b; return a / b; } int main() { setlocale(LC_ALL,""); for(int i = 0; i < 10; i++) { int x,y,r; x = (i + 4) * 20; y = (i + 2) * 3; cout << setw(3) << x << " /" << setw(3) << y << " =" << setw(3) << divmod(x,y,r) << " i reszta" << setw(3) << r << endl; } cout << endl; return 0; } |
Jest to ten sam program, co poprzednio. Zwróć uwagę na różnicę definicji parametru funkcji:
Z referencją | Ze wskaźnikiem |
int divmod(int a, int b, int & p) { p = a % b; return a / b; } |
int divmod(int a, int b, int * p) { * p = a % b; return a / b; } |
Trzeci argument jest zdefiniowany jako adres zmiennej: int & p, a nie jako wskaźnik int * p. W kodzie funkcji odwołujemy się do zmiennej po prostu nazwą parametru p = a % b, a nie wskaźnikiem * p = a % b.
Również wywołanie funkcji jest teraz uproszczone: divmod(x,y,r), a nie divmod(x,y,&r). Adres zmiennej jest automatycznie przekazywany do parametru funkcji.
Taki sposób przekazywania danych do funkcji nosi nazwę przekazywania przez referencję. Poznaliśmy dwa sposoby przekazywania danych do funkcji:
f(typ x) { funkcja otrzymuje w parametrze x wartość }
f(typ &x) { funkcja otrzymuje w parametrze x adres innej zmiennej, do której ma pełen dostęp }
Jeśli parametr przekazywany jest poprzez wartość, to w wywołaniu funkcji można w nim umieścić dowolne wyrażenie. Komputer obliczy wartość tego wyrażenia i wynik przekaże do funkcji.
Jeśli parametr przekazywany jest przez referencję, to w wywołaniu funkcji należy w nim umieścić zmienną, którą chcemy przekazać funkcji. Komputer wyznaczy adres tej zmiennej i skojarzy go z parametrem. W ten sposób parametr referencyjny będzie odpowiadał przekazanej zmiennej - jeśli funkcja go zmieni, to zmiana wystąpi w przekazanej zmiennej. W ten sposób funkcje mogą udostępniać sobie zmienne lokalne. Przeanalizuj poniższy program:
// Referencja //----------- #include <iostream> #include <iomanip> using namespace std; int set3(int & x, int & y, int & z, int n) { x = n; y = x + n / 2; z = x * y; } int main() { setlocale(LC_ALL,""); int a,b,c; cout << " n a b c" << endl << "--------------------" << endl; for(int i = 0; i < 10; i++) { set3(a,b,c,i * 3); cout << setw(5) << i * 3 << setw(5) << a << setw(5) << b << setw(5) << c << endl; } cout << endl; return 0; } |
n a
b c -------------------- 0 0 0 0 3 3 4 12 6 6 9 54 9 9 13 117 12 12 18 216 15 15 22 330 18 18 27 486 21 21 31 651 24 24 36 864 27 27 40 1080 |
![]() |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2023 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone
pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.