Předchozí [scanf, aneb formátované načítání textu]

Do teď jsme vše psali řádek po řádku do nám již známé funkce main, která také značí počátek programu, bod, kde všechno začíná. Program je však možné dále členit a to do dalších funkcí. Výhodou pak bývá rozdělení velkého problému na dílčí části, čtivost kódu a jeho struktura, rozdělení prací, abstrakce (volající nemusí vědět, jak nějaká funkce funguje, pouze co dělá) a samozřejmě možnost kód použít opakovaně bez toho, aby se musel celý znovu vypisovat. Funkce tedy vlastně tvoří blok kódu, který má jméno a je možné jej (opakovaně) volat.

Funkce se v C skládá z tzv. function head, který tvoří return type neboli návratový typ, identifier neboli jméno a parameter(list) neboli vstupy, které jsou však nepovinné. Následuje body neboli tělo funkce, blok proveditelného kódu.

Syntaxe funkce v C
Syntaxe funkce v C

Proměnné napsané v závorkách v definici funkce nazýváme parametry. Hodnoty, které funkci předáváme, když ji voláme, nazýváme argumenty.

Funkce musí být před prvním použitím známá. To znamená, že buď musí být před prvním voláním definována, nebo že je předtím deklarována pomocí tzv. function prototype. Obě možnosti si ukážeme později na příkladu. Pokud chceš vědět, co se stane, když funkce před prvním použitím není programu známá, zkus přeložit a spustit třeba tenhle prográmek.

Funkce, která má něco vracet, má návratový datový typ jinou než void, musí mít na konci klíčové slovo return následované tím, co má funkce vracet (tzv. return value). Toto klíčové slovo ukončuje funkci a vrací nějakou hodnotu na volajícího. Klíčové slovo return se může nacházet na vícero místech ve funkci. V případě main funkce jsme zatím vraceli pouze hodnotu 0 - 0 značí úspěch, jakákoliv jiná hodnota chybu.

Při psaní funkcí je nutno mít na paměti, že co funkce, to funkcionalita. To znamená, že funkce by měla mít pouze jednu jedinou povinnost, práci, kterou má vykonat. Pokud funkce dělá víc věcí najednou, je lepší ji rozdělit na vícero funkcí. S tím souvisí, že by funkce neměla mít žádný vedlejší účinek, tzv. side effect, působit jinde, než kde má, jinak, než jaká je její hlavní činnost.

Koho téma zajímá více, doporučuji následující knihu: Martin, R. C. (2008). Clean Code: A Handbook of Agile Software Craftmanship. Prentice Hall.. Citát k tématu: “Functions should do one thing. They should do it well. They should do it only.

Příklad

Výše uvedené vám teď ukážu na malém příkladu. Napíšeme si funkci, která nám poví, které ze dvou předaných čísel je větší.

#include <stdio.h>

int getMax(int nr1, int nr2)
{
    if (nr1 > nr2) 
    {
        return nr1;
    }
    
    return nr2;
}

int main(void)
{
    int x = 10;
    int y = 15;
    int max = getMax(x, y);

    printf("Vetsi z cisel x = %d a y = %d je %d\n", x, y, max);
    printf("Funkci muzeme pouzit i primo v printf: %d\n", getMax(10, 15));

    return 0;
} 

(Odkaz na GitHub)

Jak již bylo zmíněno, funkce, kterou chceme použít, musí být známá předtím, než ji zavoláme. Docílíme toho například tím, že ji definujeme v kódu výše než je její první volání. Další možnost představuje deklarace pomocí tzv. function prototype:

#include <stdio.h>

int getMax(int nr1, int nr2);

int main(void)
{
    int x = 10;
    int y = 15;
    int max = getMax(x, y);

    printf("Vetsi z cisel x = %d a y = %d je %d\n", x, y, max);
    printf("Funkci muzeme pouzit i primo v printf: %d\n", getMax(10, 15));

    return 0;
}

int getMax(int nr1, int nr2)
{
    if (nr1 > nr2) 
    {
        return nr1;
    } 
    
    return nr2;
} 

(Odkaz na GitHub)

U prototypování ani není třeba udávat názvy parametrů, compiler potřebuje hlavně znát návratový typ, název funkce a typy parametrů. Funkční kód s prototypem by tedy mohl vypadat i následovně:

#include <stdio.h>

int getMax(int, int);

int main(void)
{
    int x = 10;
    int y = 15;
    int max = getMax(x, y);

    printf("Vetsi z cisel x = %d a y = %d je %d\n", x, y, max);
    printf("Funkci muzeme pouzit i primo v printf: %d\n", getMax(10, 15));

    return 0;
}

int getMax(int nr1, int nr2)
{
    if (nr1 > nr2) 
    {
        return nr1;
    } 
    
    return nr2;
} 

(Odkaz na GitHub)

Kdybyste pořadí prohodili, tzn. v kódu nejdřív měli main a pak až funkci, kterou v main chcete použít, pak by vám compiler vydal hlášku a varoval, že něco není v pořádku. Jako vždy, klidně si to vyzkoušejte, ať víte.

Kam dál?

Opakování - kalkulačka