Kurz C++ (3.)


Ve t°etφ lekci naÜeho kurzu o C/C++ se dostßvßme k podstatnΘ Φßsti jazyka. Nejd°φve si povφme o funkcφch getchar(), putchar(), printf() a scanf(). Povφme si o velice d∙le₧itΘm p°φkazu if-else. Dßle si °ekneme, co jsou to iteraΦnφ p°φkazy neboli cykly a ukß₧u vßm vÜechny typy takov²ch cykl∙. S cykly ·zce souvisφ p°φkazy break a continue a nakonec vysv∞tlφm p°φkaz switch.

5.1. Terminßlov² vstup a v²stup

Na zaΦßtek je nutnΘ poznamenat, ₧e vÜe, co je uvedeno v tΘto lekci je podstata jazyka C a je nutnΘ, abyste vÜe sprßvn∞ pochopili, proto₧e p°i dalÜφm programovßnφ se bez toho urΦit∞ neobejdete.

Abyste mohli vyu₧φvat funkce pro vstup a v²stup musφte k vaÜemu programu p°ipojit hlaviΦkov² soubor (header file). O vklßdßnφ hlaviΦkov²ch soubor∙ jsem se ji₧ zmφnil v minulΘ lekci. Provede to p°φkazem include.

Vlo₧te nßsledujφcφ °ßdek na zaΦßtek vaÜeho programu:
  #include <stdio.h>

Nynφ m∙₧ete pou₧φvat vÜechny funkce deklarovanΘ prßv∞ v souboru stdio.h a kterΘ souvisφ s I/O (input/output - vstup/v²stup) operacemi jako je i v²stup na obrazovku a vstup z klßvesnice (dßle m∙₧e obsahovat nap°φklad v²stup na tiskßrnu Φi Φtenφ a zßpis do souboru).

5.1.1. Vstup a v²stup jednoho znaku

V²stup jednoho znaku zajiÜ¥uje funkce putchar(), kterß mß jeden parametr kupodivu typu int (nikoliv char), kter² p°edstavuje hodnotu znaku v ASCII tabulce.

Druhß funkce getchar() p°eΦte jeden znak. Pokud na °ßdek napφÜeme vφc znak∙ a stiskneme Enter, funkce p°eΦte pouze prvnφ znak a ostatnφ ignoruje.

Program p°eΦte znak, vypφÜe ho a od°ßdkuje.
Krßtky p°φklad:

  int c;

  c = getchar();
  putchar(c);
  putchar('\n');

VÜimn∞te si, ₧e jako parametr funkce putchar() m∙₧ete pou₧φt znakovou konstantu tj. znak uzav°en² mezi apostrofy nap°. 'a', '5' apod. Hodnota znakovΘ konstanty odpovφdß celoΦφselnΘ hodnot∞ z ASCII tabulky nap°. 'a' mß hodnotu 97. (ASCII tabulka nemusφ b²t na vÜech systΘmech stejnß).

Zßpis
putchar(97);
a
putchar('a');
je ekvivalentnφ.

5.1.2. Formßtovan² vstup a v²stup

Co kdy₧ ale chceme p°eΦφst vφce ne₧ jeden znak nebo naopak chceme vypsat celou v∞tu? Od toho mß C dv∞ funkce:

  • scanf() - naΦte znaky, °et∞zce nebo Φφsla z klßvesnice a ulo₧φ je v po₧adovanΘm formßtu do prom∞nnΘ.
  • printf() - vypφÜe °et∞zec v po₧adovanΘm formßtu na obrazovku.
Zp∙sob formßtovßnφ
Ob∞ funkce majφ prom∞nn² poΦet parametr∙ a my jim tedy musφme °φct, kolik parametr∙ majφ zpracovßvat. K tomu slou₧φ prvnφ parametr, co₧ je °et∞zcovß konstanta (nebo takΘ °φdφcφ °et∞zec) obsahujφcφ jistΘ znaky, kterΘ prßv∞ °φkajφ kolik mß mφt funkce parametr∙ a jakΘho jsou typu.

