Image
9.6.2016 0 Comments

C++ / Príkazy / 7. časť

Späť na úvod >> Späť na programovanie >> Späť na seriál

Náš seriál má za sebou prvých šesť častí, teda prvého pol roka. Doposiaľ sme si povedali o tom, z akých stavebných jednotiek sa program v C++ skladá, aká je jeho základná štruktúra, opísali sme si typy údajov, s ktorými môžeme pracovať, a naposledy aj operácie, ktoré nad týmito údajmi môžeme vykonávať. Na to, aby sme mohli začať písať trochu zmysluplnejšie programy ako tých pár jednoduchých účelových príkladov, na ktorých sme si ukázali to, čo sme prebrali, nám chýba ešte niečo. To niečo, ako ostatne vyplýva z názvu dnešnej časti, sú príkazy jazyka C++.

Ako sme si povedali v jednej z predchádzajúcich častí, program je postupnosť lexikálnych jednotiek. Takto podaná definícia sa bude veľmi páčiť kompilátoru, programátor má však na svoj výtvor trochu iný pohľad. Dá sa povedať, že program je postupnosť príkazov. Do určitej miery je to pravda, ale o niečo presnejšia definícia hovorí, že program v C++ je postupnosťou deklarácií. Ak tomu zatiaľ veľmi nerozumiete, nič si z toho nerobte, časom sa vám to vyjasní. Na upokojenie si môžeme povedať, že v rámci jednej funkcie je program naozaj tvorený postupnosťou príkazov.

Príkaz je teda určitý spôsob, ktorým hovoríme počítaču, čo od neho chceme. V C++ existuje viacero druhov príkazov, napočudovanie ich však zase nie je až tak veľa, čo hádam poteší tých, ktorí po prečítaní predošlej časti nadobudli predstavu, že C++ obsahuje obrovské množstvo ťažko zapamätateľných operátorov a len zanietený nadšenec je schopný naučiť sa ich všetky s úspechom používať. Ak náhodou patríte medzi nich, povzbudím vás správou – usmievajte sa, operátorov v C++ je ešte viac…

Takže príkazy v C++ môžeme rozdeliť takto: výrazový príkaz, deklaračný príkaz, zložený príkaz, príkazy výberu, príkazy cyklu a skokové príkazy. Postupne si ich opíšeme v nasledujúcich odsekoch.

Výrazový príkaz

S týmto príkazom ste sa už veľakrát stretli, aj keď o tom možno vôbec neviete. Jeho syntax je veľmi jednoduchá, je tvorený ľubovoľným výrazom, za ktorým nasleduje bodkočiarka ;. Mimochodom, v C++ takmer každý príkaz treba ukončiť bodkočiarkou, inak bude kompilátor dôrazne protestovať. Dôsledkom vykonania výrazového príkazu je vyhodnotenie daného výrazu. Je pochopiteľné, že zmysel majú iba také výrazy, ktoré majú nejaký účinok na stav programu, teda priraďovacie výrazy, ako aj všetky výrazy s vedľajším účinkom (spomeňme si napr. operátory inkrementácie/dekrementácie, ++ a ––) a ďalej volania funkcií. Podľa môjho skromného odhadu je väčšina príkazov v programe práve výrazových. Myslím, že pre tento druh príkazu netreba uvádzať nijaký príklad, stačí sa pozrieť na všetky doterajšie programy a „programčeky“, ktoré realizovali nejaký výpočet.

