Zoberme si jednoduchý príklad: Vytvorte funkciu, ktorá nájde najväčšiu hodnotu v poli.
Naivné riešenie, ktoré je zdanlivo správne:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
void maximum( ) { int pole[10]; int i, max; for (i = 0; i < 10; i++) { printf("Zadaj cislo"); scanf("%i", &pole[i]); } max = pole[0]; for (i = 1; i < 10; i++) { if (pole[i] > max) max = pole[i]; } printf("Maximum je: ", max); } |
Všimnite si, čo reálne robí funkcia (a porovnajte si s tým, čo robiť mala):
Navyše, pole je tam úplne zbytočné, stačilo napísať:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void maximum( ) { int cislo; int i, max = INT_MIN; for (i = 0; i < 10; i++) { printf("Zadaj cislo"); scanf("%i", &cislo); if (cislo > max) max = cislo; } printf("Maximum je: ", max); } |
Takisto je zbytočné použiť funkciu, keď už to píšeme takto, mohli sme tento kód rovno napísať ako súčasť main
funkcie.
Aby bola funkcia užitočná, musí umožňovať nejakú konkrétnu činnosť pre voliteľné vhodné vstupy (tzv. parametre) a/alebo produkovať určité výstupy.
Pripomeňmne si zadanie: Vytvorte funkciu, ktorá nájde najväčšiu hodnotu v poli.
return
, a volajúca funkcia sa už rozhodne, čo s tou hodnotou urobí. Po zvážení horeuvedených bodov môžeme kód prepísať napr. nasledovne:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
int maximum( int pole[10] ) { int i, max; max = pole[0]; for (i = 1; i < 10; i++) { if (pole[i] > max) max = pole[i]; } return max; } |
Ak chceme napr. použiť rovnakým spôsobom ako predtým (načítať, vyrátať maximum, vypísať), napíšeme zvyšný kód do volajúcej funkcie (napr. ak sa to hodí aj do main
):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
int main( ) { int pole[10]; int i; int najdene_max; //TODO: toto je vhodny kandidat na samostatnu funkciu... for (i = 0; i < 10; i++) { printf("Zadaj cislo"); scanf("%i", &pole[i]); } najdene_max = maximum(pole); printf("Maximum je: ", najdene_max); return 0; } |
Predstavte si, že chceme napísať program, ktorý zistí, či najväčšie číslo z 10 hodov kockou je 6. Potom stačí prepísať main
funkciu nasledovne:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
int main( ) { int pole[10]; int i; int najdene_max; //TODO: tiez vhodny kandidat na samostatnu funkciu... for (i = 0; i < 10; i++) { pole[i] = rand()%6+1; } najdene_max = maximum(pole); if (najdene_max == 6) printf("Padla aj sestka\n"); else printf("Sestka nepadla\n"); return 0; } |
Funkciu maximum
môžeme použiť bezo zmeny (kým v naivnom riešení by sme museli funkciu prerábať, resp. vyrobiť novú).
V Príklade 3 som použil v zozname parametrov funkcie int pole[10]
. Tým som ale obmedzil funkciu na prácu iba s 10-prvkovými poľami. Čo keď chceme maximum z menej prvkov ako je velkost poľa?
V jazyku C sa polia odovzdávajú do funkcií odkazom na prvú pozíciu v poli. Pre funkciu, ktorá takýto odkaz dostane to hovorí, že od daného miesta v pamäti nasledujú zaradom čísla (ak je to pole int-ov), ale nehovorí koľko tých čísel je. Aby sa to funkcia dozvedela, pridáme 1 parameter, ktorým volajúca funkcia povie, koľko čísel v poli sa má spracovať (všimnite si vynechanie veľkosti poľa v deklarácii parametra):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//PRE: pocet > 0 int maximum( int pole[], int pocet ) { int i, max; max = pole[0]; //namiesto konstantnej velkosti 10 // pouzijeme hodnotu parametra for (i = 1; i < pocet; i++) { if (pole[i] > max) max = pole[i]; } return max; } |
Pozn.: Ak pracujeme s reťazcami, veľkosť reťazca parameter byť nemusí. Prečo?
Pred funkciu som napísal do komentára predpoklad (PRE:). Ak hodnota parametra nespĺňa predpoklad, funkcia nemusí pracovať správne. Je na volajúcej funkcii (programátorovi, ktorý ju píše), aby zabezpečil dodržanie predpokladov.
Teraz už vieme napísať aj program, ktorý zistí maximum v 2 poloviciach poľa:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
int main( ) { //testujem, dam si napevno nejake hodnoty... int pole[10] = {-1,5,7,12,3,-2,15,9,31,11}; int max[2]; //maximum z prvych 5 hodnot max[0] = maximum(pole, 5); //maximum z nasledujucich 5 hodnot // vyuziva sa smernikova aritmetika // pole + 5 ukazuje na miesto v pamati // o 5 dalej ako je zaciatok pola max[1] = maximum(pole+5, 5); printf("Maximum z prvej polovice je %i\n", max[0]); printf("Maximum z druhej polovice je %i\n", max[1]); //vsimnite si, mozem pouzivat funkciu na rozne polia ;) printf("Celkove maximum je %i\n", maximum(max,2)); return 0; } |
Funkcia maximum predstavuje určitú šablónu, s ktorou sa dá ďalej pracovať. Napr. môžeme chcieť nie maximum z čísel, ale najdlhší reťazec v poli reťazcov:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
//PRE: pocet > 0 char* max_strlen( char* pole[], int pocet ) { int i; char *max; max = pole[0]; for (i = 1; i < pocet; i++) { if (strlen(pole[i]) > strlen(max)) max = pole[i]; } return max; } |
Upravil som typy prvkov v poli, a keďže ma zaujímala dĺžka reťazca, doplnil som strlen
. Použitie je podobné ako predtým:
1 2 3 4 5 6 7 8 9 |
int main( ) { //testujem, dam si napevno nejake hodnoty... char* pole[] = {"aaa", "test", "dlhy retazec", "nieco"}; printf("Najdlhsi retazec je %s\n", max_strlen(pole,4)); return 0; } |
Bez toho, aby som menil niečo v main
funkcii, viem funkciu max_strlen
mierne zrýchliť jej dodatočnou úpravou:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//PRE: pocet > 0 char* max_strlen( char* pole[], int pocet ) { int i, len, maxlen; char *max; max = pole[0]; maxlen = strlen(pole[0]); for (i = 1; i < pocet; i++) { len = strlen(pole[i]); if ( len > maxlen) { max = pole[i]; maxlen = len; } } return max; } |
Doplnením pomocných premenných len a maxlen sa nemusí vždy nanovo prepočítavať dĺžka doteraz najväčšieho reťazca (funkcia si ju pamätá).
Skúste zistiť sami (bez kompilovania, ako keby ste boli na skúške), čo robí funkcia _cotorobi_
, čo je tiež len modifikácia príkladu s maximom:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
int pocet_vyskytov(int x, int pole[], int velkost) { int pocet = 0, i; for (i = 0; i < velkost; i++) if (x == pole[i]) pocet++; return pocet; } //PRE: pocet > 0 int _cotorobi_( int pole[], int pocet ) { int i, max, n, nmax; nmax = pocet_vyskytov(pole[0], pole, pocet); max = pole[0]; for (i = 1; i < pocet; i++) { n = pocet_vyskytov(pole[i], pole+i, pocet-i); if (n > max) { nmax = n; max = pole[i]; } } return max; } |