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
// 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){
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.
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