5. díl - Podmínky (větvení) v C++

C a C++ C++ Základní konstrukce C++ Podmínky (větvení) v C++

Unicorn College ONEbit hosting Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulém dílu 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 celou dnešní lekci. 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:

if (15 > 5)
        cout << "Pravda" << endl;
cout << "Program zde pokracuje dal" << endl;
cin.get();

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á:

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();

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;
}

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

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:

  1. typ(hodnota)
  2. (typ)hodnota
  3. (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:

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 zaporného cisla neexistuje!" << endl;
cout << "Dekuji za zadani" << endl;
cin.get(); cin.get();

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:

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();

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 { }.

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:

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();

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.

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();

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:

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();

S tím si zatím vystačíme, operátory se pomocí závorek samozřejmě dají kombinovat.

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();

Switch

Switch je konstrukce 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 switche bychom napsali kód podobný tomuto:

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();

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í switche. 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.

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();

Vidíme, že kód je trochu přehlednější. Pokud bychom potřebovali v nějaké větvi switche 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 switche. 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 breaky, 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, příště nás čekají pole a cykly, tím dovršíme základní znalosti, máte se na co těšit :)


 

Stáhnout

Staženo 220x (8.14 kB)
Aplikace je včetně zdrojových kódů v jazyce C++

 

 

Článek pro vás napsal Zdeněk Pavlátka
Avatar
Jak se ti líbí článek?
7 hlasů
Autor se věnuje spoustě zajímavých věcí :)
Miniatura
Všechny články v sekci
Základní konstrukce jazyka C++
Miniatura
Následující článek
Cvičení ke 4.-5. lekci C++
Aktivity (12)

 

 

Komentáře
Zobrazit starší komentáře (1)

Avatar
Libor Šimo (libcosenior):20.5.2014 5:27

Neincludoval si knižnicu conio.h.

Editováno 20.5.2014 5:29
Odpovědět  +1 20.5.2014 5:27
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
-snaživec-
Člen
Avatar
Odpovídá na Libor Šimo (libcosenior)
-snaživec-:20.5.2014 15:47

Ked som to spravil tak mi v tej kniznici pri kompilácií vyhodilo tieto errory:

  === Build: Debug in MultiProg (compiler: GNU GCC Compiler) ===

