Programowanie w języku C/C++

Funkcje

Spis treści

          1 Podstawowe informacje
               1.1 Przykłady
          2 Wywoływanie funkcji
               2.1 Przykład
          3 Funkcje rekurencyjne
          4 Funkcje inline
          5 Przeładowanie nazwy funkcji


W programowaniu mianem funkcji określa się fragment kodu, który może być wykonywany wielokrotnie z różnych miejsc programu.

Podstawowe informacje


Ogólny zapis funkcji wygląda tak:

typ nazwa(argumenty)
{
  ciało funkcji
}

Typ określa, jaki typ danych zwraca ta funkcja, tzn. do zmiennej jakiego typu można przypisać wynik funkcji. Funkcja może nie zwracać żadnego typu, wtedy jej typem jest Void - jeśli znasz Pascala łatwiej Ci to będzie porównać do procedur. Do zwracania danej wartości przez funkcję odpowiada słowo kluczowe return. Nazwa służy do identyfikowania funkcji w programie. Nazwa funkcji nie zawsze jednoznacznie identyfikuje funkcję. Argumenty określają, jakiego typu zmienne należy przekazać do funkcji przy jej wywoływaniu. W przypadku, kiedy nazwa nie identyfikuje jednoznacznie funkcji (istnieją dwie różne funkcje o tych samych nazwach), parametry tych funkcji muszą się różnić. Mamy wtedy doczynienia z przeładowaniem nazwy funkcji (patrz niżej). Argumenty funkcji mogą przyjmować wartości domyślne. Należy w takim przypadku po nazwie argumentu dodać znak równości i wartość domyślną. Ciało funkcji jest to kod, który zostanie wykonany po wywołaniu funkcji.

Przykłady


Funkcja nie zwracająca wyniku, nie przyjmująca argumentów (typu Void):

void foo()
{
  cout << "tekst\n";
}

Funkcja nie zwracająca wyniku, przyjmująca parametr bez wartości domyślnych:

void foo(char *tekst)
{
  cout << tekst;
}

Funkcje zwracająca wynik, przyjmująca parametry bez wartości domyślnych:

int foo(int a, int b)
{
  return a + b;
}
 
int foo2(int a, int b)
{
   int c = a + b;
   return c;
}

Funkcja zwracająca wynik, przyjmująca parametry z wartością domyślną:

int foo(int a, int b = 0)
{
   return a + b;
}

Wywoływanie funkcji


Aby wywołać w programie przygotowaną wcześniej funkcję, należy po prostu wpisać w odpowiednim miejscu jej nazwę, a w nawiasach okrągłych argumenty do tej funkcji. Wywoływana funkcja musi zawsze być zadeklarowana przed miejscem, gdzie została wywołana. Można przed wywołaniem funkcji napisać tylko jej deklarację, zaś definicję (ciało) w dowolnym miejscu programu.

W językach C/C++ jeśli funkcja nie posiada argumentów należy ją wywoływać stawiając za jej nazwą pusty nawias, np foo()

Przykład


#include <iostream>
using namespace std;
 
int foo(int a, int b); // Deklaracja funkcji
 
int main()
{
   int a;
   cin >> a;
   int b = foo(a, 5);
   cout << b << endl;
 
   return 0;
}
 
int foo(int a, int b)
{
   return a+b;
}

Funkcje rekurencyjne


Funkcje rekurencyjne są to funkcje wywołujące same siebie. Może się to wydać na pierwszy rzut oka dziwne. Ten typ funkcji należy omówić na przykładzie. Jedną z takich funkcji rekurencyjnych będzie funkcja obliczających silnię z liczby. Definicja silni wygląda następująco:

0 != 1;
n != (n-1)!*n;

Jeśli rozpiszemy ten wzór, szybko się przekonamy, że silnia to po prostu iloczyn kolejnych liczb mniejszych od tej liczby i tej liczby. Dlatego pierwszą rzeczą jaką trzeba zrobić jest szkielet funkcji:

int silnia(int n)
{
}

Na dalszym etapie trzeba mieć opanowane instrukcje warunkowe. Następnym etapem jest sprawdzenie, czy argument n nie jest równy 0. Jeśli jest, można od razu zwrócić wartość (1):

int silnia(int n)
{
   if(n == 0) return 1;
}

Jeśli wartość jeszcze nie została zwrócona (a tym samem funkcja nie przerwała działania), oznacza to, że n jest różne od 0. Wyliczmy wtedy wartość silni ze wcześniej podanego wzoru:

int silnia(int n)
{
   if(n == 0) return 1;
   return silnia(n-1)*n; // rekurencja
}