╪φdφcφ °et∞zec m∙₧e obsahovat:
  • FormßtovΘ specifikace, kterΘ v₧dy zaΦφnajφ znakem "%" (procenta) a urΦujφ typ vstupnφ nebo v²stupnφ hodnoty. Konkretnφ typ je urΦen znaky, kterΘ nßsleduje t∞sn∞ za tφmto znakem.
  • ZnakovΘ posloupnosti, jsou b∞₧nΘ ΦitelnΘ °etezce, kterΘ se vypφÜφ tak jak jsou, ale dajφ se pou₧φt jen ve funkci printf().
Tabulka nejΦast∞ji pou₧φvan²ch formßtov²ch specifikacφ:
Znak za %Typ parametru
cznak - je lepÜφ pou₧φt funkci getchar() nebo putchar()
dcelΘ Φφslo typu signed int
ldcelΘ Φφslo typu signed long
ucelΘ Φφslo typu unsigned int
lucelΘ Φφslo typu unsigned long
freßlnΘ Φφslo typu float
lfreßlnΘ Φφslo typu double
LfreßlnΘ Φφslo typu long double (L musφ b²t skuteΦnΘ velkΘ)
xΦφslo v hexadecimßlnφm tvaru s mal²mi pφsmeny - 5b8f
XΦφslo v hexadecimßlnφm tvaru s velk²mi pφsmeny - 5B8F
oΦφslo v osmiΦkovΘm tvaru
s°et∞zec

P°φklady pou₧itφ printf():
  1. printf("Je presne %2d:%2d\n", hodiny, minuty);
    VypφÜe nap°φklad "Je presne 21:27".
    ╚φslem mezi % a formßtov²m znakem je poΦet cifer, kterΘ se vypφÜφ. U reßlnΘho Φφsla lze urΦit poΦet cifer p°ed a za desetinou teΦkou nßsledovn∞:
  2. printf("Cena vyrobku je %6.2f Kc\n", cena);
    VypφÜe nap°φklad "Cena vyrobku je 10.40 Kc".
    Bude vytiÜt∞no 6 cifer z toho 2 budou za desetinou teΦkou.
  3. printf("Cislo %d je hexa %XH\n", cislo, cislo);
    VypφÜe nap°φklad "Cislo 85 je v hexa 55H".
    VÜimn∞te si konverze dekadickΘho Φφsla na hexadecimßlnφ Φφslo.
P°φklady pou₧itφ scanf():
  1. scanf("%d", &cele_cislo);
    Tento p°φkaz p°eΦte celΘ Φφslo z klßvesnice a ulo₧φ ho do prom∞nnΘ cele_cislo.
    Pozor! VÜimn∞te znaku & p°ed prom∞nnou cele_cislo. Funkci scanf() p°edßvßme ukazatel na prom∞nnou cele_cislo a tento operßtor vracφ prßv∞ ukazatel. To je rozdφl od p°edchozφ funkce a zaΦφnajφcφ programßtor na to Φasto zapomene. Kompilßtor ₧ßdnou chybu nevypφÜe, ale program funguje chybn∞. Zatφm vßm staΦφ v∞d∞t, ₧e na tento operßtor nesmφte zapomenout.
  2. scanf("%f", &realne_cislo);
    Tento p°φkaz p°eΦte reßlnΘ Φφslo z klßvesnice a ulo₧φ ho do prom∞nnΘ realne_cislo.

Poznßmka: Minule jsem se zmi≥oval o objektech cout a cin. Tyto objekty majφ stejnou funkci jako funkce printf() a scanf().

5.2. BooleovskΘ v²razy

