FUNKCJE

CO trzeba umieć:


//////////////////////////////////////////////////////////////////



Funkcje to takie podprogramy, które wykorzystuje nasz główny program. Wykorzystuje się je po to, aby ułatwić sobie życie nie pisząc co kawałek tego samego, tylko wywołując jedną funkcje „n” razy oraz co ważniejsze do rekurencji, która to potrafi życie napsuć, że aż się rzygać chce, ale bez nie ani rusz :( .

Funkcje zawsze deklarujemy przed głównym programem, a za bibliotekami, czyli:

#include <stdio.h> // nasz główna biblioteka C

TUTAJ DEKLARUJEMY FUNKCJĘ

int main(){
...
}

Deklaracja:

typ_zwracany nazwa_funkcji (argumenty_funkcji);

typ_zwracany – typ zmiennej, która jest zwracana przez funkcję, jeśli funkcja nic nie zwraca dajemy void

nazwa_funkcji – dowolna (prawie) nazwa

argumenty_funkcji – zmienne których funkcja potrzebuje do działania. Przed każdą zmienną musi być jej typ

np.:
int suma(int a, int b);
void wypisz(int n, int tab[], float x);


Inicjacja funkcji może być w dwóch miejscach, razem z deklaracją lub po funkcji main.

W każdym z przypadków jest taka sama tylko inicjacja po funkcji głównej wymaga deklaracji, natomiast deklaracja z inicjacją jak sama nazwa wskazuje dodatkowej deklaracji już nie potrzebuje.

np.:

void wypisz(int t[], int n){
int i;
for(i=0;i<n;i++) printf(„%d ”, t[i]);
}

///////////////////////////////////////////////////

int suma (int a, int b){
return a+b; // polecenie zwraca wartość oraz PRZERYWA funkcje, jak break pętle
}


Wywołanie funkcji następuje w funkcji głównej, ale również może być w innej dowolnej funkcji.

np.: (wywołanie powyższych funkcji)

wypisz(t,n); // do funkcji dajemy tylko nazwy zmiennych

s=suma(x,y); // jak widać nie muszę to być takie same nazwy, bo do
// funkcji jest przekazywana
WARTOŚĆ, oraz jak
// funkcja coś zwraca musimy to coś gdzieś przypisać,
// bo to utracimy


Właśnie to funkcji jest przekazywana wartość, która jest pod zmienną, więc funkcję mogą być uniwersalne, ale nie to jest takie ważne. Ważne jest to, że funkcje nie zmieniają naszych zmiennych, czyli jak damy do funkcji „a” i „b” i sobie do nich dodamy jakieś liczby to po wyjściu z funkcji nasze „a” i „b” będą miały takie same wartości jak miały przed wejściem do niej. Natomiast tablice przekazane do funkcji ULEGAJĄ ZMIANIE, (wypalić sobie proszę to obok notki o tablicach). No dobra, ale jeśli uważnie czytałaś, to teraz w Twojej głowie może rodzić się pytanie.”Na ch*j mi te funkcje, jak nie mogę nic zmienić, a zwrócić mogę tylko jedną wartość?”. A no nie jest z tymi funkcjami tak źle :D. Bo jeśli chcemy zwrócić np. dwie wartości to używamy do tego typu strukturalnego i zwracamy właśnie jego i w ten sposób możemy zwrócić wiele wartości.

np.:

struct str{
   int x,y;
};

struct str fstr(int a, int b){
   struct str zmienna;
   zmianna.x=a*b;
   zmienna.y=a+b;

return zmienna;
}


W ten prosty sposób funkcja o nazwie fstr może zwrócić dwie wartości, ale należy pamiętać, żeby zwróconą strukturę przypisać również to typu strukturalnego str, bo w przeciwnym wypadku kompilator pokaże konflikt typów, albo wartość zostanie utracona.

Istnieje jeszcze jeden sposób na zmianę zmiennych w funkcji, ale on wymaga zmiany przekazywania argumentów do funkcji, czyli zamiast samych wartości do funkcji zostaje przekazany adres zmiennej, wtedy funkcja będzie mogła zmienić zmienną pod adresem, ale o tym troszeczkę później, bo to bardziej rozbudowany temat.

Rekurencja:

Rekurencja jest to wykonywanie funkcji przez samą siebie, czyli mamy taką sytuację, że funkcja wywołuje inną funkcję i jest to ta sama funkcja.
W rekurencji bardzo ważny jest warunek stopu, czyli taka sytuacja, w której funkcja już nie wykona samej siebie, ale zakończy działanie.

Najlepszym do tego przykładem (tak już bardzo wyświechtanym) jest licznie silni:

int silnia(int n){
  if(n==0) return 1; // warunek stopu
  else return n * silnia(n-1); // wywołanie samej siebie
}

Rekurencje ma taką fajną cechę, może „wracać”. Jeśli ktoś uważnie by rozpisał działający program, zauważyłby, że w pewnym momencie jak już ostatnia funkcja doszła do warunku stopu i została zamknięta, to program wraca do poprzedniego wywołania, w przypadku powyżej znowu następuje zamknięcie i we wszystkich kolejnych przypadkach. Dzieje się tak, ponieważ użyliśmy return, który kończy funkcję oraz dlatego, że w naszej funkcji nie ma już kodu.

Dla rozjaśnienia podam przykład dwóch kodów:
(funkcje mają za zadanie wypisać tablicę)

void write1 (int t[], int n){ // t-tablica n-rozmiar
   printf(„%d ”, t[n-1]); // wypisanie elementu
   if(n!=1) write1(t,n-1); // wywołanie funkcji
}

void write2 (int t[], int n){ // t-tablica n-rozmiar
   
   if(n!=1) write2(t,n-1); // wywołanie funkcji
   printf(„%d ”, t[n-1]); // wypisanie elementu

 
Dwie funkcje bardzo podobne do siebie. Ale trzeba się zastanowić jak działają, czyli jak wypisują elementy (Najlepiej jakbyś sam postarał się odpowiedzieć na to pytanie, a dopiero potem kontynuował czytanie)?

Pierwsza funkcja najpierw wypisze element [n-1] potem wywoła się ponownie. Nowe wywołanie wypisze element [(n-1)-1] i znowu się wywoła. Będzie tak się wywoływał, aż nasze „n” będzie równe 1, czyli na ekranie pojawi się element [0]. Oznacza to, że funkcja wypisuje elementy od tyłu.

Druga funkcja najpierw się wywoła potem znowu się wywoła i będzie tak się wywoływała, aż nasze „n” będzie równe 1. Gdy nasze „n” będzie równe 1 funkcja przestanie się wywoływać i zacznie wykonywać się dalej, ale najpierw dla n=1 (wypisze element [0]) następnie wróci do n=2 i wypisze kolejny element. Rekurencja będzie wracała i wypisywała kolejne elementy, aż nasze „n” wróci do początkowej swojej wartości, czyli wszystkie wywołania funkcji się zakończą. Możemy zauważyć, że ta funkcja wypisuje elementy
w normalnej kolejności.

I w ten magiczny sposób rekurencja już jest jasna :D

A tak na serio to naprawdę nie jest takie trudne, jak wszyscy mówią tylko trzeba pamiętać o tym by dać warunek stopu. Rekurencja to tak jakby pętla, która musi mieć jakiś warunek, blok instrukcji oraz coś (np. licznik, wskazanie) co będzie się zmieniało, aby warunek w końcu sprawił wyjście z rekurencji.

Brak komentarzy:

Prześlij komentarz