Aby sprawdzić, czy funkcja rzeczywiście działa, napiszmy prosty program korzystający z niej:

#include <iostream>
using namespace std;
 
int silnia(int n)
{
   if(n == 0) return 1;
   return silnia(n-1)*n;
}
 
int main()
{
   int a;
   cin >> a;
   cout << silnia(a) << endl;
   return 0;
}

Przykładowe wyniki to:

0 != 1;
1 != 1;
2 != 2;
3 != 6;
4 != 24;
10 !=  3628800

Funkcje inline


Funkcje inline to mechanizm występujący w C++, podobny do Makrodefinicji z klasycznego C. Polega on na tym, że funkcja nie jest wywoływana, tylko jej zawartość jest "wklejana" w określone miejsce programu. Jest to korzystne dla bardzo małych funkcji - objętość kodu zwiększa się, ale zaoszczędza się czas związany z wywołaniem funkcji.

inline int dodaj(int a, int b)
{
    return a + b;
}


Przeładowanie nazwy funkcji


Przeładowanie (ang. overloading) nazwy funkcji związane jest z tym, że ma ono więcej niż jedno znaczenie. Ogólnie rzecz biorąc - ta bardzo przydatna cecha języka C++ służy do zadeklarowania (i oprogramowania) kilku funkcji o takiej samej nazwie. To oczywiście nie wszystko. Gdyby cała idea przeładowania nazwy funkcji kończyła się na samej jej nazwie, byłoby to po prostu nielogiczne. Reasumując, możemy zmieniać typy przekazywanych argumentów funkcji, jak również ich ilość oraz typ, który zwraca funkcja (ale zmiana jedynie zwracanego typu bez zmiany listy argumentów nie powoduje przeciążenia funkcji!).

Spójrz na przykład:

int dodaj(int liczba1, int liczba2)
{
  return liczba1 + liczba2;
}
 
double dodaj(double liczba1, double liczba2)
{
  return liczba1 + liczba2;
}

Powyżej zdefiniowałem dwie funkcje dodaj(), które zostały przeładowane, tj. różnią się listą argumentów (w pierwszej użyto typu Int, w drugiej Double). Przykład z użyciem powyższych funkcji:

int main()
{
  cout << dodaj(2, 4) << endl; // wyświetli: 6
  cout << dodaj(2.5, 4.5) << endl; // wyświetli: 7
}

W pierwszym wypadku wyświetlamy wynik dodawania liczb całkowitych, a potem - za pomocą "tej samej" funkcji - wynik dodawania liczb typu zmiennoprzecinkowego. Jest to przecież wygodniejsze, niż pisanie dwóch funkcji o różnych nazwach, gdyż zmieniamy tylko wartości przekazywane do parametrów, nie grzebiąc w nazwach funkcji. Jest to przydatne szczególnie w większych programach. Oczywiście nic nie stoi na przeszkodzie, aby zmienić ilość argumentów jednej z funkcji (w przytoczonym przykładzie przekazujemy dwa argumenty w obu funkcjach).

W C++ czasami lepiej zastosować Szablony_funkcji niż przeładowywanie nazw.

9 komentarzy

Brak avatara
Bios 2014-04-14 13:45

Kolega Jarmołowicz ma rację...
Dodam że kiełby z masłem są dobre.

Brak avatara
Jarmołowicz 2014-04-14 13:41

Powiem wam co powiem. A powiem że powiem co powiem. Że powiedziałem to co mówię kiedy to mówię...

sobol 2008-06-14 09:24

ja bym jeszcze dodal ze silnia moze byc tylko z liczb nieujemnych (dodatnich i zera)

Miczu 2006-11-12 21:37

Funkcje rekurencyjne jak pięknie zrobiona ^^ z tylu zadań z matmy moge pujść na łatwizne...

Kooba 2006-08-16 14:05

Jeszcze warto wspomnieć o funkcjach inline

Coldpeer 2006-06-01 18:34

Nie chodzi przecież o podstawową składnię między C a C++ (pod C++ printf() też pójdzie :)), tylko o istotę działania funkcji więc myślę, że można dać sobie z takimi detalami spokój :P

Wolverine 2006-06-01 17:07

Nie, chyba, ze w jakis magiczny sposob umiesz korzystac z iostream w C.

Maczugos 2006-06-01 16:35

dotyczy c i c++, nie widać?

Wolverine 2006-06-01 13:19

Nie mozna bylo do Worda tego wkleic? :/ Poza tym artykul mozna by napisac tak aby dotyczyl i C i C++.