Je samozrejme možné vo výrazovom príkaze použiť výraz, ktorý nijako neovplyvní stav programu (= stav premenných programu), napr. 5 + 9;, ale takýto príkaz teoreticky nemá zmysel  (a šikovný prekladač ho v rámci optimalizácie vôbec nepreloží). Prakticky sa však používa (teda aspoň ja ho tak používam) v prípade, že deklarujete nejakú premennú, ktorej trebárs aj priradíte nejakú hodnotu, ale ďalej túto premennú v kóde nikde nepoužijete. Takáto situácia je úplne bežná počas vývoja programu, keď tá časť kódu, ktorá bude pracovať s danou premennou, ešte nie je napísaná. Prekladač v rámci zbežnej kontroly toho, čo prekladá (samozrejme, podľa nastavenia), vydá varovanie, že tá a tá premenná bola deklarovaná, ale nikde sa nepoužíva. Je to od neho isto milé, ale keď dookola prekladáte nejaký kus kódu a on vám dookola hlási to isté, po chvíli vás to prestane baviť. Toto konkrétne varovanie možno potlačiť – buď niekde v nastaveniach prekladaného projektu, alebo priamo v kóde - obyčajne pomocou krkolomného zápisu zhruba v tvare #pragma warn –aus, ale pri prvom spôsobe riskujete, že neskôr zabudnete nastavenie prepnúť späť (a je vhodné mať pri ladení programu zapnutých čo najviac varovaní – nikto nie je dokonalý a občas sa vám veru stane, že prehliadnete aj úplne drobnú a očividnú, ale z hľadiska správneho behu programu obyčajne tú najkritickejšiu chybu). A druhý spôsob, no uznajte sami, kto by si to pamätal! Pritom stačí použiť inkriminovanú premennú v nejakom triviálnom výraze bez vedľajších účinkov, teda napr. a;, a prekladač bude spokojný. Treba mať však vypnutú optimalizáciu (čo sa ináč pri ladení odporúča).

Zvláštnym typom výrazového príkazu je prázdny príkaz. Tento príkaz vznikne vtedy, ak z výrazového príkazu ten výraz jednoducho vynecháme. Zostane, pravda, tá bodkočiarka na konci. Prázdny príkaz sa používa v určitých situáciách, o ktorých si povieme o chvíľu. V podstate môže byť celá funkcia tvorená prázdnymi príkazmi, teda napr.

 

void dummy()

{

    ;

    ;

    ;

}

 

ale uznajte sami, veľké použitie by asi nemala (ak potrebujeme naozaj prázdnu funkciu – v niektorých prípadoch sa pre takúto funkciu používa názov stub, stačí ju zapísať takto: void dummy(){}).

Deklaračný príkaz

Ani deklaračný príkaz vám nie je úplne neznámy. Tento príkaz je podobný výrazovému príkazu, len namiesto výrazu obsahuje deklaráciu. Deklarácie, to je tá hmlistá oblasť, ktorej sa stále dotýkam len tak okrajovo, lebo ide o mimoriadne zamotanú tému a budeme sa jej venovať v samostatnej časti seriálu. Takže zatiaľ berte deklaračný príkaz ako príkaz, pomocou ktorého zavádzame do programu nový identifikátor (teda napr. novú premennú, ale môže to byť aj nová funkcia alebo konštanta, dokonca ani nemusí byť úplne nová, deklarovať treba aj niektoré existujúce, ale v danom úseku implicitne neviditeľné objekty … a stačí, lebo úplne odbočíme od pôvodnej témy). Za povšimnutie stojí fakt, že sa deklaračný príkaz (ako ostatne každý iný) môže nachádzať na ľubovoľnom mieste vo funkcii. Ten, kto pozná jazyk C, si isto spomenie, že v ňom boli deklarácie chápané inak ako príkazy a museli byť všetky zhromaždené na začiatku funkcie. C++ našťastie toto nezmyselné obmedzenie zrušilo a umožnilo tak deklarovať premenné tam, kde sa naozaj používajú (resp. začínajú používať) – predstavte si, že máte dlhú funkciu, na jej začiatku deklaráciu nejakej premennej, ktorú používate až na konci funkcie. Ako málo chýba k tomu, aby ste po chvíli stratili prehľad, čo k čomu patrí a čo od čoho závisí. Takto si deklarujete danú premennú pekne na konci funkcie, máte ju „na očiach“ a viete, ku ktorej časti kódu patrí. Z tohto dôvodu dôrazne odporúčam všetkým, aj ortodoxným céčkarom, deklarujte premenné tam, kde ich začínate používať!

Zložený príkaz

