Laboratorium 5

Funkcje

Deklaracja funkcji

W języku C++ obowiązuje zasada deklarowania prototypu każdej funkcji przed jej użyciem. Deklaracja funkcji ma postać typ_zwracany nazwa(argumenty);

Przykłady deklaracji

 double potega(double,int);

Deklaracja funkcji potega o typie zwracanym double (typ zmiennoprzecinkowy) i dwóch argumentach: jednym typu double, zaś drugim typu int.

 int fun(); 

Deklaracja funkcji o typie zwracanym int, bez argumentów.

Typ zwracany przez funkcje może być typem pustym void. Wtedy funkcja nie zwraca żadnej wartości.

Definicja funkcji

Składnia definicji funkcji jest następująca:

 
      typ nazwa(argumenty){
instrukcje
}

Ostatnią instrukcją powinna być instrukcja

 return wyrazenie; 

która zwraca wynik działania funkcji (w przypadku funkcji o typie zwracanym void instrukcja return nie jest konieczna).

Przykłady funkcji

Definicja funkcji potega:

      double potega(double d,int p){
        int i;
        wynik=1;
        for ( i=1 ; i<=p ; i++ )
          wynik*=d;
        return wynik;
      }
      

Wywoływanie funkcji

Wywołanie funkcji ma składnię:

 nazwa(argumenty aktualne);

Przykład:

 d=potega(5.0,3);

Przeanalizuj program potega.cpp.

Przekaz argumentów

W C++ domyślnie argumenty przekazywane są przez wartość. Zatem to co "stanie się" z argumentem przekazanym do funkcji nie ma wpływu na wartość zmiennej użytej jako argument. Przykładowo w poniższym kodzie

      void fun(int i){
        i++
        return;
      }
      ...
      int j;
      fun(j);
      

wywołanie funkcji fun nie wpłynie na zmienną j.

Czasami jednak chcemy, aby zmiany argumentu wewnątrz funkcji wpływało na zmianę przekazywanej zmiennej. Wtedy używamy przekazywania zmiennej przez referencję. Użycie odpowiednich konstrukcji ilustruje poniższy programik.

Przykład: zamiana.cpp

Przekazywanie tablic

Argumentem funkcji może być tablica. Wtedy argument ten w deklaracji ma postać

 typ[]
zaś w definicji funkcji używamy konstrukcji
 typ nazwa[]

Przykład:

      double srednia(double A[],int r){
        int i;
        double s=0;
        for ( i=0 ; i< r ; i++ )
	  sr+=A[i];
	return sr/r;
	}
	

Uwaga 1: Następująca konstrukcja

      void fun(double T[10]){ ... }
      

nie wymusza aby przekazywana tablica była 10-elementowa. Można równie dobrze przekazać do tej funkcji tablicę 5-elementową jak i 20-elementową. Dlatego nie wpisujemy rozmiaru tablicy w nawiasach kwadratowych, zaś rozmiar tablicy przekazujemy zwykle jako dodatkowy parametr.

Uwaga 2: Przekazując tablicę jako argument funkcji przekazujemy tak naprawdę jej adres. W związku z czym wszelkie zmiany zawartości tablicy wewnątrz funkcji dotyczą przekazanej tablicy!

Przykład: srednia.cpp.

Przekazywanie łańcuchów znaków

Łańcuch znaków w C++ jest tablicą typu char, w związku z czym przekazywanie tablicy do funkcji jest przekazaniem argumentu typu char[]. Jedyną różnicą jest fakt, że koniec łańcucha jest zawsze znakiem '\0', w związku z czym nie jest konieczne przekazywanie długości tablicy.

Przykład: anagram.cpp

Efekty uboczne - ostrzeżenie

Należ unikać używania efektów ubocznych przy przekazywaniu argumentów. Przykładowo sprawdź co jest wynikiem działania programiku

      void fun(int x,int y){
        cout << x << "," << y << endl;
      }
      int main(){
	int i=5;
	fun(i,i++);
      }
    

Wynika to stąd, że w przypadku Borland C++ argumenty są odkładane na stos "od końca" (czyli w powyższym przykładzie najpierw wyznaczany jest drugi argument!).

Jednakże standard ANSI nie określa w jakiej kolejności argumenty odkładane są na stosie, więc używając innego kompilatora możemy otrzymać inny wynik.

Podobnie należy być bardzo ostrożnym, jeśli jako argumentu funkcji użyjemy wyniku działania innej funkcji, która otrzymuje argument przez referencję, np.

      int f1(int &);
      ...
      fun(f1(i),i);
      ...