11. Funkce I

 
  1. Funkce jsou zßkladem programovßnφ v C a C++. Funkce jsou Φßstφ k≤du odd∞lenΘ od hlavnφho programu. Tyto Φßsti k≤du jsou volßny (provßd∞ny), kdy╛ je zapot°ebφ provΘst jistou akci v programu. Nap°. m∙╛eme mφt funkci, kterß p°ebφrß dv∞ hodnoty, provede s nimi jistΘ v²poΦty a vrßtφ v²sledek. Nebo m∙╛eme mφt funkci p°ebφrajφcφ °et∞zec, rozd∞lφ jej a vracφ Φßst tohoto °et∞zce. Nejjednodu╣╣φ typ funkce nemß parametry a vracφ void (co╛ znamenß, ╛e nevracφ nic). JinΘ funkce mohou mφt jeden nebo vφce parametr∙ a mohou vracet hodnotu.  Ka╛d² program musφ mφt prßv∞ jednu funkci se jmΘnem main (nebo WinMain) oznaΦujφcφ vstupnφ bod programu. Funkce jsou obvykle deklarovßny jako prototypy ve standardnφch nebo u╛ivatelsk²ch hlaviΦkov²ch souborech, nebo uvnit° zdrojov²ch soubor∙. Funkce jsou definovßny ve zdrojov²ch souborech programu nebo ve zp°φstupn∞n²ch knihovnßch. Nedefinujφcφ deklarace funkcφ pou╛φvajφ formßt funkΦnφho prototypu poskytujφcφ p°ekladaΦi detailnφ informace o parametrech a tφm mu umo╛≥ujφ provΘst kontrolu poΦtu parametr∙, kontrolu typ∙ parametr∙ a pou╛itφ p°φpadn²ch automatick²ch p°evod∙ typ∙. Prototypy funkcφ se v C++ musφ pou╛φvat a doporuΦuje se je pou╛φvat i v C.

  2. V jazyku C mohla b²t funkce p∙vodn∞ deklarovßna bu∩ implicitn∞ sv²m v²skytem ve funkΦnφm volßnφ, nebo explicitn∞ zßpisem:
    typ fce();
    kde typ urΦuje nßvratov² typ funkce (implicitn∞ int), p°iΦem╛ funkce m∙╛e vracet libovoln² typ s v²jimkou pole nebo funkce. Tento styl deklaracφ v╣ak neumo╛≥uje, aby p°ekladaΦ vedle kontroly nßvratovΘho typu provßd∞l takΘ kontrolu poΦtu a typ∙ parametr∙ funkce. Tento problΘm byl vy°e╣en zavedenφm prototypu funkce. Prototyp funkce zapisujeme takto:
    typ fce(seznam-deklaracφ-parametr∙);
    Deklarace specifikujφ typ ka╛dΘho parametru. P°ekladaΦ tyto informace pou╛φvß pro kontrolu sprßvnosti volßnφ funkce. V n∞kter²ch p°φpadech je p°ekladaΦ rovn∞╛ schopen p°evΘst typ parametru na po╛adovan² typ. Podφvejte se na nßsledujφcφ Φßst programu:
    long lmax(long v1, long v2);        // prototyp
    void main(int argc, char **argv)
    {
      int limit = 32;
      char ch = 'A';
      long mval;
      mval = lmax(limit, ch);            // volßnφ funkce
    }
    Proto╛e p°ekladaΦ znß prototyp funkce lmax, jsou parametry funkce (limit a ch) nejprve pou╛itφm standardnφch pravidel p°evedeny na typ long (po╛adovan² typ parametr∙) a teprve potom jsou p°edßny funkci. Bez pou╛itφ prototypu, p°ekladaΦ neznß datovΘ typy parametr∙ a neprovßdφ ╛ßdn² p°evod. Funkci jsou tedy p°edßny limit a ch jako typy int a char, co╛ funkce lmax neoΦekßvß a dostßvßme se do problΘm∙.
    Prototypy funkcφ takΘ p°ispφvajφ k lep╣φ dokumentaci programu. Nap°. funkce strcpy (kopφrovßnφ °et∞zce znak∙) mß dva parametry: zdrojov² a cφlov² °et∞zec. Otßzkou je, kter² je zdrojov² a kter² je cφlov²? Prototyp funkce
    char *strcpy(char *cil, const char *zdroj);
    v╣e objasnφ. JmΘna parametr∙ v prototypu majφ pouze dokumentaΦnφ ·Φel. Prototypy funkcφ zapisujeme v hlaviΦkov²ch souborech nebo na zaΦßtku zdrojovΘho textu programu.
    Definice funkce obsahuje t∞lo funkce, tj. k≤d, kter² se bude p°i volßnφ funkce provßd∞t. Deklarace formßlnφch parametr∙ majφ stejn² zßpis jako deklarace prom∞nn²ch. V C++ je mo╛no v deklaraci parametr∙ uvΘst implicitnφ hodnoty parametr∙. Parametry s implicitnφmi hodnotami musφ b²t poslednφmi paramery. V deklaracφch parametr∙ je mo╛nΘ pou╛φt i modifikßtor const. Definice funkce je popsßna na nßsledujφcφm obrßzku:

    Pokud funkce nevracφ ╛ßdnΘ informace, pak jejφ typ je void. Funkce typu void majφ p°φkaz return bez v²razu urΦujφcφho vrßcenou hodnotu.
    P°i volßnφ funkce jsou skuteΦnΘ parametry funkce uvedeny ve stejnΘm po°adφ jako parametry v definici funkce. PoΦet parametr∙ musφ souhlasit. Typy parametr∙ musφ b²t kompatibilnφ do tΘ mφry, aby mohly b²t p°evedeny. Pokud uvedeme definici funkce d°φve ne╛ funkci pou╛ijeme, pak prototyp funkce nenφ nutno uvßd∞t.
  3. Pou╛itφ funkce ukazuje nßsledujφcφ konzolovß aplikace:

  4. #include <iostream.h>
    #include <conio.h>
    #pragma hdrstop
    //---------------------------------------------------------------------
    #pragma argsused
    int nasob(int, int);
    void zobrazVysledek(int);
    int main(int argc, char **argv)
    {
      int x, y, vysledek;
      cout << endl << "Zadej prvnφ hodnotu: ";
      cin >> x;
      cout << "Zadej druhou hodnotu: ";
      cin >> y;
      vysledek = nasob(x, y);
      zobrazVysledek(vysledek);
      cout << endl << endl << "Stiskni libovolnou klßvesu ... ";
      getch();
      return 0;
    }
    int nasob(int x, int y)
    {
      return x*y;
    }
    void zobrazVysledek(int vysl)
    {
      cout << "V²sledek je: " << vysl << endl;
    }
    Tento program vy╛aduje zadßnφ dvou Φφsel, volß funkci nasob k vynßsobenφ zadan²ch hodnot a potom volß funkci zobrazVysledek k zobrazenφ v²sledku. Prototypy t∞chto funkcφ jsou uvedeny na zaΦßtku programu (p°ed funkcφ main). V prototypech je uveden pouze nßvratov² typ, jmΘno funkce a datovΘ typy parametr∙ funkce. Toto je minimßlnφ po╛adavek na deklaraci funkce. Je-li to zapot°ebφ, prototyp funkce m∙╛e obsahovat jmΘna parametr∙, kterΘ mohou b²t pou╛ity k dokumentovßnφ Φinnosti funkce. Nap°. deklarace funkce nasob m∙╛e b²t zapsßna takΘ takto:
    int nasob(int prvniCislo, int druheCislo);
    V na╣em p°φpad∞ je jasnΘ co funkce d∞lß a nenφ zapot°ebφ ╛ßdnß dokumentace. Definice tΘto funkce je takΘ jednoduchß. Na╣e funkce m∙╛e b²t volßna n∞kolika zp∙soby. Mohou ji b²t p°edßny konstanty, hodnoty prom∞nn²ch a v²sledek m∙╛e b²t takΘ p°edßn jinΘ funkci. Nßsleduje n∞kolik p°φklad∙ volßnφ tΘto funkce:
    vysledek = nasob(5, 2);
    vysledek = nasob(x, y);
    zobrazVysledek(nasob(x, 5));
    nasob(3, x);
    V poslednφm p°φklad∞ vrßcenß hodnota nenφ pou╛ita. Ignorovßnφ vrßcenΘ hodnoty je v na╣em p°φpad∞ nesmyslnΘ, ale v n∞kter²ch p°φpadech je to Φasto pou╛φvanΘ. Je mnoho funkcφ provßd∞jφcφch jistΘ akce a vrßcenß hodnota indikuje stav volßnφ. Pokud tato hodnota nenφ d∙le╛itß pro nß╣ program, pak ji m∙╛eme ignorovat. Nap°. v na╣ich programech jsme zatφm ignorovali hodnotu vracenou funkcφ getch (ASCII hodnota stisknutΘ klßvesy).
    Funkce m∙╛e volat jinΘ funkce. Funkce m∙╛e takΘ volat sama sebe. Toto naz²vßme rekurze.
  5. Nßsledujφcφ konzolovß aplikace zji╣╗uje, zda zadanΘ Φφslo je prvoΦφslo. Zda se jednß o prvoΦφslo urΦuje funkce je_prvocislo. Tato funkce pou╛φvß pomocnou funkci zji╣╗ujφcφ d∞litelnost Φφsel. Ob∞ tyto funkce majφ v programu uveden prototyp. Prostudujte si tento v²pis, program vyzkou╣ejte a sna╛te se pochopit jak jednotlivΘ funkce pracujφ.

  6. int je_prvocislo(int);
    int je_delitelno(int, int);
    int main(int argc, char **argv)
    {
      int n;
      cout << "Zadej p°irozenΘ Φφslo: ";
      cin >> n;
      cout << "Φφslo " << n << (je_prvocislo(n) ? " je" : " neni")
           << " prvoΦφslo." << endl;
      getch();
      return 0;
    }
    int je_prvocislo(int n)
    {
      for (int i = 2; i*i <= n; i++)
        if (je_delitelno(n, i)) return 0;
      return 1;
    }
    int je_delitelno(int n, int m)
    {
      return !(n % m);
    }
  7. Nßsledujφcφ funkce urΦuje nejv∞t╣φ spoleΦn² d∞litel dvou p°irozen²ch Φφsel. Pou╛ijte tuto funkci v konzolovΘ aplikaci, kde p°eΦtete Φitatel a jmenovatel zlomku a provedete p°φpadnΘ zkrßcenφ zlomku. V programu uve∩te i prototyp tΘto funkce.

  8. int nsd(int a, int b)
    {
      int pom;
      while (b) {
        pom = a % b;
        a = b;
        b = pom;
      }
      return a;
    }
  9. Napi╣te funkci vypisujφcφ °ßdek obsahujφcφ n znak∙ z. n a z jsou parametry funkce. Tuto funkci pou╛ijte v programu pro v²pis nap°. 50-ti znak∙ podtr╛enφ a 20-ti znak∙ hv∞zdiΦek.
  10. P°ejdeme op∞t k aplikacφm GUI. Vytvo°φme aplikaci, kde na formulß°i budou t°i editaΦnφ ovladaΦe (vyprßzdnφme je a p°ed n∞ umφstφme texty ?Prvnφ operand:?, ?Druh² operand:? a ?V²sledek:?) a tlaΦφtka ?SouΦet?, ?Rozdφl?, ?SouΦin? a ?Podφl?. Obsluha udßlosti stisku tlaΦφtka ?SouΦet? bude tvo°ena p°φkazy:

  11. int x, y;
    x = Edit1->Text.ToInt();
    y = Edit2->Text.ToInt();
    Edit3->Text = AnsiString(x + y);
    Vytvo°te obsluhy i pro ostatnφ tlaΦφtka a program vyzkou╣ejte.
  12. Do p°edchozφ aplikace p°idßme je╣t∞ dal╣φ editaΦnφ ovladaΦ, ve kterΘm budeme poΦφtat poΦet proveden²ch v²poΦt∙ (vyprßzdnφme jej a p°ed n∞j umφstφme text ?PoΦet proveden²ch v²poΦt∙:?). Pro poΦφtßnφ proveden²ch v²poΦt∙ musφme zavΘst globßlnφ prom∞nou, nazveme ji nap°. Pocet (globßlnφ prom∞nnΘ deklarujeme mimo funkce; je nutno ji deklarovat p°ed prvnφ funkcφ, ve kterΘ ji pou╛φvßme). Do v╣ech obsluh stisknutφ tlaΦφtek p°idßme p°φkazy:

  13. Pocet++;
    Edit4->Text = AnsiString(Pocet);
    Bylo by vhodnΘ na╣i prom∞nnou Pocet na poΦßtku v²poΦtu vynulovat. M∙╛eme to provΘst tak, ╛e jejφ deklaraci spojφme s inicializacφ, tzn. p°ed prvnφ obsluhu vlo╛φme:
    int Pocet = 0;
  14. Jist∞ jste si pov╣imli, ╛e kdy╛ stisknete n∞kterΘ tlaΦφtko a nemßte zadanΘ operandy je signalizovßna chyba. Na zaΦßtku obsluh stisku tlaΦφtek budeme testovat, zda oba operandy jsou zadßny. Toto testovßnφ je nutno provßd∞t ve v╣ech obsluhßch stisku tlaΦφtek a tedy vytvo°φme funkci, kterß otestuje editaΦnφ ovladaΦ zadan² parametrem funkce (pokud editaΦnφ ovladaΦ je prßzdn² vrßtφ true, jinak vrßtφ false). Tato funkce bude vypadat takto:

  15. bool NeniHodnota(TEdit *EditOvl){
      if (EditOvl->Text == "") {
        EditOvl->Color = clRed;
        EditOvl->Text = "Zadej hodnotu";
        EditOvl->SetFocus();
        return true;
      }
      else {
        EditOvl->Color = clWindow;
        return false;
      }
    }
    Parametr funkce je typu ukazatel na TEdit, co╛ je typ editaΦnφho ovladaΦe (v╣echny typy komponent zaΦφnajφ pφsmenem T) a jako skuteΦn² parametr tedy budeme moci pou╛φt Edit1 i Edit2. Pokud v editaΦnφm ovladaΦi nenφ zapsßn ╛ßdn² text, je zm∞n∞na barva ovladaΦe na Φervenou a je zde vypsßn text ?Zadej hodnotu. P°φZadej EditOvl->SetFocus(); zajistφ vybrßnφ testovanΘho editaΦnφho ovladaΦe a m∙╛eme tedy do n∞j ihned zapisovat hodnotu. Pokud editaΦnφ ovladaΦ nenφ prßzdn², pak je zm∞n∞na jeho barva na normßlnφ barvu okna (clWindow). Tuto funkci musφme je╣t∞ vyvolat na zaΦßtku v╣ech obsluh stisk∙ tlaΦφtek. Na zaΦßtek v╣ech t∞chto obsluh tedy p°idßme p°φkaz:
    if (NeniHodnota(Edit1) || NeniHodnota(Edit2)) return;
    Prove∩te v²╣e uvedenΘ zm∞ny pro v╣echna tlaΦφtka a vyzkou╣ejte. Nenφ to ale ideßlnφ °e╣enφ, nebo╗ nezaji╣╗uje aby v editaΦnφm ovladaΦi byla zapsßna Φφselnß hodnota.
  16. V dal╣φ aplikaci se seznßmφme s pou╛φvßnφm komponenty Timer (ΦasovaΦ - je ji mo╛no pou╛φt k definovßnφ ΦasovΘho intervalu). Na formulß° umφstφme tuto komponentu (je na strßnce System Palety komponent). Jedna z vlastnostφ tΘto komponenty urΦuje Φasov² interval v milisekundßch (tato vlastnost se jmenuje Interval). Do programu vlo╛φme deklaraci globßlnφ prom∞nnΘ X typu bool a vytvo°φme obsluhu udßlosti OnTimer ΦasovaΦe s p°φkazy:

  17. if (X) Color = clRed;
    else Color = clGreen;
    X = !X;
    Zjist∞te, co provßdφ tato aplikace.
  18. Vytvo°te aplikaci, ve kterΘ se pokusφte simulovat hßzenφ hracφ kostkou. Ka╛dou sekundu generujte hod a jeho v²sledek zobrazte na formulß°i (Φφseln∞). Inicializaci generßtoru nßhodn²ch Φφsel prove∩te v obsluze udßlosti OnCreate formulß°e.

NovΘ pojmy:

 11. Funkce I