Tretím typom príkazu v C++ je tzv. zložený (compound) príkaz. Niekde sa možno stretnúť s pojmom príkazový blok alebo blokový príkaz, ale slovo „zložený“ lepšie vyjadruje jeho podstatu. Zložený príkaz vyzerá takto: ľavá krútená zátvorka {, ľubovoľný (aj nulový) počet iných príkazov (ľubovoľného typu) a nakoniec pravá krútená zátvorka }. Takýto príkaz navonok vystupuje ako jediný, hoci vnútri je vlastne tvorený niekoľkými príkazmi. Primárny zmysel je zrejmý – všade tam, kde syntax jazyka C++ povoľuje jediný príkaz (kde to je, to sa dozvieme v ďalších odsekoch), musíme v prípade, že potrebujeme vykonať viacero príkazov, použiť jeden zložený. Okrem toho pre deklarácie premenných vnútri zloženého príkazu platia určité pravidlá, ale o tom teraz hovoriť nebudeme. Príklad úseku programu so zloženým príkazom:

 

double s = 3800.0;

{

    double v, t = 12.58;

    v = s / t;

    printf("v = %lg\n", v);

}

s += 1218.0;

 

Z tohto príkladu nie je síce jasné, prečo sa zložený príkaz vôbec používa, ale vidno na ňom, ako sa takýto príkaz zapisuje, a čo je hádam najdôležitejšie, že za zloženým príkazom sa nepíše bodkočiarka. Ak ju tam dáme, vytvoríme dva príkazy – jeden zložený a hneď za ním jeden prázdny, čo v mieste, kde je povolený len jediný príkaz, spoľahlivo povedie k problémom.

Tu si dovolím malú kultúrnu vložku. Je nepísaným pravidlom, že v záujme čitateľnosti zdrojové texty dodržiavajú určité formátovanie. Samozrejme, je na každom, aby si zvykol na jeden štýl, ktorý mu vyhovuje, a ten používal. Patrí však k dobrým zvykom krútené zátvorky okolo zložených príkazov a/alebo funkcií zapisovať na samostatný riadok a vnútorné (vnorené) príkazy odsadzovať príslušným počtom medzier podľa úrovne vnorenia. Jednotkou odsadenia bývajú hádam najčastejšie štyri medzery (teraz sa na mňa zosype spŕška kritiky – dobre, niekedy aj dve medzery alebo osem, alebo jeden tabulátor, ale myslím, že štyri medzery je rozumný kompromis medzi prehľadnosťou programu a zbytočným plytvaním miestom). Niektorí programátori prvú krútenú zátvorku píšu na koniec predchádzajúceho riadka (teda nie pri takom zloženom príkaze, ako sme uviedli vyššie, tam to nemá zmysel, ale napr. pri definícii funkcie), tento spôsob je však podľa mňa o niečo menej prehľadný.

Príkazy výberu

Priznám sa, veľmi sa mi nepáči pojem príkazy výberu, možno by bolo lepšie nazvať ich príkazmi vetvenia, ale asi najlepšie ich funkciu vystihuje anglický termín selection statements. A propos, pre tých, ktorí nevedia aspoň trochu po anglicky, mám zlú správu – rovno môžete prestať čítať. Prepáčte mi tú priamočiarosť, ale myslím, že programátor, ktorý nevie po anglicky, je vopred odsúdený do roly bezvýznamného štatistu. Prakticky absolútna väčšina všetkých materiálov k vývojovým nástrojom, novým technológiám a podobne je v angličtine a na Internete sa so slovenčinou tiež ďaleko nedostanete (pokiaľ sa neobmedzujete na čítanie slovenských „sajtov“ a/alebo sťahovanie obrázkov slečien v intímnych polohách). Takže ak pociťujete medzery vo vzdelaní, nestrácajte čas.

Aby sme sa však vrátili k téme, príkazy výberu sú v C++ dva, a to príkaz if a príkaz switch. Slovko „výber“ sa vzťahuje na výber cesty, ktorou sa bude program uberať v závislosti od nejakých podmienok.

Príkaz if

Príkaz if umožňuje podmienené vykonávanie určitého úseku programu na základe splnenia alebo nesplnenia zadanej podmienky. Existuje v dvoch formách:

 

if (podmienka)

    príkaz

 

a

 

if (podmienka)

    príkaz1

else

    príkaz2

 

