6. seminář - Ukazatele na funkce

TEACHINGZPC2

Funkce vyššího řádu v LISPu

Funkce vyššího řádu je funkce, která bere jako parametr funkci nebo vrací funkci. Příkladem jsou funkce mapcar a filter


    (mapcar (lambda (x) (* x x)) '(1 2 3 4 5))
    ;; -> (1 4 9 16 25)
    
    (filter (lambda (x) (evenp x)) '(1 2 3 4 5))
    ;; -> (2 4)

Funkce vyššího řádu v C

Deklarace ukazatele na funkci

Obecná deklarace ukazatele na funkci má tvar:


    navratovy_typ (*nazev)(typ1, typ2, ..., typn);

Kde navratovy_typ je návratový typ funkce a nazev je název proměnné, do které budeme funkci ukládat. Pomocí typ1 a další definujeme datové typy parametrů funkce, pokud funkce nějaké parametry má. Následující proměnná fun by tak byla deklarace ukazatele na funkci, která vrací typ double a bere dva parametry: první typu char* a druhý typu int.


    int add(int x, int y) {
        return x + y;
    }

    int multiply(int x, int y) {
        return x * y;
    }
    
    int main() {
        // promenna "function" je ukazatelem na fci, ktera
        // vraci int a bere dva parametry, oba typu int
        int (*function)(int, int) = add;
        printf("%i\n", function(10, 20));
        function = multiply;
        printf("%i\n", function(10, 20));
    }

Předání funkce v parametru funkce


    int is_small_letter(char letter) {
        return letter >= 'a' && letter <= 'z';
    }
    
    void print(int (*condition)(char), const char* ret) {
        if (condition(ret[0])) {
            printf("%s\n", ret);
        }
    }
    
    int main() {
        print(is_small_letter, "ahoj");
        print(is_small_letter, "LuSteLa");
    }

Pojmenování pomocí typedef

Pomocí typedef si můžeme vytvořit alias pro ukazatel.


    typedef int (*COND)(char);
    
    void print(COND condition, const char* ret) {
        if (condition(ret[0])) {
            printf("%s\n", ret);
        }
    }
    
    int main() {
        print(is_small_letter, "ahoj");
        print(is_small_letter, "LuSteLa");
    }

Pole funkcí

Aby vše bylo krášně nepřehledné, tak můžeme ukazatele na funkce uloži do pole


    int add(int x, int y) {
        return x + y;
    }

    int multiply(int x, int y) {
        return x * y;
    }
    
    int main() {
        int (*func_array[2])(int, int);
        func_array[0] = add;
        func_array[1] = multiply;
        
        // Volání fukncí
        printf("%i\n", func_array[0](2, 8)); // 10
        printf("%i\n", func_array[1](2, 8)); // 16
    }

Úkoly

Napište v jazyku C funkci double *map(double (*fce)(double), double *input, int length), která na hodnoty pole vstup (definiční obor) aplikuje funkci fce a vrátí pole výsledných hodnot. Velikost definičního oboru je specifikována parametrem délka.
Napište v jazyku C funkci double **map(double(*fce[])(double),double *vstup,int pocet_fce, int pocet_vstup), která na prvky pole vstup (definiční obor) mapuje postupně jednotlivé funkce z pole fce. Z vypočtených hodnot vytvoří dvourozměrné pole, které bude návratovu hodnotou z této funkce. První řádek výstupního pole bude odpovídat definičnímu oboru, druhý řádek hodnotám první funkce a tak dále, až poslední řádek bude odpovídat hodnotám poslední předané funkce. Počet funkcí je specifikován parametrem pocet_fce, velikost definičního oboru pak parametrem pocet_vstup.
Napište v jazyku C funkci double akumulator(double (*fce)(double, double), double cisla[], int pocet), která zpracuje pomocí předané funkce fce hodnoty z pole cisla, jehož velikost je dána parametrem pocet. Vytvořenou funkci otestujte ve funkci main; použitými akumulačními funkcemi mohou být například funkce pro součet nebo součin dvou reálných čísel, které je ovšem pro testování potřeba dodefinovat.