Funkce
Představte si, že během programování dojdete do stavu, kdy už je algoritmus tak rozsáhlý, že se stane nepřehledným. Například algoritmus, který pracuje s polem (stále ještě učebnicový příklad, tj. relativně přehledný), by mohl vypadat takto:

Když se na algoritmus podíváme, tak zjistíme, že se vlastně skládá z několika částí:
- načítání hodnot do pole (to zatím ponecháme v hlavní funkci, než začneme pracovat s pointery)
- hledání a výpis maxima
- hledání a výpis minima
- výpočet a výpis průměru
O co jednodušeji bude algoritmus vypadat s použitím funkcí, se můžete podívat na naprosto stejném příkladu jako je výše:

Zde jsme využili tři funkce, jejichž strukturogram samozřejmě také musíme znázornit, ale to už budeme dělat ve zvláštních strukturogramech:
Definice
Funkce je pojmenovaný blok kódu, který lze opakovaně použít. Jedná se o základní a klíčový prvek programování, které Vám umožní organizovat zdrojový kód do menších (a tedy čitelnějších celků).
Vstupy a výstupy
Funkce může být opravdu pouhým blokem kódu, jako například
void pozdrav(){
printf("Dobrý den!\n");
}
Většinou ale budeme ve funkci, tj. v bloku kódu, pracovat se vstupními nebo i s výstupními proměnnými. Představme si například lehkou modifikaci funkce pozdrav, která pozdraví odlišně v závislosti na vstupní hodnotě typ. Bude-li typ == ‚t‘ (tykání), pozdraví „Ahoj“, bude-li typ == ‚v‘ (vykání), pozdraví „Dobrý den“:
void pozdrav(char typ){
if (typ == 't'){
printf("AHoJ!\n");
}
else if (typ == 'v'){
printf("Dobrý den.\n");
}
}
Funkce pozdrav má nyní jednu vstupní proměnnou, kterou je typ (datový typ char, čili znak). Tato funkce nemá žádný výstup (funkce má datový typ void = prázdný).
Nejčastěji ale bude mít funkce i nějaký výstup, jako například:
int soucet(int x, int y){
int vysl;
vysl = x + y;
return vysl;
}
Výsledek funkce vracíme pomocí příkazu return.
Z hlediska vykonávání programového kódu si tedy můžeme představit funkci soucet jako blok, která má dva vstupy a jeden výstup:

Předávání parametrů hodnotou
Tak, jak jsme si nadefinovali funkci soucet, předáváme dva vstupní parametry (x a y) způsobem, kterému říkáme předávání hodnotou (call by value).
Funkci voláme například:
int s = soucet(a, b);
Při tomto volání již máme deklarované i inicializované proměnné a, b. Tj. máme konkrétní místa v paměti, kde jsou uložené hodnoty proměnných a i b. V momentě volání funkce se nám vyčlení další dvě místa paměti, která budou pojmenována x a y a hodnota proměnné a se zkopíruje do x, hodnota proměnné b se zkopíruje do y.
Jakékoliv změny x a y tedy nebudou mít žádný vliv na a ani na b.
Proměnným x a y tedy říkáme lokální.
Ověřit platnost tohoto tvrzení si můžeme na následujícím příkladu:
void pokusy(int a, int b){
a += 10;
b += 15;
printf("Uvnitř funkce pokusy je a = %d, b = %d.\n", a, b);
}
void main(){
int a = 1, b = 5;
printf("Před voláním funkce je a = %d, b = %d.\n", a, b);
pokusy(a, b);
printf("Po volání funkce je a = %d, b = %d.\n", a, b);
}
Zde vidíme, že i když se hodnota proměnných a a b ve funkci pokusy() změnila, proběhla tato změna pouze lokálně, protože proměnné jsme předávali hodnotou. Při volání funkce pokusy() tedy byly vyčleněny dva nové bloky paměti, do kterých se nakopírovala pro proměnnou a hodnota 1 a pro proměnnou b hodnota 5.
Ve funkci pokusy() se sice přidalo k proměnné a 10 a k proměnné b 15, ale to pouze k lokálním proměnným, což nemělo žádný vliv na proměnné a a b v hlavní funkci.

