Lekce 5 - Podmínky (větvení) v C++
V minulé lekci, Typový systém podruhé - Datové typy v C++, jsme si podrobně probrali datové typy v C++.
Abychom si něco naprogramovali, potřebujeme nějak reagovat na různé situace. Může to být například hodnota zadaná uživatelem, podle které budeme chtít měnit další běh programu. Říkáme, že se program větví a k větvení používáme podmínky. Těm se budeme věnovat celý dnešní C++ tutoriál. Vytvoříme program na výpočet odmocniny a vylepšíme naši kalkulačku.
Podmínky
Podmínky zapisujeme pomocí klíčového slova if
, za kterým
následuje logický výraz. Pokud je výraz pravdivý, provede se následující
příkaz. Pokud ne, následující příkaz se přeskočí a pokračuje se až
pod ním. Vyzkoušejme si to:
{CPP_CONSOLE} if (15 > 5) cout << "Pravda" << endl; cout << "Program zde pokracuje dal" << endl; cin.get(); {/CPP_CONSOLE}
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
Výstup programu:
Konzolová aplikace
Pravda
Program zde pokracuje dal
Pokud podmínka platí (což zde ano), provede se příkaz vypisující do
konzole text "Pravda"
. V obou případech program pokračuje
dál. Součástí výrazu samozřejmě může být i proměnná:
{CPP_CONSOLE} cout << "Zadej nejake cislo" << endl; int a; cin >> a; if (a > 5) cout << "Zadal jsi cislo vetsi nez 5!" << endl; cout << "Dekuji za zadani" << endl; cin.get(); cin.get(); {/CPP_CONSOLE}
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
Ukažme si nyní relační operátory, které můžeme ve výrazech používat:
Operátor | C-like zápis |
---|---|
Rovnost | == |
Je ostře větší | > |
Je ostře menší | < |
Je větší nebo rovno | >= |
Je menší nebo rovno | <= |
Nerovnost | != |
Obecná negace | ! |
Rovnost zapisujeme dvěma ==
proto, aby se to nepletlo s
běžným přiřazením do proměnné, které se dělá jen jedním
=
. Pokud chceme nějaký výraz znegovat (z true
udělat false
a naopak), napíšeme ho do závorky a před něj
vykřičník.
Když budeme chtít při splnění podmínky vykonat více než jen jeden příkaz, musíme příkazy vložit do bloku ze složených závorek:
#include <iostream> #include <cmath> using namespace std; int main() { cout << "Zadej nejake cislo, ze ktereho spocitam odmocninu:" << endl; int a; cin >> a; if (a >= 0) { cout << "Zadal jsi nezaporne cislo, to znamena, ze ho mohu odmocnit!" << endl; double o = sqrt(double(a)); cout << "Odmocnina z cisla " << a << " je " << o << endl; } cout << "Dekuji za zadani" << endl; cin.get(); cin.get(); return 0; }
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
Výsledek:
Konzolová aplikace
Zadej nejake cislo, ze ktereho spocitam odmocninu:
150
Zadal jsi nezaporne cislo, to znamena, ze ho mohu odmocnit!
Odmocnina z cisla 150 je 12.2474
Dekuji za zadani
Program načte od uživatele číslo a pokud je větší než 0
,
vypočítá z něj druhou odmocninu. Mimo jiné jsme použili funkci
sqrt()
, která je spolu s řadou dalších užitečných
matematických funkcí definována v souboru cmath
(Nezapomeňte ji
includovat, pokud chcete funkci používat). sqrt()
vrací hodnotu
jako double
. Protože ale dokáže pracovat s několika datovými
typy, musíme jí říct, kterou verzi chceme použít. Proměnnou
a
tedy přetypujeme na double
. To se dá provést
několika způsoby:
- typ(hodnota)
- (typ)hodnota
- (typ)(hodnota)
Bylo by hezké, kdyby nám program vyhuboval v případě, že zadáme záporné číslo. S dosavadními znalostmi bychom napsali něco jako:
#include <iostream> #include <cmath> using namespace std; int main() { cout << "Zadej nejake cislo, ze ktereho spocitam odmocninu:" << endl; int a; cin >> a; if (a >= 0) { cout << "Zadal jsi nezaporne cislo, to znamena, ze ho mohu odmocnit!" << endl; double o = sqrt(double(a)); cout << "Odmocnina z cisla " << a << " je " << o << endl; } if (a < 0) cout << "Odmocnina ze zaporneho cisla neexistuje!" << endl; cout << "Dekuji za zadani" << endl; cin.get(); cin.get(); return 0; }
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
Kód však můžeme výrazně zjednodušit pomocí klíčového slova
else
, které vykoná následující příkaz nebo blok příkazů
v případě, že se podmínka neprovede:
#include <iostream> #include <cmath> using namespace std; int main() { cout << "Zadej nejake cislo, ze ktereho spocitam odmocninu:" << endl; int a; cin >> a; if (a >= 0) { cout << "Zadal jsi nezaporne cislo, to znamena, ze ho mohu odmocnit!" << endl; double o = sqrt(double(a)); cout << "Odmocnina z cisla " << a << " je " << o << endl; } else cout << "Odmocnina ze zaporneho cisla neexistuje!" << endl; cout << "Dekuji za zadani" << endl; cin.get(); cin.get(); return 0; }
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
Kód je mnohem přehlednější a nemusíme vymýšlet opačnou podmínku,
což by v případě složené podmínky mohlo být někdy i velmi obtížné. V
případě více příkazů by byl za else
opět blok
{ }
.
Klíčové slovo else
se také využívá v případě, kdy
potřebujeme v příkazu manipulovat s proměnnou z podmínky a nemůžeme se na
ni tedy ptát potom znovu. Program si sám pamatuje, že se podmínka nesplnila
a přejde do sekce else
. Ukažme si to na příkladu: Mějme
číslo a
, kde bude hodnota 0
nebo 1
a po
nás se bude chtít, abychom hodnotu prohodili (pokud tam je 0
,
dáme tam 1
, pokud 1
, dáme tam 0
).
Naivně bychom mohli kód napsat takto:
{CPP_CONSOLE} int a = 0; // do a si přiřadíme na začátku 0 if (a == 0) // pokud je a 0, dáme do něj jedničku a = 1; if (a == 1) // pokud je a 1, dáme do něj nulu a = 0; cout << a << endl; cin.get(); {/CPP_CONSOLE}
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
Nefunguje to, že? Pojďme si projet, co bude program dělat. Na začátku
máme v a
nulu, první podmínka se jistě splní a dosadí do
a
jedničku. No ale rázem se splní i ta druhá. Co s tím? Když
podmínky otočíme, budeme mít ten samý problém s jedničkou. Jak z toho
ven? Ano, použijeme else
.
{CPP_CONSOLE} int a = 0; // do a si přiřadíme na začátku 0 if(a == 0) // pokud je a 0, dáme do něj jedničku a = 1; else // pokud je a 1, dáme do něj nulu a = 0; cout << a << endl; cin.get(); {/CPP_CONSOLE}
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
V C++ můžeme celou podmínku nahradit i tímto: a = !a;
, což
nám prohodí nulu a jedničku.
Podmínky je možné skládat a to pomocí dvou základních operátorů:
Operátor | C-like zápis | Význam |
---|---|---|
A zároveň | && | platí obojí |
Nebo | || | platí alespoň jedno |
Uveďme si příklad:
{CPP_CONSOLE} cout << "Zadejte cislo v rozmezi 10-20:" << endl; int a; cin >> a; if ((a >= 10) && (a <= 20)) cout << "Zadal jsi spravne" << endl; else cout << "Zadal jsi spatne" << endl; cin.get(); cin.get(); {/CPP_CONSOLE}
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
S tím si zatím vystačíme, operátory se pomocí závorek samozřejmě dají kombinovat.
{CPP_CONSOLE} cout << "Zadejte cislo v rozmezi 10-20 nebo 30-40:" << endl; int a; cin >> a; if (((a >= 10) && (a <= 20)) || ((a >=30) && (a <= 40))) cout << "Zadal jsi spravne" << endl; else cout << "Zadal jsi spatne" << endl; cin.get(); cin.get(); {/CPP_CONSOLE}
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
switch
Konstrukce switch
je převzatá z jazyka C (jako většina
gramatiky C++). Umožňuje nám zjednodušit (relativně) zápis více podmínek
pod sebou. Vzpomeňme si na naši kalkulačku v prvních lekcích, která
načetla 2 čísla a vypočítala všechny 4 operace. Nyní si ale budeme chtít
zvolit, kterou operaci chceme. Bez switch
bychom napsali kód
podobný tomuto:
{CPP_CONSOLE} cout << "Vitejte v kalkulacce" << endl; cout << "Zadejte prvni cislo:" << endl; float a; cin >> a; cout << "Zadejte druhe cislo:" << endl; float b; cin >> b; cout << "Zvolte si operaci:" << endl; cout << "1 - scitani" << endl; cout << "2 - odcitani" << endl; cout << "3 - nasobeni" << endl; cout << "4 - deleni" << endl; int volba; cin >> volba; float vysledek = 0; if (volba == 1) vysledek = a + b; else if (volba == 2) vysledek = a - b; else if (volba == 3) vysledek = a * b; else if (volba == 4) vysledek = a / b; if ((volba > 0) && (volba < 5)) cout << "Vysledek: " << vysledek << endl; else cout << "Neplatna volba" << endl; cout << "Dekuji za pouziti kalkulacky, aplikaci ukoncite libovolnou klavesou." << endl; cin.get(); cin.get(); {/CPP_CONSOLE}
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
Výsledek:
Konzolová aplikace
Vitejte v kalkulacce
Zadejte prvni cislo:
18
Zadejte druhe cislo:
9
Zvolte si operaci:
1 - scitani
2 - odcitani
3 - nasobeni
4 - deleni
4
Vysledek:2
Dekuji za pouziti kalkulacky, aplikaci ukoncite libovolnou klavesou.
Všimněte si, že jsme proměnnou vysledek
deklarovali na
začátku, jen tak do ni můžeme potom přiřazovat. Kdybychom ji deklarovali u
každého přiřazení, na konci podmínek by už neexistovala (existovala by
jen do skončení bloku příkazů za if
, my máme místo bloku
příkazů jen 1 příkaz, takže by zanikla ihned po jeho provedení). Bohužel
C++ není schopen poznat, zda je do proměnné vysledek
opravdu
přiřazena nějaká hodnota. Z tohoto důvodu na začátku dosadíme do
vysledek
nulu.
Další vychytávka je kontrola správnosti volby. Program by v tomto
případě fungoval stejně i bez těch else
, ale nač se dále
ptát, když již máme výsledek.
Nyní si zkusíme napsat ten samý kód pomocí switch
. Navíc k
němu ale přidáme užitečný řádek kódu. Není zrovna hezké vypisovat jen
znaky bez diakritiky. Proto zapneme podporu českých znaků. To dělá funkce
setlocale()
ze knihovny clocale
.
{CPP_CONSOLE} cout << "Vitejte v kalkulacce" << endl; cout << "Zadejte prvni cislo:" << endl; float a; cin >> a; cout << "Zadejte druhe cislo:" << endl; float b; cin >> b; cout << "Zvolte si operaci:" << endl; cout << "1 - scitani" << endl; cout << "2 - odcitani" << endl; cout << "3 - nasobeni" << endl; cout << "4 - deleni" << endl; int volba; cin >> volba; float vysledek = 0.0f; switch(volba) { case 1: vysledek = a + b; break; case 2: vysledek = a - b; break; case 3: vysledek = a * b; break; case 4: vysledek = a / b; break; } if ((volba > 0) && (volba < 5)) cout << "Vysledek:" << vysledek << endl; else cout << "Neplatna volba" << endl; cout << "Dekuji za pouziti kalkulacky, aplikaci ukoncite libovolnou klavesou." << endl; cin.get();cin.get(); {/CPP_CONSOLE}
Zkontroluj, zda výstupy programu odpovídají předloze. S jinými texty testy neprojdou.
Vidíme, že kód je trochu přehlednější. Pokud bychom potřebovali v
nějaké větvi switch
spustit více příkazů, překvapivě je
nebudeme psát do bloku, ale rovnou pod sebe. Blok {}
nám zde
nahrazuje příkaz break
, který způsobí vyskočení z celého
switch
. Blok switch
může místo case x:
obsahovat ještě možnost default:
, která se vykoná v
případě, že nebude platit žádný case
. Je jen na vás, jestli
budete switch
používat, obecně se vyplatí jen při větším
množství příkazů a vždy jde nahradit sekvencí if
a
else
. Nezapomínejte na příkazy break
, pokud jej
neuvedete, program propadne do další větve a to i když by nebyla splněná
podmínka! V minulosti se takovéto propadávání využívalo schválně,
dnešní IDE před tímto použitím ale spíše již varují.
To bychom měli.
V následujícím cvičení, Řešené úlohy ke 4.-5. lekci C++, si procvičíme nabyté zkušenosti z předchozích lekcí.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 333x (8.14 kB)
Aplikace je včetně zdrojových kódů v jazyce C++