1 Příprv studijního prormu Informtik je podporován projektem finncovným z Evropského sociálního fondu rozpočtu hlvního měst Prhy. Prh & EU: Investujeme do vší budoucnosti Funkce, intuitivní chápání složitosti Funkce definice funkce prmetry funkce deklrce funkce vrice n tém největší společný dělitel procedury výstupní prmetry přidělování pměti BI-PA1 Prormování loritmizce 1, ZS 2012-2013 Ktedr teoretické informtiky Miroslv Blík Fkult informčních technoloií České vysoké učení technické 1/29 2/29 Funkce fktoriál /* pro5-1.c */ /* vypocet fktorilu */ int i = 1, f = 1; printf("zdejte prirozene cislo: "); scnf("%d", &n); if (n<1) { printf("%d neni prirozene cislo\n", n); while (i<n) { i = i+1; f = f*i; printf("%d! = %d\n", n, f); čtení přirozeného čísl výpočet fktoriálu Fktoriál pomocí funkcí Funkce pro čtení přirozeného čísl int ctiprirozene(void) { printf("zdejte prirozene cislo: "); scnf("%d", &n); if (n<1) { printf("%d neni prirozene cislo\n", n); exit(0); return n; Hlvičk funkce int ctiprirozene(void) vyjdřuje, že funkce nemá prmetry že výsledkem volání funkce je hodnot typu int return n; předepisuje návrt z funkce, výsledkem volání je hodnot n Příkld volání funkce: int n = ctiprirozene(); 3/29 4/29 Fktoriál pomocí funkcí Funkce pro výpočet fktoriálu int fktoril(int n) { int i = 1, f = 1; while (i<n) { i = i+1; f = f*i; return f; Hlvičk funkce vyjdřuje, že funkce má jeden prmetr typu int že výsledkem je hodnot typu int Příkld volání funkce int f = fktoril(4); // vysledek se ulozi do f Fktoriál pomocí funkcí /* pro5-1b.c */ /* vypocet fktorilu */ int ctiprirozene(void) { printf("zdejte prirozene cislo: "); scnf("%d", &n); if (n<1) { printf("%d neni prirozene cislo\n", n); exit(0); return n; Proměnnou n ve funkci min lze vynecht: printf("%d! = %d\n", n, fktoril(n)); 5/29 definice funkce 6/29
2 Definice funkce Funkce je podprorm (zápis dílčího loritmu), který vrcí hodnotu (výsledek) Definici funkce tvoří hlvičk funkce tělo funkce Hlvičk funkce v jzyku C má tvr typ jméno( specifikce prmetrů ) typ je typ výsledku funkce jméno je identifikátor funke specifikcí prmetrů se deklrují prmetry funkce, kždá deklrce má tvr typ_prmetru jméno_prmetru oddělují se čárkou - nemá-li funkce prmetry, specifikce prmetrů je void - Tělo funkce je složený příkz nebo blok, který se provede při volání funkce Tělo funkce musí dynmicky končit příkzem kde x je výrz, jehož hodnot je výsledkem volání funkce Prmetry funkce Prmetry funkce jsou lokální proměnné funkce, kterým se při volání funkce přiřdí hodnoty skutečných prmetrů. Jestliže prmetr funkce je typu T, pk přípustným skutečným prmetrem je výrz, jehož hodnotu lze přiřdit proměnné typu T - tedy stejná podmínk, jko u přiřzení. /* pro5-1c.c */ int mx(int x, int y) { if (x>y) return y; int = 10, b = 20; printf("%d\n", mx(, b)); printf("%d\n", mx(32.4, b)); 7/29 8/29 Prmetry funkce Prmetry funkce předávjí vstupní dt loritmu, který funkce relizuje Čstá chyb zčátečník: funkce, která čte hodnoty prmetrů pomocí operce vstupu dt int mx(int x, int y) { scnf("%d%d", &x, &y); // nesmyslný příkz if ( x > y ) else return y; Deklrce funkce Deklrce funkce je tvořen hlvičkou funkce je zkončen středníkem Deklrcí je funkce zveden může být použit /* pro5-1d.c */ int mx(int x, int y); int min(void) { int = 10, b = 20; printf("%d\n", mx(, b)); printf("%d\n", mx(32.4, b)); int mx(int x, int y) { if (x>y) else return y; deklrce funkce definice funkce Definice funkce může být v jiném souboru (uvidíme později) 9/29 10/29 Volání funkce Funkci f můžeme vyvolt z funkce, jestliže ve funkci je znám hlvičk funkce f Hlvičk funkce se zdá buď deklrcí nebo definicí funkce. Zopkujme, že hlvičkou funkce je dáno jméno (identifikátor) funkce, počet typy prmetrů typ výsledku funkce Funkci f, která má n prmetrů vrcí výsledek typu T, můžeme vyvolt zápisem funkce, což je výrz ve tvru f(p 1, p 2,, p n ) kde p 1, p 2,, p n jsou výrzy udávjící skutečné prmetry Hodnoty skutečných prmetrů se přiřdí prmetrům funkce podle prvidel pro přiřzení pk se provede tělo funkce. Hodnotou zápisu funkce je výsledek funkce (zdný v příkzu return). Zápis funkce obvykle používáme jko výrz, tzn. v kontextu, ve kterém je uvedeno, co s výsledkem funkce udělt (npř. přiřdit nějké proměnné). Ze zápisu funkce uděláme příkz, zkončíme-li ho středníkem (výsledek funkce se pk nepoužije zpomene se) Dlší příkld funkce Funkce pro zjištění, zd dný rok je přestupný /* pro5-1e.c */ int jeprestupny(int rok) { if (rok%4==0 && (rok%100!=0 rok%400==0)) else int rok; printf("zdejte rok: "); scnf("%d", &rok); printf("rok %d ", rok); if (jeprestupny(rok)) printf("je prestupny\n"); else printf("neni prestupny\n"); 11/29 12/29
Funkce pro výpočet NSD Jednoduchý loritmus výpočtu nsd jsme již uvedli Efektivnější loritmus lze sestvit n zákldě těchto vzthů: je-li x = y, pk nsd( x, y ) = x je-li x > y, pk nsd( x,y ) = nsd( x-y, y ) je-li x < y, pk nsd( x, y) = nsd( x, y-x ) Řešení 2: while (x!=y) if (x>y) x = x-y; else y = y-x; Funkce pro výpočet NSD Do těl cyklu vnoříme místo podmíněného příkzu pro jediné zmenšení hodnoty x nebo y dv cykly pro opkovné zmenšení hodnot x y Řešení 3: while (x!=y) { while (x>y) x = x-y; while (y>x) y = y-x; 13/29 14/29 Euklidův loritmus pro výpočet NSD Vnitřní cykly řešení 3 počítjí nenulový zbytek po dělení většího čísl menším Pro výpočet zbytku po dělení slouží operátor % Euklidův loritmus lze slovně formulovt tkto: určíme zbytek po dělení dných čísel, zbytkem dělíme dělitele určíme nový zbytek, ž dosáhneme nulového zbytku; poslední nenulový zbytek je nsd Řešení 4: int zbytek = x%y; while (zbytek!=0) { x = y; y = zbytek; zbytek = x%y; return y; Procedury Procedur je podprorm (zápis dílčího loritmu), který nevrcí žádnou hodnotu V jzyku C se procedury definují jko funkce, jejichž typ výsledku je void Proceduru je možno dynmicky ukončit kdekoliv příkzem return; Příkz return není nutný, procedur končí po provedení posledního příkzu Příkld procedury: výpis většího ze dvou celých čísel void vypismx(int x, int y) { if (x>y) printf("%d", x); else printf("%d", y); Dále se budeme držet terminoloie jzyk C: řekneme-li funkce, myslíme tím: jk funkci, která vrcí hodnotu, tk proceduru, která hodnotu nevrcí (typ výsledku je void). 15/29 16/29 Vstupní výstupní prmetry Prmetrem funkce je obvykle hodnot, která slouží jko vstup dílčímu loritmu, který je funkcí relizován. Tyto prmetry nzýváme vstupními prmetry Všechny předchozí funkce měly vstupní prmetry Většin prormovcích jzyků umožňuje, by funkce (procedur) měl též výstupní prmetr Výstupní prmetr umožňuje, by funkce (procedur) přiřdil hodnotu do proměnné, která je dán skutečným prmetrem. Příkld (v pseudojzyku): procedur, která ze dvou vstupních prmetrů x y (celá čísl) uloží menší číslo do proměnné dné výstupním prmetrem mensi vetší číslo do proměnné dné výstupním prmetrem vetsi proc minmx(in int x, in int y, out int mensi, out int vetsi) { if (x<y) { mensi = x; vetsi = y; else { mensi = y; vetsi = x; Výstupní prmetry Výstupní prmetry se v jzyku C relizují tk, že funkci (proceduře) se předá dres proměnné, kterou má funkce (procedur) změnit Operátor, který dodá dresu proměnné, už známe. Je to &, který používáme ve volání funkce scnf Proměnná (prmetr) p, jejíž hodnotou může být dres proměnné typu T, se deklruje zápisem T *p Typ T* se nzývá typem ukztel n T Příkld: deklrce procedury, která ze dvou vstupních prmetrů x y (celá čísl) uloží vetší číslo do proměnné dné výstupním prmetrem vetsi menší číslo do proměnné dné výstupním prmetrem mensi void minmx(int x, int y, int *mensi, int *vetsi); Jk tuto proceduru vyvolt: int, b, min, mx; mxmin(, b, &min, &mx); 17/29 18/29 3
4 Výstupní prmetry Pro přístup k proměnné, jejíž dres je v proměnné (prmetru) typu ukztel, slouží unární operátor * (dereference) Příkld (pro5-2.c): void minmx(int x, int y, int *mensi, int *vetsi) { if (x<y) { *mensi = x; *vetsi = y; else { *mensi = y; *vetsi = x; int, b, mx, min; printf("zdejte dve cel cisl: "); scnf("%d%d", &, &b); minmx(, b, &min, &mx); printf("min = %d, mx = %d\n", min, mx); vetsi mx *vetsi Prmetry typu ukztel Skutečným prmetrem pro prmetr typu T* musí být dres proměnné typu T. Je-li proměnná jiného typu, překldč vypíše vrovné hlášení (wrnin), prorm se přeloží le nebude správně funovt Příkld (pro5-2b.c): void minmx(int x, int y, int *mensi, int *vetsi) { if (x<y) { *mensi = x; *vetsi = y; else { *mensi = y; *vetsi = x; typ int* flot, b, mx, min; printf("zdejte dve cisl: "); scnf("%f%f", &, &b); minmx(, b, &min, &mx); printf("min = %f, mx = %f\n", min, mx); typ flot* 19/29 20/29 Přidělování pměti proměnným Přidělením pměti proměnné rozumíme určení dresy umístění proměnné v pměti počítče Poznli jsme dv druhy proměnných: lobální proměnné (deklrovné mimo funkci) lokální proměnné funkcí (deklrovné v bloku funkce prmetry funkce) Globálním proměnným se přidělí pměť při spuštění prormu (sttické přidělení pměti) zůstne jim přidělen ž do ukončení běhu prormu Lokálním proměnným prmetrům funkce se pměť přidělí při volání funkce (dynmické přidělení pměti) zůstne jim přidělen jen do návrtu z funkce (po návrtu se přidělené dresy uvolní pro dlší použití) Úseky pměti přidělovné lokálním proměnným prmetrům tvoří tzv. zásobník ( stck ): úseky se přidávjí odebírjí, přičemž se vždy odebere nposledy přidný úsek ( strteie LIFO ) zásobník 1 2 3 21/29 Přidělování pměti proměnným int ; void f(void) { int b; // 2 h(4); // 4 int h(int x) { // 3 int ; // 1 f(); // 5 x b b b 4 5 zásobník stticky přidělená pměť 22/29 Problém: prvočísl Zjistěte počet prvočísel menších než zdné číslo n určete čs, který n to budete potřebovt prvočíslo: přirozené číslo větší než 1, které je beze zbytku dělitelné pouze jedničkou smo sebou. přirozené číslo: kldné celé číslo větší než 0 Aloritmus: Pro kždé číslo menší než n rozhodněte, zd jde o prvočíslo či ne rději pouze: pro kždé přirozené Nsčítejte prvočísl podproblémy : 1. zjištění zd dné číslo je prvočíslo 2. měření čsu funkce Příkld: prvočísl I Dle definice: Přirozené číslo n je prvočíslo, právě tehdy když jej beze zbytku dělí pouze číslo n číslo 1 int isprvocislo1(lon lon n) { lon lon i; if (n < 2) { int pocetdelitelu = 0; for (i = 1; i <= n; i++) { if (n % i == 0) { pocetdelitelu++; if (pocetdelitelu == 2) { else { 23/29 24/29
5 Příkld: prvočísl II Vylepšení 1. - njdeme-li prvního dělitele jiného než čísl 1 n, již to není prvočíslo int isprvocislo2(lon lon n) { lon lon i; if (n < 2) { for (i = 2; i < n; i++) { if (n % i == 0) { Příkld: prvočísl III Vylepšení 2. Číslo složené lze npst jko součin dělitelů, npř. 35=7*5; jedno je menší druhé větší int isprvocislo3(lon lon n) { lon lon i; if (n < 2) { for (i = 2; i <= n / 2; i++) { if (n % i == 0) { 25/29 26/29 Příkld: prvočísl IV Vylepšení 2. Číslo složené lze npst jko součin dělitelů, npř. 35=7*5; jedno je menší druhé větší, pokud nejsou stejné jko 49 = 7*7 int isprvocislo(lon lon n) { lon lon i; if (n < 2) { for (i = 2; i <= sqrt(n); i++) { if (n % i == 0) { sqrt(n) se vyhodnocuje před kždým průchodem cyklem int isprvocislo(lon n) { lon i; int mx = (int)sqrt(n); if (n < 2) { for (i = 2; i <= mx; i++) { if (n % i == 0) { Příkld: prvočísl V 27/29 28/29 Příkld: prvočísl V - složitost Složitost loritmu určuje jeho čsovou prostorovou náročnost t/m n Určete složitost loritmů (n zákldě odhdu čsu) pro všechny typy metod n zjištění, zd dné číslo je prvočíslo 29/29