Deklarace a definice funkce
Při psaní programů v jazyce C dříve či později narazíte na situaci, kdy chcete kód zpřehlednit a rozdělit ho do vlastních podprogramů – funkcí. V Cčku ale platí jedno přísné pravidlo: kompilátor čte kód striktně odshora dolů. Pokud se pokusíte zavolat funkci, o které překladač do té doby neslyšel, program nepůjde přeložit.
Abychom tomu předešli, musíme pochopit zásadní rozdíl mezi deklarací a definicí funkce.
- deklarace funkce je pouze jakousi hlavičkou funkce; musí být v C umístěna před prvním použitím funkce; deklarace obsahuje datový typ funkce, název funkce a v kulatých závorkách vstupní parametry a končí středníkem
- definice funkce je celá funkce (včetně hlavičky), tj. včetně těla funkce ve složených závorkách; může být v C umístěna klidně i za funkcí main()
Příklad deklarace funkce:
char nactiPismeno();
Příklad definice funkce:
char nactiPismeno(){
char pismeno;
scanf("%c", &pismeno);
return pismeno;
}
Zkuste si procvičit deklarace funkcí v následujícím drillu:
//vytvořte deklaraci funkce pozdrav bez vstupů, funkce nebude nic vracet //vytvořte deklaraci funkce writeGreetings bez vstupu, funkce nebude nic vracet //vytvořte deklaraci funkce, která bude mít vstup x, tj. číslo, které bude vypisovat, funkce nebude nic vracet //vytvořte deklaraci funkce kladneZaporne, která bude mít vstup x, tj. číslo – bude vypisovat, jestli je x kladné nebo záporné; funkce nebude nic vracet //vytvořte deklaraci funkce sudeLiche, která bude mít vstup x, tj. číslo – bude vypisovat, jestli je x sudé nebo liché; funkce nebude nic vracet //vytvořte deklaraci funkce pridejJedna, která bude mít vstup celé číslo i a bude vracet číslo o 1 vyšší //vytvořte deklaraci funkce odeberDve, která bude mít vstup celé číslo i a bude vracet číslo o 2 nižší //vytvořte deklaraci funkce secti, která bude mít vstupy dvě celá čísla m a n a bude vracet jejich součet //vytvořte deklaraci funkce vynasob, která bude mít vstupy dvě celá čísla k a l a bude vracet jejich součin //vytvořte deklaraci funkce vypisZnak, která bude mít vstup znak c a ten znak vypíše, funkce nebude nic vracet //vytvořte deklaraci funkce jePlus, která bude mít vstup znak z a bude vracet 1, jedná-li se o plus, resp. 0, nejedná-li se o plus //vytvořte deklaraci funkce jePismeno, která bude mít vstup znak c a bude vracet 1, jedná-li se o písmeno, resp. 0, nejedná-li se o písmeno
Předávání proměnných odkazem
V předchozí kapitole jsme si ukázali, že při předávání proměnných hodnotou se vlastně hodnota kopíruje do jiného místa paměti (do lokální proměnné) a tudíž tím zatěžujeme paměť. U jednoduchých proměnných nám to tolik vadit nemusí, ale u větších proměnných (pole, matice, řetězce, struktury) už by zatížení paměti mohlo být větší. Proto budeme namísto konkrétní hodnoty předávat pouze odkaz (pointer) na proměnnou (call by reference).
Zkusíme použít velmi podobný příklad tomu výše uvedenému, jen namísto hodnot a a b budeme předávat adresu proměnné a (adresa a = &a) a adresu proměnné b (adresa b = &b). Funkce tedy bude přijímat nikoliv hodnotu, ale pointer (nikoliv a, ale *a; resp. nikoliv b, ale *b):
void pokusy(int *a, int *b){
*a += 10;
*b += 15;
printf("Uvnitř funkce pokusy je a = %d, b = %d.\n", *a, *b);
}
void main(){
int a = 1, b = 5;
printf("Před voláním funkce je a = %d, b = %d.\n", a, b);
pokusy(&a, &b);
printf("Po volání funkce je a = %d, b = %d.\n", a, b);
}
Jak to vypadá v paměti, si můžeme ukázat na následujícím obrázku:

Vidíme tedy, že zde jsme nepotřebovali alokovat další paměť pro lokální proměnné, ale předáváme pouze odkazy (pointery) na již existující proměnné a tedy ve funkci měníme přímo dané proměnné.
Opět si můžete procvičit drill s deklaracemi funkcí, které využívají předávání parametrů odkazem:
//vytvořte deklaraci funkce prictiJedna, která bude mít vstupně-výstupní parametr celé číslo i; funkce nebude nic vracet //vytvořte deklaraci funkce vynasobDvema, která bude mít vstupně-výstupní parametr celé číslo m; funkce nebude nic vracet //vytvořte deklaraci funkce vratMax, která bude mít vstupní parametry: pole celých čísel pole, počet prvků v poli pocet; funkce bude vracet prvek s maximální hodnotou z pole //vytvořte deklaraci funkce vratMedian, která bude mít vstupní parametry: pole celých čísel pole, počet prvků v poli pocet; funkce bude vracet medián (hodnotu prostředního prvku z pole) //vytvořte deklaraci funkce vypoctiPrumer, která bude mít vstupní parametry: pole celých čísel pole, počet prvků v poli pocet; funkce bude vracet prvek s průměr prvků pole (pozor – průměr musí být desetinné číslo) //vytvořte deklaraci funkce vypisText, která bude mít vstupní parametr pole znaků ret; funkce nebude nic vracet //vytvořte deklaraci funkce vypisPismena, která bude mít vstupní parametr pole znaků ret; funkce nebude nic vracet //vytvořte deklaraci funkce vypisCisla, která bude mít vstupní parametr pole znaků str; funkce nebude nic vracet //vytvořte deklaraci funkce pocetCisel, která bude mít vstupní parametr pole znaků str; funkce bude vracet počet znaků, které jsou čísly //vytvořte deklaraci funkce pocetAcek, která bude mít vstupní parametr pole znaků retezec; funkce bude vracet počet malých nebo velkých písmen A
Nebo zkuste drag-n-drop kvízy:
- Pomocí tažení prvků myší vytvořte deklaraci funkce, která vrátí průměr prvků v poli.
2. Pomocí tažení prvků myší vytvořte deklaraci funkce, která vrátí počet všech písmen v řetězci.
3. Pomocí tažení prvků myší vytvořte deklaraci funkce, která vrátí počet konkrétního znaku v řetězci.
Generovaný podcast o funkcích si můžete poslechnou zde:
Podcast byl vygenerován automaticky na základě této stránky a na základě webu https://www.geeksforgeeks.org/c/c-functions/
Příklady
Příklady na funkce si můžete zobrazit zde.