Booleovsk² v²raz je v²raz, kter² vracφ bu∩ logickou 1 (TRUE - pravda) nebo logickou 0 (FALSE - nepravda). Jazyk C nemß p°φmo typ Boolean a tak mφsto toho vyu₧φvß typ int, kde hodnota 0 p°edstavuje FALSE a nenulovß hodnota (nejΦast∞ji 1, ale nenφ to podmφnkou) p°edstavuje TRUE. Nßsledujφcφ tabulka ukazuje tzv. relaΦnφ operßtory, kterΘ pou₧φvßme v podmφnkßch. VÜe si ukß₧eme na p°φkladu.
OperaceSyntaxe
rovnost= =
nerovnost!=
logick² souΦin&&
logick² souΦet||
negace!
v∞tÜφ>
menÜφ<
v∞tÜφ nebo rovno>=
menÜφ nebo rovno<=

Ka₧d² booleovsk² v²raz obsahuje jeden nebo vφce t∞chto operßtor∙.

P°φklad:
 // Toto je prirazeni, nikoliv porovnani, menime hodnotu promenne i
 i = 5

 // Zde vidite porovnani hodnoty promenne i a cisla 5
 // Vyraz vraci nenulovou hodnotu (TRUE) v pripade ze v promenne i je skutecne cislo 5, jinak vraci 0 (FALSE)

 i == 5  

5.1.1. Zkrßcene vyhodnocovßnφ logick²ch v²raz∙

ZkrßcenΘ vyhodnocovßnφ platφ pro logickΘ operace tzn. logick² souΦin a logick² souΦet. Znamenß to, ₧e jakmile je mo₧no urΦit koneΦn² v²sledek vyhodnocovßnφ skonΦφ.

P°φklad:
 // Toto je zcela sprßvnΘ a k d∞lenφ nulou nikdy nedojde,
 // proto₧e y != 0 ukonΦφ vyhodnocovßnφ d°φve ne₧ by k n∞Φemu takovΘmu doÜlo

 if(y != 0 && x / y < z)
 

5.2. P°φkaz if a if-else

Jak jsme si °φkali v²Üe, booleovsk² v²raz vracφ n∞kajou logickou hodnotu (0 nebo 1). K vyhodnocenφ takovΘhoto v²razu pou₧ijeme p°φkaz if:

 if(v²raz) { // zavorky jsou nutne
   p°φkaz_1;
 }
 p°φkaz_2;

Pokud je podmφnka v²razu spln∞na (vracφ TRUE), program provede p°φkaz_1 a potΘ i p°φkaz_2. V opaΦnΘm p°φpad∞ (pokud v²raz vrßtφ FALSE) je proveden pouze p°φkaz_2.

P°φklad:

 // Program testuje zdali hodnota promenne i je vetsi nez 5
 // V kladnem pripade vypise hlasku
 if(i > 5) {
   printf("Hodnota promenne i je vetsi nez 5\n");
 }

VÜimn∞te si, ₧e v²raz je v₧dy uzav°en do kulat²ch zßvorek () a ₧e p°φkazy "pod" if jsou uzav°eny do zßvorek slo₧en²ch {}. Pokud je "pod" if pouze jeden p°φkaz, slo₧enΘ zßvorky nejsou nutnΘ, naproti tomu kulatΘ jsou nutnΘ v₧dy!

P°φkaz if-else se liÜφ jen mßlo. P°φkazy "pod" else jsou provßd∞ny jen kdy₧ v²raz vracφ FALSE.
╚esky °eΦeno:
"Kdy₧ (if) n∞co (v²raz), tak ud∞lej tohle (p°φkaz_1), jinak (else) ud∞lej tamhleto (p°φkaz_2)."


