V tomto díle si probereme první součást jazyka C++ a tou jsou tzv. proměnné. Ty si ukážeme na datovém typu celé číslo. A také si povíme něco víc o výstupu programu.
Pro zjednodušení budu v tomto a následujících dílech psát pouze konkrétní příkazy, které budou patřit do těla funkce main, viz příklad programu v minulém díle. Nezapomeňte navíc na konci těla funkce uvést příkazy cin.get(); (abyste si stihli prohlédnout výstup programu před jeho ukončením) a return 0; (abyste operačnímu systému sdělili, že váš program proběhl úspěšně).
Proměnná představuje místo v paměti, kde si program může uchovávat informace, které si může později vyzvednout a pracovat s nimi. Do proměnných lze ukládat takřka jakoukoliv hodnotu, kterou lze jednoznačně určit. Může to být číslo, znak, text, seznam, tabulka, barva, obrázek... Proto každá proměnná má svůj datový typ, aby se vědělo, co daná hodnota reprezentuje a jak se k ní má program chovat.
V tomto díle si představíme první datový typ a tím je int, což je zkratka z anglického integer - celé číslo.
Než se proměnná začne v programu používat, musí se nejdříve deklarovat (vytvořit). Deklarace musí obsahovat datový typ a název (identifikátor) proměnné. Pokud chceme deklarovat proměnnou, která bude představovat celé číslo a bude se jmenovat cislo, uděláme to následujícím příkazem:
Jednodušší to už být nemůže...
Když už máme proměnnou, můžeme do ní přiřadit hodnotu, např. hodnotu 3. K tomu slouží operátor přiřazení, který se zapisuje znakem =. Celý příkaz vypadá takto:
Tento operátor v jazyce C++ nevyjadřuje rovnost, jako v matematice (k tomu slouží jiný operátor, na který se podíváme v některém z příštích dílů). Operátor přiřazení má jednoduchý úkol - vezme hodnotu z pravé strany a uloží ji do proměnné na levé straně. Obráceně to neumí!
Občas se může oddělená deklarace a přiřazení hodnoty hodit, ale ve většině případů chceme do proměnné přiřadit hodnotu rovnou. A proto je tu možnost přiřazení přímo při deklaraci, příkaz vypadá takto:
Také často chceme deklarovat více proměnných najednou. I toto lze napsat do jednoho příkazu. Např. pokud bychom chtěli deklarovat proměnné sirka a vyska, příkaz by vypadal takto:
Případně pokud bychom chtěli rovnou přiřadit hodnoty:
Všimněte si, že datový typ je v příkazu uveden pouze jednou. Z toho vyplývá, že pokud chceme v jednom příkazu deklarovat více proměnných, všechny musí mít stejný datový typ.
Ani jedno z těchto zjednodušení nemají vliv na výsledný strojový kód. Ať napíšeme deklaraci a přiřazení do jednoho příkazu, nebo do dvou, oboje se zkompiluje stejně. Tato zjednodušení pouze pomáhají zpřehlednit zdrojový kód (kód v jazyce C++).
Určitě jste si všimli, že jsem v názvech proměnných nepoužil diakritiku. To proto, protože to C++ nedovoluje. Pokud v názvu proměnné použijete diakritiku, v kompilátoru GCC se program nepřeloží (nezkompiluje) - kompilátor vypíše chybu. Kompilátor VC++ ji sice dovoluje, ale i tak ji nedoporučuji používat - podle standardu ji obsahovat nesmí.
Jméno proměnné může obsahovat velká a malá písmena anglické abecedy, číslice nebo podtržítko _, přičemž nesmí začínat číslicí. Dále by nemělo začínat dvěmi podtržítky, nebo jedním následovaným velkým písmenem (kompilátor může mít některá taková jména rezervovaná pro vlastní účely).
Dále název proměnné nesmí být shodný se žádným klíčovým slovem jazyka C++ (např. slovo int je rezervováno pro datový typ). Zde je seznam všech klíčových slov:
alignas, alignof, and, and_eq, asm, auto, bitand, bitor, bool, break, case, catch, char, char16_t, char32_t, class, compl, const, constexpr, const_cast, continue, decltype, default, delete, do, double, dynamic_cast, else, enum, explicit, export, extern, false, float, for, friend, goto, if, inline, int, long, mutable, namespace, new, noexcept, not, not_eq, nullptr, operator, or, or_eq, private, protected, public, register, reinterpret_cast, return, short, signed, sizeof, static, static_assert, static_cast, struct, switch, template, this, thread_local, throw, true, try, typedef, typeid, typename, union, unsigned, using, virtual, void, volatile, wchar_t, while, xor, xor_eq
Pokud budete psát názvy v češtině, tak jediné slovo, na které si budete muset dávat pozor, je slovo do.
Dále si pamatujte, že jazyk C++ je tzv. case sensitive. Tzn. že u názvů záleží na velikosti písmen, např. cislo a Cislo jsou dva různé názvy.
A nakonec by každý název proměnné měl být unikátní v rámci platnosti dané proměnné (o rozsahu platnosti proměnných si už něco málo řekneme v některém z příštích dílů).
Minule jsem posílali textovou zprávu na standardní výstup programu, který reprezentuje proměnná cout (čti sí-aut). Jaký má datový typ je pro nás momentálně nepodstatné. Název této proměnné je zkratka z anglického character output (znakový výstup).
Dnes si vytiskneme (pošleme na výstup) číselnou proměnnou. Uděláme to stejně, jako minule. Do proměnné cout pošleme operátorem << proměnnou, kterou si předtím vytvoříme. Operátor << představuje bitový posun doleva (co to znamená si řekneme někdy příště). U datového výstupu ale má jiný význam.
int cislo = 7; cout << cislo;
Všimněte si, že na rozdíl od posílání textu se u proměnné nepoužívají uvozovky ". Ty slouží pouze pro vyjádření textové hodnoty v jazyce C++, aby kompilátor věděl, jestli jde o data nebo kód jazyka. U čísel se uvozovky používat nemusí (respektive nesmí, protože by se jednalo o text a ne o číslo), protože si je kompilátor nemůže splést s ničím jiným. Pamatujete na pravidlo, že název proměnné nesmí začínat číslem?
Zkuste si vytisknout dvě číselné proměnné po sobě:
int sirka = 12, vyska = 10; cout << sirka; cout << vyska;
Dostanete tento výstup:
Toto není vůbec ideální, protože obě čísla splývají do jednoho. Existují hned dvě řešení tohoto problému. Prvním z nich je, že mezi čísly navíc vytiskneme textový oddělovač, např. znak x s mezery na obou stranách:
int sirka = 12, vyska = 10; cout << sirka; cout << " x "; cout << vyska;
Potom dostanete takovýto výstup:
Nyní jsou obě čísla čitelně oddělená.
Druhým řešením je, že každé číslo vytiskneme na samostatný řádek. Abychom docílili toho, že se bude tisknout na následující řádek, musíme nejprve ten rozepsaný ukončit. To uděláme takto:
Název endl je zkratka z anglického end of line (konec řádku). Na první pohled se může zdát, že endl je proměnná. Není tomu tak. Nyní vám radši nebudu říkat, co to vlastně je, abych vám nepletl hlavu. Zatím si pamatujte pouze to, že pokud to pošlete na výstup, ukončí se rozepsaný řádek.
Pokud tento příkaz doplníte mezi tisk proměnných, dostanete tento výstup:
Určitě jste si všimli, že se nám množí příkazy pro výstup. Proto existuje zjednodušení, které tento počet zredukuje. Nazývá se zřetězení a znamená to, že můžeme poslat víc věcí na výstup v jednom příkazu. Zřetězený výstup z předchozího příkladu by vypadal takto:
Nesnažte se ale vždy celý výstup nacpat do jednoho příkazu. Čím delší příkaz je, tím hůře se pro programátora čte (kompilátoru je to samozřejmě jedno). Proto zřetězení používejte s rozumem. Měli byste vždy psát co nejčitelnější kód - i když to znamená, že bude delší.
Jak název napovídá, hodnoty proměnných se během běhu programu mohou měnit. V praxi to znamená, že kdykoliv můžete do proměnné přiřadit novou hodnotu a tím přepsat starou. Můžeme si to ukázat na následujících příkazech:
int cislo = 3; cout << cislo << endl; cislo = 6; cout << cislo << endl; cislo = 9; cout << cislo;
Výstup bude vypadat takto:
Nejdříve se vytvoří proměnná cislo a inicializuje se (přiřazení hodnoty do proměnné, do které zatím žádná hodnota přiřazena nebyla) na hodnotu 3. Dalším příkazem se tato hodnota vytiskne. Pak se do proměnné přiřadí nová hodnota 6, která se také vytiskne. Toto se ještě jednou zopakuje s hodnotou 9.
V některých případech chceme, aby při každém spuštění programu se tiskla stejná hodnota. To je v takových případech, kdy tato hodnota není závislá na vstupu od uživatele, hardwaru atd. nebo není závislá na hodnotách jiných proměnných. Potom hodnotu není potřeba ukládat do proměnné a můžeme ji rovnou poslat na výstup:
A na konec tohoto dílu jedna perlička. Co se stane, když deklarujeme proměnnou, ale neinicializujeme ji? No... můžeme si to zkusit:
int cislo; cout << cislo;
Kompilátor GCC mi zobrazí varování, ale i přesto program přeloží. Kompilátor VC++ mi zobrazí chybu a program odmítne přeložit. Jestli má kompilátor zobrazit varování nebo chybu, závisí na jeho nastavení.
GCC program přeložil, jaká hodnota se tedy vytiskne? V tomto jednoduchém programu se pravděpodobně vždy vytiskne nula. Ale pokud byste to zkusili v nějakém složitějším programu, pravděpodobně by se zobrazilo nějaké nesmyslné číslo. Navíc při každém spuštění by se toto číslo lišilo.
To je způsobeno tím, že když v programu některá proměnná ztratí platnost, nesmaže se její hodnota, pouze se místo, na kterém tato hodnota je, označí, že je volné a může se zde vytvořit jiná. Když se v budoucnu toto místo skutečně využije pro jinou proměnnou, tak stále na tomto místě zůstává původní hodnota. Ta se přepíše až inicializací proměnné.
Proto NIKDY nepoužívejte neinicializované proměnné!!
A proč vlastně existuje možnost vytvoření neinicializované proměnné? Někdy se hodí inicializaci odložit, ale zatím neznáte žádné konstrukce, na kterých by se to dalo ukázat. Musíte si na toto počkat do příštích dílů.
V příštím díle si ukážeme, jak za nás může program počítat a tím si rozšíříme naše znalosti proměnných o tzv. výrazy.