30. července 2015 16:16

3. díl - Výrazy

Dnes se naučíme nový pojem výraz a ukážeme si několik početních operací, které může náš program provádět.

Počítáme

Počítač by se nemohl jmenovat počítač, kdyby neuměl počítat. První početní operace, kterou se naučíme, je sčítání. Jistě si ještě z první třídy pamatujete, že sčítání se v matematice značí znaménkem +. V jazyce C++ se pro sčítání používá stejný symbol, ale říká se mu operátor (matematika pouze ukazuje, jak se věci mají -> značí - proto znaménko; v jazyce C++ se zapisují příkazy, podle kterých počítač vybere operaci, kterou provede - proto operátor). Pokud tedy chceme sečíst dvě čísla, např. 7 a 5, zapíšeme to následujícím příkazem:

7 + 5;

Počítač sečte čísla a výsledek... zahodí, protože v příkazu není uvedeno, co se s výsledkem má udělat, ale i přesto je to platný příkaz (kompilátor vás možná upozorní, že jste napsali blbost).

Co tedy s výsledkem můžeme udělat? Například ho můžeme přiřadit nějaké proměnné:

int vysledek = 7 + 5;

Do proměnné vysledek se uloží výsledná hodnota, tedy 12.

Nemusíme se držet při zdi, můžeme po počítači chtít sečíst i více, než dvě čísla. Pokud chceme sčítat více čísel, zapisuje se to úplně stejně, jako v matematice:

int vysledek = 1 + 4 + 8 + 3;

Do proměnné se uloží výsledná hodnota 16.

Samozřejmě můžeme stejně i odčítat:

int vysledek = 16 - 9;

Nebo sčítání a odčítání zkombinovat:

int vysledek = 1 + 9 - 7 + 3 - 1 - 2;

Samozřejmě můžeme počítat i s hodnotami proměnných:

int a = 4, b = 6, c = 3;
int vysledek = a + b - c;
cout << vysledek;

Vytiskne se hodnota 7. Jednoduché, že?

Co je výraz

Nyní trocha teorie. Výraz je část příkazu, po jehož provedení se za výraz dosadí nějaká hodnota. Mějme např. součet dvou čísel: 4 + 6. Toto je výraz. Skládá se z operátoru + a dvou operandů 4 a 6. Operand může být cokoliv, co má nějakou hodnotu: literál (přímo napsané číslo, jako v tomto případě), proměnná, volání funkce vracející hodnotu a nebo další výraz.

Pozor! Za výrazem se nepíše středník. Středník se píše pouze za celým příkazem, ale jeden příkaz může obsahovat více výrazů a podvýrazů!

Binární operátory

Binární operátory jsou takové, které očekávají dva operandy (zleva a zprava). Operátory + a - patří mezi ně.

Ale co když máme následující výraz?

4 + 7 + 2

Nejdříve se vyhodnotí první část výrazu 4 + 7 jako hodnota 11 a tím vznikne zjednodušený výraz 11 + 2, který se vyhodnotí jako 13.

Jinými slovy: druhý operátor má operandy 4 + 7 (operand je výraz) a 2.

Unární operátory

Vedle binární operátorů existují ještě unární, které očekávají pouze jeden operand. Zpravidla se zapisují před operand, ale existují i výjimky.

Mezi unární operátory patří např. - (může mít binární i unární podobu). Unární mínus nám např. dovoluje zapsat zápornou hodnotu celého čísla:

int zaporne = -3;

Unární mínus obrací znaménko čísla. Tedy z kladného udělá záporné a ze záporného kladné. Mějme tyto příkazy:

int a = 7, b = -4;
int c = -a, d = -b;
cout << c << ", " << d;

Vytiskne se -7, 4.

Existuje také unární plus, ale to je pouze do počtu. Číslo totiž nijak nezmění.

Výraz v deklaraci

Předchozí příklad by šel zjednodušit:

int a = 7, b = -4, c = -a, d = -b;
cout << c << ", " << d;

Proměnné c se přiřadí hodnota výrazu, ve kterém figuruje proměnná a. Toto funguje i přesto, že proměnná a byla deklarována ve stejném příkazu, jako proměnná c. Záleží totiž na pořadí deklarace, která probíhá zleva doprava. Tudíž při deklaraci proměnné c už můžeme počítat s existencí proměnných a a b, ale s d ne, protože ta se deklaruje až potom.

Změna hodnoty proměnné

Předchozí příklad můžeme zjednodušit i tak, že proměnné c a d úplně vypustíme. To můžeme udělat tak, že nové hodnoty uložíme do již vytvořených proměnných:

int a = 7, b = -4;
a = -a;
b = -b;
cout << a << ", " << b;

Nejdříve se provede vyhodnocení výrazu a až potom se vypočtená hodnota přiřadí do proměnné. Proto může tento program fungovat.

Výraz ve výstupu