obj/Debug/main­.o||In function `inicjuj()':|
/usr/include/c++/4­.8/backward/co­nio.h|123|unde­fined reference to `initscr'|
/usr/include/c++/4­.8/backward/co­nio.h|124|unde­fined reference to `start_color'|
/usr/include/c++/4­.8/backward/co­nio.h|125|unde­fined reference to `cbreak'|
/usr/include/c++/4­.8/backward/co­nio.h|126|unde­fined reference to `noecho'|
/usr/include/c++/4­.8/backward/co­nio.h|128|unde­fined reference to `stdscr'|
/usr/include/c++/4­.8/backward/co­nio.h|128|unde­fined reference to `keypad'|
/usr/include/c++/4­.8/backward/co­nio.h|129|unde­fined reference to `stdscr'|
/usr/include/c++/4­.8/backward/co­nio.h|129|unde­fined reference to `scrollok'|
/usr/include/c++/4­.8/backward/co­nio.h|132|unde­fined reference to `stdscr'|
/usr/include/c++/4­.8/backward/co­nio.h|141|unde­fined reference to `init_pair'|
/usr/include/c++/4­.8/backward/co­nio.h|150|unde­fined reference to `wrefresh'|
obj/Debug/main­.o||In function `cputs(char*)':|
/usr/include/c++/4­.8/backward/co­nio.h|162|unde­fined reference to `waddnstr'|
/usr/include/c++/4­.8/backward/co­nio.h|163|unde­fined reference to `wrefresh'|
obj/Debug/main­.o||In function `cgets(char*)':|
/usr/include/c++/4­.8/backward/co­nio.h|177|unde­fined reference to `echo'|
/usr/include/c++/4­.8/backward/co­nio.h|179|unde­fined reference to `wgetnstr'|
/usr/include/c++/4­.8/backward/co­nio.h|185|unde­fined reference to `noecho'|
obj/Debug/main­.o||In function `clreol()':|
/usr/include/c++/4­.8/backward/co­nio.h|194|unde­fined reference to `wclrtoeol'|
/usr/include/c++/4­.8/backward/co­nio.h|195|unde­fined reference to `wrefresh'|
obj/Debug/main­.o||In function `clrscr()':|
/usr/include/c++/4­.8/backward/co­nio.h|201|unde­fined reference to `wbkgd'|
/usr/include/c++/4­.8/backward/co­nio.h|203|unde­fined reference to `wclear'|
obj/Debug/main­.o||In function `cprintf(char*, ...)':|
/usr/include/c++/4­.8/backward/co­nio.h|214|unde­fined reference to `vwprintw'|
/usr/include/c++/4­.8/backward/co­nio.h|218|unde­fined reference to `wrefresh'|
obj/Debug/main­.o||In function `cscanf(char*, ...)':|
/usr/include/c++/4­.8/backward/co­nio.h|227|unde­fined reference to `echo'|
/usr/include/c++/4­.8/backward/co­nio.h|232|unde­fined reference to `vwscanw'|
/usr/include/c++/4­.8/backward/co­nio.h|236|unde­fined reference to `wrefresh'|
/usr/include/c++/4­.8/backward/co­nio.h|237|unde­fined reference to `noecho'|
obj/Debug/main­.o||In function `CURSgetch()':|
/usr/include/c++/4­.8/backward/co­nio.h|257|unde­fined reference to `wgetch'|
obj/Debug/main­.o||In function `CURSgetche()':|
/usr/include/c++/4­.8/backward/co­nio.h|270|unde­fined reference to `echo'|
/usr/include/c++/4­.8/backward/co­nio.h|272|unde­fined reference to `noecho'|
obj/Debug/main­.o||In function `gotoxy(int, int)':|
/usr/include/c++/4­.8/backward/co­nio.h|279|unde­fined reference to `wmove'|
obj/Debug/main­.o||In function `kbhit()':|
/usr/include/c++/4­.8/backward/co­nio.h|286|unde­fined reference to `wtimeout'|
/usr/include/c++/4­.8/backward/co­nio.h|287|unde­fined reference to `wgetch'|
/usr/include/c++/4­.8/backward/co­nio.h|289|unde­fined reference to `nodelay'|
/usr/include/c++/4­.8/backward/co­nio.h|291|unde­fined reference to `ungetch'|
obj/Debug/main­.o||In function `putch(int)':|
/usr/include/c++/4­.8/backward/co­nio.h|297|unde­fined reference to `wechochar'|
obj/Debug/main­.o||In function `textbackgrou­nd(short)':|
/usr/include/c++/4­.8/backward/co­nio.h|312|unde­fined reference to `wbkgd'|
/usr/include/c++/4­.8/backward/co­nio.h|317|unde­fined reference to `wrefresh'|
obj/Debug/main­.o||In function `textcolor(shor­t)':|
/usr/include/c++/4­.8/backward/co­nio.h|333|unde­fined reference to `wcolor_set'|
/usr/include/c++/4­.8/backward/co­nio.h|338|unde­fined reference to `wrefresh'|
obj/Debug/main­.o||In function `window(int, int, int, int)':|
/usr/include/c++/4­.8/backward/co­nio.h|359|unde­fined reference to `COLS'|
/usr/include/c++/4­.8/backward/co­nio.h|359|unde­fined reference to `LINES'|
/usr/include/c++/4­.8/backward/co­nio.h|361|unde­fined reference to `COLS'|
/usr/include/c++/4­.8/backward/co­nio.h|362|unde­fined reference to `LINES'|
/usr/include/c++/4­.8/backward/co­nio.h|395|unde­fined reference to `newwin'|
/usr/include/c++/4­.8/backward/co­nio.h|405|unde­fined reference to `wcolor_set'|
/usr/include/c++/4­.8/backward/co­nio.h|406|unde­fined reference to `wbkgd'|
/usr/include/c++/4­.8/backward/co­nio.h|409|unde­fined reference to `cbreak'|
/usr/include/c++/4­.8/backward/co­nio.h|410|unde­fined reference to `noecho'|
/usr/include/c++/4­.8/backward/co­nio.h|411|unde­fined reference to `keypad'|
/usr/include/c++/4­.8/backward/co­nio.h|412|unde­fined reference to `scrollok'|

  More errors follow but not being shown.
  Edit the max errors limit in compiler options...
  === Build failed: 50 error(s), 0 warning(s) (0 minute(s), 1 second(s)) ===
Odpovědět 20.5.2014 15:47
Pomali ďalej zájdeš.
Avatar
Libor Šimo (libcosenior):20.5.2014 15:50

Neviem v čom to píšeš, ale podľa výpisu nie je tá knižnica k dispozícii.

Odpovědět 20.5.2014 15:50
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
-snaživec-
Člen
Avatar
-snaživec-:20.5.2014 16:08

pisem to v Code::Bloks na Xubuntu

Odpovědět 20.5.2014 16:08
Pomali ďalej zájdeš.
Avatar
Odpovídá na -snaživec-
Libor Šimo (libcosenior):20.5.2014 17:42

Tak sa pozri či máš v priečinku /usr/include/c++/4­.8/backward súbor conio.h.

Odpovědět 20.5.2014 17:42
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
-snaživec-
Člen
Avatar
Odpovědět 20.5.2014 19:38
Pomali ďalej zájdeš.
Avatar
Odpovídá na -snaživec-
Libor Šimo (libcosenior):21.5.2014 4:47

Tak potom ti asi chýba konio.c.

Pozri, keď používaš OS linux, mal by si byť schopný riešiť takýto problém. Ja to neriešim, pretože sa bavím programovaním v čistom céčku, nie c++.
Proste ak ti niečo nefunguje, najdi riešenie cez strýčka google konkrétne na tvoje podmienky.

Editováno 21.5.2014 4:52
Odpovědět 21.5.2014 4:47
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Libor Šimo (libcosenior):21.5.2014 9:46

Sorry, conio.c.

Odpovědět 21.5.2014 9:46
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovídá na -snaživec-
Libor Šimo (libcosenior):21.5.2014 12:37

Keďže som si uvedomil, že funkcia getch fungujúca vo win, nefunguje v linuxe, pozrel som sa na to cez google a tu je jeden z výsledkov:
http://stackoverflow.com/…o-h-on-linux

Odpovědět 21.5.2014 12:37
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovídá na -snaživec-
Jirka Vavřík:5.7.2014 20:21

na linuxu conio.h nefunguje a proto musíš použít:

std::cin.get();

někdy to akorát musíš dát 2x po sobě aby to fungovalo ;)
funkce akorát nečeká na stisk libovolné klávesy, ale na stisk ENTERu

Odpovědět 5.7.2014 20:21
Inteligentní nemá čas si pamatovat, inteligentní musí vymýšlet.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 11. Zobrazit vše