PĜednáška þ. 1
IAJCE
Úvod Literatura: x x x x
Záznamy pĜednášek a Vaše poznámky Herout P.: Uþebnice jazyka C, Nakladatelství KOPP, 2004, IV. pĜepracované vydání Rubeš J.: Nebojte se programovat, Computer Media 2001 Šaloun P.: Programovací jazyk C pro zelenáþe, Nakladatelství Neocortex, 2. pĜepracované vydání, 2003
Poþítaþ x
= univerzální stroj na automatické zpracování informace.
Von neumannĤv poþítaþ x x
1946 – matematik John von Neumann – schéma univerzálního poþítacího stroje základ architektury vČtšiny souþasných poþítaþĤ (kategorie PC)
x x x
struktura je nezávislá od zpracovávaných problémĤ nutné zvenþí zavést návod na zpracování – program program zpracovává data = užiteþná informace jako vstup i výstup (þísla, texty, obrázky, apod.)
Vstupní a výstupní zaĜízení (I/O = input/output)
x x
zajišĢují výmČnu informací mezi poþítaþem a okolím pĜevádČjí informaci do þíselné podoby (dvojková soustava) – vstupní zaĜízení a obrácenČ z þíselné podoby do podoby srozumitelné okolí
Procesor (CPU – Central Procesor Unit)
x x
CPU = Ĝadiþ + ALU ěadiþ podle programu dává pokyny ke zpracování dat a produkuje výstupní data.
1
PĜednáška þ. 1
IAJCE x
ALU podle pokynĤ Ĝadiþe provádí jednotlivé výpoþty a zpracovává data.
PamČĢ
x
Neumannova koncepce – program + data = tatáž pamČĢ. Nevýhoda:
x x
rozdČlena na stejnČ velké buĖky, které jsou prĤbČžnČ oþíslované (= adresa) Po sobČ jdoucí instrukce programu se uloží do pamČĢových bunČk jdoucích po sobČ, pĜístup k následující instrukci se uskuteþní z Ĝídící jednotky zvýšením instrukþní adresy o 1
Poþítaþ – HW pohled Pozn.: poþítaþ dále zkracován na PC x PC = elektronické zaĜízení, pracující pouze ve dvojkové soustavČ – všechny elektronické prvky se mohou nacházet buć ve stavu zapnuto, nebo vypnuto. x Reprezentace stavu = 1 bit. Bit, byte
1 bit = 1 b x bit: o základní jednotka informace o jedna þíslice ve dvojkové soustavČ (odtud bit = binary digit) o nejmenší þást pamČti poþítaþe x
1 Byte = 1 B = 8 bitĤ.
x
Jednotky vČtší než 1 b a 1 B – pomocí pĜedpon dle soustavy SI. Pozor: násobitelé základ 2, nikoli 10:
PamČti v PC
2
PĜednáška þ. 1
IAJCE x
vnitĜní pamČĢ (operaþní pamČĢ) RAM (Random Acces Memory = pamČĢ s náhodným pĜístupem) – rychlá (rychlost srovnatelná z CPU – 1-ky ns, velikost dnes 100ky MB až 1ky GB), obsah se po vypnutí napájení ztrácí.
x
vnČjší pamČti - dlouhodobé uložení dat HDD, CD-ROM, CD-RW, FLASH Disc apod. Vyšší kapacita než RAM, pomalejší (1-ky ms), její obsah zĤstává zachován i po vypnutí napájení
CPU
x x
x
x x x
program se spouští pouze z RAM (rychlost) – po zapnutí napájení se musí program do RAM nejprve pĜekopírovat z vnČjší pamČti (= bootování). nepracuje po jednotlivých bitech, ale s nČkolika bity najednou – dČlení CPU (i PC) na: o 8b („osmibitový CPU“) o 16b o 32b o 64b („šedesátiþtyĜbitový CPU“) = šíĜka slova – urþuje výpoþetní výkon Umí vykonávat pouze jednoduché, elementární operace: o Základní aritmetické operace (+-*/). o PĜesuny dat (CPU <–> pamČĢ, pamČĢ <–> pamČĢ). o ZámČna poĜadí vykonávaných instrukcí (podprogramy, skoky) Elementární operace CPU = instrukce. Množina všech instrukcí CPU = instrukþní soubor (~ 10-ky až 100-ky instrukcí) Každý typ procesor má svĤj vlastní odlišný instrukþní soubor
Algoritmus Trocha historie x (Abnj Abd AllƗh Muhammad ibn MnjsƗ al-KhwƗrizmƯ) o cca 780–840 o významný perský matematik o vytvoĜil systém arabských þíslic a základy algebry (konkrétnČ metody Ĝešení lineárních a kvadratických rovnic) o al-KhwƗrizmƯ –> al-goritmí –> algoritmí –> … x algorismus = „provádČní aritmetiky pomocí arabských þíslic“ x algoritmus v dnešním významu se používá až zhruba od 20. století.
Definice x x
= pĜesný návod þi postup, kterým lze vyĜešit daný typ úlohy v programování = teoretický princip Ĝešení problému (oproti pĜesnému zápisu v konkrétním programovacím jazyce) 3
PĜednáška þ. 1
IAJCE
Vlastnosti algoritmĤ x x
x
x x x
Koneþnost Každý algoritmus musí skonþit v koneþném poþtu krokĤ. Determinismus Každý krok algoritmu musí být jednoznaþnČ a pĜesnČ definován; v každé situaci musí být naprosto zĜejmé, co a jak se má provést, jak má provádČní algoritmu pokraþovat. Vstup = data, která jsou mu pĜedány pĜed zapoþetím jeho provádČní, nebo v prĤbČhu jeho þinnosti. Výstup = odpovČć na problém, který algoritmus Ĝeší. Efektivita každá operace algoritmu provedena v koneþném þase Obecnost Algoritmus neĜeší konkrétní problémy („jak spoþítat 3×7“), ale obecnou tĜídu problémĤ („ souþin dvou celých þísel“).
Zápis algoritmĤ x x x x
Slovní popis v pĜirozeném jazyce Vývojový diagram Program v pseudojazyku Program v programovacím jazyku
PĜíklad: Vypiš dvakrát slovo „ahoj“ Slovní popis v pĜirozeném jazyce
Vypiš Ahoj a vypiš Ahoj x
Algoritmus nevykazuje vlastnost hromadnosti – nelze ho použít na tisk jiného slova, a nelze ho jednoduše modifikovat na rĤzný poþet tiskĤ.
x
Opravme to: Slovo bude „Ahoj. N bude poþet opakování, a nyní N=2. Pak N-krát vypiš slovo.
Vývojový diagram
4
PĜednáška þ. 1
IAJCE
Tisk 2x Ahoj: Poc = poþítadlo tiskĤ
Pseudojazyk Poc = 1 slovo = Ahoj N = 2
5
PĜednáška þ. 1
IAJCE dokud plati (Poc <= N) provadej begin vypiš slovo Poc = Poc + 1 end Programovací jazyk
Pozn.: ZámČrnČ vypuštČno „slovo“, neboĢ práce s textem patĜí bohužel v jazyce C k ponČkud nároþnČjším þinnostem. x
PĜedchozí algoritmus v jazyce C: N = 2; Poc = 1; while (Poc <= N) { printf(„Ahoj“); Poc++; }
x
PĜedchozí algoritmus v jazyce Pascal: N := 2; Poc := 1; while (Poc <= N) do begin writeln(„Ahoj“); Poc := Poc + 1; end
Programovací jazyk (PJ) Pozn.:
x x
program = zápis algoritmu ve zvoleném programovacím jazyce programátor = þlovČk, zabývající je tvorbou programĤ.
Definice x x
x
= prostĜedek pro zápis algoritmĤ, jež mohou být provedeny na poþítaþi. = komunikaþním nástroj mezi programátorem, který v programovacím jazyce formuluje postup Ĝešení daného problému, a poþítaþem, který program interpretuje technickými prostĜedky. =formální jazyk
DČlení PJ Dle míry abstrakce od HW poþítaþe: 6
PĜednáška þ. 1
IAJCE x x
strojovČ orientované Vyšší programovací jazyky (VPJ) – High Level Programming Language
Dle využitelných programátorských technik x Strukturované – Pascal, C x OOP – C++, Java OOP = objektovČ orientované programování Dle úþelu x Pro „spustitelné aplikace“ – náš pĜípad x webové aplikace x skriptovací x atd. Ad StrojovČ orientované
x
Strojový kód o Programujeme PC na úrovni jeho instrukcí o PĜ.: CPU Intel x86 kompatibilní (napĜ. Intel Pentium, AMD Athlon apod.): Dek: Hex: Bin:
176 97 B0 61 0110000 01100001
= pokyn, aby do svého registru AL (= þást CPU) pĜesunul hodnotu 97. Kód pĜesunu = 176 x
Assembler o = programovací jazyk velice blízký strojovému kódu o jazyk symbolických adres. o tvoĜí jej pouze zástupné symboly (mnemotechnické symboly), které pĜímo odpovídají strojovému kódu. o PĜ.: 176 97 ve strojovém kódu = mov al, 61h v assembleru "mov" = název instrukce, zkratka anglického slova move (pĜesun) o lze již považovat za programovací jazyk nejnižší úrovnČ. o Program „Ahoj svete“ v assembleru (þást): push mov sub
ebp ebp,esp esp,0C0h
7
PĜednáška þ. 1
IAJCE push push push lea mov mov rep stos mov push call add cmp call xor pop pop pop add cmp call mov pop ret
ebx esi edi edi,[ebp-0C0h] ecx,30h eax,0CCCCCCCCh dword ptr es:[edi] esi,esp offset string "Ahoj svete\n" (41563Ch) dword ptr [__imp__printf (4182B8h)] esp,4 esi,esp @ILT+300(__RTC_CheckEsp) (411131h) eax,eax edi esi ebx esp,0C0h ebp,esp @ILT+300(__RTC_CheckEsp) (411131h) esp,ebp ebp
Ad vyšší
x x x x
PodstatnČ srozumitelnČjší logická struktura programĤ nejsou závislé na strojových principech poþítaþe NejznámČjší: Pascal, Basic, Fortran, C, C++, C#, Java, PHP, ASP...
Syntaxe a sémantika programovacího jazyka Syntaxe
x x
= souhrn pravidel udávajících pĜípustné tvary dílþích konstrukcí a celého programu. Syntaktický diagram jednoho „elementu“ programovacího jazyka, kterému se Ĝíká identifikátor.
8
PĜednáška þ. 1
IAJCE
= „Identifikátor je posloupnost písmen a þíslic (anglická abeceda), zaþínající písmenem.“
x
x
Platné identifikátory (uvažujeme písmena malá i velká): A a Ahoj AHOJ MujPlat1 MujPlat2
x
Neplatné identifikátory: 3plat
nutno je bez výhrady dodržovat (je to ovšem pomČrnČ snadné, viz. další odstavec o pĜekládání).
Sémantika
x x
= význam jednotlivých konstrukcí slovní popis nebo vývojové diagramy
Vznik programĤ x x
každý program pro PC napsaný ve VPJ se musí pĜetransformovat do strojového kódu vývojový diagram postupu pĜi vývoji programu (od zápisu ve VPJ do jeho funkþní podoby)
9
PĜednáška þ. 1
IAJCE
o Zdrojový kód = textový soubor s programem v PJ o PĜeklad = pĜevod do strojového kódu, provádí pĜekladaþ (Compiler) o LadČní = hledání a odstraĖování logických a bČhových chyb, rĤzné techniky - Logická chyba: Proþ to poþítá 2+2=6, netiskne, apod. - BČhová chyba: /0, zápis do pamČti, která není naše apod. – program se hroutí - chyba v programu = bug - ladČní = debugging - ladící program = Debugger PĜeklad podrobnČji
x
Nejprve tzv. kompilace (compile) jedn. modulĤ (souborĤ se ZK), pak tzv. slinkování (linking), provádí program zvaný „linker“.
10
PĜednáška þ. 1
IAJCE x
Pokud je pĜeklad do SK provádČn tímto zpĤsobem, mluvíme pak o tzv. kompilaþní implementaci programovacího jazyka.
Kompilaþní vs. interpretované jazyky
x
kompilaþní implementace PJ
o napĜ. C, Pascal, C++ x
interpretaþní metoda
o napĜ. Basic, PHP x
kombinace o NapĜ. C# (.NET), Java
Vývojové prostĜedky Editory zdrojových kódĤ
= jednoduchý textový editor (nemá pokroþilé formátovací funkce jako napĜ. MS Word), ale navíc: x ZvýrazĖování syntaxe (syntax highlight) x Formátování kódu (code formating) x Automatické doplĖování jmen apod. (code completion) PĜekladaþe
x
obvykle ovládány pĜes pĜíkazový Ĝádek velkou sadou rĤzných pĜepínaþĤ
debuggery
x
umožĖují: o Zastavení programu o Krokování o Prohlížení vnitĜních stavĤ (naþetla se ta 3 z klávesnice?)
Integrované vývojové prostĜedí
11
PĜednáška þ. 1
IAJCE x x x
= integrace editoru zdrojových kódĤ, ovládání pĜekladaþe, debuggeru a dalších funkcí do jednoho jednoho programu IDE – Integrated Development Envrironment nejznámČjší IDE pro vývoj v C (spíše C/C++): o Borland C (C++) – jen pro DOS o Borland C++ Builder o Microsoft Visual Studio (resp. jeho þást Visual C++) o KDevelop (Linux)
Historie Jazyka C x x x x x
Poþátek mezi léty 1969 a 1973 v Bellových laboratoĜích AT&T 1978 – Denis Ritchie a Brian Kernighan vydali knihu The C Programming Language – po mnoho let neformální specifikace jazyka (známa jako "K&R") 1983 – poþátek standardizace 1989 – schváleno ANSI C 1990 – ANSI C pĜejímá ISO do ISO 9899|ISO/IEC 9899:1990
Výhody a Nevýhody C Výhody x x x x
Vysoce rozšíĜený (PC, Embedded systems), široká paleta vývojových prostĜedkĤ na rĤzných platformách Na jeho výrazových prostĜedcích je založena vČtšina moderních PJ Programy jsou malé a rychlé Dovolí programátorovi témČĜ vše
Nevýhody x x x
Dovolí programátorovi témČĜ vše Jazyk nenutí programátora k pĜehlednému zápisu, programy memusí být dobĜe þitelné kompilátor poskytuje þasto zmatená chybová hlášení, pĜípadnČ vĤbec žádná.
První program v Jazyce C x
Klasický „Hello world“ #include <stdio.h> int main(void) { printf("Ahoj svete\n"); return 0; }
12
PĜednáška þ. 1
IAJCE x x
Zdrojový kód zkopírován z VS2005 – všimnČte si zvýraznČné syntaxe program po pĜeložení a spuštČní:
Rozbor programu:
x
Program v jazyce C se sestává z tzv. funkcí (cca totéž, co v matematice) – v programu musí být minimálnČ jedna, a ta se musí jmenovat main int main(void) { Vas kod return 0; }
o void = funkce nemá argumenty. x
printf("Ahoj svete\n") vytiskne na obrazovku Ahoj svete a \n odĜádkuje
x x
o printf je také funkce. Každý pĜíkaz musí být zakonþen stĜedníkem. #include <stdio.h> – vložení tzv. hlaviþkového souboru (zpĜístupní funkce pro práci s obrazovkou a klávesnicí – zde printf)
13
PĜednáška þ. 1
IAJCE
Pozn.: štábní kultura x
Vhodné formátování textu dokáže výraznČ zlepšit þitelnost kódu int JenSude(TPOLE Pole, int delka, int *NovaDelka) { TPOLE pPom, pPomDef; int i,Count=0; UCHAR pomoc; pPom = (TPOLE)malloc(delka*sizeof(UCHAR)); if (pPom == NULL) return 1; pPom = Pole; pPomDef = Pole; for(i=0;i<delka;i++) { if ((*Pole%2)==0) { pomoc = *Pole; *pPom++ = *Pole; Count++; } Pole++; } *NovaDelka = Count; Pole = pPomDef; Pole = (TPOLE)realloc((void *)Pole, Count); return 0; }
o Takto odsazený text vytvoĜilo VS2005 v podstatČ samo. x
ŠpatnČ – tentýž zdrojový text int JenSude(TPOLE Pole, int delka, int *NovaDelka) { TPOLE pPom, pPomDef; int i,Count=0; UCHAR pomoc; pPom = (TPOLE)malloc(delka*sizeof(UCHAR)); if (pPom == NULL) return 1; pPom = Pole; pPomDef = Pole; for(i=0;i<delka;i++) { if ((*Pole%2)==0) { pomoc = *Pole; *pPom++ = *Pole; Count++; } Pole++; }
14
PĜednáška þ. 1
IAJCE *NovaDelka = Count; Pole = pPomDef; Pole = (TPOLE)realloc((void *)Pole, Count); return 0; }
15
PĜednáška þ. 2
IAJCE
Zápis programu v jazyce C x x x x x
Zdrojový text – *.c (není však podmínkou) Jazyk C je case senzitive = rozlišuje velikost písmen Tzv. bílé znaky (Enter, mezera, tab …) ve ZK pĜekladaþ ignoruje oddČlovaþ v reálných þíslech („desetinná þárka“) – teþka (1.234) v programech veškeré texty (zatím) pouze anglická abeceda – bez diakritiky
KomentáĜe x x x x
pomocný text pro þtenáĜe ZK s nápovČdnými informacemi (co daný úsek kódu dČlá, proþ, jak …) pĜi pĜekladu jsou ze ZK vypuštČny – pĜekladaþ je „nevidí“ kód se komentuje prĤbČžnČ pĜi jeho vytváĜení!!! Pozn.: Ve VS2005 jsou komentáĜe zvýraznČny zelenČ
ANSI C
x x x
zaþátek komentáĜe konec komentáĜe pĜíklady
/* */
/* komentar zapsany na vice radek s vynechanim jednoho radku */ /* komentar na jednom radku */
x
Nevýhoda – složitý zápis jednoduché poznámky na jeden Ĝádek. Proto vČtšina pĜekladaþĤ povoluje i jednoĜádkové C++ komentáĜe // toto je C++ komentar. Jeho konec je totozny s koncem radku
Štábní kultura x x x x x
za uvozujícím a pĜed ukonþujícím znakem komentáĜe je mezera pokud lze, jednoĜádkové poznámky za pĜíkazy zarovnávat na tabelátor pĜed každým vČtším souvislým blokem pĜíkazĤ výrazný komentáĜ u každé „vychytávky“ alespoĖ jednoĜádkový TODO komentáĜe = komentáĜ, oznaþující a popisující další postup programování (nedodČlky)
1
PĜednáška þ. 2
IAJCE
//**************************************************************** // eliminacni smycka //**************************************************************** m = 1; // smycka bezi az od druheho radu do { // eliminacni smycka SpatneReseni = 0; // hledani m-teho maxima NaselMax = 0; // pokud najde lok. max. dam si to do 1 // TODO: osetrit mozne preteceni NaselMax MaxPwrCe[m] = 0; for(i=BLIZKA_ZONA;i
0) { // kkk = 0 -> nemam zatim zadne spatne id for(ii=0;ii
PromČnná x x
Opakování: Data a pamČĢ poþítaþe PĜíklad: o Realizace operace v programu: MujPlat = 13 TvujPlat = 68 SoucetPlatu= MujPlat + TvujPlat
CPU umí pouze seþtení dvou þísel v pamČti Adresa: 7 6 5 4 3 2 1
PAMċġ 68 81
13
CPU CPU sþítá obsah bunČk a vrací výsledek na adresu 5 x x
Programování s pomocí þísel adres je nepohodlné a nebezpeþné. Proto nám VPJ nabízí možnost si místa v pamČti pojmenovat PromČnná = místo v pamČti (nebo také tzv. datový objekt), oznaþené jménem; je v ní uložená hodnota, která se mĤže v prĤbČhu práce programu mČnit
2
PĜednáška þ. 2
IAJCE
x x
vznik promČnné – viz. pojem deklarace níže Jméno promČnné je tzv. identifikátor
identifikátor x x x x x x
= jakékoli uživatelské jméno v našem programu. Pojmenovat mĤžeme (spíše musíme) promČnnou, konstantu, funkci… Vlastnosti (= syntaxe) Max 31 znakĤ (mĤže být i delší, ale pak pĜekladaþ další znaky ignoruje) Libovolná kombinace písmen (malá i velká – case sensitive), þíslic a podtržítek (_) První znak vždy písmeno nebo podrtžítko PĜíklady odlišných identifikátorĤ MujPlat MUJPLAT mujplat
Štábní kultura x x
Používat významové identifikátory (vyjadĜuje úþel). PĜ.: oznaþení mého platu p MujPlat
x
// spatne // dobre
Pokud se jedná o sousloví, pak buć jednotlivá slova oddČlit podtržítkem muj_plat
x
Nebo dohromady, ale poþáteþní písmeno každého slova velké MujPlat
x
Krátké identifikátory používat jen v ustálených významech v naprosto jasném kontextu Indexy, parametry cyklĤ i j k Znaky c ěetČzce s
x
Jako identifikátor lze použít jakékoli slovo, až na
3
PĜednáška þ. 2
IAJCE
Klíþová slova x x x
= zvláštní identifikátory, které mají speciální význam pro pĜekladaþ jazyka C. oznaþují standardních typĤ dat, nČkterých pĜíkazĤ jazyka C apod. ANSI C jich definuje 32: auto break case char const continue default do
double else enum extern float for goto if
int long register return short signed sizeof static
struct switch typedef union unsigned void volatile while
Pozn.:
x x
pozor na case sensitivitu – všechny jsou malými písmeny!!! vČtšina editorĤ ZK klíþová slova zvýrazĖuje (VS2005 modĜe)
Datový typ x x
každá promČnná musí být urþitého datového typu. datový typ specifikuje: o množinu hodnot, jakých mĤže nabývat (napĜ. celá þísla z intervalu <-128; 127>) o množinu operací, které lze z datovým typem provést aritmetické operace – +-*/ atd. relaþní operace – porovnání atd.
x
Datových typĤ je v C celá Ĝada (podrobnČji pozdČji): celá þísla, reálná þísla, ĜetČzce, pole… NČkteré datové typy v C pro práci s þísly: char celá þísla v rozsahu -128 až 127 int celá þísla v rozsahu -2 147 438 648 až 2 147 438 647 float racionální þísla v rozsahu pĜibližnČ 3.4E-38 až 3.4E+38 (v absolutních hodnotách)
x
x
C je typový jazyk = každá promČnná má pevnČ pĜiĜazen svĤj datový typ, který nelze v prĤbČhu práce programu zmČnit o napĜ.: promČnná i datového typu int i = 10 i = 0.325
// OK // nelze, 0.325 neni cele cislo, prekladac … // … ohlasi chybu
4
PĜednáška þ. 2
IAJCE x
Názvy všech datových typĤ = klíþová slova
Deklarace promČnné x x
= pĜíkaz který pĜidČlí promČnné urþitého datového typu jméno pĜi deklaraci promČnné zároveĖ pĜekladaþ pĜidČlí promČnné pamČĢ (tedy provede „pĜidružení“ jména promČnné na konkrétní místo v pamČti) – alokace pamČti
x
syntaxe: datový_typ
x
identifikátor, ;
pĜíklady int MujPlat; float StavUctu, i;
x
// = deklarace promČnné MujPlat typu int /* jedním pĜíkazem lze deklarovat nČkolik promČnných téhož datového typu najednou */
hodnota promČnné není po deklaraci definována (ne tak docela, nČkteré promČnné = 0), lze provést deklaraci s inicializací = definice poþáteþní hodnoty promČnné int i=0, Datum; float pi=3.14592;
x
Deklaraci promČnné lze v C provést bezprostĜednČ na zaþátku každého bloku (po každé „{“ – a ještČ nČkde, ale to pozdČji) pĜíklad: int main(void) { int i; float Cislo1=10.0, Cislo2=-124.36; float Vysledek; // Vas kod return 0; }
x
Pozn.: existuje ještČ termín definice promČnné – výklad je nejasný,v nČkteré literatuĜe se oba pojmy zamČĖují
Štábní kultura x x
Po deklaracích prázdný Ĝádek Na jednom Ĝádku deklarace pouze promČnných, které jsou spolu v logickém vztahu int i,j,k; int Cislo, Vysledek;
PĜiĜazení x x
= naplnČní promČnné hodnotou (uložení hodnoty do promČnné) Syntaxe: PromČnná = výraz;
5
PĜednáška þ. 2
IAJCE
x
Pozor: není to rovnice!!!
int MujPlat; MujPlat = 68; // do promenne MujPlat priradim hodnotu 68 MujPlat = MujPlat + 120; // do MujPlat priradim hodnotu vyrazu MujPlat+120
PAMċġ
Adresa: 5 4 3 2 1
68
Adresa: 5 4 3 MujPlat 2 1
CPU
PAMċġ
68
Adresa: 5 4 3 MujPlat 2 1
CPU
PAMċġ
188
MujPlat
CPU
188 = MujPlat + 120
Pojem l-hodnota x x
„el“, l-value = vše, co mĤže stát na levé stranČ pĜiĜazovacího pĜíkazu (musí to mít adresu v pamČti) o PromČnná je l-hodnota o Konstanta 123 není l-hodnota o Výraz MujPlat + 120 není l-hodnota
Výraz x x
x
PĜedepisuje výpoþet hodnoty urþitého datového typu Skládá se z: o operandĤ PromČnných Konstant Volání funkcí o OperátorĤ (+-*/ atd) o Závorek PĜ: MujPlat = 2*(TvujPlat + sin(20*Dan);
x
PoĜadí operací je dáno: o Závorkami o Prioritou operátorĤ x +y *z je totéž jako x + (y * z) operátor násobení má vyšší prioritu než sþítání
6
PĜednáška þ. 2
IAJCE o Asociativitou operátorĤ Sþítání je asociativní zleva: x + y + z se vyhodnocuje jako (x + y) + z Pozor: nČkteré operátory jsou asociativní zprava!!!
Základní aritmetické operátory binární (pĤsobí na dva operandy) sþítání odþítání násobení reálné dČlení celoþíselné dČlení dČlení modulo x
+ * / / %
o typu dČlení rozhodují operandy: celoþíselné int/int reálné int/float float/int float/float
pozn:
o zde int = jakýkoli celoþíselný datový typ (mĤže jich být více – napĜ. již zmínČný char) o podobnČ float pĜíklad int j=13, i=13; j = j/4; i = i%4;
// j bude 3 // i bude 1 – zbytek po deleni
pĜíklad
unární (pĤsobí na jeden operand) unární plus unární mínus
+ -
pĜíklad: i = -j;
Jednoduchý vstup/výstup v C x x x x
C má spoustu funkcí pro vstup a výstup, všechny deklarovány v stdio.h Vstup z klávesnice: scanf() Výstup na obrazovku: printf() obČ funkce mají ve skuteþnosti trochu komplikovanČjší definici – níže uvedené je zatím zjednodušeno pozn.: () znaþí, že se jedná o funkci.
7
PĜednáška þ. 2
IAJCE
funkce scanf() syntaxe: scanf("format_cteni", &promenna)
sémantika:
x
x
po svém zavolání funkce vyþká na zadání pĜíslušné hodnoty na klávesnici, po stisku ENTER zadané znaky pĜeþte dle formátovací specifikace format_cteni, a nakonec pĜeþtená data uloží do promČnné promenna. znak & je tzv. adresový operátor, a je zde nutný!!!
formáty þtení: %d %f %c
celé dekadické þíslo reálné þíslo znak
funkce printf() syntaxe 1) printf("text")
Pozor na uvozovky " „“ sémantika 1)
x
funkce vytiskne text uvedený v uvozovkách printf("Ahoj svete")
syntaxe 2) printf("text ", <promenne>)
sémantika 2)
x
funkce provede analýzu textu text, a pokud obsahuje Ĝídící specifikace format_cteni, pak místo nich vytiskne obsah promČnných, uvedených ve formČ seznamu oddČleného þárkami
pĜíklad 2) float MujPlat = 7894.5; int TvujPlat = -100; printf("Muj plat je %f, tvuj pak %d\n", MujPlat, TvujPlat);
Pozor!!!
Poþty formátovacích specifikací a jejich typy by si mČly odpovídat z promČnnými, ovšem pĜekladaþ to nekontroluje -!!! float MujPlat = 7894.5;
8
PĜednáška þ. 2
IAJCE int TvujPlat = -100; printf("Muj plat je %f, tvuj pak %d\n", TvujPlat);
PĜíklad kompletního programu /* IAJCE pr02 example 1 Program spocita soucet dvou celych cisel nactenych z klavesnice a vytiskne soucet na obrazovku */ #include <stdio.h> int main(void) { int Cislo1, Cislo2; int Vysledek; // nacteni promennych z klavesnice printf("Zadej prvni cislo: "); scanf("%d", &Cislo1); printf("Zadej druhe cislo: "); scanf("%d", &Cislo2); // vlastni soucet Vysledek = Cislo1 + Cislo2; // tisk vysledku printf("Vysledek je: %d\n", Vysledek); return 0; }
9
PĜednáška þ. 3
IAJCE
ýíselné soustavy Polyadické soustavy x x
polyadická soustava Æ þíslo tvoĜeno polynomem Obraz þísla A v soustavČ o základu z: m
A( Z )
¦a
i n
i
zi
(1)
ai je symbol (þíslice) z je základ m je poþet Ĝádových míst, na kterých má základ kladný exponent (celá þást) n je poþet Ĝádových míst, na kterých má základ záporný exponent (zlomková þást þísla). Pě: 2504,36 2 10 3 5 10 2 0 101 4 10 0 3 10 1 6 10 2 ěádová þárka = místo, které oddČluje celou þást þísla od zlomkové.
kde:
NejþastČji používané þíselné soustavy:
x x
x
Desítková o z = 10 o symboly 0,1,2,3…9 Dvojková o z = 2, odpovídá technickému principu poþítaþe, jedna þíslice = bit, nevýhoda – dlouhý zápis o symboly 0,1 Hexadecimální o z = 16, používá se pro zkrácení bin zápisu (každé 4 b = jedna hexadecimální þíslice) o symboly DEC HEX 0 0 1 1 | 9 9 10 A 11 B 12 C 13 D 14 E 15 F
PĜevody soustav BIN to DEC: dosazením do (1) 100101 ( 2 )
1 2 0 0 21 1 2 2 0 2 3 0 2 4 1 2 5
37 (10 )
podrobnČjší pohled na 1B = 8b jako þíslo ve dvojkové soustavČ
1
PĜednáška þ. 3
IAJCE
bit: Váha bitu:
b7 27 128
b6 26 64
b5 25 32
b4 24 16
b3 23 8
b2 22 4
b1 21 2
b0 20 1
pĜevod do DEC: Na pĜíslušné pozici 1 Æ daná váha se zapoþítá, 0 nikoli pĜíklad: 0001 1010(2) = 16 + 8 +2 = 26(10) DEC to BIN: postupným dČlením dekadického þísla þíslem 2 a sepisováním zbytku po celoþíselném dČlení. Výsledek = zápis všech zbytkĤ v obráceném poĜadí (odspodu na „zleva doprava“) 215 : 2 = 107 1 53 1 26 1 13 0 6 1 3 0 1 1 0 1 215(10) = 11010111(2) HEX to DEC: Dosazením do vzorce (1) 1 A8 F(16 )
15 16 0 8 16 1 10 16 2 1 16 3
6799 (10 )
HEX to BIN: Každou þíslici separátnČ pĜevést na dvojkové vyjádĜení 85(16) = 1000 0101(2) BIN to HEX: ýíslo zleva doplnit nevýznamnými nulami tak, aby poþet míst byl dČlitelný 4. Každou þtveĜici þíslic separátnČ pĜevést na hex. 110001101(2) = 0001 1000 1101(2) = 18D(16)
Konstanty v Jazyce C x x
opak promČnné, bČhem výpoþtĤ se nemČní mĤže být souþástí výrazĤ, deklarací int a,b=30; // 30 je konstanta pouzita pro inicializaci promenne a float c,d=1.2345; // 1.2345 je konstanta a=-58*b;
x
// konstanta ve vyrazu
Jak þíst toto? c = 125.9898;
2
PĜednáška þ. 3
IAJCE
do promČnné c je pĜiĜazena hodnota konstantního výrazu, neboli: Nejprve je vyhodnocen výraz na pravé stranČ operátoru pĜiĜazení, výsledkem je hodnota 125.9898, a ta je pĜiĜazena do promČnné c
Pojmenované konstanty x x
odstraĖují z programu „magická þísla“ Æ nepĜehlednost kódu pĜíklad: hodnota pi
založení pojmenované konstanty #define KONSTANTA HODNOTA #include <stdio.h> #define PI 3.14592
// konstanta PI
int main(void) { // atd.
poznámky
x x
za #define není stĜedník!!! Konstanty mohou být rĤzného typu, podrobnČji viz. dále
štábní kultura x
pojmenované konstanty vždy velkými písmeny #define PI 3.14592
Uložení dat v poþítaþi, datové typy a konstanty v C podrobnČji x
PC pracuje pouze ve dvojkové soustavČ – vše musíme pĜevést na posloupnost bitĤ – kódování dat (rĤzné reprezentace þísel, znakĤ, zvuku, atd. – formát, nebo kód)
Celá þísla x
doposud známe datový typ char a int
Celá þísla bez znaménka (unsigned) x x
sign = znaménko þíslo uloženo v tzv. pĜímém kódu (význam v dekadické soustavČ je totožný s významem v soustavČ binární) DEC 0 1 131 atd.
x
BIN (pro 1 B) 0000 0000 0000 0001 1000 0011
kapacita þísla K (kolik lze zobrazit rĤzných þísel) je úmČrná poþtu bitĤ N pro uložení þísla K = 2N 1 B = 28 = 256 (rĤzných þísel)
3
PĜednáška þ. 3
IAJCE 4 B = 232 = 4 294 967 296 x x
nejmenší zobrazitelné dekadické þíslo nejvČtší zobrazitelné dekadické þíslo AMAX = 2N-1
0 AMAX
1 B = 28-1 = 255 4 B = 232-1 = 4 294 967 295 x Jak to funguje v PC? PĜi zadání dekadického þísla na klávesnici se automaticky provede pĜepoþet do soustavy dvojkové, pĜi tisku pak obrácenČ
Celá þísla se znaménkem (signed) x
Problém: Jak se ve (nejenom) dvojkové soustavČ uloží záporná þísla? (znaménko nepatĜí mezi symboly žádné þíselné soustavy) V dvojkové soustavČ – jeden bit (obvykle nejvyšší) využijeme pro uložení znaménka:
x
Obvyklá reprezentace je
x
0 – kladné znaménko 1 – záporné znaménko x x
zobrazitelný rozsah þísel (v absolutních hodnotách) = cca 1/2 neznaménkového þísla vlastní vyjádĜení záporného þísla – nČkolik možností
PĜímý kód
x x x
záporné þíslo = nejvyšší bit do 1 a žádná další zmČna Mají-li záporná þísla v nejvyšším Ĝádu 1, pak se vlastnČ pĜesouvají do druhé poloviny rozsahu zobrazitelných þísel Matematicky lze vyjádĜit obraz þísla A v pĜímém kódu P(A) vztahem: P(A) = |A| = A P(A) = ½*K + |A|
pro A >= 0 pro A <= 0
4
PĜednáška þ. 3
IAJCE
o o o o
x
Nula má dva obrazy nejmenší zobrazitelné dekadické þíslo nejvČtší zobrazitelné dekadické þíslo Vybraná þísla (pro 1 B):
0 a ½*K. -2N-1-1 2N-1-1
A -127 -126
P(A) 255 254
P(A)bin 1111 1111 1111 1110
pozn. min. záporné þíslo
-1 0 1
129 0 (128) 1
1000 0001 0000 0000 (1000 0000) 0000 0001
kladná (záporná) nula
127
127
0111 1111
max. kladné þíslo
používá se pro zobrazení mantisy u reálných þísel
doplĖkový kód (dvojkový doplnČk)
x
obraz þísla A v doplĖkovém kódu D(A): D(A) = A D(A) = Z + A
x x x x
pro A >= 0 pro A < 0
nejmenší zobrazitelné dekadické þíslo nula je nula nejvČtší zobrazitelné dekadické þíslo Pro 1 B pak budou þísla:
-2N-1 2N-1-1
A -128 -127
D(A) 128 129
D(A)bin 1000 0000 1000 0001
pozn. min. záporné þíslo
-1 0 1
255 0 1
1111 1111 0000 0000 0000 0001
nula
127
127
0111 1111
max. kladné þíslo
5
PĜednáška þ. 3
IAJCE
x x
použit pro uložení a práci se všemi typy celých þísel se znaménkem Jak to funguje? o z klávesnice zadám -1, poþítaþ uloží do pamČti 255 o v pamČti je þíslo 129, na monitor se vypíše -127
Celoþíselné datové typy v C x
celá þísla (na platformČ Win32 a Linux) typ char short int int long int
x x
pamČĢ 8 b (1 B) 16 b (2 B) 32 b (4 B) 32 b (4 B)
poznámka pĜi deklaraci lze zapsat pouze short lze pouze long
všechny mohou být unsigned nebo signed (implicitnČ – pokud nezadáte nic; pro char to není definováno, záleží na pĜekladaþi). ekvivalentní zápisy (vertikálnČ)
short short int signed short int
char signed char
Zobrazitelné rozsahy þísel (Win32, Linux) unsigned
signed
char short int int long int
0 255 -128 127 0 65 535 -32768 32767 0 4 294 967 295 -2 147 483 648 2 147 483 647 0 4 294 967 295 -2 147 483 648 2 147 483 647 x Hodnoty vychází ze vztahĤ uvedených výše, signed typy uloženy ve dvojkovém doplĖku x Pozn obsazení pamČti (udává rozsah!!!) se mĤže u rĤzných pĜekladaþĤ lišit (napĜ. v pĜekladaþích pro MS-DOS je int 2 B) x ale vždy je (v bytech) char = 1 B unsigned = signed short <= int <= long
Celoþíselné konstanty v C Dle soustavy
x x
desítková soustava (první nesmí být 0 – to je osmiþková soustava) o 12, -47992 šestnáctková – 0x…(0X…) o 0X12, 0xAAAA
rĤzné typy:
x x
typ je urþen buć její velikostí (neuveden = signed int, nevejde se = signed long) nebo explicitnČ L(l) = long, U(u) = unsigned
6
PĜednáška þ. 3
IAJCE pĜíklady: #define POCET 120LU #define N 0xFF a = a*0xA;
// = 10*a
Znaky x x
každému znaku je nutné pĜiĜadit nČjaké þíslo (nezáporné – pĜímé mapování znak <-> þíslo) existuje mnoho kódĤ (ASCII, Win1250, ISO 8859-2, Unicode…)
ASCII
x x
American Standard Code for Information Interchange kódovací tabulka pro základní znaky anglické abecedy, þíslice, netisknutelné znaky (enter, tab apod.) x 7-bitová (nejvyšší bit v byte je 0) Æ þísla 0 – 127 ASCII þíslice 0 48 1 49 | 9 57 velká písmena A 65 B 66 | Z 91 malá písmena a 97 b 98 | z 123
Znakový datový typ v C x x
Neexistuje, jednotlivé znaky v pamČti = celá þísla dle ASCII – jedno zda v char, int, signed þi unsigned atd. Pouze pro I/O lze poþítaþ donutit pracovat se znaky –zadávání þi tisk – formátovací specifikace %c u pritnf() a scanf():
unsigned char c; scanf("%d", &c); // zadam 9 // hodnota promenne c je 9 scanf("%c", &c); // zadam 9 // hodnota promenne c je 57 (ASCII kod znaku 9) printf("%d", c); // vytiskne se 57 (obsah promenne se chape jako cislo) printf("%c", c); // vytiskne se 9 (obsah promenne se chape jako znak)
x
Znak = þíslo Æ lze s nimi pĜímo provádČt aritmetické operace PĜevod malé abecedy na velkou c = c - 32
// napr. ASCII (a) je 97, ASCII (A) je 65, offset je 32
Znakové konstanty v C x x
vždy uzavĜeny mezi apostrofy'' hodnota konstanty je odvozena od odpovídajícího þísla v ASCII tabulce 7
PĜednáška þ. 3
IAJCE možnosti zápisu
x
pĜímý znak '4', 'a', '*' x ASCII hodnota v hexa soustavČ '\0xHH' – obvykle pro neviditelné znaky '0xA' je pĜechod na novou Ĝádku '0x41' je znak A (ale lepší je 'A') pozn: \ má význam zmČny významu;'0xHH' by byla vlastnČ nedovolená þtyĜznaková konstanta. Konstanta uvozená \ se nazývá escape sekvence x znakové escape sekvence ASCII Název Význam \0 0x00 Nul Nula \a 0x07 Alert (Bell) pípnutí \b 0x08 Backspace návrat o jeden znak zpČt \f 0x0C Formfeed nová stránka nebo obrazovka \n 0x10 Newline pĜesun na zaþátek nového Ĝádku \r 0x0D Carriage return pĜesun na zaþátek aktuálního Ĝádku \t 0x09 Horizontal tab pĜesun na následující tabelaþní pozici \\ 0x5C Backslash obrácené lomítko \' 0x2C Single quote apostrof PĜíklady:
PĜevod malé abecedy na velkou c = c - ('a'-'A');
// zavorky kolem a-A zajisti jako první vypocet 32
Reálná þísla
= þísla v pohyblivé Ĝádové þárce (floating point number) x þíslo A je v pamČti uloženo ve tvaru A mantisa z exp onent x x
mantisa urþuje pĜesnost, exponent rozsah PĜíklady v desítkové soustavČ: mantisa = <-200; 200> exponent = <-10; 10> 1 = 1x100 10 = 1x101 -10 = -1x101 1,2 = 12x10-1 1,2345 = 123x10-2 12,34 = 12x100 = 12
x
= 1,23 ztráta pĜesnosti
norma IEEE 754 definuje þísla s jednoduchou pĜesností þíslo uloženo na 4 B = 32 b:
dvojnásobná pĜesnost = totéž, ale na 64 b 8
PĜednáška þ. 3
IAJCE
dle IEEE 754 je hodnota þísla: A = (-1)S*2exponent-127*1,mantisa
Reálné datové typy v C x
celá þísla (na platformČ Win32) typ
pamČĢ float 32 b double 64 b long double 64 b x
poznámka dle IEE 754, jednoduchá pĜesnost dle IEE 754, dvojnásobná pĜesnost zde = double
Pozn: obsazení pamČti (udává rozsah!!!) jednotlivých typĤ se mĤže u rĤzných pĜekladaþĤ lišit, ale vždy je float <= double <= long double
Reálné konstanty v C x
rĤzné typy: o typ je urþen buć její velikostí (typ neuveden = double) o nebo explicitnČ float = pĜípona F(f)
pĜíklady: #define POCET -1.12 #define N 0.126F
// to je double konstanta // to je float konstanta
// lze i v exponencialnim tvaru a = 1e+6 * a; // nasobeni 1 000 000
Typová konverze x
veškeré operace s datovými objekty (výrazy, pĜiĜazení apod.) Æ (teoreticky) pouze se stejnými datovými typy: int a; float b=2; a = b;
(teoreticky) nelze, neboĢ a i b sice v pamČti 32 b, ovšem pro b=2 bude v pamČti 0x40000000, což po þisté kopii do int znamená 1073741824. x Aby to šlo Æ nutno provést tzv. pĜetypování, pĜekladaþ musí mezi operace s rĤznými datovými typy vložit kód, který zajistí pĜepoþet x pĜetypování = zmČna datového typu (cast expression)
implicitní x x x
provádČna automaticky = konverze z nižších typĤ na vyšší – tam, kde nemĤže dojít ke ztrátČ informace (v rozsahu þísel) napĜ. char -> int -> double
9
PĜednáška þ. 3
IAJCE
int a; float b=2; b = a;
// OK
explicitní x x
= konverze v vyšších typĤ na nižší nutno ji do programu zapsat (jinak warning kompilátoru): warning C4244: '=' : conversion from 'float' to 'unsigned char', possible loss of data
x
syntaxe: (novy_typ)vyraz
x
pĜíklad: int a; float b=2.87; a = (int)b; // OK
Pozn:
x
x
x
pĜetypování sice odstraní warning, ale stejnČ dojde ke ztrátČ informace!!! char a; float b=356.5897; a = (char)b; // bez warning pĜi kompilaci, ale pĜi práci … // … programu a=100!!!
priorita – vyšší než binární operátory (viz. crefcard.pdf – operators – cast expression to type) (int)a + b
// pretypovani a
pĜetypovat lze cokoli k * (double)(a + b) (double)30
// pretypovan vysledek vyrazu a+b… // … zavorky nutne // pretypovana celociselna konstanta, byt to není nutne,… // … probehla by implicitni konverze int-> double)
Štábní kultura x
explicitní konverzi zapisovat i na místo implicitní Æ dáváte tím najevo že víte, co dČláte int a; float b; b = (float)a; b = (float)sin((double)30) // fce sin() ma argument typu // … sin() vraci double, b je
// OK, lepsi // slo by i b = sin(30) double, 30 je konstanta typu int, … float
10
PĜednáška þ. 4
IAJCE
Další operátory Unární x
x
Inkrementaþní ++ a dekrementaþní -o ++ zvČtší promČnnou o 1 o zmenší promČnnou o 1 Lze použít pouze na promČnné (musí to být l-hodnota – (a+b)++ nelze)
DvČ možnosti zápisu
x
x
Prefix: ++x nebo --x o PromČnná je zvČtšena (zmenšena o 1) a pak je vrácena hodnota výrazu = inkrementace (dekrementace) pĜed použitím Sufix xx++ nebo x-o Nejprve je pak vrácena hodnota výrazu a pak je promČnná zvČtšena (zmenšena) o 1 = inkrementace (dekrementace) po použití
Použití
V jednoduchém výrazu (jako samostatný pĜíkaz!!!) Æ sufix i prefix stejný význam x = x+1; x++; --x;
// zvetseni promenne o 1 // v C lepe // totez jako x--;
operátory souþástí složitČjšího výrazu Æ odlišné chování: int i=5, j=1, k; i++; j = ++i; j = i++; k = --j + 2;
// // // //
i j j k
bude bude bude bude
6 7, i bude 7 7, i bude 8 8, j bude 6, i bude 8
Složené pĜiĜazení Výraz x = x + 4; Æ v C: x += 4;
lze použít následující operátory +
-
*
/
%
<<
>>
&
^
(modĜe vyznaþeny známé operátory)
Logické operace x x
x
logický = booleovský VČtšina VPJ má logický datový typ boolean – nabývá hodnot o „true“ („pravda“) o „false“ („nepravda“) V C není, je reprezentován typem int: o 0 = „false“ o nenulová hodnota = „true“
1
|
PĜednáška þ. 4
IAJCE x
Pozn. reprezentace „true“: o obvykle pouze 1 – programátor mĤže cokoli (ovšem snažit se o 1), jazyk C jako výsledek „true“ vždy poskytne 1. o PĜíklad uložení informace true/false int DamSiPivo = 0; DamSiPivo = 1;
// = zatim si nedam // = pivo si dam
Logické operátory logický souþin (AND) logický souþin (OR) negace (NOT)
&& || !
pozor!!! && a || musí být ve dvojici, & a | mají úplnČ jiný význam (bitové operace)
Primitivní logické výrazy
x
pravdivostní tabulka – platí pro int x,y x 0 0 1 1
x x
y 0 1 0 1
x && y 0 0 0 1
x || y 0 1 1 1
!x 1 1 0 0
Jsou používány v logických (booleovských) výrazech Æ jejich výsledkem je logická hodnota (int 0,1 ve významech „true“, „false“). operandy datových typĤ jiných než int o platí zásada: „0 je „false“ (i „reálná“ 0), ostatní je „true“ float a=1.256, b=0.0; float c; c b c c
= = = =
a && b; // c = 0.0000000 -10e+6; a && b; // c = 1.0000000 !b; // b = 0.0000000
o Pokud možno nepoužívat!!!
Relaþní operátory x x
pro porovnávací výrazy (porovnání hodnot operandĤ ve výrazu) hodnoty všech primitivních datových typĤ (char, int, float…) jsou uspoĜádané (lze je porovnávat) > vČtší < menší >= vČtší nebo rovno <= menší nebo rovno == rovno (v Pascalu =) != nerovno (v Pascalu <>)
2
PĜednáška þ. 4
IAJCE PĜíklad: int a=10, b = 10, v1, v2; v1 = (a>b); v2 = (a<=b);
// výsledkem vyrazu (a>b) je 0 (int ve vyznamu false) … // … a ta se priradi do v1 // v2 bude 1 (ve vyznamu true)
Pozor:
Nikdy neprovádČt test na rovnost dvou reálných datových typĤ Æ zaokrouhlování
Logické výrazy x x
Vystupují v nich spolu s operandy logické a relaþní operátory Komplikované výrazy Æ priorita operátorĤ Æ zatím dĤslednČ závorkovat
PĜíklad:
Stanovte logický výraz pro test, zda se hodnota promČnné x nachází v intervalu (-5,10> int JePlatne;
// vyznam true/false
JePlatne = ((x>-5) && (x<=10)); JePlatne = !((x<=-5) || (x>10));
// JePlatne = 1, pokud x bude z (-5;10>… // …neboli x>-5 a zaroven x<=10 // stejny vysl., ale mnohem hure citelne
hlavní použití ve spojitosti s Ĝídícími strukturami
ěídící struktury x x x
= programová struktura, skládající se z Ĝídícího pĜíkazu, který pĜedepisuje zpĤsob provedení jiných pĜíkazĤ pomocí nich ovlivĖujeme poĜadí vykonávání pĜíkazĤ programu – ty jsou jinak vykonávány „shora dolĤ“ ěídící struktury: o složený pĜíkaz(blok) = nČkolik pĜíkazĤ o vČtvení = provedení rĤzných þástí programu v závislosti na splnČní podmínky o cykly = opakování skupiny pĜíkazĤ
Složený pĜíkaz = posloupnost pĜíkazĤ uzavĜená do {} syntaxe: { prikaz 1; prikaz 2; prikaz N; }
x x
použití Æ tam kde C vyžaduje pĜíkaz jediný, ovšem situace si žádá více pĜíkazĤ (cykly, podmínky) Pozn.: Za složeným pĜíkazem se nedČlá stĜedník
3
PĜednáška þ. 4
IAJCE
VČtvení x x x
neúplné jednoduché vČtvení (podmínka) úplné jednoduché vČtvení vícenásobné vČtvení
if if else switch
Neúplné jednoduché vČtvení – pĜíkaz if Vývojový diagram:
syntaxe: if (vyraz) // „true“ vetev prikaz;
sémantika
x
jestliže má vyraz nenulovou („true“) hodnotu, pak proveć prikaz (jeden!!!)
Pozn.:
x x x
Závorky kolem vyraz jsou nutné!!! Výraz vyraz je obvykle logický výraz Pokud je tĜeba uvnitĜ pĜíkazu if použít více pĜíkazĤ, je nutné je uzavĜít do složeného pĜíkazu if (vyraz) { prikaz 1; prikaz 2; prikaz N; }
PĜíklad:
x
PĜevod þísla na absolutní hodnotu, a pĜi zmČnČ znaménka vytiskne informaþní zprávu
4
PĜednáška þ. 4
IAJCE int Cislo;
if (Cislo < 0) { // pro zaporne cislo otocim znamenko Cislo = -Cislo; // a vytisknu o tom zpravu printf("Menim znamenko\n"); } // absolutni hodnotu vytisknu printf("|Cislo| = %d", Cislo);
x
Pozor na chybný zápis bez složených závorek – Code formating editor ZK Vám hodnČ napoví!!!
Úplné jednoduché vČtvení – pĜíkaz if-else Vývojový diagram Syntaxe: if (vyraz) // „true“ vetev prikaz 1; else prikaz 2;
Sémantika
x
jestliže má vyraz nenulovou („true“) hodnotu, pak proveć prikaz 1 (jeden!!!), jinak proveć prikaz 2 (jeden!!!).
PĜíklad
x
Zachycení dČlení nulou if (Jmen != 0) { Podil = Cit/Jmen; printf("%f", Podil); } else { printf("Deleni nulou!!!");
}
x
Pozn: podmínku lze samozĜejmČ i otoþit Æ pak prohodit vČtve if a else
Poznámky Vícenásobné vČtvení pomocí if – else
5
PĜednáška þ. 4
IAJCE if (x < a) { printf("x } if ((x >= a) && printf("x } if (x >= b) { printf("x }
x x
je z (-inf;a)"); (x < b)) { je z
je z
Nevýhoda: nutno vypsat všechny možnosti Jiné Ĝešení: v pĜíkazu if (i ve vČtvi else) mĤže být samozĜejmČ další if if (x < a) { printf("x (-inf;a)"); } else { if (x >= b) { printf("x
x
PĜehlednČjší zápis if (x < a) { printf("x (-inf;a)"); } else if (x >= b) { // zvyrazneno if-else = jeden prikaz!!! printf("x
Další pĜíklad // logicke promenne int DamSiPivo, BuduRidit, Desitku, Dvanactku; // Pocitadla piv int PocetDesitek, PocetDvanactek, PocetJinychPiv; // nejaky dalsi kod if ((DamSiPivo == 1) && (BuduRidit == 0)) { if (Desitku == 1) { PocetDesitek++; } else if (Dvanactku == 1) {
6
PĜednáška þ. 4
IAJCE PocetDvanactek++; } else { PocetJinychPiv++; } } else { printf("Pivo nemuzu, dam si limo"); }
x
První if lze napsat také takto: if (DamSiPivo && !BuduRidit)
x
Pozor na toto: if (c=10) prikaz;
o Vyhodnotí se konstantní výraz, výsledkem je 10, ta se jednak pĜiĜadí do c, a jednak se použije pĜi rozhodnutí pro if – 10 je rĤzné od 0, provede se prikaz
štábní kultura { je na téže Ĝádce jako if, else, for, while, do, switch
x x
složený pĜíkaz psát vždy, i když to není nutné (kromČ vnoĜených if-else) if (vyraz) { prikaz 1; } else { prikaz 2; }
Cykly x
pro opakované provádČní þástí programu
terminologie
x x x x x
Ĝídící promČnná cyklu = promČnná, na které závisí ukonþení cyklu – nejlépe pouze jedna podmínka ukonþující cyklus = logický výraz obsahující Ĝídící promČnnou cyklu hlaviþka cyklu = klíþové slovo for nebo while a výraz v následujících () o = nutná administrativa cyklu tČlo cyklu = pĜíkazy, které se budou opakovat (výkonný kód cyklu) Pozn.: o podobnČ jako u if, vždy se opakuje pouze jeden pĜíkaz, jinak nutné {} – opČt psát vždy
cyklus for x
= cyklus s pĜedem známým poþtem opakování Æ známe: o poþáteþní hodnotu Ĝídící promČnné o koncovou hodnotu Ĝídící promČnné o zpĤsob ovlivnČní Ĝídící promČnné po každém prĤchodu cyklu
syntaxe
7
PĜednáška þ. 4
IAJCE for (IěP; vyraz; ZěP) prikaz;
sémantika
x x x
pĜed vstupem do cyklu se provede inicializace Ĝídící promČnné IěP. Poté se opakuje prikaz v tČle cyklu tak dlouho, dokud má logický výraz vyraz hodnotu „true“. Po každém obrátce cyklu se provede zmČna Ĝídící promČnné daná výrazem ZěP. vyraz se testuje pĜed každou obrátkou – cyklus nemusí probČhnout ani jednou
Typické použití
x
Souþet nČkolika þísel, poþet þísel znám již v dobČ zápisu programu (vhodné konstantou) #include <stdio.h> #define POCET 4 int main(void) { int i; double Cislo, Soucet = 0.0; // Soucet musim inicializovat na 0 for (i=1; i<= POCET; i++) { printf("Zadej %d.cislo: ", i); scanf("%lf", &Cislo); Soucet += Cislo; } printf("\nSoucet = %f\n", Soucet); return 0;
}
x
Poþet þísel není pĜedem znám, zadává se po spuštČní programu #include <stdio.h> int main(void) { int i, Pocet; double Cislo, Soucet = 0.0; printf("Zadej pocet cisel: "); scanf("%d", &Pocet); for (i=1; i<=Pocet; i++) { printf("Zadej %d.cislo: ", i); scanf("%lf", &Cislo);
8
PĜednáška þ. 4
IAJCE Soucet += Cislo; } printf("\nSoucet = %f\n", Soucet); return 0; }
Poznámky
x
Cyklus for lze zapsat mnoha dalšími zpĤsoby – nepoužívat je (viz. literatura – napĜ. Ĝídící promČnnou by šlo mČnit i uvnitĜ cyklu) pozor na stĜedník za for
x
for (i=0; i<10; i++); { printf("%d ", i); } o ; = prázdný pĜíkaz, printf() leží až za cyklem
ěídící promČnná mĤže být jakéhokoli jednoduchého datového typu, a zmČna Ĝídící promČnné mĤže být libovolná
x
double x,k; for (x=sin(30); x
cyklus while x
Vhodný, pokud ukonþovací podmínka závisí na pĜíkazu v tČle cyklu – poþet opakovaní není pĜedem znám
syntaxe while (vyraz) prikaz;
sémantika
x x
Opakuj prikaz, dokud má vyraz nenulovou („true“) hodnotu vyraz se testuje pĜed každým prĤchodem cyklu – cyklus nemusí probČhnout ani jednou
PĜíklad
x
Souþet nČkolika þísel, poþet þísel urþen tzv. zarážkou – pĜi zadání zarážky se program ukonþí (?volba zarážky – zde 0) #include <stdio.h> int main(void) {
9
PĜednáška þ. 4
IAJCE int i=1; double Cislo, Soucet = 0.0;
Cislo = 10; // cokoli, hlavne aby poprve probehlo while while (Cislo != 0) { // konec zavisi na tom, jake zadam Cislo printf("Zadej %d.cislo: ", i); scanf("%lf", &Cislo); Soucet += Cislo; i++; // pozor: i zde není ridici promenna } printf("\nSoucet = %f\n", Soucet); return 0; }
Pozn.:
x
Nekoneþná smyþka: while (1) { }
x
Cyklus for lze nahradit cyklem while – nedoporuþeno, každý cyklus má svoji oblast použití for (i=0; i<10; i++) { prikaz; } i=0; while (i < 10) { prikaz; i++; }
cyklus do-while x
Podobný cyklu while
syntaxe do prikaz; while (vyraz);
sémantika
x
Opakuj prikaz, dokud má vyraz nenulovou („true“) hodnotu
Poznámky
x
testuje podmínku až po vykonání tČla cyklu – cyklus probČhne nejménČ jednou
10
PĜednáška þ. 4
IAJCE x
while (vyraz); – každý pĜíkaz musí konþit stĜedníkem
PĜíklad
x
OšetĜení zadání správných hodnot pĜi zadání – kladná celá þísla #include <stdio.h> #define MIN 0 int main(void) { int Cislo; do { printf("Zadej kladne cele cislo: "); scanf("%d", &Cislo); if (Cislo < MIN) { printf("Spatne zadani!!!\n"); } } while (Cislo < MIN); printf("\nOK\n"); return 0; }
ZávČreþné poznámky k cyklĤm x
(pouze pro dnešek)
VnoĜené cykly
x
Výpis všech kombinací malé násobilky od 1 do POCET #include <stdio.h> #define POCET 4 int main(void) { int i,j; for (i=1; i<=POCET; i++) { for (j=1; j<=POCET; j++) { printf("%dx%d=%d\t", i,j, i*j); } printf("\n"); } return 0;
11
PĜednáška þ. 4
IAJCE }
Koneþnost cyklĤ
x x
Vlastnost algoritmĤ koneþnost – lze cyklem porušit – nejþastČji špatnČ (obrácenČ) postavenou ukonþující podmínkou Základní pravidla: o Ĝídící promČnná se musí pĜi každé otáþce zmČnit (u for relativnČ snadné, u dowhile a while se o to musí postarat programátor) o Do cyklu se musí vstoupit s jasnČ definovanými poþáteþními podmínkami
12
PĜednáška þ. 5
IAJCE
ěídící struktury pokraþování PĜíkazy break a continue x x x x
x
upravují „normální“ bČh cyklĤ Lze je použít ve všech uvedených cyklech (for, while, do-while) pokud jsou cykly vnoĜeny, pĤsobí na cyklus, ve kterém jsou uvedeny break – ukonþuje (ihned opouští) cyklus o používá se pro: pĜedþasné ukonþení cyklu (napĜ. kvĤli chybČ) Ĝádné ukonþení nekoneþného cyklu continue – skoþí na konec cyklu = vynutí bČh další smyþky cyklu o používá se mnohem ménČ než break
PĜíklad
x
Naþítání þísel. Pokud je kladné, vypíše jeho dvojnásobek, záporných si nevšímá, nula ukonþí cyklus. int i; while (1) { // printf("zadej cislo: scanf("%d", &i); if (i < 0) { continue; // } if (i == 0) { break; // } printf("%d\n", 2*i); }
nekonecna smycka ");
dalsi nacitani
konec cyklu
PĜíkaz switch x x
umožĖuje nČkolikanásobné vČtvení programu syntaxe: switch (vyraz) { case konstanta 1: // vetev 1 prikaz 1; prikaz 2; prikaz N1; break; . . . case konstanta M: // vetev M prikaz 1; prikaz 2; prikaz N2; break; default: // nepovinne prikaz 1; prikaz 2; prikaz N3; break; }
1
PĜednáška þ. 5
IAJCE x
x
Sémantika: o Vypoþte se hodnota výrazu vyraz Æ odpovídající vČtev case (konstanta = hodnota vyraz) Æ provedou se pĜíkazy v dané vČtvi o Není-li nalezena odpovídající konstanta, provede se vČtev default (nemusí být uvedena, pak se neprovede nic) Poznámky: o výraz musí být celoþíselného typu o poĜadí vČtví není pevnČ urþeno (i pro default) o pĜíkazy v jedné vČtvi se provádí až do break – lze pro nČkolik konstant vykonat tytéž pĜíkazy o VČtvení lze provést pouze podle konstant, nikoli intervalĤ Æ v tomto pĜípadČ nutné vnoĜené if-else o switch uvnitĜ cyklĤ nebo obrácenČ Æ break se vztahuje ke „svému nejbližšímu“ pĜíkazu
PĜíklad
x
Typické použití: Program vytiskne poþet piv int Piv; printf("Zadej pocet piv: "); scanf("%d", &Piv); printf("Vypil jsem "); switch (Piv) { case 1: printf("%d pivo\n", Piv); break; case 2: case 3: case 4: printf("%d piva\n", Piv); break; default: printf("%d piv\n", Piv); break; }
Podprogramy (funkce) x x
x
pro naplnČní zásady: „jednu vČc programovat pouze jednou“ – v rozsáhlých programech se spousta þástí kódu opakuje podprogram = logický celek, Ĝešící dílþí þást problému o jednou podprogram zapíšeme (definice podprogramu) o na nČkolika místech programu jej použijeme (volání podprogramu) použití podprogramĤ odpovídá pĜirozené snaze pĜi Ĝešení problémĤ postupovat hierarchicky o „shora dolĤ“ – problém postupnČ rozkládáme na menší celky, které separátnČ Ĝešíme o „zdola nahoru“ – dílþí þásti problému skládáme do vČtších celkĤ o výhodné v týmu Æ každý Ĝeší pouze þást úkolu o program se lépe ladí
2
PĜednáška þ. 5
IAJCE x
PĜíklad velmi špatného zápisu programu na výpoþet obsahu obdélníku #include <stdio.h> int main(void) { double Strana1, Strana2; // nacteni strany 1 do { printf("Zadej 1. stranu obdelniku: "); scanf("%lf", &Strana1); if (Strana1 <= 0.0) { printf("Strana musi byt kladna!!!\n"); } } while (Strana1 <= 0.0); // nacteni strany 2 (prakticky stejne jako pro stranu 1) do { printf("Zadej 2. stranu obdelniku: "); scanf("%lf", &Strana2); if (Strana2 <= 0.0) { printf("Strana musi byt kladna!!!\n"); } } while (Strana2 <= 0.0); // vypocet a tisk printf("obsah obdelniku = %lf\n", Strana1*Strana2); return 0; }
x
Lepší varianta – kód pro zadání hodnot obou stran je velmi podobný Æ podprogram #include <stdio.h> // definice podprogramu double NactiStranu(int Kterou) { double Temp; do { printf("Zadej %d. stranu obdelniku: ", Kterou); scanf("%lf", &Temp); if (Temp <= 0.0) { printf("Strana musi byt kladna!!!\n"); } } while (Temp <= 0.0); return Temp; } // "Hlavni program" int main(void) { double Strana1, Strana2; Strana1 = NactiStranu(1); // volani podprogramu Strana2 = NactiStranu(2); // volani podprogramu printf("obsah obdelniku = %lf\n", Strana1*Strana2); return 0; }
(oba výše uvedené programy poskytnou tento výstup)
3
PĜednáška þ. 5
IAJCE Poznámka
x x
V jazyce C Æ podprogram = funkce, dále jen funkce Odlišení funkce od ostatních promČnných v textech – Funkce()
Terminologie x
Hlaviþka funkce double NactiStranu(int Kterou) o double = typ návratové hodnoty (ideální funkce provede danou þinnost a
x
x x
vrátí hodnotu jako výsledek své þinnosti) o NactiStranu = jméno funkce (identifikátor) o (int Kterou) = deklarace formálního parametru (= hodnota pĜedáváná do funkce z vnČjšku) mĤže jich být i více a rĤzných typĤ TČlo funkce = výkonný kód, zapsaný mezi {}, ležící bezprostĜednČ za hlaviþkou funkce o double Temp; = deklarace lokální promČnné – lze použít pouze uvnitĜ funkce, ve které je deklarována o return Temp; = výstup návratové hodnoty z funkce (zde funkce vrací hodnotu uloženou v promČnné Temp) Definice funkce = místo ve ZK, kde je zapsána hlaviþka + tČlo funkce Volání funkce Strana1 = NactiStranu(1); o Formální parametr Kterou byl nahrazen skuteþným parametrem (zde konstantou) 1 o Návratová hodnota funkce se uloží do promČnné Strana1
Typy funkcí (podprogramĤ) x x x x x
podprogram vrací hodnotu = „funkce“ (napĜ. ObsahKruhu() – vrací vypoþtený obsah kruhu) podprogram nevrací žádnou hodnotu = „procedura“ (napĜ. TiskPozdravu() – jen vytiskne a nic nevrací) datový typ void = žádný vstupní parametr, nebo funkce nevrací hodnotu dále xxx = „skoro“ jakýkoli datový typ v C (vracet lze pouze primitivní datové typy) Funkce s parametry o
x
o napĜ. double ObjemKvadru(double a, double b, double c) o nejþastČjší Funkce bez parametrĤ o
x
xxx Funkce(xxx P1, xxx P2, xxx PN)
xxx Funkce(void)
o napĜ. generování náhodného celého þísla int Rand(void) o ménČ þasté Procedura s parametry o
void Funkce(xxx P1, xxx P2, xxx PN)
4
PĜednáška þ. 5
IAJCE
x
o napĜ. tisk þísla s doprovodným textem okolo void Tisk(double Ktere) o také velmi þasté Procedura bez parametrĤ o
void Funkce(void)
o napĜ. tisk konkrétního pozdravu void TiskPozdravu(void) o ménČ þasté
Volání funkcí x x
Program v C o skládá se z 1 nebo více funkcí nČkteré funkce už používáme o scanf() a printf()
x x
int main(void) o „hlavní funkce“ v každém programu, musí být vždy
princip práce programu v C
o poznámka: main() i NactiStranu() volají ještČ scanf() a printf(). o „hloubka volání“ není omezena Skuteþné parametry funkcí
x
PĜi volání o formální parametry „nahrazeny“ skuteþnými (zhruba, podrobnČji pozdČji) o jejich poþet, poĜadí a datové typy musí souhlasit: o Nesouhlasí poþet o Error þi warning pĜekladaþe (pĜesnČji linkeru) o Nesouhlasí datové typy o typová konverze x Na místČ každého parametru funkce o výraz, napĜ. funkce Tisk(double Ktere) mĤže mít parametr: o konstantu – Tisk(1.2345), Tisk((double)-10), Tisk(KONSTANTA) o promČnnou – Tisk(RealProm), Tisk((double)IntProm) o funkci – Tisk(ObsahKruhu(R)), Tisk((double)IntFunkce(Cislo)) o obecný výraz – Tisk(PI + 2*(double)IntFunkce(Cislo)) (Poslední dva zpĤsoby jen pro pokroþilé o program se špatnČ ladí) x Volání funkce bez parametrĤ o Funkce definovaná jako int Rand(void) se volá jako int NahCislo; NahCislo = Rand();
// prom, do ktere ulozim navratovou h. // zavorky nutne!!!
5
PĜednáška þ. 5
IAJCE
Návratová hodnota funkce x
funkce vrací hodnotu („funkce“) o prosté pĜiĜazení (stejného datového typu) Objem = ObjemKvadru(a,b,c);
“vyhodnotí se výraz – výsledkem je návratová hodnota funkce, a ta se uloží do promČnné“ o návratová hodnota funkce jako jeden z operandĤ ve výrazu CelkovyObjem = 2*ObjemKvadru(a,b,c) + ObjemValce(R,Vyska); printf("Objem = %lf", 2*ObjemKvadru(a,b,c));
x
funkce nevrací hodnotu („procedura“ – návratová hodnota void) o volání je pak // kod pred funkci Tisk(1.2345); // pro hlavicku napr. void Tisk(double Co) // kod za funkci
x
Datové typy návratové hodnoty a „místa“, kde se návratová hodnota používá, musí souhlasit, pokud ne o pĜetypování o BČžné int Cislo; double Fakt; Fakt = (double)Faktorial(Cislo); printf("Faktorial = %lf", (double)Faktorial(Cislo));
o Na void – pokud není návratová hodnota potĜeba Typický pĜíklad – funkce vrací int jako chybový kód (0 = funkce probČhla normálnČ, 1 = chyba) a pĜi základním ladČní nás nezajímá (void)Funkce(Prom); // hlavicka napr. int Funkce(double Param)
Pozn.: Není potĜeba vždy (napĜ. scanf() a printf() vrací int, a pĜesto se nepĜetypovávají)
Definice vlastních funkcí x x
PĜipomenutí: Definice funkce = místo ve ZK, kde je zapsána hlaviþka + tČlo funkce Obecná syntaxe: xxx Funkce(xxx P1, xxx P2, xxx PN) // hlavicka funkce { // zde zacina telo funkce // vykonny kod funkce return Neco; } // konec tela funkce
6
PĜednáška þ. 5
IAJCE x
Funkce nesmí být definována uvnitĜ jiné funkce, vždy každá funkce zvlášĢ o pĜíklad chybného zápisu – definice NactiStranu() uvnitĜ main() #include <stdio.h> int main(void) { // definice funkce double NactiStranu(int Kterou) { // kod funkce return Temp; } double Strana1, Strana2; Strana1 = NactiStranu(1); // volani funkce return 0; }
x
x x x
Nejprve analýza: o Co bude funkce dČlat (a podle toho jméno) o Jaké bude mít formální parametry („s þím bude pracovat“) – kolik, datové typy o Co bude vracet (datový typ) o Výsledek o mám hlaviþku tČlo funkce = „program“; posloupnost pĜíkazĤ V tČle funkce se používají formální parametry funkce jako normální promČnné („myšlenČ“ pouze pĜi zápisu kódu) Návratová hodnota funkce o pĜíkaz return o syntaxe: return vyraz; o sémantika: funkce vrací hodnotu výrazu vyraz, po tomot pĜíkazu se funkce bezprostĜednČ ukonþí (pokud je kód i za tímto pĜíkazem o neprovede se) o pĜíkazĤ return mĤže být v jedné funkci více (pĜíklad pozdČji) o return v main() o ukonþí program
Lokální promČnné
x
blok: o = posloupnost pĜíkazĤ uzavĜená do {}, kterým mohou pĜedcházet deklarace promČnných – promČnné jsou viditelné pouze v rámci bloku („vznikají“ na zaþátku bloku a na jeho konci „zanikají“) // nejaky kod, kde neni deklarovano i i = 1; // chyba, i je deklarovana v bloku nize { int i; i = 20; } k = funkce(i); // chyba, i je deklarovana v bloku vyse // nejaky kod
x
tČlo každé funkce = bloko ve funkci si lze deklarovat a používat promČnné, které nebudou „vidČt“ mimo funkci (= lze s nimi pracovat pouze uvnitĜ tČla funkce) Použití o rĤzné pomocné promČnné (napĜ. funkce pro výpoþet kvadratické rovnice – diskriminant)
7
PĜednáška þ. 5
IAJCE PĜíklad þ. 1
x
Napište funkci, která bude poþítat objem válce, a kromČ toho jej bude umČt volitelnČ i vytisknout na obrazovku (pouze školní pĜíklad o nevhodná dekompozice problému) double ObjemValce(double R, double V, int Tisk) // int Tisk je "logický" parametr 0/1 = tisk ano/ne { double Volume; // lokalni promenna Volume = PI*R*R*V; // vypoctu Objem if (Tisk == 1) { printf("Objem = %lf\n", Volume); } return Volume; // Objem je navratova hodnota }
x
V programu by se funkce dala použít napĜ. takto (pro úplnost kompletní výpis vþetnČ definice funkce ObjemValce) #include <stdio.h> #define PI 3.141592 // definice funkce double ObjemValce(double R, double V, int Tisk) { double Volume; Volume = PI*R*R*V; if (Tisk == 1) { printf("Objem = %lf\n", Volume); } return Volume; } // "Hlavni program" int main(void) { double Polomer, Vyska, Objem; // zadani hodnot printf("Zadej polomer valce: "); scanf("%lf", &Polomer); printf("Zadej vysku valce: "); scanf("%lf", &Vyska); // priklady volani funkce // 1) Tisk = 0, nic netiskne, jen pocita Objem = ObjemValce(Polomer,Vyska,0) printf("Objem valce = %lf", Objem); // 2) Tisk = 1, sama tiskne, navratovou hod. nechceme-(void) (void)ObjemValce(Polomer,Vyska,1); return 0; }
x
Poznámka: funkce by šla napsat také takto (hĤĜ se ladí) double ObjemValce(double R, double V, int Tisk) { if (Tisk) { printf("Objem = %lf\n", PI*R*R*V); } return PI*R*R*V; }
8
PĜednáška þ. 5
IAJCE
PĜíklad þ. 2 – více return
x
Napište funkci, která vrátí vČtší þíslo ze dvou argumentĤ typu int, pokud jsou stejné vrátí nulu int Porovnej(int x1, int x2) { if (x1 > x2) { return x1; } else if (x2 > x1) { return x2; } else { return 0; } }
9
PĜednáška þ. 6
IAJCE
Definice funkce, volání funkce a pĜekladaþ x
x
Pokud pĜekladaþ pĜi kompilaci narazí na volání funkce – musí mít v tomto místČ informaci o: o poþtu a typu vstupních parametrĤ o typu návratové hodnoty To lze splnit: o definicí funkce pĜed jejím prvním zavoláním (všechny zatím uvedené pĜíklady) #include <stdio.h> // 1) definice funkce double ObjemValce(double R, double V, int Tisk) { // zde je telo funkce - zkraceno return Volume; } int main(void) { double Polomer, Vyska, Objem; // 2) volani funkce Objem = ObjemValce(Polomer,Vyska,0) return 0; }
o Deklarací funkce pĜed jejím prvním zavoláním = uvedení její hlaviþky na zaþátku programu (tzv. úplný funkþní prototyp) – funkce mĤže být definována tĜeba na konci souboru se ZK (nebo i v jiném souboru) #include <stdio.h> // 1) deklarace funkce double ObjemValce(double R, double V, int Tisk); int main(void) { double Polomer, Vyska, Objem; // 2) volani funkce Objem = ObjemValce(Polomer,Vyska,0) return 0; } // 3) definice funkce double ObjemValce(double R, double V, int Tisk) { // telo funkce return Volume; }
#include o jsou tam deklarovány funkce (+ nČco navíc)
1
PĜednáška þ. 6
IAJCE
Matematické funkce x
v nČkolika hlaviþkových souborech – nutné vložit do ZK
Hlaviþkový soubor „stdlib.h“ int abs(int j); float fabsf (float x)
x
// Vrací absolutní hodnotu argumentu typu int // totéž pro typ float
pozn.: absolutní hodnota (double) je v math.h
Hlaviþkový soubor „math.h“ x
všechny funkce typu double funkce(double…)
goniometrické funkce double double double double double double
sin(double x); cos(double x); tan(double x); asin(double x); acos(double x); atan(double x);
// // // // // //
vrací sinus argumentu kosinus tangens arkussinus arkuskosinus arkustangens
zaokrouhlování a podobné operace double double double double
fabs(double j); // ceil (double x); // floor (double x);// round(double x); //
Vrací absolutní hodnotu argumentu typu double Zaokrouhlí arg na nejmenší vyšší celé þíslo Zaokrouhlí arg na nejbližší nižší celé þíslo Zaokrouhlí þíslo na nejbližší celé þíslo
logaritmy double exp(double x); // Vrací e na x double log(double x); // Vrací ln(x) double log10(double x); // Vrací log(x)
mocniny double pow(double x, double y); double sqrt(double x);
// Vrací hodnotu x na y (2^3=8) // Vrací odmocninu z þísla x
ménČ obvyklé funkce double fmod(double x, double y); //vrací celoþíselný zbytek po … // … celoþíselném dČlení argumentĤ typu double double modf(double x, double *iptr);// Vrátí desetinnou þást x a celou þást // … uloží tam, kam ukazuje iptr double atan2(double y, double x); // poþítá arcus tangens y/x
2
PĜednáška þ. 6
IAJCE
Pointery x x x x
x
þesky ukazatele velmi mocný (ale také nebezpeþný) nástroj – jazyk C bez nich nelze plnČ využít pointer = normální promČnná; její obsah (hodnota) má význam adresy v pamČti obvyklé využití – pĜístup k jiným promČnným o pole, ĜetČzce o funkce (pointer na funkci, volání odkazem) o dynamické promČnné pĜíklad: promČnná (pointer) pProm a promČnná Prom – „pProm ukazuje na Prom“
Deklarace pointeru x x
Pointer je vždy svázán s nČjakým datovým typem – napĜ. pointer na int syntaxe: datovy_typ *jmeno_pointeru o NapĜ.: double *pA, *pB; // 2x pointer na double unsigned char *pCislo1; // pointer na unsigned char
o Pozor: double *pA, pB;
// pointer na double, promenna double!!!
Štádní kultura
x
jméno pointeru bude vždy zaþínat písmenem „p“, nebo „p_“ double *pA, B; // pointer na double, promenna double unsigned char *pCislo1; // pointer na unsigned char
Práce s pointery ZjištČní adresy promČnné
x x
x
pointer o pro „nepĜímý“ pĜístup k promČnným o musím znát adresu promČnné referenþní operátor & o zjistí adresu promČnné, na kterou byl použit o (& má dva významy: referenþní operátor a bitový souþin – zatím neznáme) pĜíklad: int Prom=123, *pProm;
// 1 promenna int a 1 pointer na int
pProm = &Prom;
// pProm ukazuje na Prom
„Do promČnné pProm pĜiĜadím adresu promČnné Prom“ o pProm ukazuje na Prom
x
inicializace pointeru v deklaraci int Prom=10, *pProm=&Prom;//pointer na int inicializovan adresou Prom
3
PĜednáška þ. 6
IAJCE x
Poznámky: o vynechání & o pProm = Prom; o pProm ukazuje na adresu 10 o není naše pamČĢ o pĜekladaþ varování (pokus pĜiĜadit int do pointeru na int – int *): warning C4047: '=' : 'int *' differs in levels of indirection from 'int'
o není žádná * hvČzdiþka pĜed pProm (pProm = &Prom;)!!! o pracuji s pointerem jako s normální promČnnou (pĜiĜazuji do ní adresu jiné promČnné) o & mĤžeme používat v programu libovolnČ double Prom1, Cislo; double *pProm=&Prom1;
// pProm ukazuje na Prom1
Cislo = 156*Prom1; pProm = &Cislo;
// nejaka operace // pProm nyni ukazuje na Cislo
Práce s promČnnou prostĜednictvím pointeru
x x
opČt: pointer o pro „nepĜímý“ pĜístup k promČnným dereferenþní operátor * o pracuje s hodnotou promČnné, na kterou ukazuje pointer: int Prom=123, *pProm; int Cislo;
// 1 prom a 1 pointer na int
pProm = &Prom; // pProm ukazuje na Prom Cislo = *pProm + 10; // Cislo bude 123+10 *pProm = 58; // do Prom jsem priradil 58 pProm = &Cislo; // pProm nyní ukazuje na Cislo printf("Cislo = %d", *pProm); // tisk promenne Cislo
x
o * má tedy 3 významy (násobení, dereferenþní operátor a deklarace pointeru) Poznámky: o Vynechání * pProm = 58; = pointer ukazuje na adresu 58 (Crash!!!) printf("Cislo = %d", pProm); = tisk adresy promČnné Cislo
ZávČreþné poznámky
x x
Pointery zatím nepoužívat, kromČ tzv. volání odkazem (viz. dále) Bylo Ĝeþeno: „Pointer je vždy svázán s nČjakým datovým typem“ o nemíchat promČnné, pointery rĤzných datových typĤ (typová konverze) int *pProm; double Cislo; pProm = &Cislo;
// Chyba (warning prekladace)
4
PĜednáška þ. 6
IAJCE
Funkce – volání hodnotou a odkazem x x x
x
Klíþová záležitost!!! Bylo Ĝeþeno o„PĜi volání funkce jsou formální parametry nahrazeny skuteþnými“ Volání funkce skuteþnost: o (je-li to nutné) vypoþtou se výrazy pĜedstavující vstupní parametry o NČkde v pamČti (tzv. zásobník – stack) se vytvoĜí: všechny lokální promČnné promČnné, které mají význam formálních parametrĤ a zkopírují!!! se do nich odpovídající hodnoty skuteþných parametrĤ o Pak je zavolána funkce pracuje z hodnotami („promČnnými“) na zásobníku Vracená hodnota je uložena na zásobník o Po návratu „za volanou funkci“ se použije návratová hodnota ze zásobníku pro další práci DĤvody o konstrukce poþítaþe
5
PĜednáška þ. 6
IAJCE x
Uvedený postup pro pĜíklad z minulé pĜenášky: #include <stdio.h> #define PI 3.141592 double ObjemValce(double R, double V, int Tisk) { double Volume; Volume = PI*R*R*V; if (Tisk == 1) { printf("Objem = %lf\n", Volume); } return Volume; } int main(void) { double Polomer, Vyska, Objem; printf("Zadej polomer valce: "); scanf("%lf", &Polomer); printf("Zadej vysku valce: "); scanf("%lf", &Vyska); Objem = ObjemValce(Polomer,Vyska,0) printf("Objem valce = %lf", Objem); return 0; }
x x
Tento zpĤsob pĜedávání parametrĤ se nazývá Volání hodnotou – jazyk C nic jiného neumí Problém o pokud volání funkce = kopie skuteþných parametrĤ o ve funkci nelze zmČnit hodnoty skuteþných parametrĤ
6
PĜednáška þ. 6
IAJCE PĜíklad
x x
Napište funkci, která zamČní obsah (hodnoty) dvou promČnných typu int Nefunkþní Ĝešení #include <stdio.h> void Zamen(double p1, double p2) { double pomoc; pomoc = p1; p1 = p2; p2 = pomoc; } int main(void) { double Cislo1=10, Cislo2=20; Zamen(Cislo1,Cislo2); printf("Cislo1 = %d, Cislo2 = %d", Cislo1, Cislo2); return 0; }
Skuteþné promČnné se nezamČní (jen formální parametry uvnitĜ funkce – bod 2 a 3 v obr.) o Ĝešení = volání odkazem
7
PĜednáška þ. 6
IAJCE
Volání odkazem x
„definice“: pĜekladaþ provede funkci (= volání funkce) místo s kopiemi se skuteþnými parametry funkce o Pascal: procedure Zamen(var p1, var p2: integer);
x x
jazyk C volání odkazem nezná o nutné použít trik s pointery uvČdomte si, že: o v deklaraci int *p1 o deklarace promČnné p1 typu pointer na int o v programu *p1 o pracuje s hodnotou promČnné, na kterou ukazuje pointer p1 o &Cislo1 o poskytne adresu promČnné
8
PĜednáška þ. 6
IAJCE x
Správné Ĝešení zámČny dvou promČnných #include <stdio.h> void Zamen(int *p1, int *p2) // dva formalni parametry typu pointer na int { int pomoc; pomoc = *p1; *p1 = *p2; *p2 = pomoc; } int main(void) { int Cislo1=10, Cislo2=20; Zamen(&Cislo1,&Cislo2); // formalni i skutecne parametry souhlasi – oboje jsou adresy! printf("Cislo1 = %d, Cislo2 = %d", Cislo1, Cislo2); return 0; }
x
použití volání odkazem o zmČna hodnoty promČnné funkcí (napĜ. scanf("%d", &Prom); o zmČní pĤvodní hodnotu promČnné Prom na þíslo zadané z klávesnice) o návrat více hodnot z jedné funkce (viz. cviþení – napĜ. funkce, která najednou vypoþte obsah i obvod kruhu)
9
PĜednáška þ. 7
IAJCE
Pole – motivace x
ýastá úloha – práce s vČtším množstvím dat stejného typu o PĜ.: prĤmČrná teplota za týden a odchylka od prĤmČru v jednotlivých dnech printf("Zadej printf("Zadej printf("Zadej printf("Zadej printf("Zadej printf("Zadej printf("Zadej
T T T T T T T
pro pro pro pro pro pro pro
1.den: 2.den: 3.den: 4.den: 5.den: 6.den: 7.den:
"); "); "); "); "); "); ");
scanf("%lf",&T1); scanf("%lf",&T2); scanf("%lf",&T3); scanf("%lf",&T4); scanf("%lf",&T5); scanf("%lf",&T6); scanf("%lf",&T7);
Tprumer = (T1 + T2 + T3 + T4 + T5 + T6 + T7) / 7; printf("\nPrumerna teplota je %lf\n\n", Tprumer); printf("Odchylka printf("Odchylka printf("Odchylka printf("Odchylka printf("Odchylka printf("Odchylka printf("Odchylka
T T T T T T T
pro pro pro pro pro pro pro
1.den: 2.den: 3.den: 4.den: 5.den: 6.den: 7.den:
%lf\n", %lf\n", %lf\n", %lf\n", %lf\n", %lf\n", %lf\n",
T1-Tprumer); T2-Tprumer); T3-Tprumer); T4-Tprumer); T5-Tprumer); T6-Tprumer); T7-Tprumer);
o nelze Ĝešit cyklem s postupným výpoþtem prĤmČru o musím si pamatovat všechny teploty o nevýhody: algoritmus nevykazuje znaky hromadnosti (teploty za mČsíc, rok???) obtížná manipulace s daty (jak na hledání extrémĤ?)
Pole (array) x x x x x
int, double apod. = jednoduchý datový typ
pole = strukturovaný datový typ skládá se vČtšího množství položek – prvky pole (item) všechny prvky pole o stejný (jednoduchý) datový typ o pole je homogenní datová struktura („Pole prvkĤ typu …“ – „array of …“) index prvku (item index) o pro pĜístup k jednotlivým prvkĤm pole (pozice prvku od zaþátku pole) o celé þíslo!!!
VytvoĜení pole x x
pole = promČnná deklarace: datovy_typ JmenoPole[Pocet_prvku];
o datovy_typ = jakýkoli jednoduchý datový typ o Pocet_prvku = poþet prvkĤ pole o PĜíklady: double Teplota[7]; unsigned int MojePole[10000];
1
PĜednáška þ. 7
IAJCE x
Poznámky: o Velikost pole není „skoro“ nijak omezena (platí pro Win32, Linux) o Poþet prvkĤ musí být znám v dobČ pĜekladu, nelze jej bČhem práce programu zmČnit
Štábní kultura
x
Poþet prvkĤ = významné þíslo, vždy v programu nČkolikrát o konstanta #define POCET_PRVKU 7 double Teplota[POCET_PRVKU];
Práce s pole Po jednotlivých prvcích
x
(dále v pĜíkladech pĜedpokládáme deklaraci) #define POCET_PRVKU 7 double Teplota[POCET_PRVKU];
x
prostĜednictvím indexu o mĤže tam být jakýkoli výraz (celoþíselný) o typicky promČnná pojmenovaná i typu int (napĜ. Teplota[i]) o další pĜíklady Teplota[3] Teplota[2*k+1]
x
// liché prvky
jeden prvek pole = normální jednoduchá promČnná (lze jej používat ve výrazech): Tprumer += Teplota[i]; DalsiPole[5] = 3*sin(Teplota[2*i]);
x
Meze pole o v C vždy od 0 do poþet prvkĤ – 1 Teplota[0] // 1. prvek Teplota[3] // 4. prvek Teplota[POCET_PRVKU-1] // poslední prvek
o Pozor: Jazyk C meze nekontroluje (hrozí pĜeteþení nebo podteþení indexĤ) = možný pád programu Teplota[-1] Teplota[POCET_PRVKU]
x
// chyba // neþastČjší chyba
o Pole si v sobČ nenese informaci o své délce o vše je na programátorovi pĜedchozí pĜíklad Ĝešený pomocí pole – typicky v cyklu for #include <stdio.h> #define POCET_PRVKU 7 int main(void) { double Teplota[POCET_PRVKU], Tprumer = 0; int i; // indexy prvku pole // nacteni prvku z klavesnice for(i=0; i
2
PĜednáška þ. 7
IAJCE
Tprumer += Teplota[i]; } // vypocet a vypis prumeru Tprumer /= POCET_PRVKU; printf("\nPrumerna teplota je %lf\n\n", Tprumer); // vypocet a vypis odchylek for(i=0; i
o poznámky: pozor na for(i=0; i
x
v C nejde o pĜíklad kopie PrvniPole do DruhePole #define N 10 int PrvniPole[N], DruhePole[N]; DruhePole = PrvniPole; // chyba!!!
x
Nutno vždy Ĝešit „ruþnČ“ for(i=0; i
Práce s þástí pole
x x x
x
velikost pole je dána pĜi zápisu ZK programu pokud neznáme pĜedem pĜesnČ poþet prvkĤ pole o vytvoĜíme nejvČtší možné pole a pak pracujeme jen s jeho þástí o nutné si uchovat aktuální velikost Nebo jiný pĜípad: Teploty za mČsíc, práce s teplotami v x. týdnu KteryTyden = 3; for(i=7*(KteryTyden-1); i<7*(KteryTyden-1)+7; i++) { Teplota[i] = ...; }
Další pĜíklad: Teploty za mČsíc, práce s teplotami v x. dnu každého týdnu 3
PĜednáška þ. 7
IAJCE KteryDen = 5; for(i=0; i<4; i++) { Teplota[KteryDen] = ...; KteryDen += 7; }
Inicializace pole v deklaraci x x
lze, neinicializované pole o prvky mají nedefinovanou hodnotu pĜíklad inicializace double Teplota[POCET_PRVKU] = {1,2,-5.35,0.1245,4,43,-11};
o poþet inicializací > poþet prvkĤ o Error pĜekladaþe o poþet inicializací < poþet prvkĤ o pĜekladaþ zbývající prvky inicializuje na 0 (0.0)
VícerozmČrná pole x
x x
= pole s více indexy, napĜ.: o 2 indexy = matice, nejþastČjší pĜípad o 3 indexy = „3D“ pole („kvádr“) vícerozmČrné pole v C o jednorozmČrné pole, jehož prvky jsou pole… deklarace: datovy_typ JmenoPole[Pocet_prvku1][Pocet_prvku2][Pocet_prvku3]...;
x
o napĜ. int Pole[4][5]; = pole o 4 Ĝádcích a 5 sloupcích Inicializace v deklaraci o viz. „jednorozmČrné pole, jehož prvky jsou pole…“: int Pole[2][3] = {{11,12,13}, {21,22,23}};
x
PĜíklad uložení pole v pamČti:
x
Práce s vícerozmČrným polem o nejþastČji vnoĜené cykly for o PĜíklad: Souþet dvou matic C = A+B o rozmČrech MxN for(i=0; i<M; i++) { // pres radky for(j=0; j
4
PĜednáška þ. 7
IAJCE
Pole a funkce NejnutnČjší informace
x
jméno promČnné typu pole = pointer na zaþátek pole (1. prvek, nebo prvek s indexem 0, nebo [0][0]…); pointer je konstantní o nelze jej zmČnit.
pointer na zaþátek pole
Pole jako návratová hodnota funkce x
Nelze (ale vĤbec to nevadí, viz. dále)
Pole jako parametr funkce x x
Do funkce se vždy pĜedává argument typu pole jako pointer o volá se odkazem o pole lze ve funkci zmČnit!!! uvnitĜ funkce se s polem (formální parametr) pracuje úplnČ normálnČ
JednorozmČrná pole
x x x x
Specifikace formálního parametru o datovy_typ Identifikator[] Specifikace skuteþného parametru o JmenoPole V poli není uložena jeho délka o nutno pĜedat jako další formální parametr PĜíklad: napište funkci, která zkopíruje jedno pole prvkĤ typu int do druhého. #include <stdio.h> #define POCET_PRVKU 5 void ZkopirujPole(int Source[], int Target[], int Length) { int i; for(i=0;i
5
PĜednáška þ. 7
IAJCE x
protože: „Do funkce se vždy pĜedává argument typu pole jako pointer“ o hlaviþku lze zapsat (platí pouze pro jednorozmČrná pole!!!): void ZkopirujPole(int *Source, int *Target, int Length)
(zbytek kódu o úplnČ stejný) o Takto to (zatím) nedČlat!!! VícerozmČrná pole
x
platí totéž, co pro jednorozmČrná, kromČ: specifikace formálního parametru o druhá dimenze pole (a pĜípadnČ všechny další) musí být uvedeny jako konstanta o lze obejít o viz. další semestr o uvnitĜ funkce pracuji pouze z þástí pole – musí se ale shodovat 2. a další rozmČry formálního a skuteþného parametru (pole) x pĜíklad: kopie dvourozmČrného pole (deklarováno jako 2x3, funkce zkopíruje pouze 2x2) pozn.: _ = nutná shoda formálního a skuteþného parametru #include <stdio.h> #define RADKU 2 #define SLOUPCU 3 void Zkopiruj2DPole(int Source[][SLOUPCU], int Target[][SLOUPCU], int Rows, int Columns) { int i,j; for(i=0;i
6
PĜednáška þ. 7
IAJCE
Práce s poli Funkce pro naþtení pole z klávesnice
x
PonČkud složitČjší (problém o scanf()), nČkolik možností Ĝešení – zatím pĜes pomocnou promČnnou void NactiPole(int Array[], int Length) { int i, pom; for(i=0;i
o vícerozmČrné pole o analogicky
ěetČzce (strings) x x
ĜetČzec = jednorozmČrné pole prvkĤ typu char, zakonþené zarážkou (= speciální znak) zarážka = nutná (vhodná) souþást ĜetČzce o znak s ASCII kódem 0 o '\0' o PĜíklad: Uložení ĜetČzce délky 8 (délky pole!!!) v pamČti, aktuální obsah = slovo „Ahoj“
o manipulaci se zarážkou zajišĢuje jazyk C automaticky (v drtivé vČtšinČ pĜípadĤ) o urþuje aktuální délku ĜetČzce o z ĜetČzcem se pracuje „až po zarážku“ ěetČzcové konstanty
x x x
již používáme (printf(), scanf()) v uvozovkách o "Ahoj" platí pro nČ vše, co pro znakové konstanty (escape sekvence, spec. symboly, atd.)
7
PĜednáška þ. 7
IAJCE x
pozor: o "Ahoj" = ĜetČzcová konstanta délky 5 B(4+zarážka) o "A" = ĜetČzcová konstanta délky 2 B (1+zarážka) o 'A' = znaková konstanta (1 B)
Deklarace ĜetČzce
x
jako pole prvkĤ typu char #define MAX_DELKA 50 char Slovo[MAX_DELKA]; o maximální poþet znakĤ = MAX_DELKA-1
x
o index posledního znaku = MAX_DELKA-2 deklarace s inicializací – nČkolik možností char char char char
Slovo[MAX_DELKA] = "Ahoj"; // pĜekladaþ sám doplní zarážku Slovo[] = "Ahoj"; // pĜekladaþ doplní zarážku a urþí délku pole Slovo[] = {'A','h','o','j',0}; // zarážku nutno ruþnČ!!! Slovo[] = {'A','h','o','j','\0'};
Vstup a výstup ĜetČzce x x
formátovací specifikace %s existuje nČkolik rĤzných funkcí (viz. pĜíštČ)
Vstup ĜetČzce z klávesnice
x
lze použít scanf(): char Slovo[MAX_DELKA]; printf("Zadej retezec: "); scanf("%s", Slovo);
o pozor: Není tam &Slovo – dĤvod o jméno ĜetČzce = pointer na zaþátek pole = samo o sobČ adresa o naþítání se zastaví na prvním bílém znaku o po zadání Ahoj mami bude v pamČti pouze 'A','h','o','j',0 Výstup ĜetČzce na obrazovku
x
lze použít printf(): char Slovo1[] = "Ahoj"; char Slovo2[] = "mami"; printf("%s %s.", Slovo1, Slovo2);
o pozn.: zapisuje se pouze jméno ĜetČzce (= pointer na jeho zaþátek) o printf() tiskne znaky až po '\0'
Práce s ĜetČzcem x x x
zatím „ruþnČ“ ( jeden prvek ĜetČzce = promČnná typu char práce s ĜetČzcem jako s celkem o vždy až po '\0'
8
PĜednáška þ. 7
IAJCE x
pĜíklad: Napište funkci Append(), která pĜipojí na konec ĜetČzce s1 ĜetČzec s2 #include <stdio.h> #define MAX_DELKA 50 void Append(char s1[], char s2[]) { int i=0, j=0; // nalezeni konce s1 while (s1[i] != '\0') { // slo by i (s1[i] != 0) i++; } // kopie s2 na konec s1 while (s2[j] != '\0') { s1[i] = s2[j]; i++; j++; } } int main(void) { char Slovo1[MAX_DELKA] = "Ahoj "; char Slovo2[] = "mami"; Append(Slovo1, Slovo2); printf("%s\n", Slovo1); return 0; }
o poznámky: pozor na délku ĜetČzce s1!!! kratší varianta pĜipojení na konec (jen pro pokroþilejší) // kopie s2 na konec s1 while (s2[j] != '\0') { s1[i++] = s2[j++]; }
9