P°φklad:

 // Program testuje zdali hodnota promenne i je vetsi nez 5
 // V obou pripadech vypise logickou hlasku
 if(i > 5) {
   printf("Hodnota promenne i je vetsi nez 5\n)";
 }
 else {
   printf("Hodnota promenne i je mensi, rovna nez 5\n)";
 }

VÜimn∞te si, jak jsou p°φkazy a¥ u₧ "pod" if nebo else, mφrn∞ odsazeny oproti ostatnφm p°φkaz∙m. Je to zd∙vodu Φitelnosti programu a siln∞ doporuΦuji se toho dr₧et.
P°φkazy if-else jsou Φasto vhnφzd∞nΘ do jin²ch p°φkaz∙ if nebo if-else. Ka₧dΘ dalÜφ if je odsazeno o jeden tabelßtor doprava.
P°φklad:

 // Program nejprve testuje hodnotu promenne a a teprve pak pokracuje
 if(a != 0) {
   if(i > 5) {
     printf("Hodnota promenne i je vetsi nez 5\n");
   }
   else {
     printf("Hodnota promenne i je mensi nebo rovno nez 5\n");
   }
 }

Te∩ znovu p°epφÜu p°edchozφ p°φklad, ale trochu jinak:

 // Zde vidite uzity operator logickeho soucinu neboli AND (zaroven)
 // Vyraz v zavorkach tedy znamena:
 // Pokud a je ruzne od 0 A ZAROVEN i je vetsi nez 5, pak vypis hlasku
 if(a != 0 && i > 5) {
   printf("Hodnota promenne i je vetsi nez 5\n");
 }

V nßsledujφm p°φkladu vidφte logick² souΦet:

 // Zde vidite uzity operator logickeho soucinu neboli OR (nebo)
 // Vyraz v zavorkach tedy znamena:
 // Pokud a je ruzne od 0 NEBO i je vetsi nez 5, pak vypis hlasku
 if(a != 0 || i > 5) {
   printf("Hodnota promenne i je vetsi nez 5\n");
 }


Poznßmka:
╚asto m∙₧eme vid∞t p°φkaz if zkrßcen².

Mφsto p°φkazu:
 if(vyraz != 0)
pφÜeme jen
 if(vyraz)

a mφsto p°φkazu:
 if(vyraz == 0)
pφÜeme jen
 if(!vyraz)

5.3. Ternßrnφ operßtor

Ternßrnφ operßtor mß stejn² v²znam jako p°φkaz if-else, jen syntaxe je jinß. V n∞kter²ch p°φpadech je lepÜφ pou₧φt ternßrnφ operßtor kv∙li kratÜφmu zßpisu na jeden °ßdek, ale doporuΦuji rad∞ji pou₧φvat if-else.

Ternßrnφ operßtor mß nßsledujφcφ syntaxy:

 vyraz_podm ? vyraz_1 : vyraz_2;

P°φklad:

 // Pokud je a ruzne od 0, i bude rovno 5
 // V opacnem pripade bude i rovno 10
 i = (a != 0) ? 5 : 10;

Stejn² p°φklad s pou₧itφm if-else:

 // Funkce je uplna stejne jako v predchozim prikladu
 // Vidite ze zapis pomoci if-else je delsi, ale je prehlednejsi
 if(a != 0) {
   i = 5;
 }
 else {
   i = 10;
 }


Poznßmka: Zßvorky kolem podmφnky u ternßrnφho operßtoru nejsou nutnΘ, ale v°ele je doporuΦuji kv∙li Φitelnosti programu.

5.4. IteraΦnφ p°φkazy - cykly

Jazyk C rozliÜuje t°i typy iterace (opakovßnφ): for, while a do-while.

5.4.1. P°φkaz for

Tento cyklus pou₧ijeme v p°φpad∞, kdy₧ p°edem znßme poΦet pr∙chod∙ cyklem.
Syntaxe je nßsledujφcφ:

 for(vyraz_start; vyraz_stop; vyraz_iter) {
    prikaz;
 }

Cyklus for nejd°φve vyhodnotφ vyraz_start, otestuje pravdivost vyrazu_stop (kdy₧ v²raz vratφ FALSE, cyklus skonΦφ) a provede p°φkazy uvnit° cyklu a nakonec provede vyraz_iter. Toto celΘ se opakuje dokud vyraz_stop nevratφ nepravdu (FALSE).

Ukß₧eme si n∞kolik p°φklad∙:

// Program vypise pod sebe 20 cisel (0-19)
// Promenna i je predem deklarovana jako int
// Toto je doporucene pouziti cyklu for

 for(i = 0; i < 20; i++) {
    printf("%d\n", i);
 }

// Program vypise pod sebe 20 cisel (19-0)
// Promenna i je deklarovana primo v cyklu (toto nemusi vzdy fungovat)
// Toto je caste pouziti cyklu for

 for(int i = 19; i >= 0; i--) {
    printf("%d\n", i);
 }

M∙₧eme vyu₧φt nekoneΦn² cyklus:

// Takovy program radeji nezkousejte, protoze nikdy neskonci
// ale za chvilku si povime jak ukoncit cyklus explicitne
 for( ; ; ) {
    printf("Ahoj\n");
 }

5.4.2. P°φkaz while

DalÜφm velice d∙le₧it²m cyklem je cyklus while. Testuje podmφnku p°ed pr∙chodem cyklu, tzn., ₧e cyklus nemusφ prob∞hnout ani jednou. UkonΦovacφ podmφnka v∞tÜinou zßvisφ na p°φkazu v t∞le cyklu a my p°edem nevφme kolikrßt cyklus prob∞hne.

Syntaxe:

 while(podm) {
    prikaz;
 }

V²raz podm se testuje a pokud vrßtφ 0 (FALSE), cyklus skonΦφ.

5.4.3. P°φkaz do-while

Poslednφm iteraΦnφm cyklem je do-while (d∞lej-dokud). LiÜφ se od p°edchozßho tφm, ₧e testuje podmφnku a₧ po pr∙chodu cyklem tzn., ₧e cyklus prob∞hne alespo≥ jednou. Cyklus je ukonΦen a₧ kdy₧ v²raz v podmφnce vrßtφ 0 (FALSE).
Syntaxe:

 do {
    prikaz;
 } while(podm);

5.4.4. P°φkazy break a continue

P°φkazy break a continue ovliv≥ujφ normßlnφ pr∙b∞h cyklu. Lze je pou₧φt na vÜechny v²Üe uvedenΘ typy cykl∙.

  • break
    Tento p°φkaz ukonΦuje nejvnit°n∞jÜφ smyΦku neboli opouÜtφ okam₧it∞ cyklus.
  • continue
    Druh² uveden² p°φkaz skßΦe na konec cyklu a tφm si vynutφ dalÜφ opakovßnφ cyklu, ale cyklus neopouÜtφ.

5.4.5. P°φkaz switch

C obsahuje jak²si p°epφnaΦ neboli switch, kter² umo₧≥uje mnohonßsobnΘ v∞tvenφ programu.

Syntaxe:

 switch(vyraz) {
 case hodnota_1:   // Toto je jedna vetev
    prikaz_1;      // ...
    break;         // ...
 case hodnota_2:   // A zde zacina dalsi vetev
    prikaz_2;
    break;
 case hodnota_3:
    prikaz_3;
    break;
 default:
    prikaz_def;
    break;
 }

Program porovnßvß vyraz s jednotliv²mi hodnotami_X ka₧dΘ v∞tve a provede tu v∞tev, kde se vyraz rovnß hodnote_X.


Pozor! Nenφ-li v∞tev ukonΦena p°φkazem break, program zaΦne zpracovßvat dalÜφ v∞tve v po°adφ dokud nenarazφ na break. Proto je t°eba na konci ka₧dΘ v∞tve psßt break. Z tohoto ale vypl²vß, ₧e pokud chceme pro vφce hodnot zpracovat pouze jednu v∞tev, staΦφ vynechat p°φkaz break v t∞chto v∞tvφch.
Nap°φklad:

 switch(vyraz) {
 case hodnota_1:
    prikaz_1;
    break;
 case hodnota_2:// Zde neni break
 case hodnota_3:
    prikaz_23;
    break;
 }

Prikaz_23 se provede, kdy₧ je vyraz roven bu∩ hodnote_2 nebo hodnote_3.

5.5. P°φklad

VÜe si samoz°ejm∞ ukß₧eme na p°φkladu. P°φklad si m∙₧ete stßhnout z CD v sekci Downloads. VÜe, co pot°ebujete v∞d∞t k p°φkladu je v tΘto nebo v minulΘ lekci a popis funkce najdete v komentß°φch.

  #include <stdio.h>

  int main(int argc, char* argv[])
  {
    int iVolba, i;
    char c;
    double f, g;

    do {
      //
      // Informace pro uzivatele
      printf("1) Test smycky for\n");
      printf("2) Test smycky while\n");
      printf("3) Test smycky do-while \n");
      printf("4) Konec programu\n");
      printf("Zadejte co chcete otestovat:");
      //
      // Ulozime uzivatelovu volbu do promenne iVolba jako hodnotu typu int
      scanf("%d", &iVolba);
      //
      // Vetveni programu podle toho, co zvoli uzivatel
      switch(iVolba) {
      case 1:
        //
        // Test cyklu for
        printf("Zvolil jste prikaz for, vypisu 10 cisel a skoncim.\n");
        //
        // Cyklus for od 0 do 9
        for(i = 0; i < 10; i++) {
          printf("%d\n", i);
        }
        //
        // Nakonci jeste odradkujeme
        printf("\n");
        break;
      case 2:
        printf("\nZvolil jste prikaz while.\n");
        printf("Program cte znaky z klavesnice, tisknutelne znaky opisuje,\n");
        printf("neviditelne preskakuje a zastavi se pri precteni znaku 'z'.\n\n");
        //
        // Precteni znaku
        while((c = getchar()) != 'z') {
          if(c >= ' ') { // Vynechavame neviditelne znaky
            putchar(c); // Tisk znaku
            printf("\n"); // Odradkuju
          }
        }
        break;
      case 3:
        printf("Zvolil jste prikaz do-while. \n");
        printf("Program nacte dolni a horni mez intervalu\n");
        printf("a pote vypise vsechny cela cisla z tohoto intervalu.\n");
        //
        // Nacteme dve realna cisla
        printf("Zadejte dolni mez intervalu:");
        scanf("%lf", &f);
        printf("Zadejte horni mez intervalu:");
        scanf("%lf", &g);
        //
        // Test zdali je horni mez skutecne vetsi nez dolni mez
        if(f < g) {
          //
          // Zaokrouhleni realneho cislo na cele cislo (explicitni konverze)
          i = (int) f;
          do {
            // Vypsani celeho cisla
            printf("%d\n", i);
            // Prejdeme na dalsi cele cislo
            i++;
            // A testujeme zdali jsme jiz dosahli horni hranice intervalu
          } while(i <= g);
        }
        else {
          printf("Chyba! Zadali jste chybne meze.\n");
        }

        break;
      case 4:
        //
        // Konec
        printf("Konec...\n");
        break;
      default:
        printf("Zvolil jste kravinu\n");
        break;
      }
    //
    // Testujeme promennou iVolba na hodnotu 4,
    // coz je volba, pri ktere ma program skoncit
    } while(iVolba != 4);

    return 0;
  }


Poznßmka: Op∞t si vÜimn∞te odsazenφ jednotliv²ch v∞tvφ p°φkazu switch a odsazenφ t∞l cykl∙. Toto je velmi dobrΘ d∞lat kv∙li p°ehlednosti v programu.

5.6. Zßv∞r

Na zßv∞r vßm prozradφm, co nßs Φekß p°φÜt∞. P°φÜt∞ probereme preprocesor jazyka a funkce. Mezi p°φkazy preprocesoru pat°φ i nßm znßm² p°φkaz include. Zjistφte, ₧e p°ed ka₧d²m p°φkazem preprocesoru je znak '#'. Dßle si vytvo°φme vlastnφ funkce mimo funkci main(). Tyto funkce pak budeme volat z funkce main().

T∞Üφm se p°φÜt∞ nashledanou.