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

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

V minulém tutoriálu o programování v céčku jsme si podrobně probrali datové typy. 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í dí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:

if(5 < 15)
    printf("Pravda \n");
printf("Program zde pokracuje dal \n");

Výstup programu:

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

int a;
printf("Zadej nejake cislo \n");
scanf("%d", &a);
if(a > 5)
    printf("Zadal jsi cislo vetsi nez 5! \n");
printf("Dekuji za zadani \n");

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, napíšeme ho do závorky a před něj vykřičník. Když budeme chtít vykonat více než jen jeden příkaz, musíme příkazy vložit do bloku ze složených závorek:

#include <stdio.h>
#include <stdlib.h>
#include <math.h> // Nesmíme zapomenout na include hlavičky math.h, obsahuje funkci pro odmocninu
int main(int argc, char** argv) {
    int a;
    printf("Zadej nejake cislo ze ktereho spocitam odmocninu:  \n");
    scanf("%d", &a);
    if(a > 0)
    {
        printf("Zadal jsi cislo vetsi nez 0, to znamena, ze ho muzu odmocnit!");
        double o = sqrt(a);
        printf("Odmocnina z cisla %d je %f \n", a, o);
    }
    printf("Dekuji za zadani \n");

    return (EXIT_SUCCESS);
}
Výpočet druhé odmocniny v céčku

Často můžete vidět použití bloku i v případě, že je pod podmínkou jen jeden příkaz, mnohdy je to totiž přehlednější.

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 z knihovny math.h, která v sobě obsahuje řadu užitečných matematických funkcí, někdy si ji blíže představíme. sqrt() vrací hodnotu druhé odmocniny jako double. 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 <stdio.h>
#include <stdlib.h>
#include <math.h> // Nesmíme zapomenout na include hlavičky math.h, obsahuje funkci pro odmocninu
int main(int argc, char** argv) {

    int a;
    printf("Zadej nejake cislo ze ktereho spocitam odmocninu:  \n");
    scanf("%d", &a);
    if(a > 0)
    {
        printf("Zadal jsi cislo vetsi nez 0, to znamena, ze ho muzu odmocnit!");
        double o = sqrt(a);
        printf("Odmocnina z cisla %d je %f \n", a, o);
    }
    if(a <= 0)
        printf("Odmocnina ze zaporneho cisla neexistuje");

    printf("Dekuji za zadani \n");
    return (EXIT_SUCCESS);
}

Všimněte si, že musíme pokrýt i případ, kdy se a == 0, nejen když je menší. 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 <stdio.h>
#include <stdlib.h>
#include <math.h> // Nesmíme zapomenout na include hlavičky math.h, obsahuje funkci pro odmocninu
int main(int argc, char** argv) {

    int a;
    printf("Zadej nejake cislo ze ktereho spocitam odmocninu:  \n");
    scanf("%d", &a);
    if(a > 0)
    {
        printf("Zadal jsi cislo vetsi nez 0, to znamena, ze ho muzu odmocnit!");
        double o = sqrt(a);
        printf("Odmocnina z cisla %d je %f \n", a, o);
    }
    else
        printf("Odmocnina ze zaporneho cisla neexistuje");

    printf("Dekuji za zadani \n");
    return (EXIT_SUCCESS);
}

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

    printf("%d", a);

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;

printf("%d", a);

Podmínky je možné skládat a to pomocí dvou základních operátorů:

Operátor C-Like zápis
A zároveň &&
Nebo ||

Uveďme jsi příklad:

int a;
printf("Zadej cislo v rozmezi 10-20 \n");
scanf("%d", &a);
if ((a >= 10) && (a <= 20))
    printf("Zadal jsi spravne \n");
else
    printf("Zadal jsi spatne \n");

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

int a;
printf("Zadej cislo v rozmezi 10-20 nebo 30-40 \n");
scanf("%d", &a);
if (((a >= 10) && (a <= 20)) || ((a >=30) && (a <= 40)))
    printf("Zadal jsi spravne \n");
