Stručný obsah Předmluva 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26.
Úvod do programování v jazyce C++ Celočíselné datové typy Datové typy pro reálná čísla Základní řídicí příkazy Iterační příkazy Pole Základy používání funkcí Ukazatele a odkazy Pokročilé používání funkcí Ukazatelová aritmetika Znaky Řetězce Datové typy – shrnutí a doplnění Příklady použití struktur Operátory – shrnutí a doplnění Direktivy, paměťové třídy, modulární programování Základy objektově orientovaného programování Třída string Dědičnost Výjimky Přetěžování operátorů Proudová knihovna a práce se soubory Šablony Abstraktní datové typy (ADT) Zbývající informace k operátorům jazyka C++ Parametry a návratová hodnota programu
A. Základní algoritmy řazení Slovo závěrem Seznam doporučené literatury pro další studium Rejstřík
11 15 33 63 79 97 113 127 149 173 197 207 223 247 261 287 301 329 373 379 403 425 449 473 501 539 553 559 585 587 589
3
K2335_sazba.indd 3
18.12.2017 9:29:28
K2335_sazba.indd 4
18.12.2017 9:29:29
Obsah Předmluva
11
KAPITOLA 1
Úvod do programování v jazyce C++ Základní pojmy IDE – integrované vývojové prostředí První program Pár zajímavostí Rozdělení základních datových typů
15 16 20 25 31 32
KAPITOLA 2
Celočíselné datové typy Celá čísla Celá čísla bez znaménka Celá čísla se znaménkem Charakteristiky celočíselných datových typů Uložení vícebajtových proměnných v paměti Základní vstupně-výstupní operace Pokročilejší operace s proměnnými a proudy Aritmetické operace s celými čísly Pokročilé použití aritmetiky Zadávání číselných literálů v různých soustavách Celočíselné datové typy dle standardu C99
33 34 34 37 39 40 40 45 49 52 58 59
KAPITOLA 3
Datové typy pro reálná čísla Vlastnosti datových typů pro reálná čísla v jazyce C/C++ Vstupně-výstupní operace z pohledu reálných čísel Aritmetické operace s reálnými čísly Implicitní a explicitní typové konverze Priorita a asociativita dosud probraných operátorů Funkce z matematické knihovny
63 65 68 70 71 75 76
KAPITOLA 4
Základní řídicí příkazy Konstrukce logických výrazů Vývojové diagramy Podmíněný příkaz if Používání bloků Složitější větvení Podmíněný příkaz switch
79 79 84 85 87 88 90
5
K2335_sazba.indd 5
18.12.2017 9:29:29
Obsah
Použití příkazu switch bez příkazu break Kdy nejde příkaz switch použít Zkrácené vyhodnocování logického výrazu Podmínkový operátor
92 93 94 95
KAPITOLA 5
Iterační příkazy Cyklus while – cyklus s podmínkou na začátku Cyklus do..while – cyklus s podmínkou na konci Cyklus for – cyklus s určeným počtem opakování Break – předčasné ukončení cyklu Continue – vynechání jednoho kroku cyklu Příklady
97 97 99 103 105 106 107
KAPITOLA 6
Pole Deklarace pole Inicializace prvků pole Základní operace s poli Konstanty Příklady použití polí Pokročilejší příklady Míříme k funkcím!
113 113 114 115 116 117 120 125
KAPITOLA 7
Základy používání funkcí Výhody používání funkcí Obecný zápis funkce Předávání parametrů hodnotou Návratová hodnota Příklady Dopředná deklarace funkce Základní knihovní funkce jazyka Globální a lokální data Rekurze Datová struktura zásobník
127 127 127 128 129 130 134 135 137 138 143
KAPITOLA 8
Ukazatele a odkazy Deklarace proměnné typu ukazatel Reference proměnné Dereference ukazatele Další informace k ukazatelům Dynamická alokace paměti Některé triky s ukazateli Odkazy (reference)
149 149 150 150 152 153 156 166
6
K2335_sazba.indd 6
18.12.2017 9:29:29
Obsah
KAPITOLA 9
Pokročilé používání funkcí Předávání parametrů funkce přes ukazatel – výstupní parametry Předávání parametrů funkce odkazem – výstupní parametry podruhé Implicitní parametry funkcí Přetížení jména funkce Inline funkce (řádkové funkce, též vložené funkce) Zásobník a jeho souvislost s funkcí Volací konvence Ukazatel na funkci Funkce s proměnlivým počtem parametrů Extern „C“ Nepoužité parametry
173 173 175 177 181 183 185 186 188 191 193 194
KAPITOLA 10
Ukazatelová aritmetika Souvislost ukazatele a pole Problémy s používáním polí ve funkcích
197 200 202
KAPITOLA 11
Znaky Datový typ char Funkce pro práci se znaky Vstup a výstup znaků Lokalizace Datový typ wchar_t
207 207 209 212 218 221
KAPITOLA 12
Řetězce Datový typ char* Funkce pro práci s řetězci Vstup a výstup řetězců Objektová podpora řetězců Pole řetězců Řazení pole řetězců Dynamická alokace pole řetězců Řetězce širokých znaků
223 223 228 232 234 234 238 242 244
KAPITOLA 13
Datové typy – shrnutí a doplnění Definice nového datového typu Přehled datových typů Datový typ enum – výčet Datový typ struct – sktruktura Datový typ union – sjednocení (unie) Datový typ bitové pole Datový typ class – třída
247 247 247 248 249 253 256 258
7
K2335_sazba.indd 7
18.12.2017 9:29:29
Obsah
KAPITOLA 14
Příklady použití struktur Vlastnosti struktur v jazyce C++ Komplexní číslo Implementace zásobníku pomocí struktury Spojový seznam řízený strukturou Spojový seznam řešený metodami Porovnání statické a dynamické alokace struktur
261 261 263 268 272 280 284
KAPITOLA 15
Operátory – shrnutí a doplnění Rozdělení operátorů Ternární operátor Bitové operátory Operátory přiřazení Operátor čárka (operátor zapomenutí) Selektory Souhrnná tabulka priority a asociativity operátorů Přetěžování operátorů
287 287 288 289 292 292 297 299 299
KAPITOLA 16
Direktivy, paměťové třídy, modulární programování 301 Direktivy (příkazy preprocesoru) Paměťové třídy Modifikátory const a volatile Modulární programování Prostory jmen (jmenné prostory)
301 309 312 314 322
KAPITOLA 17
Základy objektově orientovaného programování Definice třídy Problematika zapouzdření a inline metody Konstruktory Destruktor Dědičnost – základní informace Ukazatel this Spřátelení Konstantní členy Statické členy Vložené datové typy Statická a dynamická alokace objektu Diagram třídy
329 330 334 336 339 346 351 356 358 362 367 370 370
8
K2335_sazba.indd 8
18.12.2017 9:29:29
Obsah
KAPITOLA 18
Třída string
373
Stručný popis Příklad
373 376
KAPITOLA 19
Dědičnost Úvodní příklad PROG_01 Podrobnější pohled na dědičnost Polymorfní pole Časná a pozdní vazba RTTI – dynamická identifikace typů Specifické operátory pro přetypování Abstraktní třída a čisté virtuální metody Vícenásobná dědičnost
379 379 383 384 386 387 389 392 401
KAPITOLA 20
Výjimky Výjimka je třída aneb hierarchie standardních výjimek Příklad PROG_01 – vylepšení třídy TClovek, výjimka range_error Příklad PROG_02 – výjimka typu int Příklad PROG_03 – použití vlastní výjimky Příklad PROG_04 – vylepšení třídy TIntArray Příklad PROG_05 – zachycení pomocí bázové třídy Nezachycené a neočekávané výjimky Pokročilejší obsluha výjimek
403 404 405 407 408 410 413 414 421
KAPITOLA 21
Přetěžování operátorů Pravidla pro přetěžování operátorů Přetížení operátoru přiřazení (provedení hluboké kopie) Přetížení insertoru Příklady Informace o operátorech new a delete Přetížení operátoru přetypování
425 425 430 430 431 440 446
KAPITOLA 22
Proudová knihovna a práce se soubory Hierarchie proudů Standardně deklarované proudy Metody proudů ios, istream a ostream Souborové proudy Příklady použití souborových proudů Řetězcové (paměťové) proudy Definice proudových manipulátorů
449 449 450 450 453 455 463 466
9
K2335_sazba.indd 9
18.12.2017 9:29:29
Obsah
KAPITOLA 23
Šablony Genericita Šablony funkcí Šablony objektových typů a jejich metod Standardní knihovna šablon STL
473 473 473 480 485
KAPITOLA 24
Abstraktní datové typy (ADT) Rozdělení datových typů Signatury operací a axiomy Vložené datové typy ADT seznam ADT polymorfní seznam ADT zásobník ADT fronta ADT seznam s ukazovátkem Implementace Testovací příklad
501 501 502 503 503 506 512 520 528 532 536
KAPITOLA 25
Zbývající informace k operátorům jazyka C++ Ukazatel do třídy „Chytré“ ukazatele Souhrnná tabulka operátorů jazyka C++
539 539 543 550
KAPITOLA 26
Parametry a návratová hodnota programu Parametry argc a argv Návratová hodnota Program na kopírování souborů
553 553 555 555
DODATEK A
Základní algoritmy řazení Selectsort Insertsort Bubblesort Quicksort Heapsort Test řadicích algoritmů
Slovo závěrem Seznam doporučené literatury pro další studium Rejstřík
559 560 561 562 563 565 577
585 587 589
10
K2335_sazba.indd 10
18.12.2017 9:29:29
KAPITOLA
Datové typy pro reálná čísla
3
V této kapitole: Vlastnosti datových typů pro reálná čísla v jazyce C/ C++ Vstupně/výstupní operace z pohledu reálných čísel Aritmetické operace s reálnými čísly Implicitní a explicitní typové konverze Priorita a asociativita dosud probraných operátorů Funkce z matematické knihovny
V kapitole 2 jsme se seznámili s celočíselnými datovými typy. Pro uložení číselných hodnot ve velkém rozsahu obvykle nepožadujeme tak velkou přesnost, jakou nám poskytují celá čísla. Obvykle vystačíme s přesností například 6 desítkových číslic. Pro reprezentaci reálných čísel pak používáme datové typy obecně označované jako čísla v plovoucí řádové čárce (anglicky float-point). Takové číslo je reprezentováno dvěma složkami: mantisou a exponentem. Mantisa (M) je hodnota čísla, exponent (E) určuje řád. Viz tento předpis (pro desítkovou soustavu): reálné číslo = M ⋅ 10E
Příklady zápisů čísel v tomto formátu: 1,602·10-19 (elementární náboj); 6,023·1023 (Avogadrova konstanta).
Standard IEEE 754 Tento standard byl vyvinut již roku 1985 a stal se obecným standardem pro čísla v plovoucí řádové čárce. Postupně bylo zavedeno několik formátů čísel v plovoucí řádové čárce. Běžně se používají formáty šíře 16, 32, 64, 80, 128, 256 bitů. Na úrovni jazyka C/C++ se pak používají formáty označované jako single, double a extended:
63
K2335_sazba.indd 63
18.12.2017 9:29:40
KAPITOLA 3 Datové typy pro reálná čísla
Single – jednoduchá přesnost, šíře 32 bitů, hodnotu čísla stanovíme pomocí vzorce: A = (−1)S ⋅ 1, M ⋅ 2E-127. Ĝádová þ árka pro mantisu i exponent s
E
M
1b
8 bitĤ
23 bitĤ
Obrázek 3.1 Formát 32bitového čísla v plovoucí řádové čárce (single)
Double – dvojnásobná přesnost, šíře 64 bitů, hodnotu čísla stanovíme pomocí vzorce: A = (−1)S ⋅ 1, M ⋅ 2 E-1023. s
E
M
1b
11 bitĤ
52 bitĤ
Obrázek 3.2 Formát 64bitového čísla v plovoucí řádové čárce (double)
Extended – rozšířená dvojnásobná přesnost, šíře 80 bitů, hodnotu čísla stanovíme pomocí vzorce: A = (−1)S ⋅ 1, M ⋅ 2 E-16 384. s
E
M
1b
15 bitĤ
64 bitĤ
Obrázek 3.3 Formát 80bitového čísla v plovoucí řádové čárce (extended)
V obrázcích 3.1 až 3.3 mají symboly následující význam: s – znaménko čísla, E – exponent uložený v posunutém kódu, M – mantisa uložená v kódu se skrytou jedničkou (celá mantisa je 1,M), tímto způsobem se rozsah mantisy zvýší o jeden bit. Některé kombinace jsou vyhrazeny pro reprezentaci zvláštních stavů, například: nekonečno – E = samé 1, M = samé 0, s = 0/1 (kladné i záporné nekonečno), NaN (Not A Number, česky není číslo) – E = samé 1, M = nenulové číslo, používá se pro uložení výsledku pro případy operací: 0/0, ∞/∞, √(–1), ... Realizace operací s čísly v plovoucí řádové čárce vyžaduje značnou výpočetní podporu. Připomeňme, že jednodušší procesory nemají podporu pro operace s čísly v plovoucí řádové čárce implementovánu na hardwarové úrovni. Veškeré výpočty s těmito čísly jsou pak realizovány programově a představují pro procesor nezanedbatelné zpoždění. Naproti tomu procesory doplněné koprocesorem nebo procesory s integrovanou jednotkou FPU (float-point unit, jednotka pro výpočty v plovoucí řádové čárce) mají pro práci s čísly
64
K2335_sazba.indd 64
18.12.2017 9:29:40
Vlastnosti datových typů pro reálná čísla v jazyce C/C++
v plovoucí řádové čárce hardwarovou podporu, takže doba výpočtu může být srovnatelná s celočíselnou aritmetikou.
Vlastnosti datových typů pro reálná čísla v jazyce C/C++ K dispozici jsou tři datové typy pro operace s čísly v plovoucí řádové čárce: float, double a long double, které se liší oborem hodnot. Tyto typy se také liší velikostí v bajtech a přesností, která je určena počtem platných cifer (číslic). Tabulka 3.1 Vlastnosti datových typů pro reálná čísla Typ
Přibližný obor hodnot
float odpovídá single (viz obr. 3.1), velikost: 4 bajty, přesnost: 6 platných desítkových cifer
±1,2×10–38 až ±3,4×10+38
double odpovídá double (viz obr. 3.2), velikost: 8 bajtů, přesnost: 15 platných desítkových cifer
±2,2×10–308 až ±1,8×10+308
long double odpovídá extended (viz obr. 3.3), velikost: 16 bajtů, přesnost: 18 platných desítkových cifer
±3,4×10–4932 až ±1,2×10+4932
Charakteristiky těchto typů jsou stručně shrnuty v tabulce 3.1. Jelikož jsou mantisa a exponent uloženy v binární podobě, je uváděn pouze přibližný obor hodnot v desítkové soustavě. Podobně uváděná přesnost mantisy v počtu desítkových cifer je zaokrouhlena dolů na nejbližší celé číslo. Rovněž můžeme vysledovat jistou nesymetrii oboru hodnot pro nejnižší a nejvyšší hodnoty. Poněkud zvláštní je typ long double. Řada implementací jazyka C/C++ používá pro realizaci tohoto typu rozšířenou dvojitou přesnost (extended), která historicky pochází z koprocesoru Intel 8087. Tento typ standardně zabírá 80 bitů, tedy 10 bajtů. Z principiálních důvodů je však pro proměnnou long double tradičně alokováno ne 10, ale 16 bajtů. Důvodem je tzv. zarovnávání paměti. Přístup procesoru do datové paměti totiž probíhá obvykle v blocích, které jsou násobkem 4 bajtů. Některé překladače řeší tento problém implementací dvou variant pro reálná čísla v přesnosti větší než double. Například se můžeme setkat s typy __float80 a __float128. Typ __float80 odpovídá přesnosti extended, přesto však v paměti zabírá 16 bajtů. Typ __float128 odpovídá přesnosti quadruple (čtyřnásobná přesnost), v paměti zabírá také 16 bajtů.
65
K2335_sazba.indd 65
18.12.2017 9:29:40
KAPITOLA 3 Datové typy pro reálná čísla
Zápis literálů a charakteristiky typů Formát zápisu reálných literálů v desetinném tvaru se vyznačuje používáním tečky místo obvyklé desetinné čárky, například: 1.2345. Reálné literály lze také zapisovat v semilogaritmickém tvaru, například: 1.602E-19. Literály reálných čísel jsou standardně brány ve dvojnásobné přesnosti (double). Pro rozlišení literálů v různé přesnosti používáme přípony: F nebo f pro typ float, D nebo d pro typ double a L nebo l pro typ long double. Přesné charakteristiky datových typů pro čísla v plovoucí řádové čárce lze získat pomocí symbolů z hlavičkového souboru FLOAT.H (resp. CFLOAT v jazyce C++). Vybrané symboly jsou uvedeny v tabulce 3.2. Tabulka 3.2 Vybrané charakteristiky čísel v plovoucí řádové čárce Symbol
Význam
FLT_DIG
počet platných desítkových cifer typu float
FLT_MIN
minimální hodnota typu float
FLT_MAX
maximální hodnota typu float
DBL_DIG
počet platných desítkových cifer typu double
DBL_MIN
minimální hodnota typu double
DBL_MAX
maximální hodnota typu double
LDBL_DIG
počet platných desítkových cifer typu long double
LDBL_MIN
minimální hodnota typu long double
LDBL_MAX
maximální hodnota typu long double
Níže je doplněn krátký program, který pro každý z uvedených typů vypíše postupně: velikost v bajtech, počet platných desítkových číslic, minimální a maximální hodnotu. Můžete tyto údaje porovnat s tabulkou 3.1. Dále je deklarována globální konstanta pi (není deklarována v rámci žádné funkce, proto je k dispozici v celém zdrojovém souboru). Hodnota této konstanty odpovídá Ludolfovu číslu π. Nakonec jsou vypsány velikosti typů __float80 a __float128. PROG_01: #include <iostream> #include <float.h> using namespace std; const double pi=3.14159265; int main(int argc, char** argv) { cout<<“sizeof(float)=“<<sizeof(float)<<endl; cout<<“FLT_DIG=“<<FLT_DIG<<endl; cout<<“FLT_MIN=“<<FLT_MIN<<endl;
66
K2335_sazba.indd 66
18.12.2017 9:29:40
Vlastnosti datových typů pro reálná čísla v jazyce C/C++
cout<<“FLT_MAX=“<<FLT_MAX<<endl; cout<<endl; cout<<“sizeof(double)=“<<sizeof(double)<<endl; cout<<“DBL_DIG=“<<DBL_DIG<<endl; cout<<“DBL_MIN=“<<DBL_MIN<<endl; cout<<“DBL_MAX=“<<DBL_MAX<<endl; cout<<endl; cout<<“sizeof(long double)=“<<sizeof(long double)<<endl; cout<<“LDBL_DIG=“<<LDBL_DIG<<endl; cout<<“LDBL_MIN=“<<LDBL_MIN<<endl; cout<<“LDBL_MAX=“<<LDBL_MAX<<endl; cout<<endl; cout<<“pi=“<<pi<<endl; cout<<“sizeof(__float80)=“<<sizeof(__float80)<<endl; cout<<“sizeof(__float128)=“<<sizeof(__float128)<<endl; return 0; }
Výpis programu v konzoli: sizeof(float)=4 FLT_DIG=6 FLT_MIN=1.17549e-038 FLT_MAX=3.40282e+038 sizeof(double)=8 DBL_DIG=15 DBL_MIN=2.22507e-308 DBL_MAX=1.79769e+308 sizeof(long double)=16 LDBL_DIG=18 LDBL_MIN=3.3621e-4932 LDBL_MAX=1.18973e+4932 pi=3.14159 sizeof(__float80)=16 sizeof(__float128)=16
Poznámka: Výpis proměnné pi je zaokrouhlen na 6 cifer přesto, že typ double má přesnost 15 cifer. Jedná se pouze o výchozí nastavení formátu pro výpis reálných čísel. Níže se dozvíme, jak lze formát výpisu upravit.
67
K2335_sazba.indd 67
18.12.2017 9:29:41
KAPITOLA 3 Datové typy pro reálná čísla
Vstupně-výstupní operace z pohledu reálných čísel Informace ke vstupně-výstupním operacím z kapitoly 2 můžeme nyní rozšířit o přehled dalších manipulátorů a doplnit informacemi, které platí pro reálná čísla. Při výpisu hodnoty můžeme nastavit parametry, které určí, jak přesně výpis proběhne: šířka – určuje minimální počet znaků, které se mají vypsat. Uvažujme například výpis čísla 56 na 5 míst. V tomto případě je třeba přidat další 3 znaky, aby celková šířka výpisu byla 5 znaků. Znak, který se použije jako výplň, je obvykle mezera (je možné jej ale změnit pomocí parametru výplňový znak). Pokud uvažujeme výpis čísla 56 v šířce 0, vypíše se prostě 56 (výpis hodnoty nesmí být zkreslen). Šířku nastavuje manipulátor setw. přesnost – určuje počet číslic za desetinnou tečkou, které se zobrazí. Například výpis čísla π (3,14159265 …) při šířce 5 a přesnosti 3 vypadá takto: 3.142 (při výpisu probíhá nezbytné zaokrouhlení); platí pro formáty fixed a scientific. Přesnost nastavuje manipulátor setprecision. výplňový znak – určuje znak, který se použije jako výplň při výpisu hodnoty ve větší šířce; jako výchozí výplňový znak je použita mezera. Výplňový znak nastavuje manipulátor setfill. zarovnávání – určuje způsob zarovnání výpisu hodnoty a místo, kam se budou vkládat výplňové znaky. Rozlišujeme (uvažujme výpis čísla -1 při šířce 5): zarovnání doleva (left) – výpis hodnoty je zarovnán doleva, výplň se vkládá zprava: -1□□□, zarovnání doprava (right) – výpis hodnoty je zarovnán doprava, výplň se vkládá zleva: □□□-1, mezi znaménko a hodnotu (internal) – výpis znaménka je vlevo, následují výplňové znaky a nakonec vypisovaná hodnota: -□□□1. Přehled běžně používaných manipulátorů pro výpis uvádí tabulka 3.3. Na začátku jsou připomenuty dříve popsané manipulátory endl, dec, oct a hex. Tabulka 3.3 Přehled manipulátorů Manipulátor
Použitelnost pro čísla
Význam
endl
celá/reálná
ukončí řádek a nastaví kurzor na začátek následujícího řádku
dec
celá
přepne zobrazení celých čísel do desítkové soustavy
oct
celá
přepne zobrazení celých čísel do osmičkové soustavy
hex
celá
přepne zobrazení celých čísel do šestnáctkové soustavy
showpos
celá/reálná
zajistí zobrazení znaménka i pro nezáporná čísla (kladná čísla včetně nuly)
68
K2335_sazba.indd 68
18.12.2017 9:29:41
Vstupně-výstupní operace z pohledu reálných čísel
Manipulátor
Použitelnost pro čísla
noshowpos
celá/reálná
left
celá/reálná
přepne na zarovnávání doleva (výplň zprava)
right
celá/reálná
přepne na zarovnávání doprava (výplň zleva)
internal
celá/reálná
přepne na vyplnění mezi znaménkem a hodnotou
fixed
reálná
přepne výpis reálných čísel do tvaru s pevnou pozicí desetinné tečky
scientific
reálná
přepne výpis reálných čísel do exponenciálního tvaru
uppercase
celá/reálná
přepne výpis čísel tak, že znaky se zobrazují jako velká písmena (týká se výpisu celých čísel v šestnáctkové soustavě a reálných čísel v exponenciálním tvaru)
nouppercase
celá/reálná
přepne výpis čísel tak, že znaky se zobrazují jako malá písmena (týká se výpisu celých čísel v šestnáctkové soustavě a reálných čísel v exponenciálním tvaru)
setw(w)
celá/reálná
nastaví šířku následujícího výpisu dle w, chybějící znaky do požadovaného počtu jsou realizovány zvolenou výplní (pokud zadání šířky nezopakujeme před každým výpisem, bude mít následující výpis opět šířku 0)
setfill(f)
celá/reálná
nastaví výplňový znak na f (znakové literáry píšeme mezi apostrofy)
setprecision(p) reálná
Význam vypne zobrazení znaménka pro kladná čísla (znaménko se zobrazuje pouze pro záporná čísla)
nastaví výpis reálných čísel na počet desetinných míst daných p
Poslední tři manipulátory jsou parametrické (jsou řízeny parametrem zapsaným v závorkách). Pro použití těchto manipulátorů je nutné do zdrojového textu vložit hlavičkový soubor iomanip: #include <iomanip>
Pro lepší pochopení připojujeme několik příkladů použití výše popsaných manipulátorů pomocí tabulky 3.4. Tabulka 3.4 Příklady formátování výpisu Příklad
Výpis
Vysvětlení
cout<<56;
56
normální výpis kladné hodnoty (bez znaménka +)
cout<<-56;
-56
výpis záporné hodnoty musí vždy obsahovat znaménko –
cout<<showpos<<56;
+56
výpis kladné hodnoty včetně znaménka
cout<<setw(5)<<left<<-56;
-56□□
šířka 5, zarovnání doleva: po výpisu čísla se připojí 2 mezery
cout<<setw(5)<<right<<-56;
□□-56
šířka 5, zarovnání doprava: před výpisem čísla se vloží 2 mezery
cout<<setw(5)<<internal<<-56;
-□□56
šířka 5, zarovnání mezi: mezi znaménko a číslice se vloží 2 mezery
69
K2335_sazba.indd 69
18.12.2017 9:29:41
KAPITOLA 3 Datové typy pro reálná čísla
Příklad
Výpis
Vysvětlení
cout<<fixed<<3.141519265;
3.141519
výpis reálného čísla v desetinném tvaru
cout<<fixed<<setprecision(3) <<3.141519265;
3.142
zobrazí se 3 číslice za desetinnou tečkou (+zaokrouhlení)
cout<<scientific<<setprecision(3) <<3.141519265;
3.142e+000
výpis v exponenciálním tvaru, zobrazí se 3 číslice za desetinnou tečkou (+zaokrouhlení)
cout<<setw(10)<<left<<setfill(‚0‘) <<fixed<<setprecision(3) <<3.141519265;
3.14200000
výpis v desetinném tvaru, 3 platné číslice za desetinnou tečkou, zbytek se doplní nulami do celkové šíře 10 znaků (zarovnání doleva)
cout<<setw(10)<<right<<setfill(‚0‘) <<fixed<<setprecision(3) <<3.141519265;
000003.142
výpis v desetinném tvaru, 3 platné číslice za desetinnou tečkou, vlastní výpis předchází nuly do celkové šíře 10 znaků (zarovnání doprava)
Aritmetické operace s reálnými čísly Pro reálná čísla lze používat běžné aritmetické operátory stejné jako pro celá čísla. Jsou zde však dva drobné rozdíly: 1.
Operátor % (modulo, zbytek po celočíselném dělení) nemá pro aritmetiku reálných čísel smysl, jeho použití s reálným číslem je chápáno jako chyba.
2.
Operátor / (dělení) má v reálné aritmetice smysl reálného dělení, tedy například výraz 5.0/2.0 má výsledek 2,5.
Přehled operátorů použitelných pro reálná čísla je uveden v tabulkách 3.5 a 3.6. V tabulce 3.5 jsou běžné binární operátory (mají levý a pravý operand), v tabulce 3.6 jsou unární operátory (mají pouze jeden operand). Tabulka 3.5 Základní aritmetické operátory Operátor
Příklad zápisu
Význam
+
x+y
součet dvou čísel uložených v proměnných x a y
–
x–y
rozdíl dvou čísel uložených v proměnných x a y
*
x*y
součin dvou čísel uložených v proměnných x a y
/
x/y
podíl dvou čísel uložených v proměnných x a y
Tabulka 3.6 Unární aritmetické operátory Operátor
Příklad zápisu
Význam
+
+x
kladné znaménko čísla
–
–y
záporné znaménko čísla (násobení –1)
++
x++ nebo ++x
x++ postinkrement, ++x preinkrement
––
x–– nebo ––x
x–– postdekrement, ––x predekrement
70
K2335_sazba.indd 70
18.12.2017 9:29:41
Implicitní a explicitní typové konverze
Implicitní a explicitní typové konverze Při práci s různými datovými typy se často nevyhneme konstrukci, kde v rámci jednoho výrazu použijeme proměnné nebo literáry různých číselných typů (doplníme nyní informace ke kapitole 2). Vznikají pak tyto otázky: Jak překladač tento problém řeší? V jaké aritmetice se počítá? Může dojít k chybnému vyhodnocení výrazu? Překladač může provádět dva základní typy převodů (konverzí) dat: Implicitní typová konverze – slovem implicitní označujeme případ, kdy k převodu dochází automaticky; překladač použije implicitní převod v případě, kdy je to nezbytně nutné. Explicitní typová konverze – slovem explicitní označujeme případ, kdy je převod vynucen programátorem tak, že ho v programu předepíše pomocí operátoru přetypování.
Implicitní typové konverze K implicitní typové konverzi dochází v níže uvedených případech: 1.
Konverze samostatných operandů: Před vyhodnocením výrazu se samostatné operandy převádějí takto: char nebo short
se konvertují na int, unsigned char nebo unsigned short se konvertují na int (pokud int může reprezentovat jejich hodnotu, tzn. nepřeteče) nebo na unsigned int (pokud se nezdařila konverze na int). 2.
Binární operace: Pokud mají operandy binární operace různý typ, konvertuje se typ operandu s nižší prioritou na typ operandu s vyšší prioritou. Priorita je pevně dána (typy char a short se nejdříve konvertují na int), viz obrázek 3.4 (typ int má nejnižší prioritu): int unsigned int long unsigned long long long unsigned long long float double long double
Obrázek 3.4 Priorita pro konverzi operandů binární operace 3.
Převod vynucený přiřazením: V přiřazovacích příkazech je typ na pravé straně konvertován na typ na levé straně. Pokud překladač takovou konverzi nedokáže provést, označí daný řádek programu jako chybný.
71
K2335_sazba.indd 71
18.12.2017 9:29:41
KAPITOLA 3 Datové typy pro reálná čísla
Vysvětlující příklad – Uvažujeme tyto proměnné: int a; float b=3.3; short c=2;
A nyní, jak se vyhodnotí výraz: a=b*c;
Bude se postupovat v těchto krocích: Použije se pravidlo pro samostatné operandy. Operand b je typu short a proto se převede na hodnotu typu int. Operand c je typu float a převádět se nebude. 2. Operátorem * je předepsána binární operace. Operand c je typu float a má tak vyšší prioritu. Proto se operand b dříve převedený na typ int převede ještě jednou a to na typ float. Výsledkem operace je hodnota 6.6. 3. Nyní se výsledek výrazu přiřazuje do proměnné a, která je typu int. Použije se pravidlo pro přiřazení. Reálná hodnota 6.6 se převede na celé číslo tak, že se odsekne desetinná část (pozor: nezaokrouhluje se!). Výsledek je tedy 6 a je to hodnota typu int. Je-li třeba provést při převodu z reálného čísla na celé zaokrouhlení, přičteme k zaokrouhlovanému číslu 0,5. Například: a=b*c+0.5;. Hodnota 6,6 je tedy zvýšena na 7,1 a po odseknuté desetinné části je výsledek zaokrouhlen na 7. 1.
Možné problémy implicitních převodů Převod z nižšího na vyšší typ (tzv. povýšení) je bez problémů. Nedochází ke ztrátě uložené informace, pouze se změní datový typ uložené hodnoty. Problémy přináší převod z vyššího typu na nižší typ. Zde může v některých případech dojít ke ztrátě (zkreslení) údaje. Uvažujme níže uvedený příklad. PROG_02: #include <iostream> using namespace std; int main(int argc, char** argv) { int a=123456; short b=a; cout<<b<<endl; return 0; }
Výpis programu v konzoli: -7616
72
K2335_sazba.indd 72
18.12.2017 9:29:41