Prvá z oboch uvedených foriem spôsobí, že procesor vyhodnotí podmienku uzavretú v zátvorkách, a ak je jej hodnota nenulová, vykoná uvedený výkonný príkaz. Ak je podmienka nulová, pokračuje sa nasledujúcim príkazom. Tu vidíme prvý prípad, keď syntax jazyka C++ povoľuje len jeden príkaz. Ak chceme realizovať viacero príkazov, použijeme spomínaný zložený príkaz. Je lepšie, keď výkonný príkaz (jednoduchý či zložený) píšeme na samostatný riadok – pri krokovaní programu tak vieme, či bola podmienka splnená, alebo nie. Jednoduchý príkaz obyčajne odsadíme, pri zloženom odsadíme len vnorené príkazy, obe zátvorky ponecháme v jednej úrovni s doterajším textom. Prirodzene, ak sa vám takýto spôsob zápisu zdrojového textu nepáči, vytvorte si vlastný, ale pokiaľ možno konzistentný a nemenný.

V nasledujúcom príklade sa inkrementuje hodnota premennej x a v prípade, že dosiahne hodnotu 640, vynuluje sa a inkrementuje sa hodnota inej premennej y. Obe premenné x a y môžeme brať napríklad ako súradnice nejakého objektu pohybujúceho sa po riadkoch štandardnej VGA obrazovky. Keď objekt prejde cez pravý okraj, objaví sa na ľavom okraji o riadok nižšie:

 

x++;

if (x == 640)

{

    x = 0;

    y++;

}

 

V prípade, že výkonným príkazom príkazu if je iný ako zložený príkaz, musí za ním nasledovať bodkočiarka. Za zloženým príkazom sa, naopak, bodkočiarka nepíše. Výkonným príkazom môže byť hocijaký príkaz, teda aj ďalší príkaz if, takáto konštrukcia je potom, samozrejme, ekvivalentná jedinému príkazu if s podmienkami spojenými operátorom logického súčinu. Na mieste podmienky môže stáť ľubovoľný výraz aritmetického typu alebo typu ukazovateľ, rozhodujúca je jeho hodnota (nulová/nenulová). Tento fakt môžeme s úspechom využiť a prepísať uvedený príklad takto:

 

if (++x == 640)

{

    ...

}

 

Pri vyhodnocovaní výrazu sa inkrementuje premenná x, potom sa jej hodnota porovná s konštantou 640. V prípade rovnosti je celý výraz nenulový a vykoná sa príslušný zložený príkaz. Takýto spôsob zápisu je pre C++ typický a za cenu trošku ťažšej zrozumiteľnosti zdrojového textu napomáha jeho skrátenie a zefektívnenie jeho zápisu. Mimochodom, skúste sa zamyslieť, prečo v tomto príklade nemôžeme použiť postfixový variant operátora ++.

Ak prvá forma príkazu if predstavovala akúsi jednocestnú výhybku, druhá forma umožňuje výber z dvoch alternatív, z ktorých sa vykoná práve jedna. Pri vykonávaní tejto druhej formy procesor opätovne vyhodnotí podmienku a v prípade, že jej hodnota bude nenulová, vykoná príkaz1, po jeho skončení pokračuje prvým príkazom za celou konštrukciou if. V opačnom prípade, t. j. hodnota podmienkového výrazu je nulová, procesor vykoná príkaz2. Pre oba príkazy platí to, čo sme už uviedli – ak sú jednoduché, píše sa za nimi bodkočiarka, ak sú zložené, bodkočiarka sa nepíše (a pre príkaz1 sa ani nesmie!).

Niekedy potrebujeme vetviť program podľa viacerých alternatív. Jednou z možností je nasledujúca konštrukcia (nie je ničím výnimočná, ide v skutočnosti o sériu dvojcestných príkazov if):

 

if (podmienka1)

    príkaz1

else if (podmienka2)

    príkaz2

else if ...

    ...

else

    príkazn

 

Keby sme striktne dodržiavali odsadzovanie jednotlivých blokov podľa spomenutých pravidiel, dlhšie konštrukcie by boli príliš posunuté vpravo, preto sa takáto séria príkazov častejšie formátuje tak ako v našom príklade. Sémantika tejto konštrukcie je jednoduchá – postupne sa vyhodnocujú jednotlivé podmienkové výrazy, a keď sa narazí na prvý, ktorého hodnota je nenulová, vykoná sa jeho príslušný výkonný príkaz. V prípade, že ani jedna z podmienok nie je splnená, vykoná sa príkazn (ak ho uvedieme; samozrejme, nemusí tam byť, v takom prípade sa jednoducho pokračuje prvým príkazom za celou konštrukciou).