else
    printf("Zadal jsi spatne \n");

Switch

Zápis více podmínek pod sebou (relativně) zjednodušuje konstrukce switch. 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:

double a;
double b;
int volba; // Mohli bychom použít char abychom zbytečně nepoužívali moc místa
double vysledek;
printf("Vitejte v kalkulacce \n");
printf("Zadejte prvni cislo: \n");
scanf("%lf", &a);
printf("Zadejte druhe cislo: \n");
scanf("%lf", &b);
printf("Zvolte si operaci: \n");
printf("1 - scitáni \n");
printf("2 - odcitani \n");
printf("3 - nasobeni \n");
printf("4 - deleni \n");
scanf("%d", &volba);
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))
    printf("Vysledek: %lf", vysledek);
else
    printf("Neplatná volba \n");
    printf("\n");
    printf("Dekuji za pouziti kalkulacky");
Kalkulačka s podmínkami v jazyce C

Všimněte si, že jsme proměnnou výsledek deklarovali na začátku, jen tak do ni můžeme potom přiřazovat. Kdybychom ji deklarovali u každého přiřazení, Céčko by kód nezkompilovalo a vyhodilo by chybu. Proměnná může být deklarována (založena v paměti) vždy jen jednou. Další vychytávka je kontrola správnosti volby. Program by v tomto případě fungoval stejně i bez 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:

double a;
double b;
int volba; // Mohli bychom použít char abychom zbytečně nepoužívali moc místa
double vysledek;
printf("Vitejte v kalkulacce \n");
printf("Zadejte prvni cislo: \n");
scanf("%lf", &a);
printf("Zadejte druhe cislo: \n");
scanf("%lf", &b);
printf("Zvolte si operaci: \n");
printf("1 - scitani \n");
printf("2 - odcitani \n");
printf("3 - nasobeni \n");
printf("4 - deleni \n");
scanf("%d", &volba);
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))
    printf("Vysledek: %f", vysledek);
else
    printf("Neplatná volba \n");
printf("\n");
printf("Dekuji za pouziti kalkulacky");

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. Kdybyste s tím měli problémy, použijte sekvenci if - else.

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 181x (32.31 kB)
Aplikace je včetně zdrojových kódů v jazyce c

 

  Aktivity (3)

Článek pro vás napsal Monarezio
Avatar
Autor se věnuje Javě, PHP, C, HTML ale furt se tyto jazyky učí. Zajímá ho spíše game design a píše svůj vlastní 2d engine v JavěFX.

Jak se ti líbí článek?
Celkem (5 hlasů) :
55555


 



 

 

Komentáře

Avatar
Daniel Vítek
Tým ITnetwork
Avatar
Daniel Vítek:

Jak jde udělat větvení pomocí switche s textovými příkazy ?

 
Odpovědět 15.9.2014 11:20
Avatar
xxxvodnikxxx
Člen
Avatar
Odpovídá na Daniel Vítek
xxxvodnikxxx:

Myslim, že céčko Stringy v case nepodporuje, ale je možný to řešit např. takhle http://stackoverflow.com/…with-strings

btw Monarezio - To okno výstupu je z netbeans?
Je možný v nich nějak pod win zprovoznit kompilátor a programovat Céčko ? dík..
Objevil jsem Cintr https://edux.fit.cvut.cz/…tbeans/CIntr
ale nějak mi nešel zprovoznit

Odpovědět  -1 15.9.2014 22:22
Unix- svět, kde chcete být nulou :) (UID)
Avatar
Monarezio
Redaktor
Avatar
Odpovídá na Daniel Vítek
Monarezio:

String (textový řetězec) Céčko nepodporuje ale je v céčku něco jako by String ale tím se chci zabývat později :). potřebuješ na to znát pole.

Odpovědět 16.9.2014 17:44
First, solve the problem. Then, write the code.
Avatar
Monarezio
Redaktor
Avatar
Odpovídá na xxxvodnikxxx
Monarezio:

Pořádně jsem nepochopil co potřebuješ? Myslíš nainstalovat kompilátor do netbeanu? Pokud ano tak to máš v prvním tutoriálu ( http://www.itnetwork.cz/…-kompilatoru ) :)

Odpovědět  +2 16.9.2014 17:45
First, solve the problem. Then, write the code.
Avatar
Johny Petka
Člen
Avatar
Johny Petka:

Ahoj, prosím o pomoc, mám problém s funkcí sqrt() v jazyce C. Pouzivam
NetBeans IDE 8.1 a Debian.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

/*
*
*/
int main(int argc, char** argv) {
int a;
double o = sqrt (a);

printf("Zadej cislo, ktere muzu odmocnit : \n");
scanf("%d", &a);
if (a>=0)
printf("Odmocnia cisla %d je %f",a,o);
return (EXIT_SUCCESS);

výstup:

cd '/home/chlup/Net­BeansProjects/tet­s'
/usr/bin/make -f Makefile CONF=Debug
"/usr/bin/make" -f nbproject/Makefile-Debug.mk QMAKE= SUBPROJECTS= .build-conf
make[1]: Vstupuje se do adresáře „/home/chlup/Net­BeansProjects/tes­t“
"/usr/bin/make" -f nbproject/Makefile-Debug.mk dist/Debug/GNU-Linux/test
make[2]: Vstupuje se do adresáře „/home/chlup/Net­BeansProjects/tes­t“
mkdir -p dist/Debug/GNU-Linux
gcc -o dist/Debug/GNU-Linux/tets build/Debug/GNU-Linux/main.o
build/Debug/GNU-Linux/main.o: In function `main':
/home/chlup/Net­BeansProjects/tet­s/main.c:28: undefined reference to `sqrt'
collect2: error: ld returned 1 exit status
nbproject/Makefile-Debug.mk:62: návod pro cíl „dist/Debug/GNU-Linux/test“ selhal
make[2]: *** [dist/Debug/GNU-Linux/tets] Chyba 1
make[2]: Opouští se adresář „/home/chlup/Net­BeansProjects/tes­t“
nbproject/Makefile-Debug.mk:59: návod pro cíl „.build-conf“ selhal
make[1]: *** [.build-conf] Chyba 2
make[1]: Opouští se adresář „/home/chlup/Net­BeansProjects/tet­s“
nbproject/Makefile-impl.mk:39: návod pro cíl „.build-impl“ selhal
make: *** [.build-impl] Chyba 2

googlil jsem, na par forech jsem nasel, ze muze byt problem s libm.so, jenze
mi nejak uniklo, co s tim libm.so delat, jsem zacatecnik. Dekuji za Vas cas :)

 
Odpovědět 18. dubna 20:19
Avatar
Libor Šimo (libcosenior):

Po 1. nemáš uzavretý blok main()
po 2.
int a;
double o = sqrt (a);
je blbosť, pretože a nemáš definované.

Skús to takto:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

/*
*
*/
int main(int argc, char** argv)
{
    int a;
    //double o = sqrt (a);

    printf("Zadej cislo, ktere muzu odmocnit : \n");
    scanf("%d", &a);
    if (a>=0)
    printf("Odmocnia cisla %d je %f",a , sqrt(a));
    return (EXIT_SUCCESS);
}
Odpovědět 19. dubna 6:04
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Johny Petka
Člen
Avatar
Odpovídá na Libor Šimo (libcosenior)
Johny Petka:

Díky moc za reakci :) a omlouvám se, tělo jsem uzavřené měl, neokopíroval jsem složenou závorku. Vyzkušel jsem Tvůj prográmek a přesto mi výstup hází toto :

