{
#inclu ude de <s <stdi tdio td io.h h>
/* * Imp m po or rt m ma ate em ma at ti ické ic ého hl hlav vič ičk ko o vé h #i inc clu lude <m <mat at a th.h> >
#inclu #in cl de <s clu cl <s dio <stdio io io.h o.h> .h h> h>
/* / * Defi De efi n ni ničn ič ční čn ní í i in inici nici ic ci c iali i int t m ai ain() () flo fl oat at pi pi = 3 3.1 3. . 415 15 5f f; ; { /* Defi /* efin ni ic ce lo loká oká káln l ntí íc cmma ch h p(r prom oměn mě ný nýc ch int i nt main( ain in( npr n( n() ) om { int A A_x, A_ A _ y, B B_x _x _x, x, B_ B_ y; y; un nsi ns ig gn g ne ed int pol int / Defi /* efinice lokáln kál ká ln ní uns p pr rign om o m ědn né, do p print print in ntf( nt f(”Zadejte p f(” doub ble vzd zdal alen nos ost tB Bod odu; u; scanf scanf(”%d”, &pol lo /* Inicial al liza izac iz ace lo ace lokprintf( promě ě pálních printf(” ”Obvod kru uh uh return 0; A_x = 2; A_y = 5; } B_x = 10; B_y = 17; /* Vypočtení vzdálenosti no no mezi d
}
Programování v jazyce C Ján Hanák
Nakladatelství a vydavatelství
w w w. co m p u t e r m e d i a . c z
R
Obsah Obsah
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 27 28 29 30 31 32 33
Úvod ........................................................................................................................................ 6 1. Definice základních termínů ................................................................................................ 8 2. Klasifikace programovacích jazyků .................................................................................... 9 3. Základní paradigmata programování ................................................................................ 10 4. Historie programovacích jazyků C, C++ a C++/CLI ........................................................... 12 5. Spuštění Visual C++ 2010 Express a založení prvního projektu jazyka C ve vývojovém prostředí .................................................................................................... 22 5.1. Instalace produktu Visual C++ 2010 Express a první dotek s vývojovým prostředím .................................. 22 5.2. Visual C++ 2010 Express, programovací jazyky a vývoj softwaru ........................................................................ 24 5.3. Založení prvního projektu jazyka C .............................................................................................................................. 25 5.4. Zdrojový kód prvního programu v jazyce C ........................................................................................................... 29
6. Sestavení programu jazyka C .......................................................................................... 32 7. Spuštění programu jazyka C a charakteristika exekučních modelů jedno- a vícevláknových programů jazyka C ................................................................... 34 7.1. Exekuční modely jedno- a vícevláknových programů ............................................................................................ 39
8. Základní řídící konstrukce strukturovaného programování ............................................ 42 9. Program = data + algoritmy .............................................................................................. 45 9.1. Konstrukce algoritmu pro vypočtení kořenů kvadratické rovnice .................................................................... 46 9.2. Konstrukce algoritmu pro zjištění hmotnostního indexu BMI osoby ................................................................. 47 9.3. Konstrukce algoritmu grafické transformace pro invertování bitové mapy .................................................... 48 9.4. Konstrukce algoritmu pro šifrování otevřeného textu pomocí Cézarovy šifry ......................................... 50
10. Vlastnosti algoritmů ...................................................................................................... 51 11. Výpočetní složitost algoritmů ......................................................................................... 55 11.1. Matematická definice O-notace ................................................................................................................................. 58 11.2. Matematická definice 11.3. Matematická definice
Ω-notace Θ-notace
................................................................................................................................. 58 ................................................................................................................................. 59
12. Prostředky pro reprezentaci algoritmů ............................................................................ 63 13. Datové typy ..................................................................................................................... 71 14. Definice proměnných ...................................................................................................... 75 14.1. Agregovaná definice více proměnných v jednom definičním příkazu .......................................................... 79
15. Přiřazovací příkaz ........................................................................................................... 80 15.1. Definiční inicializace proměnných .............................................................................................................................. 82 15.2. Agregovaná definiční inicializace více proměnných v jednom příkazu .................................................... 83 15.3. Vícenásobné přiřazení .................................................................................................................................................... 85
16. Praktické cvičení: program pro výpočet hmotnostního indexu BMI ............................. 86
3
Programování v jaz yce C 17. Číselné soustavy ............................................................................................................. 92 17.1. Desítková (decimální) číselná soustava ..................................................................................................................... 92 17.2. Osmičková (oktálová) číselná soustava ..................................................................................................................... 92 17.3. Šestnáctková (hexadecimální) číselná soustava .................................................................................................. 93 17.4. Dvojková (binární) číselná soustava .......................................................................................................................... 94
18. Konstanty ......................................................................................................................... 95 18.1. Celočíselné konstanty ...................................................................................................................................................... 95 18.2. Reálné konstanty ................................................................................................................................................................. 95 18.3. Znakové konstanty ............................................................................................................................................................. 97 18.4. Řetězcové konstanty ........................................................................................................................................................... 98
19. Praktické cvičení: program pro vypočtení vzdálenosti mezi dvěma body v rovině ......... 99 20. Globální proměnné .......................................................................................................... 101 21. Konstantní proměnné ..................................................................................................... 104 22. Direktiva preprocesoru #define a definice symbolických konstant .............................. 106 23. Typové konverze ............................................................................................................ 108 23.1. Implicitní typové konverze ........................................................................................................................................... 108 23.2. Explicitní typové konverze ........................................................................................................................................... 110
24. Alokační kapacita proměnných .................................................................................... 113 25. Operátory ....................................................................................................................... 115 25.1. Aritmetické operátory ..................................................................................................................................................... 117 25.2. Operátory pro inkrementaci a dekrementaci ........................................................................................................ 121 25.3. Logické operátory ............................................................................................................................................................ 123 25.4. Relační operátory ............................................................................................................................................................. 124 25.5. Přiřazovací operátory ..................................................................................................................................................... 125 25.6. Bitové operátory ................................................................................................................................................................ 126 25.7. Operátory bitového posunu ....................................................................................................................................... 127
26. Priorita a asociativita operátorů .................................................................................... 130 27. Rozhodovací příkazy ...................................................................................................... 133 27.1. Rozhodovací příkaz if ..................................................................................................................................................... 134 27.2. Rozhodovací příkaz if-else ........................................................................................................................................... 135 27.3. Rozhodovací příkaz if-else if… .................................................................................................................................... 138 27.4. Rozhodovací příkaz if-else if-else ............................................................................................................................... 139 27.5. Praktické cvičení: program na detekci kolize mezi automobilem a chodcem ............................................ 141 27.6. Rozhodovací příkaz switch ......................................................................................................................................... 143 27.7. Dvojcestné rozhodování pomocí ternárního operátoru (?:) ................................................................................ 146
28. Programové cykly ........................................................................................................... 148 28.1. Cyklus for ............................................................................................................................................................................. 148
4
Nadpis kapitoly 28.2. Cyklus while ...................................................................................................................................................................... 153
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 27 28 29 30 31 32 33
28.3. Cyklus do-while ............................................................................................................................................................... 155
29. Funkce ............................................................................................................................ 157 29.1. Praktické cvičení: programy s funkcemi pro přesný a aproximovaný výpočet n! ....................................... 163 29.2. Funkce a statické lokální proměnné ........................................................................................................................ 166
30. Struktury ........................................................................................................................ 169 30.1. Deklarace struktury ........................................................................................................................................................ 171 30.2. Instanciace struktury ....................................................................................................................................................... 172 30.3. Inicializace instance struktury ................................................................................................................................. 173 30.4. Použití inicializované instance struktury .............................................................................................................. 175 30.5. Alokační kapacita instance struktury ...................................................................................................................... 178
31. Pole ................................................................................................................................. 180 31.1. Praktické cvičení: program na vyhledání minimální a maximální hodnoty v jednorozměrném automatickém poli ........................................................................................................................................................... 185 31.2. Kopírování jednorozměrného automatického pole ............................................................................................... 187 31.3. Alokační kapacita jednorozměrného automatického pole ............................................................................... 188 31.4. Jednorozměrné automatické pole instancí struktur ............................................................................................. 190 31.5. Dvojrozměrné automatické pole .............................................................................................................................. 191
32. Ukazatele ....................................................................................................................... 197 32.1. Získání hodnoty ukazatele ............................................................................................................................................ 202 32.2. Přiřazování ukazatelů ..................................................................................................................................................... 203
33. Pokročilá práce s funkcemi .......................................................................................... 205 33.1. Mechanismy předávání argumentů parametrickým funkcím ................................................................... 205 33.2. Rekurze a rekurzivní funkce .................................................................................................................................... 208 33.3. Funkce a pole .................................................................................................................................................................. 210 33.4. Funkce a instance struktur ........................................................................................................................................... 212
Závěr .................................................................................................................................... 214 O autorovi ........................................................................................................................... 214
5
Programování v jaz yce C 3.
Základní paradigmata programování
Za poslední desetiletí se v informatice vyvinula tři základní paradigmata programování: 1. Strukturované (procedurální) programování. Popis: Program je množinou funkcí (někdy též označovaných jako podprogramy), které implementují parciální algoritmy, jež řeší delegované úlohy. Vizualizace:
Obr. 1: Grafi cký model strukturovaného programu
10
3. Základní paradigmata programování 2. Objektově orientované programování (OOP).
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 27 28 29 30 31 32 33
Popis: Program je kolekcí diskrétních virtuálních objektů. Virtuální objekt je abstraktním modelem reálného objektu skutečného světa, přičemž v sobě zapouzdřuje data a metody. Objekty mezi sebou komunikují prostřednictvím zpráv. Vizualizace:
Obr. 2: Grafi cký model objektově orientovaného programu
3. Komponentové programování. Popis: Program je sadou komponent. Komponenta je softwarová součástka, která disponuje vyšší úrovní abstrakce a zavádí pokročilou funkcionalitu. Interně je každá komponenta složena z konečné a neprázdné množiny objektů, které mezi sebou vedou informačně prospěšný dialog. Vizualizace:
Obr. 3: Grafi cký model komponentového programu
11
7. Spuštění programu jazyka C 7.1.
Exekuční modely jedno- a vícevláknových programů
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 27 28 29 30 31 32 33
Jedno- a vícevláknové programy se liší svými exekučními modely. Exekuční model neboli model zpracování programu nám umožňuje zkoumat, jak budou prováděny algoritmy, jež program implementuje. Teorie programování rozlišuje následující exekuční modely jedno- a vícevláknových programů: 1. Sekvenční exekuční model. Sekvenční exekuční model je typický pro jednovláknové programy. Jak jsme již zmínili, jednovláknový program realizuje zpracování algoritmů sekvenčně, tedy na sériové bázi. Bez ohledu na to, na jak výkonném počítačovém systému jednovláknový program spustíme, program bude obsazovat pouze jedno z dostupných výpočetních jader procesoru. Na jednojádrovém procesoru je takovéto rozvržení pochopitelné. Pokud ovšem máme vícejádrový procesor, tak zjišťujeme, že jednovláknový program se sekvenčním exekučním modelem není schopen využít všechnu výpočetní kapacitu takto dimenzovaného procesoru. Při 4jádrovém procesoru budou tři výpočetní jádra nevyužita, a to samozřejmě není to, co bychom chtěli. V informatice a v programování obecně je naším cílem vytvářet takové programy, které se dovedou přizpůsobit jakékoliv hardwarové platformě a umí z ní vytěžit maximální porci výkonu.
Obr. 14: Vizualizace sekvenčního exekučního modelu
2. Pseudoparalelní exekuční model. Pseudoparalelní exekuční model se vztahuje k vícevláknovým programům. Jelikož se nechceme pouštět do rigorózních vědeckých analýz, přijmeme domluvu, podle níž budeme říkat, že vícevláknové programy jsou zpracovávány pseudoparalelně tehdy, pokud běží na počítačovém systému, jenž obsahuje jeden jednojádrový procesor. Když je něco „pseudo“, tak se to tváří jinak, než jak to ve skutečnosti je. Pseudoparalelní zpracování tedy není skutečně paralelní, jenom z vnějšku, z pohledu vnějšího pozorovatele se zdá, že paralelní je. Pseudoparalelní zpracování vícevláknového programu na jednoprocesorovém systému probíhá iterativním preemptivním stylem, v němž procesor střídavě provádí instrukce všech programových vláken.
39
Programování v jaz yce C 8.
Základní řídící konstrukce strukturovaného programování
Kterýkoliv strukturovaný program můžeme vytvořit pouze s třemi základními řídícími konstrukcemi, jimiž jsou sekvence, selekce a iterace. Sekvence znamená postupné zpracování lineární posloupnosti programových příkazů. Tyto příkazy jsou realizovány sekvenčně, tedy jeden za druhým, a to v takovém pořadí, v jakém jsou zapsány ve zdrojovém kódu programu.
Obr. 18: Sekvence
Na obr. 18 vidíme sekvenční zpracování třech programových příkazů P1, P2 a P3. Nejprve je zpracován příkaz P1, poté příkaz P2 a nakonec příkaz P3. Selekce je základní rozhodovací konstrukce. Na základě rozhodovacího výrazu může program přijmout v určitém čase rozhodnutí o tom, jaký bude jeho další průběh. Když je v programu diagnostikována rozhodovací řídící konstrukce, existuje více variant dalšího toku programu. Říkáme, že program se větví. Větvení programu představuje existenci konečné a neprázdné množiny cest, jimiž se smí zpracování programu ubírat. Selekce je vždy jednoznačná a deterministická. To se projevuje v tom, že program si po přijetí rozhodnutí (tedy po vyhodnocení rozhodovacího výrazu) vybere právě jednu z možných větví a tou bude pokračovat dál.
Obr. 19: Selekce se dvěma větvemi (dvojcestné rozhodování)
42
10. Vlastnosti algoritmů 10. Vlastnosti algoritmů
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 27 28 29 30 31 32 33
Na předchozích řádcích jsme nadnesli zjednodušenou definici algoritmu, podle níž jsme za algoritmus považovali jakýkoliv postup složený z konečného počtu kroků, který nás dovede k určitým výsledkům. Ve skutečnosti jsou však na algoritmy kladeny mnohem rigoróznější požadavky, které zřetelně definují, jaké vlastnosti musí algoritmus mít. Za algoritmus je obecně považován pouze takový postup, který splňuje následující kritéria: 1. Všeobecnost. Algoritmus je předpis, který vede k řešení všeobecné kategorie neboli třídy úloh (problémových oblastí). Kupříkladu algoritmus pro řešení kvadratické rovnice se dá použít pro nalezení kořenů jakékoliv rovnice, která disponuje kvadratickým, lineárním a absolutním členem. Totéž lze konstatovat o algoritmu pro výpočet indexu BMI. Pomocí zmíněného algoritmu je možné vypočítat hmotnostní index jakéhokoliv člověka, autora této knihy či ctěného čtenáře nevyjímaje. Algoritmy tedy mají generickou povahu, mění se pouze vstupní data a vypočtené výsledky. 2. Jednoznačnost. Každý algoritmus musí být jednoznačný, což znamená, že v kterémkoliv jeho kroku musí být jasně předepsáno, jak se bude postupovat dál. Není jednoduše možné, abychom měli algoritmus, který si v jistém okamžiku nebude „vědět rady“ s dalším postupem. Algoritmická jednoznačnost znamená, že algoritmus se musí za každých okolností umět rozhodnout, jakou činnost vykoná v příštím kroku. Definice algoritmu z hlediska jednoznačnosti musí být absolutně přesná: algoritmus nesmí zůstat na pochybách ani tehdy, když před ním vyvstane několik variant dalšího postupu. Oba uváděné algoritmy jsou jednoznačné. Kupříkladu když vypočteme hodnotu diskriminantu, dovedeme určit, zda bude množina kořenů kvadratické rovnice prázdná, či nikoliv. Stejně tak nám nečiní potíže vynést soud o hmotnosti osoby, když jsme pomocí vzorečku vypočetli její hmotnostní index. 3. Konečnost. Za algoritmus je dle definice považován pouze takový postup, který je složen z konečného počtu elementárních kroků. Těch kroků, které musí algoritmus provést v zájmu dosažení výsledku, může být třeba 10, 100 nebo milion, ale vždy se musí jednat o konečnou cifru. Postup, který se nedovede k výsledku dopracovat po absolvování konečného počtu kroků, nemůžeme nazývat algoritmem. Například nelze sestrojit algoritmus pro výpočet součtu všech přirozených čísel, poněvadž těchto čísel je nekonečné množství. Oba naše ukázkové algoritmy jsou konečné, neboť k jejich realizaci si vystačíme s několika málo úkony. 4. Rezultativnost. Rezultativnost je velice důležitá vlastnost algoritmu, která praví toto: Po realizaci konečného počtu kroků nás musí algoritmus dovést k finálnímu výsledku. Definice tedy jednoznačně stanovuje, že postup daný algoritmem musí vyústit do jistého řešení zkoumaného problému. Jakkoliv efektivní a promyšlený může algoritmus být, jestliže nás nedovede ke kýženému výsledku, je nám naprosto k ničemu. Jinými slovy, na co by nám byl takový algoritmus vyřešení kvadratické rovnice, který by
51
Programování v jaz yce C 11.1. Matematická definice O-notace Ať f(n) a g(n) jsou dvě nezáporné funkce definované na množině přirozených čísel (N). Říkáme, že f(n) je velké O od funkce g(n), a zapisujeme f(n)=O(g(n)) nebo též f(n) ∈ O(g(n)), jestliže existuje přirozené číslo n0 a konstanta c>0 takové, že pro každé n ≥ n0 platí f(n) ≤ c × g(n). Ve zkratce lze O-notaci definovat takto: f(n)∈O(g(n) ) ⇔ ∃ c >0,∃ n 0>0: ∀n ≥ n 0 : f(n) ≤ c × g(n) Pokud je f(n)=O(g(n)), můžeme prohlásit, že řád funkce f(n) je menší nebo nanejvýš rovný řádu funkce g(n). O(g(n)) proto slouží jako horní odhad složitosti funkce f(n). O naší funkci T(n)=an 2 + bn + c tak povíme, že její asymptotická časová složitost je v O(n 2 ). Méně formálně: můžeme identifikovat takovou kladnou konstantu c, že počínaje nějakým číslem n0 bude graf funkce f(n) ležet vždy „pod“ grafem funkce c × g(n). Tuto situaci znázorňuje obr. 26.
Obr. 26: Vizualizace horního odhadu asymptotické časové složitosti algoritmu pomocí O-notace
Pro informatiky je nejdůležitější O-notace, protože jim dává garanci horního odhadu asymptotické časové složitosti algoritmu. Pomaleji, než udává O-notace, algoritmus už nepoběží. Kromě O-notace, která slouží k vyjádření horní meze časové složitosti algoritmu, jsou však zajímavé také další odhady, a sice odhad dolní a průměrné složitosti. Pro asymptotické dolní ohraničení složitosti algoritmu se používá Ω-notace (Ω je Omega) a pro asymptotické průměrné ohraničení složitosti algoritmu se zase aplikuje Θ-notace (Θje Théta).
11.2. Matematická definice Ω-notace Ať f(n) a g(n) jsou dvě nezáporné funkce definované na množině přirozených čísel (N). Říkáme, že f(n) je Ω od funkce g(n), a zapisujeme f(n)=Ω(g(n)) nebo též f(n)∈Ω(g(n)), jestliže existuje přirozené číslo n0 a konstanta c>0 takové, že pro každé n ≥n0 platí f(n) ≥ c × g(n).
58
11. Výpočetní složitost algoritmů Ve zkratce lze Ω-notaci definovat takto:
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 27 28 29 30 31 32 33
f(n)∈Ω(g(n) ) ⇔ ∃ c >0,∃ n 0>0: ∀n ≥ n 0 : f(n) ≥ c × g(n)
Obr. 27: Vizualizace dolního odhadu asymptotické časové složitosti algoritmu pomocí Ω -notace
11.3. Matematická definice Θ-notace Ať f(n) a g(n) jsou dvě nezáporné funkce definované na množině přirozených čísel (N). Říkáme, že f(n) je Θ od funkce g(n), a zapisujeme f(n)=Θ(g(n)) nebo též f(n) ∈ Θg(n)), právě tehdy, když současně platí f(n)=O(g(n)) a f(n)=Ω(g(n)). Přesněji lze definici Θ-notace přepsat pomocí přirozených konstant c1 a c 2 následujícím způsobem: f(n)∈ Θ(g(n) ) ⇔ ∃ c1,c2>0, ∃n 0>0: ∀n ≥ n 0 : c1 × g(n) ≤ f(n) ≤ c2 × g(n) Při použití Θ-notace se zkoumá asymptotické oboustranné omezení funkce f(n).
Obr. 28: Vizualizace průměrného odhadu asymptotické časové složitosti algoritmu pomocí Θ-notace
59
14. Definice proměnných 14. Definice proměnných
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 27 28 29 30 31 32 33
Proměnné vytváříme v jazyce C pomocí definičního příkazu, jehož všeobecná podoba vypadá takto: DatovyTyp IdentifikatorPromenne;
Příkaz, který zavádí do programu novou proměnnou, se skládá ze tří částí: 1. Datový typ. Každá proměnná musí disponovat svým datovým typem. To je důležité hned ze dvou důvodů. Zaprvé, již od okamžiku vytvoření proměnné musí být jasné, jaký typ dat neboli hodnot může být do dotyčné proměnné ukládán. Zadruhé, překladač musí poznat datový typ proměnné, aby pro ni mohl alokovat dostatečně rozsáhlý paměťový prostor. V této souvislosti je zapotřebí poznamenat, že v definičním příkazu existuje mezi datovým typem a proměnnou relace 1:1. Jinými slovy, proměnná je spojena vždy s právě jedním datovým typem. Není jednoduše možné, abychom proměnné přisoudili dva datové typy, neboť to bychom uvedli překladač do nesnází (ten by ovšem kontroval generováním chybového hlášení). Jako datový typ proměnné může posloužit kterýkoliv z primitivních nebo uživatelsky deklarovaných datových typů. 2. Identifikátor proměnné. Identifikátor proměnné čili název proměnné představuje uživatelsky přívětivé pojmenovávání, které může programátor proměnné přiřadit. V jazyce C platí pro názvosloví proměnných jisté pojmenovací konvence. Povězme si tedy, na co bychom si měli při pojmenovávání proměnných dát pozor: • Název proměnné nesmí obsahovat mezery. • Název proměnné nesmí začínat číslicí. • Název proměnné nesmí být totožný s klíčovým slovem nebo spojením klíčových slov jazyka C. • Název proměnné se nesmí shodovat s názvem jiné proměnné, která byla ve zdrojovém kódu jazyka C již dříve definována. Nejčastější chybou u začínajících programátorů je snaha složit název proměnné z více slov, které podle intuice oddělují mezerami. Pro mezeru v identifikátoru proměnné ovšem není místo. Pokud se nelze vyhnout víceslovnému názvu, máme na výběr z několika alternativ: • Jednotlivá slova v názvu proměnné budeme separovat symbolem podtržení (_). Proměnná se tedy může jmenovat třeba Moje_Mala_Promenna nebo také moje_mala_promenna. • V praxi se často uplatňuje velbloudí notace, podle níž se slova ve víceslovném názvu nijak neoddělují a první slovo je psáno s malým začátečním písmenem. Všechna další slova jsou však již psána s velkými začátečními písmeny. Název dřívější proměnné se tak použitím velbloudí notace změní na mojeMalaPromenna.
75
Programování v jaz yce C 16. Praktické cvičení: program pro výpočet hmotnostního indexu BMI Vyzbrojeni základními znalostmi o proměnných, přiřazovacích příkazech, operátorech a operandech se můžeme směle pokusit o zkonstruování složitějšího programu. Co takhle program pro výpočet hmotnostního indexu BMI? Děkujeme pěkně, sem s ním. #include <stdio.h> int main() { int hmotnost = 70; float vyska = 1.77, indexBMI; indexBMI = hmotnost / (vyska * vyska); printf(”Index BMI osoby, ktera meri %f m ” ”a vazi %d kg je %f.”, vyska, hmotnost, indexBMI); return 0; }
Komentář k zdrojovému kódu jazyka C: První 2 příkazy v těle hlavní funkce main zakládají 3 lokální proměnné (hmotnost, vyska a indexBMI), přičemž dvě z nich rovněž explicitně inicializují. Program předpokládá, že hmotnost uživatele bude zadána jako celé číslo, a proto lokální proměnné hmotnost při její definici přisuzuje datový typ int. Lokální proměnná vyska je typu float – i to je v pořádku, poněvadž matematický vzorec pro výpočet hmotnostního indexu počítá s tím, že výška osoby bude zadána v desetinné podobě (jde o výšku v metrech). Lokální proměnná indexBMI je rovněž typu float, neboť výsledný hmotnostní index bude mít podobu reálné hodnoty. Na celém programu je patrně nejsložitější přiřazovací příkaz, jenž provádí inicializaci proměnné indexBMI: indexBMI = hmotnost / (vyska * vyska);
Dobrá, v tomto momentě nás nejvíc zajímá, jak bude probíhat inicializace proměnné indexBMI, není-liž pravda? Nejprve musíme určit hodnotu aritmetického výrazu, jenž se rozprostírá na pravé straně od operátoru =. Zdejší výraz je bezesporu složitější než ten, o němž jsme již psali. Jestliže se ptáte proč, máme pro vás tyto důvody: 1. V aritmetickém výrazu se nacházejí dva operátory: 1. Operátor / (lomítko) uskutečňující operaci dělení. 2. Operátor * (hvězdička) provádějící operaci násobení. 2. Aritmetické operátory / a * mají stejnou prioritu. Jelikož index BMI vypočítáme tak, že hmotnost osoby vydělíme druhou mocninou její výšky, musíme nejprve vypočítat tuto druhou mocninu. Operace násobení tak musí být vykonána jako první, proto její prioritu zvyšujeme použitím závorek.
86
16. Praktické cvičení Závorky zde plní stejnou roli jako v běžné matematice: nařizují, která operace má být uskutečněna dřív. Užití závorek v uvedeném aritmetickém výrazu je velice důležité, poněvadž bez jejich asistence by program počítal nesprávné hodnoty hmotnostních indexů.
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 27 28 29 30 31 32 33
Překladač bude při vyhodnocení aritmetického výrazu postupovat tak, jak znázorňuje následující model (operace, které jsou v jednotlivých krocích modelu realizovány, jsou vyznačeny šedou podkladovou barvou): 1. Zjistí aktuální hodnotu lokální proměnné vyska: indexBMI = hmotnost / (vyska vyska * vyska); vyska
2. Vypočte druhou mocninu aktuální hodnoty lokální proměnné vyska: indexBMI = hmotnost / (vyska vyska * vyska vyska);
3. Aktuální hodnotu lokální proměnné hmotnost vydělí hodnotou součinu, jenž byl zjištěn v předcházejícím kroku tohoto modelu: indexBMI = hmotnost / (vyska * vyska) vyska);
4. Vypočtenou hodnotu hmotnostního indexu přiřadí do lokální proměnné indexBMI: indexBMI = hmotnost / (vyska * vyska) vyska);
Když program sestavíme, překladač zahlásí jedno varování, které se pojí s řádkem, v němž je definována lokální proměnná vyska: float vyska = 1.77, indexBMI;
Jak se dozvíme v jedné z příštích kapitol této publikace, samostatně stojící (diskrétní) číselné hodnoty, jako je 1.77 v našem zdrojovém kódu, jsou považovány za číselné konstanty. Konstanta 1.77 je reálnou konstantou, které překladač implicitně přisoudí datový typ double. Když se podíváme na fragment zdrojového kódu, tak zjistíme, že se snažíme reálnou konstantu 1.77 typu double přiřadit do lokální proměnné vyska, jejímž typem je float. Tuto přiřazovací operaci ovšem nelze provést přímo, protože se liší datové typy entit po obou stranách přiřazovacího operátoru (float ↔ double). Aby překladač vyřešil vzniklou situaci, automaticky změní datový typ reálné konstanty 1.77 z double na float, čímž problém spojený s nesouladem datových typů rázem zmizí. Operace, kterou překladač právě provedl, se v programování označuje termínem implicitní typová konverze. Ačkoliv změna datového typu reálné konstanty nebude mít v našem případě žádný negativní dopad, ne vždy je tomu tak. Musíme si totiž uvědomit, že překladač implicitně převádí hodnotu přesnějšího typu double na hodnotu méně přesného typu float. Takováto typová konverze může být poznačena ztrátou dat. A právě z tohoto důvodu generuje překladač varování. I když totiž překladač typovou konverzi zpracuje ve své vlastní režii, emituje varování, které má programátora upozornit na fakt uskutečnění implicitní typové konverze, která může mít potenciálně nebezpečné implikace.
87
Programování v jaz yce C 17. Číselné soustavy 17.1. Desítková (decimální) číselná soustava Jakoukoliv hodnotu desítkové soustavy můžeme zapsat v podobě součtu mocnin čísla 10. Uvažujme například o číslu 1253: (1253)10=1×1000+2×100+5×10+3×1 (1253)10=1×103+2×102+5×101+3×100 Poznámka: Při pojednání o reprezentaci čísel v různých pozičních číselných soustavách platí konvence, že samotná číselná hodnota je zapsána v závorkách a základ číselné soustavy, v níž je hodnota udána, je umístěn v dolním indexu. Tuto konvenci budeme na stránkách naší knihy dodržovat, neboť je nejenom efektivní, nýbrž také dobře vizuálně čitelná. Pokaždé, když se podíváte na dolní index dotyčné číselné hodnoty, budete okamžitě vědět, v jaké soustavě je tato hodnota interpretována. Desítková soustava používá pro vyjádření číselných hodnot deset číslic: 0, 1, 2, 3, 4, 5, 6, 7, 8 a 9.
17.2. Osmičková (oktálová) číselná soustava Osmičková soustava pracuje s mocninami čísla 8, přičemž libovolná hodnota je v této číselné soustavě vyjádřena posloupností cifer z intervalu <0, 7>. (6203)8=6×83+2×82+0×81+3×80 Pro převedení osmičkové konstanty 6203 do desítkové soustavy rozvineme mocniny čísla 8 a vypočteme celý součet, poté obdržíme ekvivalent čísla 6203 v desítkové soustavě. (6203)8=6×512+2×64+0×8+3×1 (6203)8=3072+128+0+3 (6203)8=(3203)10 Jak je vidět, dospěli jsme k závěru, že osmičkové hodnotě 6203 připadá číslo 3203 v desítkové číselné soustavě. Čtenáři se zvídavější povahou mohou v této chvíli namítnout, zda jsme s to nabídnout důkaz o zpětné konverzi. Jednoduše řečeno, jak dokážeme, že číslo 3203 v desítkové soustavě je doopravdy protějškem čísla 6203 v osmičkové soustavě? Důkaz o této skutečnosti podáme tak, že desítkovou číselnou hodnotu budeme neustále dělit osmi, přičemž si vždycky poznačíme zbytek po dělení. Matematický algoritmus, jenž charakterizuje tento proces, uvádí tab. 2. Tab. 2: Algoritmus pro převod celočíselné hodnoty z desítkové do osmičkové číselné soustavy
92
Pořadí operací
Podíl
Zbytek po dělení
3203 : 8
400
3
400 : 8
50
0
50 : 8
6
2
6:8
0
6
20. Globální proměnné 20. Globální proměnné
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 27 28 29 30 31 32 33
Proměnné se v programování dělí na dvě základné skupiny: lokální proměnné a globální proměnné. Klasifikačním kritériem pro zařazení proměnné do jedné z uvedených skupin je její oblast platnosti. Lokální proměnné, s nimiž jsme prozatím intenzivně pracovali, se vážou na funkci, v níž jsou definovány. Všechny proměnné definované v hlavní funkci main jsou lokální proměnné, protože jejich oblastí platnosti je tělo této funkce. Lokální proměnné nelze přímo použít jinde, tedy mimo funkci, ve které jsou situovány jejich definiční příkazy. Jestliže je nutno zvětšit programový blok, v rámci kterého bude proměnná dosažitelná neboli viditelná, můžeme s výhodou využít globální proměnné. Definiční příkaz zakládající globální proměnnou není umístěn v těle žádné funkce. Ve skutečnosti se definice globální proměnné nachází „nad“ všemi přítomnými funkcemi. Vzhledem k tomu, že stavbu uživatelsky definovaných funkcí budeme rozebírat až později, v této kapitole se budeme soustředit pouze na zkoumání vztahu mezi globálními proměnnými a hlavní funkcí main. Definice globální proměnné se uskutečňuje přesně podle generického syntaktického vzoru, který platí rovněž pro lokální proměnné. Každá globální proměnná musí být svůj datový typ a identifikátor. Globální proměnné jsou překladačem jazyka C implicitně inicializovány, což znamená, že v závislosti na svých datových typech vždy obdrží určité výchozí inicializační hodnoty. Pro globální proměnné integrálních datových typů je implicitní inicializační hodnotou celočíselná nula. Pro globální proměnné reálných datových typů je implicitní inicializační hodnotou reálná nula. Pro globální proměnné znakového datového typu char je implicitní inicializační hodnotou nulový znak. Upozornění: Zatímco globální proměnné jsou překladačem jazyka C implicitně inicializovány, pro lokální proměnné to neplatí. Jsme-li spokojeni s implicitní inicializační hodnotou globální proměnné, můžeme tuto proměnnou okamžitě použít v kterémkoliv platném výrazu nebo příkazu libovolné funkce, jež tvoří syntaktický skelet programu jazyka C. Definované, ovšem explicitně neinicializované lokální proměnné nemohou být použity tímto způsobem, poněvadž jejich inicializační hodnoty nejsou implicitně definovány. Lokální proměnné musejí být vždy nejprve explicitně inicializovány a až poté se smí vyskytnout ve výrazech a příkazech jazyka C. Následující program jazyka C demonstruje práci s globální proměnnou: #include <stdio.h> /* Definiční inicializace globální proměnné. */ float pi = 3.1415f; int main() { unsigned int polomer; printf(”Zadejte polomer kruhu (jako cele cislo): ”); scanf(”%d”, &polomer); printf(”Obvod kruhu s polomerem %d je %.2f.\n”, polomer, 2 * pi * polomer); return 0; }
101
Programování v jaz yce C 21. Konstantní proměnné Proměnnou jsme definovali jako datový objekt, do kterého je možné ukládat hodnoty určitého datového typu. Ukázali jsme si, jak se proměnné definují a jak se do nich přiřazují hodnoty. Přitom jsme se vší důkladností pravili, že jakmile je proměnná na světě, můžeme její hodnotu měnit tolikrát, kolikrát budeme chtít. Proměnná coby datový kontejner může měnit svou hodnotu, to je fakt, který plyne již ze samotného názvu „proměnná“. Nyní bychom se měli obeznámit s konstantními proměnnými, což jsou proměnné, jež nesmí po svých prvotních inicializacích měnit své hodnoty. Poznámka: V programovací hantýrce jsou konstantní proměnné velice často označovány za konstanty. Nicméně takováto interpretace vede ke konfliktům s „opravdovými“ konstantami, o nichž jsme mluvili v předcházejících podkapitolách této publikace. Abychom dodrželi jasnou a přehlednou linii výkladu, budeme proměnné, jež nelze reinicializovat, nazývat konstantními proměnnými. Konstantní proměnné v jazyce C poznáme docela snadno, protože v jejich definičních příkazech se vyskytuje modifikátor const: const DatovyTyp IdentifikatorPromenne = InicializacniHodnota;
– nebo – DatovyTyp const IdentifikatorPromenne = InicializacniHodnota;
Když se v definici proměnné objeví modifikátor const, máme jasný důkaz o tom, že se jedná o konstantní proměnnou. Ze syntaktického hlediska se může modifikátor const nacházet před specifikací datového typu konstantní proměnné, nebo až za ní. Tip: Domníváme se, že lepším řešením je uvádět modifikátor const před datovým typem konstantní proměnné, protože je tak okamžitě zřejmé, že manipulujeme s konstantní proměnnou. Tato vizuální pomůcka nabývá na ceně zejména při práci s robustnějšími strukturovanými programy. Konstantní proměnná musí mít samozřejmě svůj identifikátor, v tomto ohledu se nijak neodlišuje od běžné čili nekonstantní proměnné. Jistě si vzpomínáte na program pro výpočet obvodu kruhu. V tomto programu jsme definovali globální proměnnou pi, která uchovávala aproximovanou hodnotu čísla π. Vzhledem k tomu, že hodnota této reálné konstanty se nikdy nebude měnit, jako logický nám přijde návrh přetvořit globální proměnnou na globální konstantní proměnnou.
104
25. Operátory 25. Operátory
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 27 28 29 30 31 32 33
Přestože jsme se v uplynulých kapitolách seznámili s některými aritmetickými operátory, jako jsou +, – či *, operátory mají v jazyce C, a potažmo v celém oboru programování, tak silnou pozici, že by byla naprostá chyba, kdybychom jim v této publikaci nevěnovali samostatnou kapitolu. Již víme, že operátory jsou symboly, které předepisují provedení rozličných programových operací. Tak kupříkladu operátor + sčítá hodnoty, zatímco operátor * je násobí. Rovněž jsme si řekli, že entity, s nimiž operátory pracují, se nazývají operandy. Výraz jsme potom definovali jako smysluplnou posloupnost operandů a operátorů, která produkuje hodnotu jistého datového typu. Ve výbavě jazyka C se nachází celá hromada operátorů. Abychom se ve všech těch operátorech rychle neztratili, rozdělíme je do homogenních skupin podle 2 elementárních klasifikačních kritérií. První kritérium je funkční: jeho užitím budeme operátory třídit podle jejich funkce, tedy podle druhu programových operací, které uskutečňují. Z funkčního hlediska jsou v jazyce C k dispozici následující kategorie operátorů: 1. Aritmetické operátory 2. Operátory pro inkrementaci a dekrementaci 3. Logické operátory 4. Relační operátory 5. Přiřazovací operátory 6. Bitové operátory 7. Operátory bitového posunu 8. Speciální operátory Na operátory ovšem nemusíme nahlížet pouze striktně ve vztahu k jejich funkci. Operátory totiž můžeme klasifikovat také podle počtu operandů, s nimiž pracují. Tak dostáváme mnohem užší, přesněji tříprvkovou, množinu operátorů přítomných v jazyce C: 1. Unární operátory – spolupracují s jedním operandem. 2. Binární operátory – spolupracují se dvěma operandy. 3. Ternární operátory – spolupracují se třemi operandy. Pokud operátor ke své práci vyžaduje pouze jeden operand (například jednu proměnnou), pak je to operátor unární. Označíme-li unární operátor symbolem α a operand symbolem O, pak jejich vzájemný vztah můžeme zapsat takto: αO a v některých případech, u inkrementačních a dekrementačních operátorů, také takto: Oα α
115
25. Operátory 25.1. Aritmetické operátory
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 27 28 29 30 31 32 33
Matematické operace patří k nejčastěji vykonávaným úkonům v programování. Provádění základních aritmetických operací, jako jsou sčítání, odečítání, násobení a dělení, nám umožňují následující aritmetické operátory: • • • • •
operátor pro sčítání +, operátor pro odečítání – , operátor pro násobení *, operátor pro dělení /, operátor pro zjištění zbytku po celočíselném dělení %.
Se čtveřicí operátorů +, –, * a / jsme se již setkali, takže víme, jak pracují. Všechno jsou to vesměs binární operátory, které reflektují základní matematické operace prováděné s operandy. Jako praktické cvičení pro zopakování základních aritmetických operátorů si napíšeme program, který bude zobrazovat kalorickou hodnotu vybraného jídla. Prostudujme následující fragment zdrojového kódu jazyka C: #include <stdio.h> int main() { int bilkoviny, cukry, tuky; int energetickyObsah; float denniPodil; printf(”Zadejte, kolik gramu bilkovin obsahuje vase jidlo: ”); scanf(”%d”, &bilkoviny); printf(”Zadejte, kolik gramu cukru obsahuje vase jidlo: ”); scanf(”%d”, &cukry); printf(”Zadejte, kolik gramu tuku obsahuje vase jidlo: ”); scanf(”%d”, &tuky); energetickyObsah = (bilkoviny * 4) + (cukry * 4) + (tuky * 9); denniPodil = ((float)energetickyObsah / 2000) * 100; printf(”\nVase jidlo obsahuje %d kcal.”, energetickyObsah); printf(”\nKonzumaci tohoto jidla jste pokryli %.2f %% z vaseho ” ”optimalniho \ndenniho energetickeho prijmu potravy.\n”, denniPodil); return 0; }
Komentář k zdrojovému kódu jazyka C: Náš program si nejprve od uživatele vyžádá informace o jídle. Stěžejní je přitom množství (v gramech) spotřebovaných živin, jimiž jsou bílkoviny, cukry a tuky. K úschově těchto hodnot definujeme tři celočíselné lokální proměnné, jejichž názvy jsme zvolili tak, aby nám napovídaly, k čemu slouží. Vstupní data, která obdržíme od uživatele, ukládáme do předem připravených lokálních proměnných. Jakmile víme, kolik gramů bílkovin, cukrů a tuků spotřebované jídlo obsahuje, vypočteme jeho energetickou hodnotu v kilokaloriích (kcal).
117
Programování v jaz yce C 26. Priorita a asociativita operátorů Všechny operátory jazyka C mají svou prioritu. Priorita říká, v jakém pořadí budou realizovány programové operace, které jsou předepsané jednotlivými operátory. Kdyby nebyla stanovena přesná prioritní pravidla, tak by překladač nedovedl správně vyhodnocovat programové výrazy. Kupříkladu výraz a * b – c bude překladač vyhodnocovat jako (a * b) – c, poněvadž ze zapsaných aritmetických operátorů má operátor součinu (*) vyšší prioritu než operátor rozdílu (–). Jistě, zmíněný aritmetický výraz je triviální, neboť nám dovoluje přímo aplikovat pravidla, která známe z matematiky. Ovšem věděli bychom, jak postupovat, kdyby bylo znění výrazu takovéto: a * b % c? Modulo neboli operátor zbytku po celočíselném dělení (%) vypočte zbytek po celočíselném dělení svých operandů a ten vrátí v podobě své návratové hodnoty. Otázkou ale zůstává, zda bude překladač vyhodnocovat výraz a * b % c jako (a * b) c anebo jako a * (b % c). Za předpokladu, že je výraz zapsán korektně, tak překladač musí vždy vědět, jak určit jeho hodnotu. A to i za těch okolností, kdy se bude potýkat s vpravdě komplikovanými výrazy. Překladač se při své práci nejprve řídí prioritou operátorů. Podle priority smíme operátory jazyka C kategorizovat do homogenních prioritních tříd, přičemž v každé prioritní třídě se nacházejí operátory se stejnou prioritou. Například binární aritmetické operátory *, / a % sdílejí stejnou prioritní třídu (označme ji pro lepší orientaci identifikátorem PT1), což znamená, že disponují totožnou prioritou. Další binární aritmetické operátory + a – jsou umístěny v jiné prioritní třídě (PT2) a opět sdílejí stejnou prioritu. Prioritní třídy vytvářejí komplexní hierarchii. Přitom platí, že priorita operátorů patřících do jednotlivých prioritních tříd klesá ve směru odshora dolů. Omezíme-li se na prioritní třídy PT1 a PT2, pak můžeme konstatovat, že prioritní třída PT1 disponuje v celkové hierarchii vyšší prioritou než prioritní třída PT2. Z toho samozřejmě plyne, že binární aritmetické operátory *, / a % mají přednost před operátory + a –. Hierarchii prioritních tříd vybraných operátorů jazyka C uvádíme v tab. 11. Někdy se stává, že prioritní pravidla pro jednoznačné vyhodnocení výrazů nestačí. To se děje tehdy, sejdou-li se v jednom výrazu (nebo podvýrazu) operátory se stejnou prioritou (čili operátory z totožné prioritní třídy). Jak vidíme, v tomto kontextu jsou překladači pravidla pro stanovení priority k ničemu, neboť pomocí nich nedovede přijmout kvalifikované rozhodnutí. Proto potřebujeme další mechanismus, jenž bude schopen vzniklou nejednoznačnost odstranit. Tímto mechanismem jsou asociativní pravidla, která nařizují, v jakém pořadí budou prováděny operace předepsané operátory se stejnou prioritou. Asociativita je vlastnost operátorů, podle níž dokáže překladač určit, zda se operátor váže (čili asociuje) s levým nebo pravým operandem. Pořadí determinované asociativitou operátorů bude vždy dáno dvěma směry: buď zleva doprava, nebo zprava doleva. Pro lepší názornost použijeme směrové šipky: → pro operátory asociativní zleva doprava a ← pro operátory asociativní zprava doleva. Tak třeba všechny binární aritmetické operátory jsou asociativní zleva doprava (→).
130
26. Priorita a asociativita operátorů 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 27 28 29 30 31 32 33
Tab. 11: Hierarchie prioritních tříd vybraných operátorů jazyka C Prioritní třída
Operátory
Asociativita
1.
() [] -> .
zleva doprava (→)
2.
! ~ ++ -- + - * & (Typ) sizeof
zprava doleva (←)
3.
*/%
zleva doprava (→)
4.
+-
zleva doprava (→)
5.
<< >>
zleva doprava (→)
6.
< <= > >=
zleva doprava (→)
7.
== !=
zleva doprava (→)
8.
&
zleva doprava (→)
9.
^
zleva doprava (→)
10.
|
zleva doprava (→)
11.
&&
zleva doprava (→)
12.
||
zleva doprava (→)
13.
?:
zprava doleva (←)
14.
= += -= *= /= %= &= ^= |= <<= >>=
zprava doleva (←)
15.
,
zleva doprava (→)
Vraťme se nyní k vyhodnocení výrazu a * b % c. Vzhledem k tomu, že operátory * a % mají stejnou prioritu, musí si překladač pomoci jejich asociativitou. Ta má orientaci →, což znamená, že výraz bude vyhodnocen jako (a * b) % c. Pokud předpokládáme následující inicializaci proměnných: a = 50, b = 2 a c = 4, tak hodnotou výrazu bude 0 (100 % 4 = 0). Přirozeně, ne všechny operátory jsou asociativní →, nemálo z nich má přesně opačnou asociativitu. Jedním z takovýchto operátorů je přiřazovací operátor (=). Asociativitu operátoru = jsme objevili již dávno a implicitně jsme s ní pracovali, aniž bychom ji nazvali příslušným odborným termínem. Jednoduše řečeno, v příkazu p = V; , kde p je proměnná zvoleného datového typu a V je výraz, bude vždy nejprve vyhodnocen výraz V a až poté bude hodnota výrazu V přiřazena do proměnné p. Podotkněme, že v závislosti na datovém typu proměnné a datovém typu hodnoty výrazu mohou (ovšem nemusí) být zpracovány implicitní typové konverze. Rozvineme-li úvahy o asociativitě operátoru =, pak okamžitě vyřešíme i otázku vícenásobného přiřazení. Příkaz m = n = o = p; bude vyhodnocen jako m = (n = (o = p));. Tip: Pokud si nejsme jisti, jakou prioritu a asociativitu mají operátory v zapsaném výrazu, můžeme si pomoci uzávorkováním těch částí výrazu (čili podvýrazů), které mají být provedeny před ostatními. Vložíme-li podvýraz do závorek, zvyšujeme preferenci jeho zpracování. S prioritou tak ovlivňujeme rovněž asociativitu operátorů. Jenom prosím nezapomínejme na skutečnost, že v kterémkoliv výrazu musí být sudý počet závorek.
131
27. Rozhodovací příkazy 27. Rozhodovací příkazy
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 27 28 29 30 31 32 33
S rozhodovacími problémy se v běžném životě setkáváme velice často. Přijetí jistého rozhodnutí se odvíjí od charakteru rozhodovacího problému, vstupních dat a potenciálních alternativ, jimiž se může naše rozhodování ubírat. Proces rozhodování lze graficky znázornit pomocí rozhodovacího stromu. Na obr. 35 je znázorněn vývojový diagram s rozhodovacím stromem, který řeší rozhodování o koupi nového auta.
Obr. 35: Vývojový diagram rozhodovacího stromu řešící rozhodování o zakoupení nového auta
Programovací jazyk C obsahuje sadu rozhodovacích příkazů, jejichž pomocí mohou vývojáři realizovat programová rozhodnutí a větvit tak tok programu. Jde o následující příkazy: • Příkaz if pro realizaci jednocestného rozhodování. • Příkaz if-else pro realizaci dvojcestného rozhodování. • Příkaz if-else if… pro realizaci vícecestného rozhodování. • Příkaz if-else if-else pro realizaci vícecestného rozhodování. • Příkaz switch pro realizaci vícecestného rozhodování. • Ternární operátor ?: pro realizaci dvojcestného rozhodování. Všechny zmíněné rozhodovací příkazy rozebereme v textu následujících podkapitol.
133
Programování v jaz yce C 27.1. Rozhodovací příkaz if Rozhodovací příkaz if umožňuje větvení toku programu podle jednostranné podmínky. Jeho generický syntaktický model vypadá takto: if(PV) P1;
– nebo – if(PV) { P1; P2; ... Pn; }
kde: • PV je podmínkový výraz, jehož hodnotou bude buď logická pravda, nebo logická nepravda. • P1, P2, … Pn jsou příkazy jazyka C, jež budou zpracovány pokaždé, když bude hodnotou PV logická pravda. Rozhodování pomocí příkazu if se uskutečňuje takto: 1. Vyhodnotí se PV. 2. Jestliže je hodnotou PV logická pravda, tak se zpracují příkazy umístěné v těle větve if. Pokud je v těle větve if situován právě jeden příkaz, není nutno explicitně vyznačovat její tělo pomocí složených závorek. Naopak, nacházejí-li se v těle větve if alespoň dva příkazy, musí být její tělo explicitně vyznačeno složenými závorkami. 3. Jestliže je hodnotou PV logická nepravda, tak rozhodování končí. Dochází k opuštění rozhodovacího příkazu if a ke zpracování nejbližšího možného příkazu, jenž následuje za rozhodovacím příkazem if. Vizualizaci jednocestného rozhodování pomocí příkazu if můžeme vidět na obr. 36. Jednocestné rozhodování nám sdělí, zda přirozené číslo, které zadal uživatel na vstupu, je sudé: #include <stdio.h> int main() { int cislo; printf(”Zadejte prirozene cislo: ”); scanf(”%d”, &cislo); if(cislo % 2 == 0) printf(”Bylo zadano sude cislo.\n”); return 0; }
134
27. Rozhodovací příkazy Tento program nemá žádná kritická místa, jenom si musíme uvědomit, že sudé přirozené číslo je každé číslo, jehož zbytek po dělení dvojkou je nulový.
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 27 28 29 30 31 32 33
Obr. 36: Pracovní model příkazu if
27.2. Rozhodovací příkaz if-else Rozhodovací příkaz if-else uskutečňuje řízení toku programu podle oboustranné podmínky. Jeho generický syntaktický model je následující: if(PV) P1; else R1;
– nebo – if(PV) { P1; P2; ... Pn; } else { R1; R2; ... Rn; }
kde: • PV je podmínkový výraz, jehož logickou hodnotu lze určit. • P1, P2, … Pn jsou příkazy, které budou provedeny tehdy, bude-li hodnotou PV logická pravda. • R1, R2, … Rn jsou příkazy, jež budou zpracovány v případě, kdy bude hodnotou PV logická nepravda.
135
27. Rozhodovací příkazy 27.5. Praktické cvičení: program na detekci kolize mezi automobilem a chodcem
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 27 28 29 30 31 32 33
Představme si tuto modelovou situaci: Automobil jede po cestě, když se v jisté vzdálenosti od něj objeví chodec. Cílem našeho dalšího praktického cvičení je zjistit, zda mezi dopravním prostředkem a člověkem dojde ke kolizi, či nikoliv. Budeme přitom postupovat následovně: 1. Celkovou vzdálenost, která dělí automobil od chodce, označíme identifikátorem SC. Dodejme, že celková vzdálenost je dána dráhou, která dělí automobil a chodce v čase t0 čili v čase, kdy auto jede počáteční rychlostí v0 a řidič spatří chodce na cestě před sebou. 2. Při analýze pohybu automobilu rozdělíme celou dráhu na dvě menší dráhy: jedna z nich bude reakční dráha (SR) a druhá bude brzdná dráha (SB). Reakční dráha je dráha, kterou automobil urazí během reakčního času (tR), tedy času, jenž je vymezen časovým intervalem, na jehož konci si řidič automobilu uvědomí, že v zájmu zabránění kolize s objektem na cestě má sešlápnout brzdový pedál a snížit tak rychlost auta. Brzdná dráha je pak dráha, která je nutná k úplnému zastavení vozidla. Jelikož počítáme s úplným zabrzděním, konečná rychlost automobilu (vF) bude nulová. 3. Problém detekce kolize má fyzikální charakter, přičemž pro jeho vyřešení využijeme několik matematických vztahů z mechaniky, jedné z disciplín moderní fyziky. Je zřejmé, že ke kolizi nedojde v případě, že SR + SB < SC. Protože reakční dráhu ujede automobil v počáteční rychlosti v0, můžeme ji vypočítat takto: SR = v0 tR 4. Výpočet brzdné dráhy je o něco komplikovanější, neboť v něm musíme uvažovat se zpomalením automobilu v důsledku aktivace brzdných mechanizmů. Všeobecný vzorec pro výpočet brzdné dráhy má tuto podobu: SB =
v F2- v 02 2a
kde: • vF je konečná rychlost automobilu, • v0 je počáteční rychlost automobilu, • a je koeficient zpomalení. Jelikož z našich předpokladů vyplývá, že vF = 0, tak samozřejmě i vF2 = 0. Všeobecný vzorec pro stanovení brzdné dráhy proto smíme upravit následujícím způsobem: SB =
- v 02 2a
141
Programování v jaz yce C Ovšem co to ve skutečnosti znamená? Pomozme si praktickou ukázkou. Povězme, že počáteční rychlost automobilu bude 60 km/h, celková vzdálenost (SC) bude 50 m, reakční čas (tR) bude 0,45 s a koeficient zpomalení (a) bude -6,5 m/s2. Poznámka: Ještě než začneme s dosazováním hodnot do vzorců, musíme unifikovat jednotky všech veličin. Jelikož budeme chtít mít všechny veličiny zadány v metrech nebo v sekundách, budeme muset počáteční rychlost auta převést z km/h na m/s. To znamená dělit rychlost zadanou v km/h reálnou konstantou 3,6. Platí, že 60 km/h se přibližně rovná 16,67 m/s. 5. Reakční a brzdnou dráhu vypočítáme takto: SR = 16,67 × 0,45 = 7,5 m SB =
- 16,672 = 2×(- 6,5)
- 277,89 = 21,38 m - 13
ST = SR + SB = 7,5 + 21,38 ≅ 29 m V našem fyzikálním modelu tedy automobil zcela zastaví po ujetí 29 metrů, takže ke kolizi s chodcem naštěstí nedojde.
Obr. 40: Detekce kolize mezi automobilem a chodcem
142
27. Rozhodovací příkazy Přejděme nyní k algoritmizaci fyzikální úlohy:
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 27 28 29 30 31 32 33
#include <stdio.h> int main() { int celkovaDraha; float pocatecniRychlost, reakcniCas, zpomaleni; float reakcniDraha, brzdnaDraha; printf(”Zadejte pocatecni rychlost auta (v km/h): ”); scanf(”%f”, &pocatecniRychlost); pocatecniRychlost /= 3.6f; printf(”Zadejte celkovou drahu mezi autem a chodcem (v m): ”); scanf(”%d”, &celkovaDraha); printf(”Zadejte delku reakcniho casu (v s): ”); scanf(”%f”, &reakcniCas); printf(”Zadejte zpomaleni (v m/s2): ”); scanf(”%f”, &zpomaleni); reakcniDraha = pocatecniRychlost * reakcniCas; brzdnaDraha = -(pocatecniRychlost * pocatecniRychlost) / (2 * zpomaleni); printf(”Reakcni draha je %.2f m.\n”, reakcniDraha); printf(”Brzdna dráha je %.2f m.\n”, brzdnaDraha); printf(”Auto zcela zabrzdi po ujeti %.2f m.\n”, reakcniDraha + brzdnaDraha); if (reakcniDraha + brzdnaDraha < celkovaDraha) { printf(”Mezi autem a chodcem nedojde ke kolizi.”); } else { printf(”Mezi autem a chodcem dojde ke kolizi.”); } return 0; }
Komentář k zdrojovému kódu jazyka C: Program věrně kopíruje fyzikální výklad, jejž jsme uvedli, a proto se domníváme, že byste se neměli setkat s žádnými kritickými pasážemi. Jenom připomínáme, že program očekává zadání záporné hodnoty pro koeficient zpomalení.
27.6. Rozhodovací příkaz switch Rozhodovací příkaz switch byl navržen speciálně pro vícecestné rozhodování. Nejprve uvedeme jeho generický syntaktický skelet a pak si vysvětlíme, jak tento příkaz provádí své rozhodování.
143
Programování v jaz yce C 28. Programové cykly Programový cyklus nebo jen cyklus je označení pro iterativní syntaktickou konstrukci, která umožňuje opakované zpracování množiny příkazů, zpravidla na základě vyhodnocení stanoveného rozhodovacího výrazu. Programovací jazyk C zná tři základní typy cyklů: 1. Cyklus for 2. Cyklus while 3. Cyklus do-while. Průchod cyklem se v terminologii programování označuje iterací cyklu. Iterace cyklu tedy označuje jedno opakování cyklu. Během jedné iterace cyklu jsou postupně zpracovány všechny programové příkazy, jež jsou umístěny v těle cyklu. Po zpracování každé iterace přijímá cyklus rozhodnutí o tom, zda bude provedena rovněž další iterace cyklu, či nikoliv. Toto rozhodnutí obvykle vyplývá z vyhodnocení určitého rozhodovacího výrazu (nebo podmínky, jak někdy také zkráceně říkáme). V následujících podkapitolách podáme výklad všech zmíněných cyklů jazyka C.
Obr. 41: Schematický model programového cyklu
28.1. Cyklus for Schematický model cyklu for má následující podobu: for(IV; RV; M V) { P1; P2; ... Pn; }
148
28. Programové cykly První řádek definice cyklu for tvoří hlavičku cyklu. V hlavičce cyklu jsou seskupeny tři součásti uzavřené v závorkách. Těmito součástmi jsou:
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 27 28 29 30 31 32 33
• IV – inicializační výraz. IV inicializuje řídící proměnnou cyklu for. Každý cyklus, nejenom cyklus for, pracuje s proměnnou, která řídí jeho život. Z uvedeného důvodu se tato proměnná označuje termínem řídící proměnná cyklu. I když je na programátorovi, jaký datový typ, identifikátor a inicializační hodnotu bude řídící proměnná cyklu mít, v praxi se nejčastěji setkáváme s celočíselnými řídícími proměnnými. V jazyce C musí být řídící proměnná cyklu for definována před tímto cyklem. Jazyk C neumožňuje, na rozdíl od jazyků C++, C++/CLI a C#, aby byla řídící proměnná cyklu for definována přímo v jeho hlavičce. Řídící proměnnou cyklu for tak bude v naprosté většině případů lokální proměnná, která bude definována v těle funkce, v níž je cyklus for situován. Po zpracování IV obsahuje řídící proměnná cyklu for požadovanou inicializační hodnotu. • RV – rozhodovací výraz. Rozhodovací výraz tvoří nutnou součást hlavičky cyklu for, poněvadž podle hodnoty rozhodovacího výrazu přijímá cyklus rozhodnutí o provedení své další iterace. Rozhodovacím výrazem smí být jakýkoliv syntakticky korektně zapsaný a sémanticky smysluplný výraz, jehož hodnotou je buď logická pravda, nebo logická nepravda. Jestliže je hodnotou RV logická pravda, vykoná se další iterace cyklu for. Pokud bude naopak hodnotou RV logická nepravda, další iterace cyklu for se neuskuteční. Za těchto okolností cyklus for končí svou činnost. • MV – manipulační výraz. Manipulační výraz aplikuje jistou, zpravidla aritmetickou, manipulační operaci na řídící proměnnou cyklu for. Manipulačním výrazem bývá inkrementační výraz, jehož smyslem je inkrementovat hodnotu řídící proměnné cyklu for před vstupem do následující iterace tohoto cyklu. Podobně může manipulačním výrazem být také dekrementační výraz, který dekrementuje hodnotu řídící proměnné cyklu for. Ve všeobecnosti ale smíme konstatovat, že manipulačním výrazem cyklu for může být jakýkoliv validní výraz, který požadovaným způsobem modifikuje stav řídící proměnné tohoto cyklu. Tělo cyklu for tvoří konečná a neprázdná množina programových příkazů P1, P2, … Pn, které jsou ohraničeny složenými závorkami {}. Jestliže bude provedena iterace cyklu for, dojde ke zpracování všech příkazů uložených v jeho těle. Podle všeobecného modelu dále zkonstruujeme konkrétní cyklus for a vysvětlíme jeho pracovní model. #include <stdio.h> int main() { int i; for(i = 1; i <= 10; i++) { printf(”%d\n”, i); } return 0; }
149
Programování v jaz yce C Předestřený cyklus for bude zpracován takto: 1. Při vstupu do cyklu se nejprve provede IV. Tento výraz inicializuje řídící proměnnou cyklu for (s identifikátorem i a datovým typem int). Explicitní inicializační hodnotou řídící proměnné cyklu je 1. 2. Vyhodnotí se rozhodovací výraz i<=10. Přesněji řečeno, rozhodovací výraz je v tomto konkrétním případě relačním výrazem. (K tomuto závěru dojdeme snadno, neboť operátor <= je binárním relačním operátorem.) Rozhodovací výraz vyhodnotíme tak, že za identifikátor proměnné i dosadíme aktuální hodnotu řídící proměnné cyklu for. Tou je 1, vyhodnocujeme tedy výraz 1<=10. Relační operátor zjistí, že mezi operandy 1 a 10 existuje relace, protože jednička je menší hodnota než desítka. Hodnotou rozhodovacího výrazu je logická pravda (1), což cyklus for přiměje k tomu, aby vykonal svou 1. iteraci. Během ní je vykonán příkaz, jenž se nachází v těle cyklu. Tento příkaz je dobře srozumitelný: jeho úloha spočívá v zobrazení aktuální hodnoty řídící proměnné cyklu for (ano, tou bude v 1. iteraci 1). 3. Po vykonání příkazu v těle cyklu for přichází na řadu zpracování manipulačního výrazu. Tímto výrazem je i++ čili postfixová inkrementace řídící proměnné cyklu. Všimněme si prosím, že na konci 1. iterace cyklu zvyšujeme hodnotu jeho řídící proměnné. Z jedničky děláme dvojku a tu vzápětí přiřazujeme do proměnné i. Tím je 1. iterace cyklu for u konce a začíná se další iterace. 4. Ve své 2. iteraci cyklus pomíjí IV a rovnou přechází na testování rozhodovacího výrazu. Bude dobré, když budeme mít na paměti skutečnost, že IV je zpracováván pouze jednou, a to při vstupu do cyklu for. Vyhodnocení rozhodovacího výrazu znamená testování relace mezi operandy 2 a 10 (připomeňme, že aktuální hodnotou řídící proměnné cyklu je v 2. iteraci dvojka). Přirozeně, tato podmínka je splněna, a proto cyklus for provede příkaz, který zobrazí aktuální hodnotu řídící proměnné. Cyklus pokračuje inkrementací řídící proměnné (na hodnotu 3), čímž se končí jeho 2. iterace. 5. 3. iterace cyklu má podobný průběh jako ta předcházející: cyklus vyhodnocuje rozhodovací výraz, a protože výsledkem tohoto procesu je opět logická pravda (3<10), znovu se na výstupu zobrazí aktuální hodnota řídící proměnné cyklu. 6. Charakterizovaná posloupnost operací se opakuje tak dlouho, dokud nebude hodnotou rozhodovacího výrazu logická nepravda. To se děje v 11. iteraci cyklu, v níž bude řídící proměnná obsahovat hodnotu 11. Vzhledem k tomu, že výraz 11<=10 není pravdivý, jeho hodnotou bude logická nepravda (0). V této situaci cyklus for zamítá provedení další iterace a končí svou činnost. Praktickou implikací pracovního modelu cyklu for je skutečnost, že program obsahující náš cyklus zobrazí na výstupu posloupnost celých čísel z intervalu <1, 10>.
150
28. Programové cykly Grafickou podobu pracovního modelu cyklu for uvádíme na obr. 42.
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 27 28 29 30 31 32 33
Obr. 42: Pracovní model cyklu for
Cyklus for nám poslouží například při výpočtu faktoriálu libovolného čísla. Jak víme z matematiky, definice faktoriálu má rekurentně-rekurzivní povahu: n! = n ×( n-1)! pro každé n ∈ N ∪ {0}, přičemž 0! = 1. Zdrojový kód programu v jazyce C má následující syntaktický obraz: #include <stdio.h> int main() { int i, n, faktorial = 1; printf(”Zadejte n: ”); scanf(”%d”, &n); /* Výpočet n! provádí cyklus for. */ for(i = 2; i <= n; i++) { faktorial *= i; } printf(”%d! je %d.\n”, n, faktorial); return 0; }
151
Programování v jaz yce C Komentář k zdrojovému kódu jazyka C: Zadání pro výpočet faktoriálu patří mezi úlohy, které elegantně vyřešíme pomocí programového cyklu. V našem případě jsme upotřebili cyklus for s tímto nastavením: • V hlavičce cyklu je inicializována řídící proměnná cyklu i typu int. Explicitní inicializační hodnotou řídící proměnné je 2, což je vzhledem k povaze úlohy pochopitelné. • Rozhodovací výraz zjišťuje, zda je hodnota řídící proměnné cyklu menší nebo rovna hodnotě proměnné n (v této proměnné je uložen člen, jehož faktoriál hodláme vypočítat). • Manipulačním výrazem je postfixová inkrementace řídící proměnné, což znamená, že na konci každé iterace cyklu bude hodnota proměnné i zvýšena o 1. • Do těla cyklu jsme vložili jediný příkaz, který postupně, s probíhajícími iteracemi cyklu, vypočítavá faktoriál zadaného čísla. Poznámka: Podotkněme, že příkaz faktorial *= i;
můžeme ekvivalentně nahradit příkazem faktorial = faktorial * i;
Pro lepší názornost budeme analyzovat zpracování cyklu for po jednotlivých iteracích pro výpočet 5! (tab. 12). Tab. 12: Analýza iterativního výpočtu 5! pomocí cyklu for Iterace
RV
Je hodnotou RV logická pravda?
Výraz
Hodnota výrazu (uložena v proměnné faktorial)
1.
2 <= 5
Ano
1*2
2
2.
3 <= 5
Ano
2*3
6
3.
4 <= 5
Ano
6*4
24
4.
5 <= 5
Ano
24 * 5
120
5.
6 <= 5
Ne
-
120
Jak se dozvíme po spuštění programu, 5! je 120. Zkusme s programem trošičku experimentovat a zjišťujme faktoriály dalších přirozených čísel. Jenom berme v potaz, že hodnoty faktoriálů rostou docela rychle. Kupříkladu 10! představuje číslo větší než 3,6 milionu.
152
29. Funkce 29. Funkce
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 27 28 29 30 31 32 33
V ryze strukturovaném programovacím jazyce, jakým je jazyk C, je funkce základní stavební buňkou každého správně navrženého strukturovaného programu. Mnozí autoři funkci velice často definují jako podprogram, který provádí exaktní algoritmizaci řešené úlohy. Techničtěji bychom mohli funkci popsat jako vyhrazený blok programového kódu, který obsahuje konečnou a neprázdnou množinu programových příkazů. Tyto příkazy implementují určitý algoritmus a jejich zpracování vede k vykonání algoritmu a k nalezení řešení úlohy. Každý strukturovaný program obsahuje hlavní funkci main, která vystupuje jako vstupní bod tohoto programu. Když uživatel vydá pokyn na spuštění programu, operační systém automaticky zavolá hlavní funkci main a zahájí zpracování jejích příkazů. Poznámka: Podobně na funkce nahlížejí i programovací jazyky, k nimž řadíme C++, C# nebo C++/CLI – ty ovšem navíc funkce zapouzdřují do tříd coby abstraktních objektových uživatelsky deklarovaných datových typů. O těchto jazycích říkáme, že jsou hybridní, což je dáno tím, že kromě strukturovaného paradigmatu zavádějí rovněž objektově orientované paradigma vývoje počítačového softwaru. Ve všeobecnosti platí, že když je programovací jazyk hybridní, tak v sobě integruje syntakticko-sémantické konstrukce pro podporu více programovacích paradigmat. Všechny programy jazyka C, které jsme dosud společně vytvořili, obsahují hlavní funkci main. V této kapitole se naučíme, jak mohou programátoři vytvářet své vlastní, takzvané uživatelsky definované funkce. Poté si ukážeme, jak se uskutečňuje komunikační dialog mezi hlavní funkcí main a uživatelsky definovanými funkcemi. Když budeme chtít v jazyce C vytvořit svou vlastní funkci, budeme ji muset deklarovat a definovat. V terminologii programování jsou termíny „deklarace funkce“ a „definice funkce“ velice významné. Není správné tyto termíny zaměňovat, neboť každý determinuje odlišnou programovou konstrukci. Deklarace funkce je příkaz, který překladači oznamuje, že chceme vytvořit svou vlastní funkci. Když funkci deklarujeme, zavedeme do zdrojového kódu jazyka C její prototyp. Dovolíme si poznamenat, že v praxi se termíny „deklarace funkce“ a „prototyp funkce“, respektive „deklarace funkce“ a „funkční prototyp“ volně zaměňují. To je v pořádku, protože oba termíny mají synonymický význam, přičemž identifikují totožnou programovou konstrukci. Prototyp funkce sděluje překladači následující informace o funkci: • Datový typ návratové hodnoty funkce • Identifikátor funkce • Seznam formálních parametrů funkce
157
30. Struktury 30. Struktury
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 27 28 29 30 31 32 33
Struktura je v programovacím jazyce C agregovaný heterogenní uživatelsky deklarovaný datový typ (UDDT). Struktura se skládá z konečné a neprázdné množiny datových členů, jež jsou ze syntaktické stránky nejčastěji reprezentovány proměnnými primitivních datových typů. Každý datový člen správně deklarované struktury musí mít svůj identifikátor a datový typ. Struktury umožňují efektivně modelovat datové entity reálného světa. Díky tomu, že struktury provádějí zapouzdření datových členů do jednoho logického celku, dovolují nám pracovat s množinou spřízněných datových členů jako s jedním datovým objektem. Pomocí struktur dovedeme modelovat například následující entity: 1. Student – charakterizovaný svým jménem, příjmením, adresou, ročníkem studia, počtem zapsaných předmětů, počtem dosažených kreditů atd. 2. Vysokoškolský pedagog – charakterizovaný svým jménem, příjmením, adresou, mzdou, funkčním zařazením, počtem vyučovaných předmětů, počtem odborných publikací a vědeckých prací atd. 3. Počítač – charakterizovaný procesorem, počtem výpočetních jader uvnitř procesoru, kapacitou operační paměti, úložním prostorem pevného disku, modelem zvukové a grafické karty, cenou atd. 4. MP3 přehrávač – charakterizovaný kapacitou operační paměti, počtem skladeb, počtem podporovaných multimediálních formátů, barvou svého krytu, cenou, možností přehrávat videosoubory atd. 5. Automobil – charakterizovaný výkonem motoru (v KW), spotřebou (v litrech na 100 km), cenou, počtem míst na sezení, počtem dveří, barvou karoserie, délkou, šířkou a výškou atd. 6. Výrobek – charakterizovaný svým identifikačním číslem, názvem, cenou, složením komponent atd. 7. Matematický vektor – charakterizovaný uspořádanou n-ticí celočíselných nebo reálných hodnot. 8. Programové vlákno fyzického procesu programu jazyka C – charakterizované svým identifikátorem, alokační kapacitou přiděleného paměťového prostoru, prioritou, stavem, celkovým časem provádění atd. Jak si můžeme všimnout, pomocí struktur můžeme modelovat nejenom živé entity (student, vysokoškolský učitel), ale i neživé entity (počítač, automobil). Neživé entity lze rozdělit na hmotné neživé entity a nehmotné (abstraktní) neživé entity. Abstraktní entitou je třeba vektor, ale také integrál, rovnice nebo jakýkoliv jiný matematický objekt. Struktury samozřejmě umí popsat datové složení všech zmíněných typů entit.
169
30. Struktury 30.4. Použití inicializované instance struktury
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 27 28 29 30 31 32 33
Po instanciaci a inicializaci instance může být tato nabídnuta klientům k přímé manipulaci. Klienti mohou číst hodnoty datových členů instance nebo je měnit podle svých potřeb. Následující ukázka mění složky 3D vektoru a vzápětí je zobrazuje na výstupu: #include <stdio.h> struct Vektor3D { int x, y, z; }; int main() { struct Vektor3D vektor; vektor.x = vektor.y = vektor.z = 1; printf(”Slozky 3D vektoru po inicializaci: %d, %d, %d.\n”, vektor.x, vektor.y, vektor.z); vektor.x += 1; vektor.y += 2; vektor.z += 3; printf(”Slozky 3D vektoru po reinicializaci: %d, %d, %d.\n”, vektor.x, vektor.y, vektor.z); return 0; }
Komentář k zdrojovému kódu jazyka C: Ihned poté, co vytvoříme a inicializujeme nový 3D vektor, zobrazujeme jeho složky na výstupu. V další etapě pak provádíme reinicializaci 3D vektoru, přičemž upravenou podobu jeho složek rovněž zobrazujeme na výstupu. Samozřejmě můžeme stávající zdrojový kód upravit tak, abychom dovedli s 3D vektorem uskutečnit jistou manipulační operaci, kupříkladu jej vynásobit skalárem: #include <stdio.h> struct Vektor3D { int x, y, z; }; int main() { struct Vektor3D vektor; int skalar; printf(”Zadejte slozky 3D vektoru (jako cela cisla oddelena mezerami): ”); scanf(”%d %d %d”, &vektor.x, &vektor.y, &vektor.z); printf(”Zadejte skalar (jako cele cislo), jenz bude pouzit k modifikaci 3D vektoru: ”); scanf(”%d”, &skalar); printf(”Puvodni 3D vektor: %d, %d, %d.\n”, vektor.x, vektor.y, vektor.z); vektor.x *= skalar; vektor.y *= skalar; vektor.z *= skalar; printf(”Novy 3D vektor: %d, %d, %d.\n”, vektor.x, vektor.y, vektor.z); return 0; }
175
Programování v jaz yce C Komentář k zdrojovému kódu jazyka C: Pomineme-li standardní pracovní postup se strukturou Vektor3D, tak jedinou obměnou je uživatelská inicializace vytvořeného 3D vektoru (uživatel sám zadá na vstupu hodnoty, jež budou posléze uloženy do příslušných datových členů instance struktury Vektor3D). Poznámka: Když voláme funkci scanf za účelem načtení více hodnot najednou, zadáváme více formátových specifikátorů (v našem případě jsou 3). V řídícím řetězci funkce scanf jsou tyto formátové specifikátory odděleny mezerami. To znamená, že uživatel zadá na vstupu 3 celočíselné hodnoty (složky 3D vektoru), které budou také odděleny mezerami (ekvivalentně mohou být tyto hodnoty odděleny rovněž symboly nového řádku, které vložíme stiskem klávesy ENTER). Program na výstupu zobrazí nejprve složky 3D vektoru neprodleně po jeho uživatelské inicializaci a poté nás obeznámí rovněž s podobou nového 3D vektoru, který vzešel z multiplikativní operace se skalárem. Kromě vynásobení 3D vektoru skalárem smíme uskutečnit také součet a rozdíl dvou 3D vektorů. Více informací již podává další program jazyka C: #include <stdio.h> struct Vektor3D { int x, y, z; }; int main() { /* Vytvoření 4 3D vektorů. */ struct Vektor3D vektor1, vektor2; struct Vektor3D souctovyVektor, rozdilovyVektor; /* Inicializace vytvořených 3D vektorů. */ printf(”Zadejte slozky 1. 3D vektoru (jako cela cisla oddelena mezerami): ”); scanf(”%d %d %d”, &vektor1.x, &vektor1.y, &vektor1.z); printf(”Zadejte slozky 2. 3D vektoru (jako cela cisla oddelena mezerami): ”); scanf(”%d %d %d”, &vektor2.x, &vektor2.y, &vektor2.z); /* Vypočtení součtového 3D vektoru. */ souctovyVektor.x = vektor1.x + vektor2.x; souctovyVektor.y = vektor1.y + vektor2.y; souctovyVektor.z = vektor1.z + vektor2.z; /* Vypočtení rozdílového 3D vektoru. */ rozdilovyVektor.x = vektor1.x - vektor2.x; rozdilovyVektor.y = vektor1.y - vektor2.y; rozdilovyVektor.z = vektor1.z - vektor2.z; /* Zobrazení složek všech 3D vektorů na výstupu. */ printf(”1. 3D vektor: %d, %d, %d.\n”, vektor1.x, vektor1.y, vektor1.z); printf(”2. 3D vektor: %d, %d, %d.\n”, vektor2.x, vektor2.y, vektor2.z); printf(”Souctovy vektor: %d, %d, %d.\n”, souctovyVektor.x, souctovyVektor.y, souctovyVektor.z); printf(”Rozdilovy vektor: %d, %d, %d.\n”, rozdilovyVektor.x, rozdilovyVektor.y, rozdilovyVektor.z); return 0; }
176
Programování v jaz yce C Závěr Když zvládnete algoritmizaci a programování v jazyce C, přičemž najdete v programování zalíbení, je rozumné zvážit potenciální cesty budoucího rozvoje vašeho odborného profilu. Abyste měli představu, co vám může tento svět nabídnout, uvádíme možné směry dalšího postupu: 1. Seznamte se s datovými strukturami a algoritmy, které s nimi manipulují. 2. Absolvujte pokročilý kurz programátorských technik v jazyce C. 3. Naučte se jazyk C++ a ovládněte základy objektově orientovaného programování (OOP). 4. Studujte jazyk C# a naučte se vytvářet programy s grafickým uživatelským rozhraním s podporou OOP. 5. Věnujte čas paralelnímu a paralelnímu objektově orientovanému programování (POOP) v jazycích C, C++ a C#. Zvládnete-li tuto pětihvězdičkovou sadu programátorských kurzů, pak z vás budou opravdové IT hvězdy. Vaše hodnota na trhu práce bude enormně vysoká a možnosti takřka nekonečné. A můžete udělat vše pro to, aby se z tohoto světa stalo lepší místo pro život!
O autorovi Ing. Ján Hanák, Ph.D., MVP, vystudoval Ekonomickou univerzitu v Bratislavě. Pracuje jako vysokoškolský pedagog na zdejší Katedře aplikované informatiky Fakulty hospodářské informatiky (KAI FHI). Přednáší a vede semináře týkající se programování a vývoje počítačového softwaru v programovacích jazycích C, C++ a C#. Kromě zmíněné trojice jazyků patří k jeho oblíbeným programovacím prostředkům také Visual Basic, C++/CLI a F#. Je nadšeným autorem odborné počítačové literatury. V jeho portfoliu můžete najít následující knižní tituly: 1. Programování v jazyce C. Kralice na Hané: Computer Media, 2010. 2. C++: Akademický výučbový kurz. Bratislava: Vydavateľstvo EKONÓM, 2010. 3. Inovácie v jazykoch Visual Basic 2010, C# 4.0 a C++. Brno: Artax, 2010. 4. Visual Basic 2010 – Hotové riešenia. Bratislava: Microsoft Slovakia, 2010. 5. C#: Akademický výučbový kurz, 2. aktualizované a rozšírené vydanie. Bratislava: Vydavateľstvo EKONÓM, 2010. 6. Praktické paralelné programovanie v jazykoch C# 4.0 a C++. Brno: Artax, 2009. 7. C++/CLI – Praktické príklady. Brno: Artax, 2009.
214
Nadpis kapitoly 8. C# 3.0 – Programování na platformě .NET 3.5. Brno: Zoner Press, 2009.
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 27 28 29 30 31 32 33
9. C++/CLI – Začínáme programovat. Brno: Artax, 2009. 10. C#: Akademický výučbový kurz. Bratislava: Vydavateľstvo EKONÓM, 2009. 11. Základy paralelného programovania v jazyku C# 3.0. Brno: Artax, 2009. 12. Objektovo orientované programovanie v jazyku C# 3.0. Brno: Artax, 2008. 13. Inovácie v jazyku Visual Basic 2008. Praha: Microsoft, 2008. 14. Visual Basic 2008: Grafické transformácie a ich optimalizácie. Bratislava: Microsoft Slovakia, 2008. 15. Programovanie B – Zbierka prednášok (Učebná pomôcka na programovanie v jazyku C++). Bratislava: Vydavateľstvo EKONÓM, 2008. 16. Programovanie A – Zbierka prednášok (Učebná pomôcka na programovanie v jazyku C). Bratislava: Vydavateľstvo EKONÓM, 2008. 17. Expanzívne šablóny: Príručka pre tvorbu "code snippets" pre Visual Studio. Bratislava: Microsoft Slovakia, 2008. 18. Kryptografia: Príručka pre praktické odskúšanie symetrického šifrovania v .NET Framework-u. Bratislava: Microsoft Slovakia, 2007. 19. Príručka pre praktické odskúšanie vývoja nad Windows Mobile 6.0. Bratislava: Microsoft Slovakia, 2007. 20. Príručka pre praktické odskúšanie vývoja nad DirectX. Bratislava: Microsoft Slovakia, 2007. 21. Príručka pre praktické odskúšanie automatizácie aplikácií Microsoft Office 2007. Bratislava: Microsoft Slovakia, 2007. 22. Visual Basic 2005 pro pokročilé. Brno: Zoner Press, 2006. 23. C# – praktické příklady. Praha: Grada Publishing, 2006. 24. Programujeme v jazycích C++ s Managed Extensions a C++/CLI. Praha: Microsoft, 2006. 25. Přecházíme z jazyka Visual Basic 6.0 na jazyk Visual Basic 2005. Praha: Microsoft, 2005. 26. Visual Basic .NET 2003 – Začínáme programovat. Praha: Grada Publishing, 2004. V letech 2006 – 2010 byl jeho přínos vývojářským komunitám oceněn celosvětovými vývojářskými tituly Microsoft Most Valuable Professional (MVP) s kompetencí Visual Developer – Visual C++.
215
Programování v jaz yce C Společnost Microsoft ČR udělila Ing. Jánovi Hanákovi, MVP, v roce 2009 ocenění za mimořádně úspěšné odborné knižní publikace „Objektovo orientované programovanie v jazyku C# 3.0“ a „Inovácie v jazyku Visual Basic 2008“. Společnost Microsoft Slovakia udělila Ing. Jánovi Hanákovi, MVP, v roce 2009 ocenění za zlepšování akademického ekosystému a za signifikantní rozšiřování technologií a programovacích jazyků Microsoftu na akademické půdě. Kontakt s vývojáři a programátory udržuje zejména prostřednictvím technických seminářů a odborných konferencí, na nichž aktivně vystupuje. Za všechny vybíráme tyto: • Technický seminář Vývojářské technologie a nástroje pro vývoj softwarových produktů nové generace. KAI FHI EU a Microsoft Slovakia. Bratislava 29. 4. 2010. • Technický seminář Paralelné programovanie. KAI FHI EU a Microsoft Slovakia. Bratislava 21. 10. 2009. • Konference Software Developer 2007, příspěvek na téma Představení produktu Visual C# 2005 a jazyka C# 3.0. Praha 19. 6. 2007. • Technický seminář Novinky ve Visual C# 2005. Microsoft Slovakia. Bratislava 3. 10. 2006. • Technický seminář Visual Basic 2005 a jeho cesta k Windows Vista. Microsoft Slovakia. Bratislava 27. 4. 2006. Jako autor má letité zkušenosti s působením v elektronických a tištěných médiích. Během své kariéry pracoval na pozici odborného autora nebo odborného redaktora v následujících počítačových časopisech: PC WORLD, SOFTWARE DEVELOPER, CONNECT!, COMPUTERWORLD, INFOWARE, PC REVUE a CHIP. Dohromady publikoval více než 250 odborných a populárních prací věnovaných vývoji počítačového softwaru.
Autora můžete zastihnout na následující adrese elektronické pošty:
[email protected].
216