Výraz můžeme zapsat i do příkazu pro tisk. Předchozí příklad bychom zjednodušili takto:

int a = 7, b = -4;
cout << -a << ", " << -b;

Opět se nejdříve vyhodnotí výrazy a až potom se výsledky vytisknou. V tomto případě se hodnoty proměnných nezmění.

Násobení

Počítač také umí násobit. Ale pro tuto operaci se nepoužívá tečka nebo křížek jako v matematice, ale znak hvězdičky *. Vynásobení dvou čísel potom vypadá takto:

int vysledek = 5 * 3;

Výraz se vyhodnotí jako hodnota 15.

Ovšem co se stane nyní:

int vysledek = 2 * 4 + 6 * 3;

Pokud si dobře pamatujete na matematiku, násobení má před sčítáním a odčítáním přednost. Stejně tak tomu je i v jazyce C++. Výraz se tedy vyhodnotí jako hodnota 26, nikoliv 42.

Takto by mohlo vypadat zjednodušování tohoto výrazu:

2 * 4 + 6 * 3
8 + 6 * 3
8 + 18
26

Závorky

Pokud chceme toto chování obejít, slouží na to v jazyce C++ stejně jako v matematice závorky. Pokud chceme například v předchozím výrazu nejdříve sečíst čísla 4 a 6 a až potom provést násobení, výraz zapíšeme takto:

2 * (4 + 6) * 3

A nebo pokud chceme jednotlivé operátory vyhodnocovat zleva doprava, zapíšeme to takto:

((2 * 4) + 6) * 3

Vnitřní závorka by šla vynechat, protože násobení má přirozeně přednost před sčítáním. Ale závorky navíc nejsou vůbec na škodu - přebytečné závorky stejně kompilátor ignoruje. Navíc někdy závorky zpřehledňují kód a když si nejste jisti prioritou operátorů, je lepší závorky napsat, i když nejsou potřeba, aby jste se vyhnuli případné chybě.

Pokud vás ve škole učili nesmysl typu, že pokud je v sobě zanořeno více závorek, tak se rozlišují tvarem, tak na to u programování rychle zapomeňte. V C++ se pro změnu priority používají pouze kulaté závorky. Není potřeba používat žádné další, protože stejně se závorky nemohou křížit (nedávalo by to smysl), takže je jasné, že ukončovací závorka ukončuje vždy tu naposledy otevřenou (a dosud neuzavřenou).

Dělení

Pro dělení se v C++ používá operátor / a použití je stejné jako u ostatních operátorů:

cout << 6 / 3;

Vytiskne se číslo 2.

Operátor dělení má stejnou prioritu jako násobení, tedy výraz:

2 + 8 / 4 * 2 - 3

Je roven hodnotě 3, protože nejdříve proběhne dělení, potom násobení (operátory na stejné úrovni se zpracovávají zleva) a až nakonec sčítání a odčítání.

U dělení byste si ale měli dávat pozor na jednu vlastnost. Pokud dělíme celá čísla, výsledek je také celé číslo! Pokud máme následující výraz:

7 / 2

Očekávali bychom výsledek 3,5. Jenže tato hodnota není celé číslo. Při dělení celých čísel procesor ve výsledku vynechá desetinnou část, takže výsledek bude 3. Pamatujte, že se jedná opravdu o vynechání, ne zaokrouhlení! Tento výraz:

2999 / 1000

Bude roven hodnotě 2, i když správně by mělo vyjít 2,999.

Modulo

Nebo-li zbytek po celočíselném dělení. Možná si pamatujete, když jste se kdysi na prvním stupni učili poprvé dělit a ještě jste neuměli desetinná čísla, že jste vedle výsledku psali ještě zbytek, který jste již vydělit neuměli. Datový typ celé číslo je v tomto případě na tom úplně stejně, jako jste na tom byli vy - také neumí desetinná čísla. Proto nemůže vždy libovolná čísla podělit. Např. pokud máme 11 / 4, což vychází jako 2, jenže pokud to vynásobíme zpátky 2 * 4, dostaneme hodnotu 8 a ne 11, kterou jsme dělili. A rozdíl mezi těmito dvěma hodnotami je právě zbytek po dělení. A tuto hodnotu v jazyce C++ dostaneme použitím operace modulo. Slouží k tomu operátor % (nemá nic společného s procenty!):

cout << 11 % 4;

Vytiskne se hodnota 3.

Asi si říkáte, k čemu je něco takového dobré. Proto si to ukážeme na praktickém příkladu. Představme si, že v proměnné máme uložen počet sekund a chceme tento časový údaj vytisknout ve tvaru mm:ss - tedy potřebujeme celkový počet sekund přepočítat na celé minuty a zbývající sekundy. Např. pokud máme celkový počet sekund roven hodnotě 205. My chceme, aby se vytiskl text 3:25 (3 * 60 + 25 je rovno hodnotě 205). K tomuto můžeme využít vlastnosti celočíselného dělení (desetinná část se vynechá) a operátoru modulo:

int sekund = 205;
cout << sekund / 60 << ":" << sekund % 60;

205 ÷ 60 je 3,4167, ale desetinná část se vynechá, takže dostaneme hodnotu 3. 205 - 3 × 60 je 25, což jednodušeji dostaneme operátorem modulo.

Pokud si budete do tohoto příkladu zkoušet dosazovat jiná čísla, možná narazíte na jednu nedokonalost. Pokud dosadíte např. číslo 65, vytiskne se 1:5, ale my bychom byli radši, aby se vytisklo 1:05, jak jsme u časových údajů zvyklí. Bohužel na řešení tohoto problému zatím nemáte dostatečné znalosti jazyka C++.

Výraz s operátorem přiřazení

Pokud jste pozorní, možná vás napadlo, že jsme si říkali o operátoru přiřazení. Ano, i = je operátor a tímpádem operace přiřazení je výraz! A výraz musí po provedení nabývat nějaké hodnoty. U operátoru přiřazení se jedná o hodnotu, která byla přiřazena do proměnné. Takže pokud máme následující příkazy:

int cislo;
cout << (cislo = 5);

Nejdříve se do proměnné cislo uloží hodnota 5 a výraz se také vyhodnotí jako 5, tudíž se toto číslo pošle na výstup.

Možná si říkáte, k čemu jsou zde potřeba závorky. To proto, protože operátor přiřazení má nejnižší prioritu a mi potřebujeme, aby se nejdříve provedlo přiřazení a až pak se výsledek odeslal na výstup.

Operátor přiřazení má od operátorů, které jsme si již ukázali, jednu zvláštnost. Nevyhodnocuje se zleva doprava, ale zprava doleva. Pokud tedy máme:

int a, b;
a = b = 5;

Nejdříve se vyhodnotí podvýraz b = 5 jako hodnota 5 (jeho dalším efektem je změna hodnoty proměnné b) a tato hodnota se následně přiřadí do a. Jak vidíte, tato vlastnost nám dovoluje do více proměnných uložit naráz jednu hodnotu.

Jak funguje řetězení výstupu

V minulém díle jsme si ukázali zřetězení výstupu. Nyní si vysvětlíme, jak je možné, že takto může fungovat. << je také operátor. Je binární, tedy očekává dvě hodnoty a po zpracování se vyhodnotí jako nějaká hodnota. Pokud se nalevo od operátoru nachází proměnná cout, očekává se, že napravo bude hodnota, která se má vytisknout. Po vytisknutí se výraz vyhodnotí opět jako proměnná cout a pokud následuje další operátor <<, je připravena na další hodnotu k tisku. Tedy pokud máme tento příkaz:

cout << 1 << 2;

Nejdříve se provede první část výrazu cout << 1 a vyhodnotí se jako cout. Celý výraz se tedy zjednoduší na cout << 2. Po provedení zjednodušeného výrazu se výraz opět vyhodnotí jako proměnná cout, ale s ní se už nic nebude dělat, protože ve výrazu nezbyla žádná operace, která by se měla provést.

Priorita a asociativita operátorů

Na závěr tohoto dílu bych rád ještě zopakoval operátory, které již známe a jejich priority. Nejlepší shrnutí bude asi tabulkou:

Priorita Operátory Typ Asociativita
1. +, - unární zprava
2. *, /, % binární zleva
3. +, - binární zleva
4. << binární zleva
5. = binární zprava

Pamatujte, že operace se provádí podle priorit operátorů (nižší číslo = vyšší priorita) - pokud jste prioritu nezměnili vložením závorek.

Asociativita znamená, kterým směrem se vyhodnocují operátory se stejnou prioritou. Všimněte si, že i u unárních operátorů je uvedena asociativita. To proto, protože můžete napsat k jednomu operandu více unárních operátorů. Ty se vždy vyhodnocují zprava doleva. Např.:

+-1

Nejdříve se provede operátor - a až potom +. Ale pozor, pokud byste chtěli napsat něco takového:

--1

Tak to znamená něco jiného, protože -- je samo o sobě operátorem (o něm v příštím díle). Pokud byste z nějakého důvodu chtěli napsat dva unární plusy nebo mínusy po sobě, tak máte dvě možnosti:

-(-1);
- -1;

V prvním případě použijeme pro oddělení závorky, v druhém mezeru.

Příště

Příště se naučíme několik dalších operátorů, které nám mohou zjednodušit naše výrazy. A dále se podíváme na čtení ze vstupu a napíšeme si první interaktivní program.

Hodnocení

Celkové hodnocení
2 hlasy
Vaše hodnocení
Vyberte počet hvězdiček

Komentáře

Jméno:
Předmět:
Komentář:
  :):-|:P:D;):(8)[evil][arrow][idea][?][!]
Kontrola:
Žádné komentáře.
© 2011 - 2017 SuperMartas a Tomáš Hypeš