Pri používaní druhej formy príkazu if môže dôjsť k nasledujúcej situácii. Majme úsek kódu:

 

if (podmienka1)

    if (podmienka2)

        príkaz1

    else

        príkaz2

 

Vidíme, že tento úsek obsahuje dva príkazy if, z ktorých len jeden má aj časť else. Otázkou tu je ktorý. Ako ste si zrejme domysleli z formátovania celého príkladu, uvedená časť else patrí k druhému z oboch if. Pri realizácii tohto kódu procesor najprv vyhodnotí podmienku1. Ak je jej hodnota nenulová, začne vykonávať druhý príkaz if (štandardným spôsobom). Ak je však jej hodnota nulová, program pokračuje nasledujúcim príkladom za celým uvedeným úsekom. Ak chceme, aby sa časť else vzťahovala na prvý if, musíme ten druhý (vnorený) uzavrieť do krútených zátvoriek a vytvoriť z neho zložený príkaz (hoci if sám osebe je príkazom jednoduchým):

 

if (podmienka1)

{

    if (podmienka2)

        príkaz2

}

else

    príkaz1

 

Vyskúšajte si oba tvary (so zátvorkami aj bez), aby ste sa presvedčili o ich funkcii.

Na záver si uvedieme krátky príklad použitia druhej formy príkazu if. Predpokladajme, že v premennej choice typu char je písmeno predstavujúce voľbu používateľa z nejakého menu, ktoré umožňuje vytvorenie nového objektu a modifikáciu alebo zmazanie existujúceho objektu (napríklad položky v nejakej databáze):

 

char choice;

 

...  // výber z menu

 

if (choice == 'C')

    Create();

else if (choice == 'M')

    Modify();

else if (choice == 'D')

    Delete();

else

{

    Beep();

    PrintError("Unknown choice!");

}

 

Funkcie Create(), Modify(), Delete() realizujú príslušné operácie s objektmi, funkcia Beep() vydá varovné pípnutie a PrintError() vypíše chybovú správu.

Príkaz switch

Druhým príkazom výberu je príkaz switch. Tento príkaz má podobnú funkciu ako zreťazenie viacerých dvojcestných príkazov if, na rozdiel od nich však umožňuje vetvenie na základe jedinej podmienky. Jeho syntax je v podstate veľmi jednoduchá:

 

switch (výraz)

    príkaz

 

Výkonný príkaz príkazu switch je prakticky vždy zložený (inak nemá príkaz switch vôbec význam). Ako sme si povedali, zložený príkaz predstavuje postupnosť iných príkazov. V rámci príkazu switch môžu byť jednotlivé vnorené príkazy označené pomocou špeciálnych návestí v tvare:

 

{

    ...

case konštantný-výraz:

    príkaz

    príkaz

    ...

}

 

Samozrejme, že nie každý príkaz musí mať pred sebou návestie. Každé návestie sa skladá z kľúčového slova case, za ktorým nasleduje konštantný výraz a dvojbodka. Rôzne návestia musia mať rôzne konštantné výrazy! Okrem toho sa môže v zloženom príkaze vyskytovať najviac jedno zvláštne návestie default:.

Pri realizácii príkazu switch sa vyhodnotí jeho podmienkový výraz. Tento výraz musí byť celočíselného typu. Potom sa vypočítaná hodnota porovnáva s konštantnými výrazmi v jednotlivých návestiach zloženého príkazu. Ak sa s nejakým konštantným výrazom zhoduje, program bude pokračovať príkazmi nasledujúcimi za daným návestím. Ak sa nezhoduje so žiadnym výrazom, budú sa vykonávať príkazy nasledujúce za návestím default: (ak tam je; ak nie, pokračuje sa nasledujúcim príkazom za príkazom switch). Pozor! Po skoku riadenia za príslušné návestie bude procesor vykonávať všetky nasledujúce príkazy nezávisle od ďalších prípadných návestí až po koniec celého zloženého príkazu. Ak chceme tento zložený príkaz ukončiť skôr, musíme použiť kľúčové slovo break, ktoré spôsobí okamžité vyskočenie z aktuálneho bloku, v našom prípade zo zloženého príkazu príkazu switch.

