| ← preprocesor | C/C++ | funkce → |
Konečně se dostáváme k té zábavné části programování. Konstrukce, které si v této kapitole vysvětlíme dělají program programem. Díky nim se může program na základě dat rozhodovat, co bude dělat a tím takříkajíc „ožít“. Cykly nám zase umožní dělat nějaké akce opakovaně a tak výrazně zefektivní práci při programování. V této kapitole naplno využijeme relačních operátorů.
Podmínka if-else je velice podobná podmíněnému operátoru
? : a ještě více
podmíněnému překladu
preprocesoru.
Větvení programu pomocí podmínky if-else je následující:
if (podminka) telo bloku else if (podminka) telo bloku else if (podminka) telo bloku else telo bloku
Podmínky musí být v kulatých závorkách. Tělo bloku může být blok (ve špičatých závorkách), nebo jen jeden příkaz (ukončený středníkem). Podmínek else if může být konečně mnoho a nejsou povinné, stejně jako není povinná podmínka else.
Vyhodnocování podmínek probíhá do té doby, než se některá vyhodnotí jako pravdivá (TRUE). Pak se provedou příkazy v bezprostředně následujícím bloku. Další podmínky se již nevyhodnocují. Pokud se žádná podmínka nevyhodnotí jako TRUE, pak se provede tělo bloku za else (pokud část else existuje). Else se umisťuje vždy na konec. Je to de facto to samé, jako by jste uvedli na konci else if(1)...
V příkladu si ukážeme několikeré využití podmínky if-else. Připomínám, že funkce scanf má jako návratovou hodnotu počet správně načtených položek nebo EOF při pokusu číst ze zavřeného vstupu.
1: /*------------------------------------------------*/ 2: /* ifelse.c */ 3: #include <stdio.h> 5: #define CISLO 5 6: #define MIN 0 7: #define MAX 10 9: int main(void) 10: { 11: int x = -1; 12: int navrat; 13: printf("Na jake cislo myslim? Hadej mezi %2i a %2i: ", MIN, MAX); 15: navrat = scanf("%i", &x); 17: if (navrat == EOF) { 18: printf("\ascanf nemuze cist. Je uzavren standardni vstup stdin\n"); 19: return 1; /* ukoncime funkci main -> konec programu */ 20: } else if (navrat != 1) { /* chceme nacist 1 polozku */ 21: printf("\aNezadal jsi cislo!\n"); 22: return 1; 23: } 25: if (x < MIN) 26: printf("Tak to bylo malo trochu hochu!\n"); 27: else if (x > MAX) 28: printf("Tak to bylo trochu moc!\n"); 29: else if (x == CISLO) 30: printf("UHADNULS :-))\n"); 31: else 32: printf("Smula. Zkus to znovu.\n"); 34: return 0; 35: } 37: /*------------------------------------------------*/
Možný výstup:
Na jake cislo myslim? Hadej mezi 0 a 10: 5 UHADNULS :-))
Zkuste si například zadat místo čísla řetězec nebo uzavřít standardní vstup (CTRL+z v DOSu a CTLR+d v Linuxu).
Přepínač switch obsahuje několik návěstí (case) s celočíselnou hodnotou, nebo rozmezí NIZSI ... VYZSI (např. 1 ... 5 nebo 'a' ... 'e'). Mezi třemi tečkami a hodnotami NIZSI a VYZSI vždy vynechávejte mezery.
Na základě argumentu za klíčovým slovem switch
přeskočí program na návěstí se stejnou hodnotou jakou má výraz v kulatých
závorkách za switch a pokračuje vykonáváním příkazů
za ním.
Přepínač switch může obsahovat návěstí default,
na které program skočí tehdy, když argument za klíčovým slovem
switch
neodpovídá hodnotě za žádným návěstím case.
Default není povinné a může se použít kdekoliv (první před všemi case, mezi nimi i jako poslední).
switch (vyraz)
{
case hodnota:
prikazy
case hodnota:
prikazy
default:
prikazy
}
Příkaz break je speciální příkaz, který způsobí „vyskočení“ z těla příkazu switch (a také cyklů, viz dále). Program pak pokračuje ve vykonávání příkazů za blokem switch.
1: /*------------------------------------------------*/ 2: /* switch.c */ 3: #include <stdio.h> 5: int main(void) 6: { 7: char znak; 9: printf("Opravdu chcete smazat vsechny data na disku? [a/n/k]> "); 10: znak = (char) getchar(); 12: switch (znak) { 13: default: 14: printf("Mel si zmacknout \'a\',\'n\' nebo \'k\' a ne \'%c\'\n", 15: znak); 16: case 'k': 17: return 0; 18: case 'N': 19: printf("Stejne smazu co muzu!\n"); 20: break; 21: case 'n': 22: printf("Nechcete? Smula!\n"); 23: case 'a': 24: case 'A': 25: printf("Data byla smazana !!!\n"); 26: break; 27: } 28: printf("Ne, nebojte, to byl jenom zertik.\n"); 29: return 0; 30: } 32: /*------------------------------------------------*/
Možný výstup:
Opravdu chcete smazat vsechny data na disku? [a/n/k]> n Nechcete? Smula! Data byla smazana !!! Ne, nebojte, to byl jenom zertik.
nebo
Opravdu chcete smazat vsechny data na disku? [a/n/k]> a Data byla smazana !!! Ne, nebojte, to byl jenom zertik.
Všimněte si rozdílu mezi break a
return 0. Příkaz break
skočí za blok příkazu switch,
ale return ukončí funkci main
a tím celý program.
Druhé použití break (na konci
switch) je zbytečné, je tam jen pro ilustraci.
Funkce getchar() z knihovny
<stdio.h> vrací hodnotu datového typu int. Proto ji bylo
nutno přetypovat na typ char.
Tato funkce načte ze standardního vstupu znak a vrátí jej jako svou
návratovou hodnotu, přičemž vrací speciální hodnotu EOF v případě
uzavřeného standardního vstupu.
Tuto možnost v programu
nekontrolujeme, ale vy již jistě víte, jak to (pomocí konstrukce
if-else) udělat.
Tuto a další podobné funkce budeme probírat podrobněji později.
Předem vás upozorňuji, že použití skoku goto může velice znepřehlednit program a jeho čtení se pak může stát hororem. Proto se vyhýbejte tomuto skoku co můžete a raději jej nepoužívejte vůbec. Ostatně, ani to není nutné. Pomocí ostatních rozhodovacích příkazů se tomu lze vždy vyhnout. A teď k příkazu.
Za příkazem goto je název návěští, na které má program skočit. Návěští se v programu určuje jednoduše tak, že se zapíše jeho jméno a za ním dvojtečka. Můžete skákat pouze na návěstí v rámci jedné funkce. A jak by řekl Spok, z logiky věci vyplývá, že nemohou být dvě návěstí stejného jména.
1: /*------------------------------------------------*/ 2: /* goto.c */ 3: #include <stdio.h> 5: int main(void) 6: { 7: char znak; 9: printf("Opravdu chcete smazat vsechny data na disku? [a/n/k]> "); 10: znak = (char) getchar(); 12: if ((znak == 'a') || (znak == 'A')) 13: goto ano; 14: if (znak == 'n') 15: goto ne; 16: if (znak == 'N') 17: goto ne2; 18: if (znak == 'k') 19: goto konec2; 21: printf("Mel si zmacknout \'a\',\'n\' nebo \'k\' a ne \'%c\'\n", znak); 22: konec2: 23: return 0; 25: ne2: 26: printf("Stejne smazu co muzu!\n"); 27: goto konec; 28: ne: 29: printf("Nechcete? Smula!\n"); 31: ano: 32: printf("Data byla smazana !!!\n"); 33: konec: 34: printf("Ne, nebojte, to byl jenom zertik\n"); 35: return 0; 36: } 38: /*------------------------------------------------*/
Pomocí cyklů můžeme vykonávat nějakou činnost opakovaně. Můžeme cyklit buďto jeden příkaz, nebo nějaký blok příkazů. Pokud chceme cyklus z nějakého důvodu ukončit, můžeme v bloku uvést příkaz break. Cyklus se tak ukončí a program pokračuje příkazy za tělem cyklu. Jinou možností je příkaz continue. Tento příkaz přeruší vykonávání dalších příkazů v těle cyklu a program skočí na začátek cyklu. Podívejme se na cyklus for.
for (inicializace; podmínka; výraz)
telo cyklu
Cyklus for provádí příkazy
v těle cyklu tak dlouho, dokud
platí podmínka. Tato podmínka může být jakýkoliv výraz
vracející celočíselnou hodnotu. Může obsahovat konstanty, proměnné,
relační operátory (==,>,|| atp.) a není povinná. V případě, že
žádnou podmínku neuvedete, překladač za ní dosadí číslo
jedna, což bude mít za následek věčné provádění cyklu. Cyklus pak
můžete ukončit jen pomocí break.
Podmínka se vyhodnocuje
před každým začátkem cyklu (i po příkazu
continue). Pokud se hned
na poprvé vyhodnotí jako FALSE, pak tělo cyklu neproběhne ani
jednou.
Část inicializace také není povinná. Může v ní být
libovolný výraz. Tato část proběhne jen jednou (před začátkem
cyklu).
Poslední část v příkazu označená jako výraz se
provádí po každém ukončení cyklu (před vyhodnocením podmínky) a
taktéž není povinný.
Typické použití cyklu for:
1: /*------------------------------------------------*/ 2: /* for.c */ 3: #include <stdio.h> 5: int main(void) 6: { 7: int x; 9: for (x = 1; x < 10; x++) { 10: if ((x % 2) != 0) 11: continue; 12: printf("Sude cislo: %i\n", x); 13: } 14: printf("\nA nebo trochu jinak:\n\n"); 16: x = 1; 17: for (;;) { 18: if (x >= 10) 19: break; 20: if ((x % 2) == 0) 21: printf("Sude cislo: %i\n", x); 22: x++; 23: } 24: return 0; 25: } 27: /*------------------------------------------------*/
Výstup z programu:
Sude cislo: 2 Sude cislo: 4 Sude cislo: 6 Sude cislo: 8 A nebo trochu jinak: Sude cislo: 2 Sude cislo: 4 Sude cislo: 6 Sude cislo: 8
Cyklus for se také často využívá při práci s poli. Například inicializace pole samými nulami (všimněte si indexování pole od 0 do N-1):
#define N 100
int x, pole [N];
for (x = 0; x <= N - 1;x++)
pole[x] = 0;
Cyklus do má tu vlastnost, že
proběhne alespoň jednou. Je
ukončen klíčovým slovem while, za kterým je
podmínka v kulatých závorkách a platí o ní totéž, jako u cyklu
for.
Tato podmínka se vyhodnocuje až po průchodu cyklem.
V cyklu do můžete pro řízení chodu programu
využít příkazů break i
continue. Tělo
cyklu může být jeden příkaz nebo blok (ve špičatých závorkách).
do
telo cyklu
while ( podminka );
Cyklus while je podobný, jen s tím rozdílem, že se podmínka vyhodnocuje před provedením cyklu.
while ( podminka )
telo cyklu
Zda použijete cyklus for, do nebo while záleží jen na vaší fantazii a preferenci.
1: /*------------------------------------------------*/ 2: /* while.c */ 3: #include <stdio.h> 5: int main(void) 6: { 7: int iterace = -1; 8: int navrat; 9: do { 10: printf("Zadejte pocet iteraci <0,10>: "); 11: navrat = scanf("%i", &iterace); 12: if (!navrat) 13: return 1; /* uzivatel nezadal cislo; navrat == 0 */ 14: if (navrat == EOF) { 15: printf("stdin je uzavren.\n"); 16: return 1; 17: } 18: } while ((iterace < 0) || (iterace > 10)); 20: while (iterace) { 21: printf("%i ", iterace--); 22: } 24: printf("\n"); 25: return 0; 26: } 28: /*------------------------------------------------*/
Možný výstup:
Zadejte pocet iteraci <0,10>: -5 Zadejte pocet iteraci <0,10>: 15 Zadejte pocet iteraci <0,10>: 5 5 4 3 2 1
Lomené závorky v cyklu while v příkladu jsou sice nadbytečné, ale zlepšují tak čitelnost kódu a snižuje se riziko chyby při úpravě zdrojového kódu. Častou chybou je totiž přidání příkazu za příkaz u cyklu while (nebo i for) a zapomenutí uzavření těchto příkazů do bloku. Jako v následujícím fragmentu kódu, kde se vytiskne 10x písmeno „X“ a jen jedenkrát „Y“.
for (i = 0; i < 10; i++)
printf("X");
printf("Y");
| ← preprocesor | C/C++ | funkce → |
