Upotreba funkcija
Do sada smo koristili "gotove" funkcije iz standardnih biblioteka. Sve ove funkcije smo pozivali iz glavne funkcije našeg programa, Main funkcije, koja predstavlja specijalnu funkciju, jer izvršavanje programa počinje od nje i sve programe, bez obzira na njihovu dužinu, pisali smo u toj jednoj funkciji.
Bez ulaženja u detalje objektno orijentisanog programiranja koje nije tema ovog priručnika, bitno je samo da se spomene da su funkcije u objektno orijentisanim jezicima, kao što je jezik C#, uvek deo nekih klasa, i da se kao takve nazivaju metode.
Pogledajmo ponovo primer iz lekcije "Unos podataka".
static void Main(string[] args) { int zbir = 0; float prosek; const int brPredmeta = 11; int ocena; Console.WriteLine("Sta imas iz srpskog?"); ocena = int.Parse(Console.ReadLine()); zbir += ocena; Console.WriteLine("Sta imas iz matematike?"); ocena = int.Parse(Console.ReadLine()); zbir += ocena; Console.WriteLine("Sta imas iz fizickog?"); ocena = int.Parse(Console.ReadLine()); zbir += ocena; Console.WriteLine("Sta imas iz engleskog?"); ocena = int.Parse(Console.ReadLine()); zbir += ocena; Console.WriteLine("Sta imas iz fizike?"); ocena = int.Parse(Console.ReadLine()); zbir += ocena; Console.WriteLine("Sta imas iz hemije?"); ocena = int.Parse(Console.ReadLine()); zbir += ocena; Console.WriteLine("Sta imas iz ruskog?"); ocena = int.Parse(Console.ReadLine()); zbir += ocena; Console.WriteLine("Sta imas iz muzickog?"); ocena = int.Parse(Console.ReadLine()); zbir += ocena; Console.WriteLine("Sta imas iz likovnog?"); ocena = int.Parse(Console.ReadLine()); zbir += ocena; Console.WriteLine("Sta imas iz kung-fu-a?"); ocena = int.Parse(Console.ReadLine()); zbir += ocena; Console.WriteLine("Sta imas iz kibernetike?"); ocena = int.Parse(Console.ReadLine()); zbir += ocena; prosek = (float)zbir / brPredmeta; Console.WriteLine("Tvoj prosek je: " + prosek); }
Kao što vidiš, dobili smo prilično dugačak program u kome ima dosta ponavljanja sličnih ili istih operacija i blokova naredbi. Ovaj program možemo da napišemo na kraći i jednostavniji način, koristeći funkciju. U primeru koji sledi pokazano je kako se piše i koristi jedna jednostavna funkcija. Ova funkcija nas podseća na Main funkciju iz naših prethodnih programa.
static int StaImasIz(string imePredmeta) { int ocena; Console.WriteLine("Sta imas iz " + imePredmeta); ocena = int.Parse(Console.ReadLine()); return ocena; } static void Main(string[] args) { int zbir = 0; float prosek; const int brPredmeta = 11; zbir += StaImasIz("srpskog"); zbir += StaImasIz("matematike"); zbir += StaImasIz("fizickog"); zbir += StaImasIz("engleskog"); zbir += StaImasIz("fizike"); zbir += StaImasIz("hemije"); zbir += StaImasIz("ruskog"); zbir += StaImasIz("muzickog"); zbir += StaImasIz("likovnog"); zbir += StaImasIz("kung-fu-a"); zbir += StaImasIz("kibernetike"); prosek = (float)zbir / brPredmeta; Console.WriteLine("Tvoj prosek je:" + prosek); }
Dobili smo značajno kraći i pregledniji program u kome smo deo programa stavili u odvojenu funkciju StaImasIz. Obično je telo funkcije veoma složeno, za razliku od ovog primera. Posle kreiranja funkcije, možemo je iz ostalog dela programa pozivati po imenu, a funkcije mogu da pozivaju i jedne druge. Funkcija može čak i da poziva samu sebe (to se koristi u rekurzivnim algoritmima). Za sada nemoj da pozivaš funkciju iz same sebe.
Nabrojaćemo sve razloge za upotrebu funkcija:
-
Kada imamo više ponavljanja istih blokova naredbi (operacija) u različitim delovima programa (time skraćujemo tekst programa).
-
Upotrebom funkcija, program se deli na odvojene blokove. Svaki blok radi određeni posao. Ovako olakšavamo čitljivost/razumevanje programa. Osmišljavanje, razumevanje i održavanje manjih blokova koda je lakše.
-
Kada se deo programa moze izvršiti sa različitim parametrima. Ovi parametri se prosleđuju funkciji kao argumenti funkcije.
Definisanje funkcije
Prikazana funkcija StaImasIz uzima kao argument (argumenti funkcije su varijable čije se vrednosti tokom pozivanja funkcije) tekstualni podatak koji predstavlja naziv predmeta, na primer "fizike", a kao rezultat vraća ocenu iz tog predmeta koja je ceo broj, pa je tip njenog rezultata int.
Uopšteno, možemo svaku funkciju da definišemo na sledeći način:
TIP REZULTAT ime_funkcije(OPIS ARGUMENATA FUNKCIJE) { TELO FUNKCIJE }
Ovo je ilustrovano sledećim dijagramom.
Na početku se navodi TIP REZULTATA koji je neki od već poznatih tipova podataka i označava kakav je rezultat koji funkcija vraća.
Često se kaže i "tip funkcije", a tada se misli upravo na tip njenog rezultata. Funkcija ima svoje jedinstveno ime ime_funkcije.
Između zagrada se navodi OPIS ARGUMENATA FUNKCIJE koji je lista argumenata funkcije. Za svaki argument se navodi njegov tip i ime (identifikator). Na primer, funkcija Izracunaj(int a, char ch, float x) ima u listi upisana tri argumenta i to: a, ch i x, čiji su tipovi podataka navedeni ispred.
Niz naredbi koje će se izvršiti kada se pozove funkcija čine TELO FUNKCIJE. Telo funkcije započinje nakon otvorene vitičaste zagrade, a završava se zatvorenom vitičastom zagradom.
Naredba return rezultat; u telu funkcije služi za vraćanje rezultata koji funkcija daje.
Ispred tipa rezultata je potrebno, u konzolnim aplikacijama kreiranim u jeziku C#, dodati i reč static.
Pozivanje funkcije
Funkcija se izvršava tako što se "poziva" u (glavnom) programu ili drugoj funkciji. Funkcija se poziva navođenjem njenog naziva i argumenata zapisanih u redosledu koji je zadan deklaracijom, kao u primeru StaImasIz("kung-fu-a") gde učenika pitamo koju ocenu ima iz Kung-Fu-a.
Povratna vrednost funkcije
U programskom jeziku C# očekujemo da funkcija vrati neku vrednost. Ova povratna vrednost ima svoj tip kao i ostale vrednosti u C#, pa može biti tipa int, float, char ili bilo šta drugo. Vrednost funkcije vraćamo sa komandom return.
float Kvadriraj(float x) { float rezultat; rezultat = x * x; return rezultat; }
Funkcija iz gornjeg primera vraća vrednost promenljive "rezultat" kao povratnu vrednost funkcije. Takođe, možemo koristiti i izraz u return komandi. Na primer možemo da napišemo return (x * x); umesto poslednje dve linije funkcije. Ukoliko zaboravite povratnu vrednost u nekoj funkciji, dobićete poruku upozorenja (eng. warning) od C# kompajlera da funkcija mora da vrati vrednost. Upozorenja kompajlera ne zaustavljaju izvršavanje programa, ali greške zaustavljaju. Ipak, dobra je praksa obraćati pažnju i na ova upozorenja i popraviti kod tako da se prevodi bez upozorenja.
Funkcije koje ne vraćaju vrednost
Prema pravilima pisanja programa na jezicima C, C++ i C#, svaka funkcija ima tip. Ako nam nije potrebno da funkcija na mesto poziva vrati vrednost, deklarišemo (objavljujemo) da je tip funkcije, to jest njene povratne vrednosti, tip void (srpski: nevažeći, prazan).
void test() { /* kod funkcije ali bez povratne vrednosti */ }
Tip void se ne može koristiti. Njegovom upotrebom u deklaraciji samo saopštavamo da funkcija ne vraća neki podatak, tj. vrednost. Zato se pozivi funkcija tipa void pišu u programu kao naredbe, a ne kao izrazi.
Funkcija tipa void ne mora, ali može, da sadrži naredbu return. Ukoliko je sadrži, onda je to bez ikakvog izraza. Pogledajmo kako to izgleda na primeru:
void ispisUpozorenja() { Console.WriteLine("Upozorenje!"); }
Poziv ove funkcije sa nekog drugog mesta u programu bi izgledao ovako:
ispisUpozorenja();
Argumenti funkcije
Funkcije mogu da prihvataju ulazne parametre u formi promenljivih i izraza i ove ulazne promenljive se mogu koristiti u telu funkcije.
Do sad su parametri služili da prenesu vrednost sa mesta poziva u funkciju i to su ulazni parametri, a moguće je preneti i vrednost iz funkcije (tako da parametri budu izlazni), ali o tome će biti reči u nekoj od narednih lekcija.