Najlepšie hádam bude ozrejmiť si celú vec na príklade. Predpokladajme, že v premenných a a b sú dve čísla, s ktorými chceme vykonať jednu z aritmetických operácií na základe voľby používateľa. Tu je daný kód:

 

double a, b, res;

char op;

 

...  // voľba operácie

 

switch (op)

{

case '+':

    res = a + b;

    break;

case '-':

    res = a - b;

    break;

case '*':

    res = a * b;

    break;

case '/':

    if (b != 0.0)

    {

        res = a / b;

        break;

    }

default:

    error();

}

 

Premenná op by mala obsahovať jednu z hodnôt '+', '-', '*' alebo '/'. Podľa jej obsahu sa vyberie príslušné návestie a vykoná sa daná operácia. Výsledok sa uloží do premennej res. V prípade, že je v premennej op iný znak ako jeden zo štyroch uvedených, zavolá sa funkcia error(). Obsah res v takom prípade zostane nezmenený. Všimnite si v tomto príklade, že v prípade požiadavky na vydelenie oboch premenných sa testuje, či premenná b (t. j. deliteľ) nie je náhodou nulová. Ak nie je, delenie sa vykoná a príkaz sa ukončí kľúčovým slovom break. Čo sa však stane vtedy, keď b bude obsahovať hodnotu 0.0? Zložený príkaz príkazu if sa nevykoná a bude sa pokračovať ďalším príkazom. Tentoraz ním však nie je príkaz break, ale (návestím default: označené) volanie funkcie error(). Inými slovami, funkcia error() sa vyvolá nielen pri chybnom kóde požadovanej operácie, ale aj pri požiadavke delenia nulovým deliteľom.

Záver

Rozprávanie o príkazoch jazyka C++ si dokončíme nabudúce, keď si povieme o príkazoch cyklu a o skokových príkazoch. Potom si uvedieme nejaký väčší príklad, v ktorom použijeme maximum z toho, čo sme doteraz prebrali. Jemne sa dotkneme aj problematiky vstupu údajov z klávesnice, aby náš program bol aspoň trochu interaktívny. Potom nám z neobjektovej časti C++ zostáva prebrať deklarácie a všetky záludnosti s nimi spojené (okrem iného rozsah platnosti, viditeľnosti, ukladaciu triedu, linkovanie, používateľské typy), štandardné konverzie, dynamickú alokáciu pamäte a ešte niečo o funkciách. Keď sa tým všetkým úspešne prepracujeme, povieme si o štandardnej knižnici jazyka C (o základných funkciách, ktoré poskytuje) a potom už sa vrhneme na prostriedky, ktoré C++ poskytuje na podporu objektovoorientovaného programovania.

C++

Nechajte si posielať prehľad najdôležitejších správ emailom

Mohlo by Vás zaujímať

Ako na to

Tipy a triky: Ako na snímku obrazovky na akomkoľvek počítači s Windows?

02.12.2016 00:13

Ak snímky obrazovky robíte často apotrebujete napríklad funkcie na posun stránok alebo snímanie zobrazenia pri vyššom rozlíšení displeja, zrejme používate nejakú špecializovanú aplikáciu. Väčšina použ ...

Ako na to 1

Tipy a triky: Ako aplikácii prednastaviť spúšťanie s administrátorskými právami?

30.11.2016 00:10

Väčšina aspoň trochu skúsenejších používateľov vie, že aj keď máte na operačnom systéme Windows vytvorený administrátorský účet, aplikácie pre bezpečnosť nefungujú vždy splnými administrátorskými práv ...

Ako na to 2

Tipy a triky: Ako vypnúť uzamykaciu obrazovku vo Windows 10?

29.11.2016 00:10

Rozčuľuje vás, že pred každým prihlásením doúčtu vášho počítača musíte prejsť uzamykacou obrazovkou? Windows 10 na tejto obrazovke ukazuje čas,dátum anejakú zaujímavú fotografiu zrôznych kútov sveta. ...

Žiadne komentáre

Vyhľadávanie

Kyocera - prve-zariadenia-formatu-a4-s-vykonom-a3

Najnovšie videá