Bez toho, aby sme si mohli údaje zapamätávať sa programovať nedá. Na zapamätanie nejakých hodnôt nám slúžia premenné. Premennú si môžeme predstaviť ako krabičku, do ktorej vieme všeličo strčiť. Krabičky majú svoje meno a aj svoj typ.
Premennú s menom si môžeme predstaviť ako krabičku s nálepkou. Meno krabičky/premennej slúži na to, aby sme s nimi vedeli pracovať. Napríklad "ulož číslo do tamtej premennej" počítač nepochopí, on by rád počul "ulož číslo do premennej s menom `a'".
Typ premennej zase určuje, čo do nej môžeme vkladať. Do premennej typu
int (odvodené od anglického slova integer) môžeme ukladať celé číslo, do
premennej typu string (z angličtiny sa dá preložiť ako reťazec) zasa môžeme vkladať reťazce
znakov (na stringy potrebujeme knižnicu). Neskôr sa naučíme používať
oveľa viac typov premenných, dokonca vyrábať vlastné typy.
Ako premenné používať? Na to, aby sme mohli s premennou niečo robiť, si
ju musíme vytvoriť (deklarovať). To sa robí príkazom <typ-premennej> <meno-premennej>;
napríklad int cislo;
Do premenných môžeme vkladať priradením, teda pomocou =. Syntax je
<meno-premennej> = <výraz>, napríklad a = 4. O výrazoch si
povieme viac neskôr, dôležité zatiaľ je, že výraz musí mať nejakú hodnotu.
Napríklad výraz 4 má hodnotu 4. Výraz a má hodnotu toho, čo je
vnútri premennej/krabičky s menom a. Výraz 4 + 7 má hodnotu 11.
Pokiaľ v a je číslo 5, tak výraz a + 5 má hodnotu 10.
Výraz musí mať hodnotu preto, lebo práve táto hodnota sa uloží do premennej:
Napríklad keď napíšeme a = 3 + 8; tak do a sa priradí číslo 11.
Cvičenie: Skúste určiť, čo robí nasledovný program. Aké hodnoty budú na
konci v premenných a, b, c?
int main(){
int a;
a = 4;
a = 7;
int b, c;
b = a;
c = a + b;
a = a + 4;
}
Aby sme vedeli lepšie pozorovať, čo sa v programe deje, naučíme sa vypisovať
premenné na obrazovku. Bude na to slúžiť príkaz printf(), ale teraz bude
použitý zložitejšie. Funkcii printf() totiž môžeme do zátvoriek napísať
viac argumentov ako jeden. Prvý argument totiž nemusí byť obyčajný reťazec,
ale môže byť špeciálny formátovací reťazec. Od obyčajného sa líši tým, že
obsahuje podivné značky ako %d %lf %4d a mnohé ďalšie.
Tieto značky sú pri spracovaní funkciou nahradené hodnotami, ktoré určíme v
ďalších argumentoch tejto funkcie.
Vyskúšajte si skompilovať a spustiť nasledovný program.
#include <cstdio>
int main() {
printf("%d + %d = %d\n",4,7,4+7);
}
Mal by vypísať reťazec 4 + 7 = 11. Totiž funkcii printf sme dali
4 argumenty (argumenty oddeľujeme čiarkou) reťazec "%d + %d = %d\n" a
tri výrazy 4, 7 a 4+7 s hodnotami 4, 7 a 11. Funkcia najprv
zoberie prvý argument, ktorý musí byť reťazec, nájde tam všetky výskyty
%<nieco> a nahradí ich hodnotami ďalších argumentov. %d znamená,
že argument bude celé číslo, ktoré chceme vypísať v desiatkovej sústave. O
iných značkách si povieme viac neskôr, slúžia buď na vypisovanie iných typov
objektov (reálne čísla, znaky, reťazce...) alebo na rôzny spôsob ich
vypísania (počet desatinných miest, sústava...).
Keďže premenné sú tiež výrazy, tak môžeme vypisovať ich hodnoty takto:
#include <cstdio>
int main() {
int a;
a = 17;
printf("premenna a ma hodnotu %d\n",a);
}
Alebo bez zbytočných blábolov:
#include <cstdio>
int main() {
int a = 7;
printf("%d\n",a);
}
Všimnite si riadok int a = 7;. Ide o skrátený zápis dvoch príkazov
int a; a = 7. Dá sa to použiť aj pri deklarácií viacerých premenných,
teda int a = 1, b = 2, c = 3; je skrátený zápis pre int a = 1;
int b = 2; int c = 3;
Cvičenie: Skúste na rôznych miestach programu z cvičenia 1 vypísať hodnoty premenných. Všelijako upravujte program a pozorujte, čo sa deje.
K číselným premenným treba poznamenať ešte niekoľko dôležitých vecí. Každá číselná premenná a aj každé číslo má obmedzenú veľkosť.
Napríklad premenná typu int môže mať v sebe uložené len celé číslo od
$-2147483648$ po $2147483647$. Je to preto, že int je v pamäti zapísaný ako
32 jednotiek a núl. Teda si vieme zapamätať len $2^{32}$ rôznych hodnôt. V
prípade premennej typu int sú to hodnoty od $-2^{31}$ po $2^{31}-1$
(záporných čísel je presne polovica, kladných čísel je o 1 menej, kvôli číslu
0).
Cvičenie: Vyskúšajte si spustiť príkaz printf("%d\n", 2147483647 + 1);.
Existujú premenné aj s menším rozsahom, napríklad short int má rozsah
$-32768..32767$ alebo $-2^{15}..2^{15}-1$. char má rozsah $-128..127$
resp. $-2^7..2^7-1$. Premenná typu bool má len dve hodnoty
false resp. 0 (nepravda) alebo true resp. 1 (pravda).
Väčší rozsah majú zasa premenné long long, od $-2^{63}..2^{63}$. Pri ich
vypisovaní však treba dávať pozor, namiesto "%d" treba písať
"%lld" na Linuxe alebo "%I64d" na Windowse.
Existujú aj typy premenných, ktoré neukladajú záporné čísla. Napríklad
unsigned int má rozsah $0..2^{32}-1$. Pri ich používaní musíme byť
obozretní, lebo sa vám môže stať, že mínus jedna je viac ako nula.
(Totiž $-1$ v bezznamienkovom inte bude $4294967295$, kvôli tomu, ako sa
udržujú hodnoty v pamäti.)
Každá hodnota je v pamäti počítača reprezentovaná ako postupnosť núl a
jednotiek — bitov. Osem bitov je jeden bajt. Napríklad int má veľkosť 4
bajty, čiže 32 bitov. char má zase len jeden bajt — 8 bitov. Keď máme v
premennej typu char uložené číslo 47, tak v pamäti počítača to vyzerá
ako 00101111. Rovnaké číslo v premennej typu int vyzerá 00000000
00000000 00000000 00101111.
Poznámka, niektoré počítače alebo systémy majú iné poradie bitov v pamäti.
Čísla sú teda v pamäti napísané v dvojkovej (binárnej) sústave. Tá je veľmi podobná našej desiatkovej (decimálnej), takže sa jej netreba báť. Aby sme sa neplietli, tak teraz chvíľu budeme písať sústavu do dolného indexu, lebo napr. $11_2 \neq 11_{10}$. (Alebo $3_{10} \neq 11_{10}$)
Keď v desiatkovej sústave napíšeme $325_{10}$ myslíme tým tri stovky, dve desiatky a päť jednotiek. V dvojkovej sústave napr. $1101_2$ je jedna osmička, jedna štvorka, žiadna dvojka a jedna jednotka. Dokopy $8+4+0+1 = 13$, teda $1101_2 = 13_{10}$.
Matematicky zapísané, $325_{10} = 3\cdot 100 + 2\cdot 10 + 5\cdot 1$. Ak chceme napísať $325_{10}$ v dvojkovej sústave, musíme použiť namiesto mocnín desiatky ($1$, $10$, $100$, $1000$, ...) mocniny dvojky ($1$, $2$, $4$, $8$, $16$, ...). Teda $325 = 1\cdot 256 + 0\cdot 128 + 1\cdot 64 + 0\cdot 32 + 0\cdot 16 + 0\cdot 8 + 1\cdot 4 + 0\cdot 2 + 1\cdot 1$. Preto $325_{10} = 101000101_2$.
Opačný prevod sme už zvládli vyššie, napríklad ak nás zaujíma hodnota $101111_2$, stačí jednoducho sčítať $1\cdot 1 + 1\cdot 2 + 1\cdot 4 + 1\cdot 8 + 0\cdot 16 + 1\cdot 32 = 47_{10}$.
Cvičenie: Preveďte z desiatkovej sústavy do dvojkovej nasledovné čísla $31$, $200$, $1024$.
Cvičenie: Preveďte z dvojkovej sústavy do desiatkovej čísla $10101$, $100000000$, $1100110011$.
Cvičenie: Sčítajte v binárnej sústave čísla $110110$ a $1111101$. Následne ich preveďte do desiatkovej sústavy a sčítajte v desiatkovej sústave. Výsledok preveďte naspäť do dvojkovej a výsledok overte.
110110 = 54
+ 1111101 = + 125
------- ---
10110011 = 179
Kladné čísla sú v pamäti reprezentované práve v dvojkovej sústave. Keď je číslo
príliš veľké, jednoducho sa zahodia prvé bity — ukážeme si to na príklade.
Premenná typu unsigned char má jeden bajt (8 bitov) a teda je schopná
reprezentovať čísla od 0 po 255. Nie je žiadným prekvapením, že 5 bude
zapamätané ako $00000101$, či $255$ ako $11111111$. Čo sa stane, keď ku $255$
pripočítame 1? Dostaneme $11111111 + 1 = 100000000$. Keďže si môžeme zapamätať
len 8 bitov, musíme prvú jednotku zahodiť. Dostaneme $00000000$, čo je 0.
Preto pri premennej unsigned char $255+1 = 0$ alebo $100\cdot 100 = 16$.
Ale ako je to s premennými ktoré podporujú aj záporné čísla? Kladné čísla sa
reprezentujú tak ako predtým, napríklad v premennej typu char $0 =
00000000$ až $127 = 01111111$.
Čo sa stane, keď od nuly odpočítame 1? $00000000 - 1 = ...11111111111111$ (nekonečné čislo) ale nás zaujíma len posledných 8 bitov, čo je $11111111$. Takže $-1 = 11111111$. Keď ďalej odpočítavame 1 dostávame $-2 = 11111110$, $-3 = 11111101$ ... $-128 = 10000000$.
Super je, že sa nám zachovali logické vlastnosti, napríklad že $-1 + 1 = 0$, $-50 + 40 = -10$, $-31 + 100 = 69$... bez toho, aby sme museli pri práci s binárnym čislom rozlišovať, či je číslo záporné alebo kladné. Jednoducho sčítame čísla pod sebou a ak sa výsledok nezmestí, tak zahodíme prvé bity.
Napr. $-1 + (-1) = 11111111 + 11111111 = 1011111110 \rightarrow 11111110 = -2$.
Tento spôsob reprezentovania záporných čísel sa nazýva aj dvojkový doplnkový kód.
Vtip: "Ľudí môžeme rozdeliť do 10 skupín — tých, ktorí rozumejú binárnej sústave a tých, ktorí jej nerozumejú."
Sčítavať, odčítavať, násobiť, priraďovať, porovnávať... sa dajú len premenné a čísla rovnakých typov. (Všimnite si, že aj čísla (napríklad číslo 45) majú svoje typy.)
Pokiaľ sú pri operácii typy rôzne, treba ich pretypovať a naštastie v
C++ sa mnohé pretypovanie robí automaticky. Napríklad medzi číslami.
int a = 47; char c = a; nie je žiaden veľký problém. (V tajnosti
prebehne jedno pretypovanie, v príkaze c = a, sa a vyhodnotí ako
(int)47, pretypuje sa na (char)47 a následne sa priradí i
c = (char)47.
Pokiaľ pretypujeme z menších premenných do väčších, číslo sa doplní nulami
zľava. (char)19 $= 00010011 \rightarrow 00000000 00000000 00000000 00010011 =$ (int)19
Z väščích do menších, sa zasa zahadzujú prvé bity — pozor pri tomto
pretypovaní sa môže číslo zmeniť. (int)200 $= 00000000 00000000 00000000 11001000 \rightarrow 11001000 =$ (char)(-56) Tento jav sa volá pretečenie.
Bežné čísla, ktoré napíšete v programe majú typ int. Teda aj pri
char a = 20; nastáva pretypovanie z int do char.
Keď niekde napíšete číslo $123\,456\,789\,123$, tak vám pravdepodobne kompilátor
vypíše varovanie, lebo dané číslo je typu int, ale nezmestí sa do jeho
rozsahu. Treba písať 123465789123LL alebo 123456789123ll.
Pri operáciach ako sčítanie, násobenie... na rôznych typoch sa najprv obe čísla pretypujú na všeobecnejší typ, až potom sa spočítajú.
Napríklad ak char a = 20; a int b = 20; tak výsledkom a * b
bude 400.
Treba si dávať pozor na nasledovnú vec.
Cvičenie: Skopírujte, skompilujte a spustite nasledovný program. (Pokiaľ
používate windows, použite miesto %lld %I64d)
#include<cstdio>
int main(){
ll a = 1000000*1000000;
printf("d = %lld\n",d);
}
Čo vypísal? Prečo? Ako by ste ho opravili, aby naozaj vypísal $1\,000\,000\,000\,000$?
Pretypovanie bežne funguje automaticky, ale vieme ho spôsobovať aj ručne.
Syntax je (<typ>)<hodnota> alebo <typ>(hodnota) alebo použijeme
obe dvojice zátvoriek.
Cvičenie: Aké budu hodnoty v a, b po nasledovných priradeniach?
int a = 1234, b;
b = (char)a;
b = char(a);
b = char(a)*a;
Poznámka, bool nie je číselný typ. Teda bool(int(4)) nie
je 0 hoci posledný bit v zápise 4 je 0. Pre bool platí, že
bool(0) je false (resp. 0), všetky ostatné čísla sa zmenia na
true (resp. 1).
Ku číslam sa hodí spomenúť ešte dve číselné operácie, delenie / a zvyšok
po delení %.
Keď pracujeme s celými číslami, tak chceme aby aj podiel bol celé číslo. Preto sa výsledok vždy zaokrúhľuje smerom k nule. $3/2$ nie je $1.5$ ale $3/2 = 1$, $11/3 = 3$, $14/7 = 2$, $-15/3 = -5$, $-100/3 = -33...$
Zvyšok po delení určite poznáte so základnej školy, dá sa definovať ako $a \% b = a - (a/b)\cdot b$. Napríklad $47 \% 10 = 47 - 47/10\cdot 10 = 47 - 4\cdot 10 = 47 - 40 = 7$, $-5 \% 3 = -2$.