cd '/home/chlup/Net­BeansProjects/tet­s'
/usr/bin/make -f Makefile CONF=Debug
"/usr/bin/make" -f nbproject/Makefile-Debug.mk QMAKE= SUBPROJECTS= .build-conf
make[1]: Vstupuje se do adresáře „/home/chlup/Net­BeansProjects/tet­s“
"/usr/bin/make" -f nbproject/Makefile-Debug.mk dist/Debug/GNU-Linux/tets
make[2]: Vstupuje se do adresáře „/home/chlup/Net­BeansProjects/tet­s“
mkdir -p build/Debug/GNU-Linux
rm -f "build/Debug/GNU-Linux/main.o.d"
gcc -c -g -MMD -MP -MF "build/Debug/GNU-Linux/main.o.d" -o build/Debug/GNU-Linux/main.o main.c
mkdir -p dist/Debug/GNU-Linux
gcc -o dist/Debug/GNU-Linux/tets build/Debug/GNU-Linux/main.o
build/Debug/GNU-Linux/main.o: In function `main':
/home/hydra/Net­BeansProjects/tet­s/main.c:29: undefined reference to `sqrt'
collect2: error: ld returned 1 exit status
nbproject/Makefile-Debug.mk:62: návod pro cíl „dist/Debug/GNU-Linux/tets“ selhal
make[2]: *** [dist/Debug/GNU-Linux/tets] Chyba 1
make[2]: Opouští se adresář „/home/chlup/Net­BeansProjects/tet­s“
nbproject/Makefile-Debug.mk:59: návod pro cíl „.build-conf“ selhal
make[1]: *** [.build-conf] Chyba 2
make[1]: Opouští se adresář „/home/chlup/Net­BeansProjects/tet­s“
nbproject/Makefile-impl.mk:39: návod pro cíl „.build-impl“ selhal
make: *** [.build-impl] Chyba 2

BUILD FAILED (exit value 2, total time: 118ms)

 
Odpovědět 19. dubna 18:33
Avatar
Odpovídá na Johny Petka
Libor Šimo (libcosenior):

Vykasli sa .na netbeans a nainštaluj si code::blocks.
Pozri sem:h
ttp://www.itnet­work.cz/cplus­plus/cecko-linux/tutorial-c-linux-codeblocks

Editováno 19. dubna 18:37
Odpovědět 19. dubna 18:36
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Johny Petka
Člen
Avatar
 
Odpovědět 19. dubna 19:46
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Monarezio
DarkCoder:

Obecná negace ! není relační operátor ale logický. Operátory && a || jsou rovněž logické, pojem základní nikomu nic neřekne.

Používáme-li funkci, kontroluji nejen její návratový typ ale i typy parametrů které přebírá. Funkce sqrt() opravdu nepřebírá typ i. Argumentem funkce je typ double. Takže buď proměnná a bude typu double nebo je třeba argument přetypovat na double.

double o = sqrt((double)a);

Výraz

(a == 0) je lepší psát jako (!a)  a  (a == 1) je lepší psát jako (a)
printf("Vysledek: %lf", vysledek);

pro typ double se používá %f

else
    printf("Neplatná volba \n");
    printf("\n");
    printf("Dekuji za pouziti kalkulacky");

Pokud není použit blok, je dobré dodržovat odsazování. Odsazení v tomto případě může vést čtenáře k domněnce, že všechny příkazy za else patří k sobě.

scanf("%d", &volba);
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))
    printf("Vysledek: %f", vysledek);
else
    printf("Neplatná volba \n");

Kód lze zapsat lépe:

scanf("%d", &volba);
switch(volba)
{
    case 1:
        printf("Vysledek: %f\n", a+b);
        break;
    case 2:
        printf("Vysledek: %f\n", a-b);
        break;
    case 3:
        printf("Vysledek: %f\n", a*b);
        break;
    case 4:
        printf("Vysledek: %f\n", a/b);
        break;
    default: printf("Neplatná volba \n");
}

Není třeba používat proměnnou výsledek, vyhodnocení výrazu lze předat jako argument funkci printf().
Navíc odpadá zbytečné porovnávání na neplatnou volbu.

 
Odpovědět 6. října 1:23
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 10.