utorak, 16 aprila, 2024
Kako da...?

Uvod u programski jezik C (8. deo)

Autor: Nikola Hardi

U prethodnim brojevima ste imali priliku da čitate o C programskom jeziku. Nadamo se da smo uspeli da predstavimo dovoljan deo ovog programskog jezika da biste mogli da počnete stvarati svoje programe, ili da lakše savladate naprednije stvari. Narednim tekstovima će biti završen serijal i u njemu možete da pročitate neke stvari koje smo primetili da nedostaju u prethodnim tekstovima. Takođe, daćemo i nekoliko smernica za dalje istraživanje, učenje i igranje. Počećemo od funkcija.

U istoriji razvoja programskih jezika postoji jedan trenutak kada su tadašnji programeri primetili da neke delove koda koriste više puta. U to vreme su se programi pisali na bušenim karticama, a „matematička biblioteka” je bio termin koji je označavao skup kartica sa korisnim kodovima za matematiku, uvezanih mašnom. Funkcije, ili potprogrami, kako ih neki još zovu, jesu delovi koda koje je moguće po potrebi pozvati. Nakon izvršenog koda, koji ta funkcija ima, procesor nastavlja da izvršava kod od mesta na kojem je funkcija bila pozvana.

Pre nego što pređemo na detaljan opis kako se deklarišu, definišu i pozivaju funkcije u C-u, biće objašnjeno zašto su one toliko važan mehanizam. Osnovna svrha je da se kod koji se ponavlja izdvoji na jedno mesto i samo poziva. Tako je omogućeno da taj deo koda iskoristite na nekom drugom svojem projektu ili ga podelite sa drugima. Drugi razlog je jednostavnije održavanje projekata. Softver uvek ima greške i to se ne dovodi u pitanje. Naravno, primećujete da je mnogo elegantnije ispraviti grešku na jednom mestu (unutar funkcije) nego na svakom mestu gde bi se taj kod pojavio (kada se pozivaju te funkcije).

Funkcije mogu da obuhvate i kod koji nije doslovno isti. Kod možemo da „parametrizujemo”. To znači da pri svakom pozivu funkcije možemo da podesimo neke delove koda. Naprimer, ako imamo funkciju za ispis imena, možemo da joj postavimo parametar koje ime želimo da bude ispisano. To se postiže putem parametara ili argumenata. U ovom tekstu nećemo praviti razliku između parametara i argumenata iako ona formalno postoji.

Poslednja stvar koju treba da pomenemo kada pričamo o ideji funkcija je da one mogu, a ne moraju, da imaju rezultat. Strogo rečeno, potprogrami koji imaju rezultat su funkcije, a potprogrami koji nemaju rezultat su procedure. Metode su jako slične funkcijama, ali se uglavnom pominju u kontekstu objektno orijentisanog programiranja. Niko vam neće suditi ako funkciju nazovete procedurom ili obrnuto, ali lepo je znati šta je šta. Najčešće ćete ipak čuti za izraz funkcije ili metode, pa ćemo i mi ove termine koristiti većom slobodom.

Kao i kod promenljivih, funkcija mora da bude deklarisana pre nego što je pozovemo. Deklaracija funkcije se naziva još i njenim „potpisom” i sastoji se od tipa povratne vrednosti, imena potprograma i liste parametara, završno sa znakom tačka-zarez. Ukoliko uz deklaraciju funkcije želimo i da je definišemo, to može da bude urađeno tako što se izostavi znak tačka-zarez i u nastavku potpisa se napiše telo potprograma.

Primer procedure bez parametara:

void procedure() { puts("Hello world!"); }

Primer funkcije sa dva parametra:

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

Primećujete da parametri imaju svoj tip i naziv. Ponašaju se slično promenljivim. Unutar funkcije mogu biti deklarisane dodatne promenljive. Rezultat funkcije, koji se još naziva i povratna vrednost, „vraća” se naredbom return. Važno je reći da se izvršavanjem naredbe return prekida izvršavanje cele funkcije, što je ilustrovano sledećim primerom.

Primer prekida izvršavanja funkcije naredbom return:

int min(int a, int b) { if(a < b) return a; else if(b < a) return b; }

Ukoliko je broj a manji od broja b, izvršavanje će se završiti već u drugoj liniji ove funkcije, a do druge provere neće ni doći. Zanimljivo je primetiti i da ova funkcija ima grešku. Šta se događa ukoliko su brojevi jednaki?

Funkcije imaju svrhu samo ako ih koristimo, odnosno „pozivamo”. Funkcije se pozivaju po imenu, a od promenljivih se razlikuju po tome što se u pozivu funkcije piše i par zagrada, unutar kojih su vrednosti parametara kada je to potrebno.

Primer poziva fukcije sum():

int zbir = sum(2, 3);

Poslednja stvar koja je ostala nedorečena je da se parametri u funkciju mogu preneti po vrednosti ili po adresi. Praktična upotreba i detalji o razlikama su ipak možda previše za jedan uvodni kurs o C-u. Najvažnije stvari koje treba imati na umu su da, kada parametre koristite kao u našim primerima funkcija sum() i min(), tada se oni prenose po vrednosti i praktično se kopiraju. To znači da ako dodelimo nove vrednosti parametrima, te vrednosti će važiti samo unutar funkcije, a ne i na mestu gde je funkcija pozvana. Da bi takve dodele bile vidljive i van funkcije, koristi se prenos parametara po adresi. To zapravo znači da se pri navođenju parametara u deklaraciji koriste pokazivači, a pri pozivu funkcije se koriste adrese (pokazivači ili adrese promenljivih).

Primer prenosa parametara po adresi:

void swap(int *a, int *b) { int tmp; tmp = *a; *a = *b; *b = tmp; }

Poziv:

	int a = 5, b = 7; swap(&a, &b);

Trebalo bi da ovaj tekst pokrije osnovne stvari o rukovanju potprogramima. Ukoliko vam je potrebna inspiracija kako da uvežbate rad sa funkcijama, evo lepog problema:

Pokušajte da napišete funkciju za ispis elemenata niza na standardni izlaz. Zatim napišite funkciju za sortiranje niza u kojoj ćete pozivati funkciju za ispis niza i posmatrajte kako elementi niza menjaju svoja mesta.

Ukoliko vas zanima nešto više, ili nam se potkrala neka greška, molimo vas da nam se javite. Srećno!

Naredni deo ovog serijala možete pročitati ovde.

Prethodni deo ovog serijala možete pročitati ovde.