Jazyk C
středa 8:50 A3 úterý 14:20 HI3
Úvodní strana Titulní strana Obsah
Petr Kolář místnost A-10 tel: +420-485 353 673 e-mail:
[email protected]
WWW: http://www.kai.vslib.cz/~kolar/cecko/ Pracovní verze!
JJ
II
J
I
Strana 1 z 89 Zpět Celá obrazovka Zavřít Konec
Literatura • Herout, P.: Učebnice jazyka C, III upravené vydání. Kopp, České Budějovice 1994. ISBN 80-85828-21-9. – doporučeno • Kernighan, B. W. – Ritchie, D. M.: The C Programming Language. Second Edition. Prentice Hall 1988. ISBN 0-13-110362-8, K&R – klasická učebnice, která ovšem popisuje dnes již zastaralou „normuÿ jazyka
Úvodní strana
• Kernighan, B. W. – Ritchie, D. M.: Programovací jazyk C. SNTL – Alfa, Bratislava 1988 – slovenský překlad prvního vydání předchozího titulu
Obsah
Titulní strana
JJ
II
J
I
Strana 2 z 89 Zpět Celá obrazovka Zavřít Konec
Překladače jazyka C Kompletní profesionální vývojové prostředí pro jazyk C mívá cenu desítek tisíc Kč. Úvodní strana
Existuje však řada volně dostupných překladačů a jednoduchých vývojových prostředí, které jsou pro výuku plně dostačující: V OS Linux je vývojové prostředí s gcc, gdb, součástí prakticky všech distribucí. Pro Windows: DJGPP http://www.delorie.com/djgpp/ – kompletní aktuální vývojové prostředí (ovšem s uživatelským rozhraním poplatným MS-DOSu a roku 1990). Archivy zabírají asi 20 MB (nebo více podle množství použitých balíků). Výběr souborů se provádí pomocí ZIP Picker. V Čechách zrcadleno na serveru ftp://ftp.zcu.cz/pub/win/simtelnet/gnu/djgpp/. Borland Museum: http://community.borland.com/museum/ – starší verze integrovaného prostředí s překladačem C od firmy Borland. Turbo C++ verze 1.01 (2,7 MB) nebo Turbo C verze 2.01 (1,1 MB).
Titulní strana Obsah
JJ
II
J
I
Strana 3 z 89 Zpět Celá obrazovka Zavřít Konec
Srovnání jazyků Pascal a C C pro praktické programování původním „standardemÿ je kniha K&R, standardy z let 1989-90 a 1999 „language of choiceÿ modulární programování (oddělená kompilace) objektová rozšíření C++, Objective C, C# rozsáhlé standardní knihovny jsou volnou součástí jazyka, množství dalších knihoven
Pascal pro výuku od počátku existence standardu jazyka, je však příliš omezující → rozšíření „language of bondage and disciplineÿ modulární programování v rozšířeních objektové rozšíření Turbo Pascal, Delphi standardní funkce jsou nedílnou součástí jazyka
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 4 z 89 Zpět Celá obrazovka Zavřít
#include <stdio.h>
Konec
int main() { printf("Hello, world!\n"); return 0; }
program Hello(Output); begin Writeln(’Hello, world!’); end.
Proč jazyk C? C je univerzální programovací jazyk. Proč jazyk C stojí za pozornost mezi desítkami jiných univerzálních programovacích jazyků? Jedná se o jazyk pro opravdové programování. Niklaus Wirth, autor jazyka Pascal, věnoval značné úsilí, aby jeho jazyk, určený pro výuku programování, byl co možná nejbezpečnější, aby bylo obtížné v něm programovat ošklivě. Popularita jaké Pascal dosáhl, svědčí o tom, že Wirth vytvořil něco lepšího, než o co usiloval. Nicméně něco je možné napsat ve standardním Pascalu jen s velkým úsilím, něco vůbec ne. Obhájci Pascalu se chlubí, že Pascal má od začátku závaznou normu, ale neprogramují v ní. Množství vzájemně nekompatibilních rozšíření (nejvýznamnější z nich je asi Turbo Pascal) svědčí o tom, že standardnímu Pascalu mnoho užitečných rysů chybí.
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 5 z 89 Zpět
Jazyk C prošel několikaletým vývojem, kdy se skutečně používal i na věci nesnadné a komplikované (přenos operačního systému Unix na počítače několika značně odlišných typů). Během vývoje byl doplněn o vlastnosti, které se ukázaly jako užitečné (např. prototypy funkcí), a naopak některé vlastnosti matoucí, zbytečně složité nebo zbytečné byly odstraněny. Důležitými mezníky vývoje jazyka C bylo vydání jeho standardů – ANSI X3.159-1989, ANSI/ISO/IEC 9899:1990 a ISO/IEC 9899:1999. Jazyk C vytvořili programátoři pro programátory. Díky tomu neobsahuje podobné přehmaty jako parametry procedur volané jménem z jazyka Algol 60
Celá obrazovka Zavřít Konec
– vlastnost, která se obtížně implementuje, nepříliš efektivně překládá a přitom je možné ji nahradit něčím mnohem čistším a průhlednějším (parametry volanými referencí), nebo „návaznostÿ souborů na operační systém pomocí parametrů programu v Pascalu. Způsob zápisu algoritmů v jazyce C je velice podobný zápisu v jazycích Algol, Pascal, Basic, PL/I, Modula–2, Ada, což tyto jazyky favorizuje před jazyky s méně obvyklou syntaxí (Fortran, Cobol, Forth, Perl, . . . ). Syntaxe jazyka C umožňuje stručné vyjádření algoritmu a navíc často naznačuje překladači možnost optimalizace. Jazyk C umožňuje oddělený překlad jednotlivých částí programu, používání a vytváření knihoven. Díky tomu je možné jej používat i na rozsáhlé projekty a pro týmovou práci. Jazyk C nepokutuje programátora za použití některých svých vlastností (číselná návěští v Pascalu s nutností je předem deklarovat, logické spojky and a or v Pascalu s povinným vyhodnocením obou operandů), ani nenabízí „mocnéÿ konstrukce, které je snadné použít, ale které vedou ke komplexním operacím a k udivení nad pomalým během programu. Většinu příkazů jazyka je možné přeložit jednou nebo několika málo strojovými instrukcemi. Jazyk C je relativně jednoduchý. Nejedná se o ohromné monstrum, jakým je například jazyk PL/I (O) nebo dokonce Ada, pro kterou několik let neexistoval překladač. Nejedná se ani o jazyk, na který si činí vlastnické právo některá firma či jiná organizace. Jazyk C je k dispozici na většině platforem, od jed-
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 6 z 89 Zpět Celá obrazovka Zavřít Konec
nočipových mikropočítačů (překladače pro ně samozřejmě pracují na větších strojích – jedná se o tzv. křížové překladače; cross compilers), přes domácí a osobní počítače, pracovní stanice, střediskové počítače až k superpočítačům. Nejrozšířenější operační systémy (DOS a UNIX) jsou napsány jazyce C. Jazyk C nenutí programátora použít jediný správný přístup; tentýž algoritmus je možné zapsat s použitím různých prostředků a do různé míry zhuštěně. C je typickým jazykem volby. Programování v jazyce C však přináší i některá nebezpečí. Některé konstrukce mohou různé překladače chápat odlišně – speciálně se to týká datových typů – rozsah stejně pojmenovaných celočíselných typů je v různých prostředích různý. Také reprezentace složených typů může být v programech vytvořených různými překladači různá, což může způsobovat chyby při výměně souborů nebo síťové komunikaci. Téměř žádný překladač nehlídá přetečení rozsahu číselných hodnot. U funkcí s proměnným počtem parametrů se typy těchto parametrů nekontrolují. Při práci s řetězci a ukazateli se lze snadno dopustit chyb, které překladač neodhalí. Standardní knihovna obsahuje funkce, jejichž používání je nebezpečné (gets). Některé konstrukce může překladač chápat díky opomenutí programátora jinak, než byly zamýšleny. Mezi časté chyby patří například použití operátoru = namísto == pro porovnávání, zapomenutí příkazu break na konci větve uvnitř switch, neuvedení hlavičkového souboru pro použité funkce, chybné používání ukazatelů a nesprávné sestavení programu.
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 7 z 89 Zpět Celá obrazovka Zavřít Konec
Lexikální symboly Stejně jako jsou základním stavebním kamenem přirozeného jazyka slova, ze kterých se skládají věty, základním stavebním kamenem programu v jazyce C jsou lexikální symboly, ze kterých se skládají příkazy, definice a deklarace: čeština slovo věta, odstavec text
jazyk C lexikální symbol příkaz, deklarace, definice kompilační jednotka
Jazyk C rozlišuje šest tříd lexikálních symbolů:
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 8 z 89
• Identifikátory • Klíčová slova • Konstanty
Zpět Celá obrazovka
• Řetězce
Zavřít
• Operátory
Konec
• Ostatní oddělovače
Identifikátory Identifikátory – začínají písmenem nebo znakem podtržítko (_) a obsahují alfanumerické znaky, tj. písmena, číslice a znaky podtržítko; nepoužívejte identifikátory začínající podtržítkem, pokud nevíte, co děláte.
Úvodní strana Titulní strana
Klíčová slova Klíčová slova – několik desítek vybraných slov, které mají speciální význam v programu v jazyce C.
Obsah
JJ
II
J
I
Strana 9 z 89
Konstanty Zpět
V jazyce C lze používat celočíselné, reálné a znakové konstanty. Řetězcové konstanty jsou považovány za zvláštní druh lexikálních symbolů.
Celá obrazovka Zavřít
Celočíselné mohou být zapsány v desítkové, osmičkové nebo šestnáctkové soustavě; reálné pouze v desítkové soustavě.
Konec
Celočíselné konstanty Celočíselné konstanty začínají vždy číslicí. • konstanta, která začíná 0x nebo 0X, je zapsána v šestnáctkové soustavě, skládá se z číslic a písmen a až f nebo A až F, které reprezentují číslice 10 až 15
Úvodní strana
• pokud konstanta začíná 0, je zapsána v osmičkové soustavě, a může obsahovat pouze číslice 0 až 7
Obsah
• pokud konstanta začíná jinou číslicí než 0, je v desítkové soustavě Pokud konstanta přesahuje největší číslo typu int, je typu long; jinak je typu int. Celočíselné konstanty mohou být (bez ohledu na to, v jaké jsou zapsány číselné soustavě) zakončeny znaky U, L, UL, LL, nebo ULL, které stanovují, že se číslo má považovat za konstantu typu unsigned, long, unsigned long, long long, resp. unsigned long long. Toto zakončení lze psát i malými písmeny, ovšem malé l se snadno plete s číslici 1.
Titulní strana
JJ
II
J
I
Strana 10 z 89 Zpět Celá obrazovka Zavřít Konec
Reálné konstanty Reálné konstanty vyhovují následujícímu syntaktickému diagramu: To znamená, že reálné konstanty začínají číslicí nebo desetinnou tečkou a musí být zapsány v desítkové soustavě; skládají se z mantisy a nepovinného exponentu; mantisa obsahuje aspoň jednu číslici a nejvýše jednu desetinnou tečku, exponent je uveden znakem e nebo E, za kterým může být znaménko + nebo - a alespoň jedna číslice; reálná konstanta může být zakončena znakem f nebo F, která zajistí, že konstanta bude typu float a nikoli typu double. Příklady reálných konstant: 1.0, 0., .5, -12.345e27.
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 11 z 89 Zpět Celá obrazovka Zavřít Konec
Znakové konstanty Libovolný tisknutelný znak (včetně mezery) s výjimkou znaku apostrof mezi znaky apostrof: ’ ’, ’\"’, ’A’, ’6’. Nebo escape posloupnost mezi znaky apostrof: \n \11 \n \r \t \b \f \\ \’ \"
kód řídícího znaku v osm.soust bez 0 znak s kódem 9 (v kódu ASCII znak TAB) znak konce řádku (newline) návrat vozíku (carriage return) tabelátor (tab) backspace (o znak zpět) form feed (přechod na novou stránku) znak \ znak ’ znak "
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 12 z 89 Zpět Celá obrazovka
Znakové konstanty jsou typu char. Zavřít Konec
Řetězce Řetězec je posloupnost (může být i prázdná) tisknutelných znaků různých od znaku uvozovky (") a escape posloupností jako u konstant typu char uzavřená mezi znaky uvozovky:
Úvodní strana
"Ahoj", "\"", "\r\n"
Titulní strana
Dlouhé řetězce lze na libovolném místě rozdělit znakem uvozovky, odřádkováním, libovolným počtem mezer a dalšími uvozovkami. Řetězce se chovají jako pole znaků s paměťovou třídou static. Překladač vyhradí v paměti tolik bytů, kolik znaků nebo escape posloupností obsahuje řetězec, plus jeden navíc a do každého bytu uloží jeden znak (nebo hodnotu zadanou escape posloupností) a na konec přidá znak ’\0’. Většina řetězcových funkcí pracuje s těmito řetězci zakončenými znakem s kódem 0, řetězec sám proto znak s kódem 0 nesmí obsahovat, funkce by jej považovaly za konec řetězce.
Obsah
JJ
II
J
I
Strana 13 z 89 Zpět Celá obrazovka Zavřít
Operátory Operátory jsou tvořeny jedním nebo více nealfanumerickými znaky. Kromě notoricky známých operátorů +, -, *, /, <, >, <=, >= a ( ) obsahuje jazyk další více či méně exotické operátory:
Konec
Prior. 1 1 1 2 2 2 2 2
Operátor ( ) [ ] -> . ! ~ + ++ -& *
Vyhodn. −→
Oper. −
−→ −→ ←− ←− ←−
2 2 1 1 1
←− ←−
1 1
* / %
←− ←− −→
1 1 2
+ << >> < <= > >= == != & ^ | && ||
−→ −→ −→ −→ −→ −→ −→ −→ −→
2 2 2 2 2 2 2 2 2
2 3 4
(type)
5 6 7 8 9 10 11 12 13
sizeof
Význam pořadí vyhodnocování, parametry funkce přístup k prvku pole přístup k položce záznamu logická negace, bitová negace unární plus, unární minus inkrement (+1), dekrement (−1) ukazatel na objekt objekt, na který ukazatel ukazuje změna typu velikost objektu v bytech násobení, dělení, zbytek po dělení sčítání, odčítání bitový posun vlevo, vpravo porovnání je rovno, není rovno bitové and bitové xor bitové or logické and logické or
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 14 z 89 Zpět Celá obrazovka Zavřít Konec
14 15 15
? : = *= /= %= += -=
←− ←− ←−
3 2 2
15 15 16
&= ^= |= <<= >>= ,
←− ←− −→
2 2 2
podmíněný výraz přiřazení, znásobení, vydělení zbytek po dělení, přičtení, odečtení bitové and, xor, or posunutí doleva, doprava vyhodnotit zleva doprava, použít poslední výsledek
Úvodní strana Titulní strana Obsah
Slouží pro jednotlivé operace (například + pro sčítání, - pro odčítání, = pro přiřazení hodnoty, == pro test na rovnost, -> pro přístup k položce záznamu, na který ukazuje ukazatel, [ ] pro přístup k prvku pole a podobně)
JJ
II
J
I
Strana 15 z 89
Ostatní oddělovače Ostatní oddělovače – symboly používané zejména pro oddělování příkazů jako {, }, ;, apod.
Zpět Celá obrazovka Zavřít Konec
Bílé znaky Překladač při zpracování programu rozděluje vstupní text na lexikální symboly tak, že vždy načítá co nejdelší posloupnost znaků, která může být lexikálním symbolem. Příkaz a4=210*297; je možné psát bez mezer, protože
se v něm střídají identifikátory a konstanty složené z alfanumerických znaků s operátory a oddělovači z nealfanumerických znaků. Jméno typu int a identifikátor main však musí být odděleny alespoň jedním znakem mezera, tabelátor nebo znak konce řádku (tzv. bílé znaky), protože jinak by je překladač považoval za identifikátor intmain. Mezi libovolné dva lexikální symboly je možné napsat jakýkoli počet bílých znaků pro zpřehlednění programu.
Úvodní strana Titulní strana Obsah
Direktivy preprocesoru Zvláštní pravidla platí pro direktivy preprocesoru, které začínají znakem křížek (#) a jménem direktivy, a musí být na samostatném řádku. Jedná se zejména o příkazy pro vkládání souborů #include <soubor.h> #include "soubor.h"
pro definice konstant a maker #define JMENO hodnota #define makro(p1) ((p1)*(p1))
a pro podmíněný překlad #ifdef JMENO #if výraz #else #endif.
JJ
II
J
I
Strana 16 z 89 Zpět Celá obrazovka Zavřít Konec
Komentáře Součástí bílých míst oddělujících lexikální symboly mohou být i komentáře. Tradiční komentáře v jazyce C začínají dvojicí znaků /*, končí dvojicí */ a není je možné vnořovat. Většina novějších překladačů umí pracovat i s komentáři používanými v jazyce C++, které začínají dvojicí znaků // a končí s koncem řádku.
Úvodní strana Titulní strana Obsah
Protože není možné komentáře vnořovat, je problém s vykomentováváním částí programu – pokud bychom použili standardní komentář mezi /* a */ a vykomentovaná část programu by obsahovala také komentáře, překladač by první dvojici znaků */ pochopil jako konec komentáře a další text by se pokoušel překládat. V takovém případě je možné pro vykomentovávání částí programu používat direktivu preprocesoru pro podmíněný překlad – například takto:
JJ
II
J
I
Strana 17 z 89 Zpět Celá obrazovka
#ifdef 0 ... vykomentovaná část programu /* může obsahovat komentáře, ale nesmí obsahovat * křížící se direktivy preprocesoru #if, #else, #endif */ #endif
Zavřít Konec
Výraz, kterým se přiřazuje do proměnné a4 součin čísel 210 a 297 je možné psát a4 = 210 * 297 ;
ale i a4=210*297; Úvodní strana
nebo a4
=
Titulní strana
210
Obsah
* 297
;
JJ
II
J
I
Strana 18 z 89 Zpět Celá obrazovka Zavřít Konec
První program Snad každá kniha o jazyce C začíná ukázkou jednoduchého programu v tomto jazyce – programu, který vypíše na obrazovku nápis Hello, world! a odřádkuje. Zde je tento program:
Úvodní strana Titulní strana
#include <stdio.h> Obsah
main() { printf("Hello, world!\n"); }
JJ
II
J
I
Strana 19 z 89
Jazyk C prošel od svého vzniku určitým vývojem, takže novější překladače budou pravděpodobně vypisovat při překladu uvedeného programu varování. Text programu upravený podle současných standardů vypadá takto:
Zpět Celá obrazovka Zavřít
#include <stdio.h> int main() { printf("Hello, world!\n"); return 0; }
Konec
Jazyk C používá volný formát zápisu, který programátorovi umožňuje různými způsoby formátovat zdrojový text. Program by bylo možné zapsat kompaktněji takto: #include <stdio.h> int main(){printf("Hello, world!\n");return 0;}
Text #include <stdio.h>, stejně jako další příkazy začínající znakem # musí být na samostatném řádku; jedná se o direktivy preprocesoru, pro které platí zvláštní pravidla. Ze zbývajícího textu bylo možné odstranit většinu mezer a odřádkování (kromě mezery mezi slovy int a main, která by bez mezery splynula v jedno slovo intmain). Výsledný zápis je ale méně přehledný než předešlý, takže je lépe se takovémuto „šetřeníÿ vyhýbat.
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 20 z 89 Zpět
Na programu je vidět několik podstatných rysů: Celá obrazovka
• Procedura printf není součástí jazyka, ale patří do standardní knihovny. Aby ji bylo možné použít, musí být do programu pomocí direktivy preprocesoru #include vložen hlavičkový soubor obsahující mj. deklaraci funkce printf. • Hlavní program je funkce se jménem main. • Za jménem funkce se vždy píší závorky (i když jsou prázdné).
Zavřít Konec
• Pro tisk na standardní výstup (normálně na obrazovku, ale je možné přesměrovat), se používá procedura printf. • Odřádkování se zajistí vložením posloupnosti \n do tisknutého řetězce. • Pro ohraničení bloku slouží složené závorky { a }, a nikoli příkazy begin a end.
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 21 z 89 Zpět Celá obrazovka Zavřít Konec
Jednoduché typy Ve standardu jazyka C jsou následující typy: char, unsigned char, signed char, short, unsigned short, int, unsigned, long, unsigned long, float a double.
Úvodní strana Titulní strana
Celočíselné typy typ signed char unsigned char short unsigned short int unsigned long unsigned long long long unsigned long long
Obsah
rozsah SCHAR_MIN až SCHAR_MAX 0 až UCHAR_MAX SHRT_MIN až SHRT_MAX 0 až USHRT_MAX INT_MIN až INT_MAX 0 až UINT_MAX LONG_MIN až LONG_MAX 0 až ULONG_MAX LLONG_MIN až LLONG_MAX 0 až ULLONG_MAX
obvyklý rozsah -128 až 127 0 až 255 -32768 až 32767 0 až 65536 jako long nebo short
JJ
II
J
I
Strana 22 z 89 Zpět Celá obrazovka
-2147483648 až 2147483647 0 až 4294967296
Zavřít Konec
Reálné typy typ float double long double
přesnost 7 desítkových číslic 15 desítkových číslic 19 desítkových číslic
rozsah ±1.1755 × 10−38 .. ± 3.4028 × 1038 ±2.2251 × 10−308 .. ± 1.7976 × 10308 ±3.3622 × 10−4932 .. ± 1.1897 × 104932
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 23 z 89 Zpět Celá obrazovka Zavřít Konec
Standardní aritmetické konverze Při množství číselných typů je stanoveno, že při vyhodnocování aritmetického výrazu se automaticky provádějí následující standardní konverze (tento postup přesně platí pro binární operátory +, -, * a /, u ostatních operátorů je poněkud modifikován):
Úvodní strana Titulní strana
1. hodnoty typu signed char a short se převedou na typ int a 2. hodnoty typu unsigned char a unsigned short se převedou na typ unsigned; potom 3. je-li jeden z operandů typu long double, převede se druhý na tento typ a provede se operace pro tento typ 4. jinak je-li jeden z operandů typu double, převede se druhý na tento typ a provede se operace pro tento typ 5. jinak je-li jeden z operandů typu float, převede se druhý na tento typ a provede se operace pro tento typ 6. jinak je-li jeden z operandů typu unsigned long, převede se druhý na tento typ a provede se operace pro tento typ 7. jinak je-li jeden z operandů typu long, převede se druhý na tento typ a provede se operace pro tento typ 8. jinak je-li jeden z operandů typu unsigned, převede se druhý na tento typ a provede se operace pro tento typ
Obsah
JJ
II
J
I
Strana 24 z 89 Zpět Celá obrazovka Zavřít Konec
9. jinak musí být oba operandy typu int, a provede se operace pro tento typ V normě podle K&R se navíc převáděly všechny hodnoty typu float na typ double. Kromě těchto implicitně prováděných konverzí lze konverzi vynutit operátorem změny typu: ( typ ) výraz. Příklad je v kapitole „Výpočty s celými číslyÿ.
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 25 z 89 Zpět Celá obrazovka Zavřít Konec
Výpočty s celými čísly • Každý celočíselný typ reprezentuje omezený interval celých čísel • Pokud nedojde při výpočtu k překročení číselného rozsahu jsou výpočty přesné • Překročení číselného rozsahu se ale snad v žádné implementaci nekontroluje (to není vlastnost jazyka C, ale týká se to téměř všech programovacích jazyků)
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 26 z 89 Zpět Celá obrazovka Zavřít Konec
/* K zadanému roku vypočítá datum velikonoc podle Gaussova vzorce */ #include <stdio.h> int main() { int r, k, pr, d, e, den;
Úvodní strana Titulní strana Obsah
printf("Rok: "); scanf("%d", &r); k=r/100; pr=k-k/4; d = (19*(r%19) + (15-(8*k+13)/25+pr)%30) % 30; e = (2*(r%4)+4*(r%7)+6*d+(4+pr)%7) % 7; den=22+d+e; if (d==29 && e==6) den-=7; if (d==28 && e==6 && r/19>10) den-=7; if (den>31) printf("Velikonoce: %d. 4. %d\n", den-31, r); else printf("Velikonoce: %d. 3. %d\n", den, r); }
JJ
II
J
I
Strana 27 z 89 Zpět Celá obrazovka Zavřít Konec
/* * Pro zadané datum spočítá den v týdnu * (1=pondělí, 2=úterý, ... 6=sobota, 0=neděle) */ Úvodní strana
#include <stdio.h> int main() { int rok, mesic, den, p; printf("Zadej datum dd.mm.rrrr: "); if (scanf("%d.%d.%d", &den, &mesic, &rok)==3) { if (mesic<3) { mesic+=12; rok--; } p=(long)rok*365+rok/4-rok/100+rok/400+(306*(mesic+1))/10+den-1; printf("Den v týdnu: %d\n", (int) (p % 7)); } else { printf("Spatně zadané datum."); } }
Titulní strana Obsah
JJ
II
J
I
Strana 28 z 89 Zpět Celá obrazovka Zavřít Konec
Výpočet kořenů kvadratické rovnice Napíšeme program, který vypočítá kořeny kvadratické rovnice ax2 + bx + c = 0
Úvodní strana Titulní strana
Podle hodnoty diskriminantu D
Obsah
D = b2 − 4ac
JJ
II
J
I
musíme rozlišit tři případy Strana 29 z 89
jestliže D > 0 jestliže D = 0 jestliže D < 0
√ x1,2 = −b±2a D x1,2 = −b 2a √ −D −b x1,2 = 2a ± 2a i
Zpět Celá obrazovka
(dvojnásobný kořen) Zavřít Konec
Budeme potřebovat tři reálné proměnné pro uložení koeficientů a, b, c. Aby nebylo nutné počítat diskriminant opakovaně, použijeme pro jeho uložení další proměnnou.
V jazyce C je nutné každou proměnnou deklarovat. Deklarace bude vypadat takto: double a, b, c, D; Úvodní strana
V programu budeme potřebovat podmíněný příkaz. Jeho syntaktický diagram vypadá takto: - else - příkaz
- if - ( - výraz - ) - příkaz Výraz bývá nejčastěji relační – porovnání s použitím jednoho z následujících operátorů:
Titulní strana Obsah
JJ
II
J
I
Strana 30 z 89
== != < > <= >=
je rovno není rovno je menší než je větší než je menší nebo rovno je větší nebo rovno
V případě, že je výraz pravdivý, provede se příkaz uvedený za kulatou závorkou. Pokud by mělo být provedeno více příkazů, je nutné použít složený příkaz. Příkaz, který se má provést při
Zpět Celá obrazovka Zavřít Konec
#include <stdio.h> #include <math.h> void main() { float a, b, c, D; printf("Program na výpočet kořenů kvadratické rovnice ax^2+bx+c=0\n\n"); printf("Koeficient a: "); scanf("%f", &a); printf("Koeficient b: "); scanf("%f", &b); printf("Koeficient c: "); scanf("%f", &c); printf("Rovnice %G.x^2 %+G.x %+G = 0\n", a, b, c); if (a==0) { if (b==0) { if (c==0) { printf("Rovnici vyhovuje každé x.\n"); } else { printf("Rovnice nemá řešení.\n"); } } else { printf("Lineární rovnice; řešení x = %G.\n", -c/b); }
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 31 z 89 Zpět Celá obrazovka Zavřít Konec
} else { D=b*b-4*a*c; if (D>0) { printf("Řešení: x1 = %G, x2 = %G.\n", (-b+sqrt(D))/(2*a), (-b-sqrt(D))/(2*a)); } else if (D==0) { printf("Řešení: x1,2 = %G.\n", -b/(2*a)); } else { printf("Řešení: x1,2 = %G +- %Gi.\n", -b/(2*a), fabs(sqrt(-D)/(2*a))); } } }
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 32 z 89 Zpět Celá obrazovka Zavřít Konec
Výpočet Ludolfova čísla π Napíšeme program, který vypočítá Ludolfovo číslo pí. Použijeme vzorec π 1 1 = arctg + arctg 4 2 3
Úvodní strana Titulní strana
Pro výpočet hodnoty funkce arctg použijeme Taylorův vzorec Obsah
x3 x5 x7 x9 arctgx = x − + + − + . . . (pro x < 1) 3 5 7 9
JJ
II
J
I
#include <stdio.h> #include <math.h>
Strana 33 z 89
void main() { int n; double moc2, moc3; double znam; double epsilon; double clen, suma;
Celá obrazovka
epsilon=1e-9; znam=1.0;
Zpět
Zavřít Konec
moc2=1.0/2.0; moc3=1.0/3.0; n=1; clen=moc2+moc3; suma=clen; while (fabs(clen)>epsilon) { n=n+2; znam=-znam; moc2=moc2/4.0; moc3=moc3/9.0; clen=znam/n*(moc2+moc3); suma=suma+clen; }
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 34 z 89
printf("Ludolfovo číslo: %.10lG\n", 4.0*suma); }
Zpět Celá obrazovka Zavřít Konec
Výpočet faktoriálu #include <stdio.h> #include
Úvodní strana
unsigned long factorial(unsigned long n) { unsigned long fnm1; if (n<=1) return 1UL; /* 1UL is 1 of type unsigned long */ fnm1=factorial(n-1); if (ULONG_MAX/n
Titulní strana Obsah
JJ
II
J
I
Strana 35 z 89
int main() { unsigned long n, f; printf("Program na výpočet faktoriálu\n"); printf("Zadej číslo: "); if (scanf("%lu", &n)!=1) { fprintf(stderr, "Nebylo zadáno číslo!\n"); return 2; } printf("Počítám %lu!\n", n); f=factorial(n); if (f==0) {
Zpět Celá obrazovka Zavřít Konec
fprintf(stderr, "Výsledek je příliš velký!\n"); return 1; } printf("%lu! = %lu\n", n, f); return 0; }
Úvodní strana Titulní strana
Problémem rekurzivního výpočtu faktoriálu je, že i když hlídám aritmetické přetečení, dojde k přetečení zásobníku dříve než k aritmetickému přetečení.
Obsah
JJ
II
J
I
Strana 36 z 89 Zpět Celá obrazovka Zavřít Konec
Práce s logickými hodnotami Jazyk C nemá (na rozdíl od Pascalu) zvláštní typ pro logické hodnoty. Logické hodnoty často používáme, niž bychom je potřebovali někam ukládat: Úvodní strana
if (a>b) max=a; else max=b; if (max>0 && max<=10) ...
Titulní strana Obsah
– && je logické „aÿ (konjunkce).
JJ
II
V jazyce C lze pro ukládání logických hodnot použít libovolný celočíselný typ:
J
I
Strana 37 z 89
int a_je_vetsi; a_je_vetsi = (a>b); if (a_je_vetsi) max=a; else max=b;
Zpět Celá obrazovka Zavřít
Jako hodnota „nepravdaÿ se v jazyce C používá 0, jako „pravdaÿ 1. Příkazy if a while a logické operátory &&, || (logické „neboÿ – disjunkce), a ! (negace) jsou benevolentnější – za hodnotu „pravdaÿ považují libovolnou nenulovou hodnotu.
Konec
Pravdivostní tabulka v jazyce C: a
b
a && b
a || b
!a
!b
0 0 nenula nenula
0 nenula 0 nenula
0 0 0 1
0 1 1 1
1 1 0 0
1 0 1 0
Úvodní strana Titulní strana
Logické operátory && a || v jazyce C mají dvě sympatické vlastnosti: • Mají správné priority – ve výrazu i>0 && i<=10 není nutné (na rozdíl od Pascalu) používat závorky. • V případě, že po vyhodnocení jednoho členu je zřejmé, jaká bude hodnota celého výrazu, zbývající členy se již nevyhodnocují (tzv. shortcircuit evaluation). Díky tomu je možné jednoduše zapisovat složené podmínky jako while (i<MAX_A && hodnota>a[i]) i=i+1;.
Obsah
JJ
II
J
I
Strana 38 z 89 Zpět Celá obrazovka Zavřít Konec
Typ pole Pole je složený datový typ – proměnná typu pole obsahuje několik hodnot (prvků) téhož typu. Počet prvků pole se stanovuje při deklaraci. Jednotlivé prvky se vybírají pomocí indexu, který v jazyce C může být libovolného celočíselného typu a index prvního prvku je vždy 0. U pole lze projít všechny prvky pomocí cyklu. Pole může mít více rozměrů než jeden. Je dobrou praxí deklarovat horní meze všech polí pomocí konstant a tyto konstanty používat na všech místech, kde se jedná o horní mez pole:
Úvodní strana Titulní strana Obsah
JJ
II
J
I
#define MAXPRVKU 10 Strana 39 z 89
double pole[MAXPRVKU]; int i;
Zpět Celá obrazovka
pole[0]=0.0; pole[MAXPRVKU-1]=1.0; pole[MAXPRVKU/2]=2.0;
Zavřít Konec
For cyklus Jazyk C má zajímavou syntaxi i sémantiku for-cyklu: Úvodní strana
for (výraz1; výraz2; výraz3) příkaz; Titulní strana
znamená přesně totéž co výraz1; while (výraz2) { příkaz; výraz3; }
Zapamatujte si, jak vypadá for cyklus přes všechny prvky pole:
Obsah
JJ
II
J
I
Strana 40 z 89 Zpět Celá obrazovka Zavřít
#define MAXPRVKU 10 Konec
double pole[MAXPRVKU]; int i; for (i=0; i<[MAXPRVKU; i++) pole[i]=0.0;
Podprogramy, funkce, procedury K čemu slouží Nejobvyklejší odpověď na otázku, k čemu slouží podprogramy, funkce nebo procedury, bývá „aby bylo možné určitou akci provádět na různých místechÿ. Tato odpověď nám však téměř vůbec nepomůže k tomu, abychom vytvářeli srozumitelné a pěkné programy. Pokud se budeme držet tohoto principu a čirou náhodou budeme mít napsat program, ve kterém se žádná činnost neprovádí vícekrát, bude výsledkem jedna, velmi dlouhá a nesrozumitelná funkce. Lidská mysl je schopna obsáhnout pouze objekty omezené složitosti. Proto je třeba při programování rozdělovat řešení složitých problémů na menší části, kterým je člověk schopen snadno porozumět. Tyto části se realizují pomocí podprogramů. Každý podprogram by měl řešit určitou dobře definovatelnou a definovanou úlohu.
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 41 z 89 Zpět Celá obrazovka Zavřít
HLAVNÍM DŮVODEM POUŽÍVÁNÍ FUNKCÍ JE ZLEPŠENÍ SROZUMITELNOSTI PROGRAMU Při programování (nebo při čtení cizího programu) je v každém stádiu důležité, co dělají jednotlivé podprogramy, ale ne jak to dělají (to je zajímavé až při bližším pohledu).
Konec
Proto jsou podprogramy prostředkem programové abstrakce. K snazšímu pochopení přispívají mnemotechnické názvy procedur a proměnných a rozumné komentáře, které popisují části programu z hlediska řešeného problému a ne z hlediska použitého programovacího jazyka. Úvodní strana
Podprogramy v jazyce C – funkce
Titulní strana Obsah
V různých jazycích se používají různé názvy pro podprogramy; v jazyce Pascal se například podprogramy dělí na funkce (které vracejí hodnotu) a procedury (které hodnotu nevracejí). V jazyce C je rozlišování funkcí a procedur dosti uvolněné – každou funkci je možné vyvolat jako proceduru (pokud nezáleží na vrácené hodnotě). V jazyce C se obvykle podprogramům říká pouze funkce, i když lze vytvářet funkce, které nevracejí žádnou hodnotu (funkce typu void). Deklarace – sděluje překladači, jak funkce vypadá (jaké má jméno, hodnotu jakého typu vrací, kolik má parametrů a jaké jsou jejich typy) – funkci deklarujeme zapsáním její hlavičky Definice – definuje, co funkce dělá – obsahuje hlavičku a tělo funkce Použití – vyvolání funkce ve výrazu nebo příkazu Každá funkce může mít pouze jedinou definici. Deklarací může být více, ale
JJ
II
J
I
Strana 42 z 89 Zpět Celá obrazovka Zavřít Konec
nesmí být v rozporu mezi sebou ani s definicí. Použití funkce by měla předcházet deklarace nebo definice (pokud nepředchází, doplní si překladač, že se jedná o funkci bez parametrů vracející typ int). Úvodní strana
V jazyce C musí být za jménem funkce vždy otvírací kulatá závorka (i když funkce nemá žádné parametry).
Titulní strana Obsah
Definice funkcí nelze v jazyce C vnořovat. Funkční hodnota se v jazyce C vrací příkazem return hodnota;.
JJ
II
Každá funkce by měla mít co možná nejjednodušší interakci se svým okolím. Přesněji veškeré interakce s okolím by měly být prováděné pomocí parametrů.
J
I
Funkce, která mění i jiné hodnoty než své parametry, se nazývá funkce s postranními efekty (side effects). Pokud možno bychom se takovýmto funkcím měli vyhýbat, stejně jako funkcím, které jsou kromě parametrů ovlivňovány jinými hodnotami.
Strana 43 z 89 Zpět Celá obrazovka Zavřít Konec
Typ ukazatel Ukazatele slouží jako odkazy na jiné proměnné. Zatímco běžná proměnná může během výpočtu měnit svoji hodnotu, proměnná typu ukazatel může ukazovat na různé proměnné (měly by být téhož typu, ale toto omezení lze v případě potřeby obejít). Zatímco ve standardním Pascalu lze ukazatele používat pouze pro odkazy na dynamicky vytvářené proměnné, v jazyce C je jejich použití mnohem širší – mohou ukazovat na libovolné proměnné včetně lokálních.
Deklarace proměnných typu ukazatel
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 44 z 89
Ukazatele se deklarují takto: typ *identifikátor;
Pro práci s ukazateli slouží unární operátory & a *. Operátor &objekt je získání adresy objektu – je-li objekt typu t, je výraz typu „ukazatel na tÿ, neboli *t. Operátor *ukazatel je dereference ukazatele – jeho hodnotou je proměnná, na kterou ukazatel ukazuje. Hodnota NULL – je zaručeno, že žádný ukazatel na některý objekt nemá hod-
Zpět Celá obrazovka Zavřít Konec
notu NULL.
Porovnání operací s ukazateli v jazyce C a v Pascalu Úvodní strana
operace dereference ukázání na objekt prázdná hodnota alokace paměti uvolnění paměti přístup k položce
C
Pascal
*ptr &objekt NULL ptr=malloc(sizeof(typ)) free(ptr) ptr->item
ptr^ @objekt (pouze Turbo Pascal) nil new(ptr) dispose(ptr) ptr^.item
Titulní strana Obsah
JJ
II
J
I
Strana 45 z 89 Zpět Celá obrazovka Zavřít Konec
int i, j, k, l; int *p, *q, *r; p=&i; /* p ukazuje na i, lze provést i když i není inicializováno */ i=1; j=2; q=&j; /* q ukazuje na j */ r=q; /* r ukazuje tam, co q (tj. na j) */ *p=*q; /* p ukazuje nadále na i, ale tímto se do i uloží 2 */ p=NULL; /* p neukazuje nikam */ *p=*q; /* chybně p neukazuje nikam, nelze tam kam ukazuje něco uložit */ r=&k; /* r ukazuje na k */ *r=3; /* tam, kam r ukazuje dej 3, tj. do k */ p=r; /* O.K. p ukazuje na k */
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 46 z 89 Zpět Celá obrazovka
Prohození obsahu proměnných void prohod(int *p1, int *p2) { int temp; temp=*p1; *p1=*p2; *p2=temp;
Zavřít Konec
}
Proměnná temp musí být skutečně typu int a ne int *. Pokud by byla typu int *, nebylo by možné do ni přiřadit hodnotu. Úvodní strana
#include <stdlib.h> #include <string.h>
Titulní strana Obsah
int prohodcokoli(void *p1, void *p2, int size) { void *ptemp; ptemp=malloc(size); if (ptemp==NULL) return 0; memcpy(ptemp, p1, size); memcpy(p1, p2, size); memcpy(p2, ptemp, size); free(ptemp); return 1;
JJ
II
J
I
Strana 47 z 89 Zpět Celá obrazovka Zavřít
} Konec
Ukazatele a pole Identifikátor pole se chová jako ukazatel. Má typ „ukazatel na typ prvku poleÿ. Jeho hodnota je ukazatel na nultý prvek pole (první prvek v poli, který má index nula).
Úvodní strana
Přesto se pole a ukazatel od sebe liší:
Titulní strana Obsah
• Identifikátor pole není l-hodnota – není možné do něj přiřadit hodnotu. • Pokud deklarujeme pole, máme skutečně prostor pro počet položek, který je uveden v deklaraci; pokud deklarujeme ukazatel, máme prostor pouze pro tento ukazatel; aby bylo možné ukládat hodnoty na místo, kam ukazatel ukazuje, je potřeba buď s ním někam ukázat: ptr=&proměnná; nebo alokovat místo: ptr=malloc(n*(sizeof(*ptr)));.
JJ
II
J
I
Strana 48 z 89 Zpět Celá obrazovka Zavřít Konec
Algoritmus quicksort Pracuje na principu „rozděl a panujÿ – při třídění vzestupně jsou na začátek pole přemístěna malá čísla, na konec velká a na obě části zvlášť je znovu uplatněn stejný algoritmus. Opakuje se dokud část, která se má třídit, nemá méně než dva prvky – pak je jistě setříděná.
Úvodní strana Titulní strana
1
3 5
7 9
2
4 6
8 0 Obsah
1
3 5
0 9
2
4 6
8 7
JJ
II
1
3 5
0 6
2
4 9
8 7
J
I
Strana 49 z 89 Zpět Celá obrazovka Zavřít Konec
Aritmetika ukazatelů Je-li p ukazatel a n celé číslo, pak výrazy p+n a p-n jsou výrazy typu ukazatel a mají hodnotu „ukazatel na prvek o n míst dáleÿ, resp. „ukazatel na prvek o n míst zpětÿ. Ukazují-li ukazatele p a q do téhož pole, je výraz p-q typu int a jeho hodnotou je počet prvků mezi ukazateli q a p.
Úvodní strana Titulní strana Obsah
Typ void * – slouží pro konverze ukazatelů. JJ
II
J
I
Strana 50 z 89 Zpět Celá obrazovka Zavřít Konec
Funkce pro vstup a výstup Funkce pro vstup a výstup lze rozdělit na několik skupin: hlavičkový soubor operace otevření souboru vytvoření souboru zavření souboru posunutí v souboru je konec souboru? vstup znaku znaku návrat znaku řetězce bloku formátovaný výstup znaku znaku řetězce bloku formátovaný
stdio.h
stdio.h
conio.h
(gets) scanf stdout putchar fputchar puts printf
io.h
Úvodní strana
file handle
FILE fopen fopen fclose fseek feof stdin getchar fgetchar
curses.h
(initscr)
FILE getc fgetc ungetc fgets fread fscanf
klávesnice
klávesnice
getch getche ungetch cgets
getch
cscanf
scanw
FILE putc fputc fputs fwrite fprintf
obrazovka
obrazovka
putch
addch insch addstr
open creat close lseek eof
file handle
Titulní strana Obsah
JJ
II
J
I
Strana 51 z 89 Zpět
ungetch getnstr
Celá obrazovka
read
cputs
Zavřít
file handle
write cprintf
printw
Konec
Ve druhém sloupci tabulky jsou funkce pro práci se standardním vstupem a výstupem. O otevírání a zavírání standardního vstupu a výstupu se stará operační systém. Místo dalších chybějících funkcí lze použít příslušné funkce ze třetího sloupce, u kterých se na místě parametru typu FILE * použije stdin – standardní vstup, nebo stdout – standardní výstup. Funkce gets pro vstup řádku ze standardního vstupu by se rozhodně neměla používat, protože neumožňuje zadat maximální délku čteného řetězce. Díky tomu může dojít k přetečení použitého řetězce, které může mít za následek přepsání dalších proměnných, havárii programu a za určitých podmínek i ohrožení bezpečnosti operačního systému. Místo funkce gets používejte fgets. Ve třetím sloupci jsou funkce pro práci s libovolnými soubory používající vyrovnávací paměti (buffered input/output). Pokud program pracuje s jinými soubory než se standardním vstupem a výstupem, obvykle používá právě tyto funkce. Ve čtvrtém sloupci jsou funkce pro práci s obrazovkou a klávesnicí, které byly použity u překladačů firmy Borland pro OS MS-DOS. Mají jednoduchou podporu oken v textovém režimu, umožňují přemisťovat a zjišťovat pozici kursoru na obrazovce a mazat obrazovku. Jedná se o funkce převzaté z turbopascalské jednotky Crt. Jsou dostupné pouze pokud použitý překladač má knihovny pro zajištění kompatibility s překladači Borland. V OS Unix existuje pro podobný účel knihovna curses, resp. ncurses, která má ovšem poněkud jiné funkce a zcela jiné ovládání.
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 52 z 89 Zpět Celá obrazovka Zavřít Konec
V pátém sloupci jsou funkce z knihovny curses, která umožňuje vytvářet okna v textovém režimu v Unixu. Její použití je poměrně komplikované. V posledním sloupci jsou funkce, které tvoří minimální nadstavbu nad službami pro práci se soubory, které poskytuje operační systém. Jako odkazy na soubory se používají malá celá čísla, tak zvané manipulátory (file handles), které vracejí funkce open a creat (funkce se skutečně jmenuje creat a ne create). Tyto funkce nepoužívají vyrovnávací paměti, proto jsou při práci s malými bloky málo efektivní. Při otevírání souboru je nutné stanovit způsob práce se souborem: zda se bude pouze číst, pouze zapisovat nebo obojí, zda se má připisovat na konec, zda má být existující soubor přepsán a konečně zda mají být konvertovány znaky \n (newline) na znaky používané pro ukončení řádku v příslušném operačním systému (při výstupu; při vstupu bude prováděna opačná konverze). Způsob práce se souborem stanovuje zvláštní parametr funkcí fopen a open. Druhý parametr funkce fopen udává způsob práce se souborem. Je to řetězec, který je složen z hodnot uvedených v jednotlivých částech následující tabulky:
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 53 z 89 Zpět Celá obrazovka Zavřít Konec
r r+ w w+ a a+ t b jinak
hodnota parametru mode ve funkci fopen (read) otevřít existující soubor pro čtení otevřít existující soubor pro čtení a zápis (update) (write) vytvořit soubor pro zápis; existující soubor bude přepsán vytvořit soubor pro zápis a čtení (update); pokud soubor se zadaným jménem existuje, bude přepsán (append) otevřít soubor pro připisování na konec; pokud soubor neexistuje, bude vytvořen otevřít soubor pro připisování na konec a čtení; pokud soubor neexistuje, bude vytvořen otevřít v textovém režimu otevřít v binárním režimu otevřít v režimu určeném proměnnou fmode
Podobně funkce open má jako druhý parametr celé číslo, které je tvořeno logickým součtem konstant uvedených v jednotlivých částech následující tabulky, a které určuje způsob práce se souborem:
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 54 z 89 Zpět Celá obrazovka Zavřít Konec
O O O O O O O O O O O O
RDONLY WRONLY RDWR NONBLOCK NDELAY SYNC APPEND CREAT TRUNC EXCL BINARY TEXT
příznaky pro access v open otevřít jen pro čtení otevřít jen pro zápis otevřít pro čtení a zápis neblokující přístup (pouze při práci s FIFO v Unixu) totéž jako O NONBLOCK výstupní funkce skončí až po fyzickém zápisu na zařízení před každým zápisem nastavit file pointer na konec souboru vytvořit soubor existující soubor bude při otevření zkrácen na délku 0 po dobu otevření nebude soubor moci otevřít jiný program otevřít v binárním režimu otevřít v textovém režimu
Při zpracování vstupu je někdy potřeba načíst (provést vstupní konverzi) číslo, které se nachází v již načtených datech. Pro tento účel lze použít funkci sscanf, která funguje podobně jako scanf, ale místo ze standardního vstupu čte ze řetězce. Obdobně pro výstup existuje funkce sprintf, které formátovaný výstup ukládá do řetězce a ne do souboru. Pro vstupní konverze existují i specializované funkce:
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 55 z 89 Zpět Celá obrazovka Zavřít Konec
druh konverze konverze řetězec konverze řetězec konverze řetězec konverze řetězec konverze řetězec konverze řetězec konverze řetězec konverze řetězec
funkce → → → → → → → →
typ typ typ typ typ typ typ typ
integer long long long unsigned long unsigned long long float double long double
strtol strtoll strtoul strtoull strtof strtod strtold
funkce atoi atol atoll, atoq Úvodní strana Titulní strana
atof
Program pro výpis obsahu souboru na standardní výstup Ošetření všech chyb, ke kterým může dojít při vstupu a výstupu, bývá komplikované. Ovšem v situacích, kdy může dojít k chybě, by program měl testovat, zda k ní nedošlo, a pokud ano, měl by o ní srozumitelně informovat uživatele.
Obsah
JJ
II
J
I
Strana 56 z 89 Zpět Celá obrazovka
#include <stdio.h> #include <errno.h> FILE *fp; char buffer[1000]; int code=0; int main(int argc, char *argv[])
Zavřít Konec
{ if (argc!=2) { fputs("Usage: typec filename\n", stderr); return 1; } Úvodní strana if (!(fp=fopen(argv[1], "rt"))) { fprintf(stderr, "Error opening file %s: %s\n", argv[1], strerror(errno)); Titulní strana return 2; } else { Obsah while (!feof(fp)) { JJ II if (!fgets(buffer, sizeof(buffer)-1, fp) && errno!=0) { fprintf(stderr, "Error reading file %s: %s\n", argv[1], strerror(errno)); J I code=2; break; Strana 57 z 89 } else { Zpět if (fputs(buffer, stdout)==EOF) { fprintf(stderr, "Error writing stdout: %s\n", strerror(errno)); Celá obrazovka code=3; break; Zavřít } Konec } } if (fclose(fp) && code==0) { /* This error shouldn’t happen */ fprintf(stderr, "Error closing file %s: %s\n", argv[1], strerror(errno)); code=2;
} /* Check whether flushing buffers doesn’t cause an error; it would be really bad luck if it does, but what if the stdout is redirected to a disk file, disk is just full and there is no space to write the contents of bufffers? */ if (fflush(stdout) && code==0) { fprintf(stderr, "Error flushing stdout: %s\n", strerror(errno)); code=3; } } return code; }
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 58 z 89
Načítání čísel
Zpět Celá obrazovka
Pro třídicí program vytvoříme funkci, která načítá čísla typu double. Funkce bude vracet hodnotu 1, pokud bylo načteno číslo a 0 jinak:
Zavřít Konec
#include #include #include #include
<stdio.h> <stdlib.h> <string.h> "readdbl.h"
#define BUFLEN 80 char buffer[BUFLEN]; int readdouble(double *value) { double val; char *p; int status; int len; status=0; /* Nic neprecteno */ if (fgets(buffer, BUFLEN, stdin)!=NULL) { val=strtod(buffer, &p); if (p!=buffer) { *value=val; status=1; /* Cislo nacteno */ } /* Jeste docist zbytek radku, pokud nebyl docten */ len=strlen(buffer); while (len>0 && buffer[len-1]!=’\n’) { if (fgets(buffer, BUFLEN, stdin)==NULL) break; len=strlen(buffer); } } return status; }
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 59 z 89 Zpět Celá obrazovka Zavřít Konec
S touto funkcí lze snadno napsat proceduru na přečtení předem neznámého počtu prvků do pole (maximální počet načtených prvků je samozřejmě omezen velikostí pole): #include <stdio.h> #include "rdwrarr.h" #include "readdbl.h" int readarray(double x[], int n) { int i; i=0; while (i
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 60 z 89 Zpět Celá obrazovka
} Zavřít
void writearray(double *x, int n) { int i; for (i=0; i
Konec
Vazba programu na operační systém Jazyk C byl navrhován s jasnou představou, jakým způsobem má program komunikovat s operačním systémem. Činnost programu je možné ovlivnit pomocí parametrů, které se zadávají na příkazovém řádku za jménem programu. Naopak program při svém skončení informuje operační systém, jak byl úspěšný, pomocí tzv. návratového kódu.
Úvodní strana Titulní strana Obsah
Zpracování parametrů Jazyk C umožňuje elegantně číst parametry programu zadaná na příkazovém řádku při jeho spouštění. Parametry bývají často jména souborů, ale není to podmínkou. Pro zpřístupnění parametrů programu je nutné definovat funkci main jako funkci se dvěma parametry. První parametr musí být typu int, druhý typu char *[] (pole ukazatelů na znak). Jména parametrů mohou být libovolná, ale tradičně se používají jména argc a argv (jako argument count a argument values). Použití parametrů ilustruje následující ukázka: #include <stdio.h> int main(int argc, char *argv[])
JJ
II
J
I
Strana 61 z 89 Zpět Celá obrazovka Zavřít Konec
{ int i; printf("Jméno programu: %s\n", argv[0]); printf("Počet parametrů: %d\n", argc-1); for (i=1; i<argc; i++) printf("Parametr %d: %s\n", i, argv[i]); return 5;
Úvodní strana Titulní strana
}
Návratový kód
Obsah
JJ
II
J
I
Strana 62 z 89
Funkce main by měla být typu int a její provádění by mělo končit příkazem return vracejícím celé číslo (případně je možné ukončit program v libovolné funkci voláním procedury exit, která má jako parametr celé číslo, jež bude také použito pro nastavení návratového kódu). Je zvykem, že vrácená hodnota informuje o úspěšnosti běhu programu. Hodnota 0 znamená běh bez chyb, nenulové hodnoty obvykle znamenají chyby, tím závažnější, čím je vrácená hodnota vyšší, ale konkrétní použití může být i odlišné. Ačkoli je hodnota typu int používají se hodnoty 0 až 255.
Zpět Celá obrazovka Zavřít Konec
Funkce pro práci s řetězci Jsou definovány v hlavičkovém souboru string.h. Lze je rozdělit na funkce pro práci s ASCIIZ řetězci, funkce pro práci s ASCIIZ řetězci omezené délky, a funkce pro práci poli znaků. U funkcí z druhé a třetí skupiny se zadává délka nebo maximální délka řetězce; funkce z poslední skupiny nepovažují znak s kódem nula za konec řetězce. Operace zjištění délky vyplnění znakem zkopírování připojení na konec porovnání <, =, > porovnání, malá=velká porovnání, malá=velká vyhledání znaku vyhledání podřetězce
ASCIIZ řetězec strlen strset strcpy strcat strcmp stricmp strcmpi strchr strstr
řetěz. omez. délky
blok paměti
strnset strncpy strncat strncmp strnicmp strncmpi
memset memcpy memcmp memicmp memchr
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 63 z 89 Zpět Celá obrazovka Zavřít Konec
Další funkce • memmove – Zkopíruje blok bytů, vypořádá se s překrýváním zdrojového a cílového bloku • memccpy – Zkopíruje blok bytů zakončený zadaným znakem zadané ma-
ximální délky • stpcpy – Zkopíruje řetězec, vrátí ukazatel na koncovou nulu v kopii • strdup – Naalokuje paměť na haldě a do ní zkopíruje řetězec • strrchr – Vrátí poslední výskyt zadaného znaku v řetězci nebo NULL • strspn – Vrátí délku počáteční části prvního řetězce, která obsahuje pouze znaky z druhého řetězce, strcspn – která neobsahuje žádný znak z druhého řetězce • strpbrk – Vyhledá první výskyt libovolného znaku z druhého řetězce v prvním řetězci • strtok – Postupně vrací části z prvního řetězce, které neobsahují žádný znak z druhého řetězce • strlwr – Převede velká písmena v řetězci na malá, strupr – malá na velká, strrev – malá na velká a velká na malá • strcoll – Porovná dva řetězce, bere v potaz národní zvyklosti podle nastavení setlocale • strxfrm – Transformuje řetězec tak, aby následné porovnání dvou transformovaných řetězců pomocí strcmp vrátilo stejnou hodnotu jako strcoll na původní řetězce • strerror – Vrátí textový popis chyby zadaného čísla
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 64 z 89 Zpět Celá obrazovka Zavřít Konec
Oddělený překlad Oddělený překlad (samostatná kompilace) je prostředek, který usnadňuje vytváření rozsáhlých programů. Úvodní strana
• Program je rozdělen na logické celky – kompilační jednotky, moduly
Titulní strana
• Každá kompilační jednotka se překládá zvlášť
Obsah
• Jeden modul obsahuje obvykle definice datových struktur a funkcí, které s nimi pracují
JJ
II
• Program se sestavuje z jedné nebo několika kompilačních jednotek
J
I
• Větší množství přeložených kompilačních jednotek lze sloučit do knihovny • Pokud se změní pouze jedna kompilační jednotka, stačí přeložit pouze ji a znovu sestavit program • Na různých modulech mohou pracovat různí lidé • Některé moduly mohou být použity ve více programech (znovupoužitelnost)
Strana 65 z 89 Zpět Celá obrazovka Zavřít Konec
Program je rozdělen na části, moduly (například modul pro vytváření menu, vstup údajů, zpracování údajů, grafický výstup na obrazovku, výstup na tiskárnu a práci se soubory). Každý modul je umístěn ve zvláštním zdrojovém souboru obsahující definice všech potřebných objektů (procedur, proměnných, konstant a typů). Každý zdrojový soubor se překládá samostatně. Aby objekty definované v jednom modulu mohly být používány v dalších, musí každý z těchto modulů obsahovat deklarace použitých objektů. V jazyce C je zvykem umísťovat tyto deklarace do tzv. hlavičkových souborů, které se vloží direktivou #include do všech zdrojových souborů, ve kterých se budou používat.
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 66 z 89 Zpět Celá obrazovka Zavřít Konec
Rozdíl mezi definicí a deklarací: Definice skutečně vytvoří proměnnou (vyhradí pro ni místo) nebo proceduru (definuje, jaké budou příkazy v těle procedury). Deklarace pouze oznamuje, že existuje (to znamená „někde je definovánÿ) objekt s určitého jména, typu a dalších vlastností.
Úvodní strana Titulní strana
Následující příklad ukazuje jednoduché použití samostatně kompilovaných modulů. Souboru modul.c obsahuje definice proměnné x a procedury printx() pro tisk obsahu této proměnné.
Obsah
JJ
II
J
I
Strana 67 z 89
Soubor modul.c: #include "modul.h" int x;
Zpět Celá obrazovka Zavřít Konec
void printx() { printf("%d\n", x); }
Souboru modul.h obsahuje deklarace objektů definovaných v modul.c. Tento soubor se pomocí direktivy #include vkládá, do každého souboru, ve kterém se používá sdílená proměnná x nebo procedura printx().
Soubor modul.h:
Úvodní strana Titulní strana
extern int x; Obsah
void printx();
Příklad programu, který používá objekty z modul.c.
JJ
II
J
I
Strana 68 z 89
Soubor program.c:
Zpět Celá obrazovka
#include "modul.h" Zavřít
void main() { x=2; printx(); x++; printx(); }
Konec
Makra preprocesoru Jednou z funkcí preprocesoru je používání maker s parametry. Vhodně definovaná makra mohou značně zlepšit srozumitelnost programu. Úvodní strana
Makra s parametry se definují pomocí direktivy #define – stejně jako konstanty. Jméno makra je od #define odděleno alespoň jednou mezerou, bezprostředně za jménem je otevírací kulatá závorka, jeden nebo více parametrů oddělených čárkami a uzavírací kulatá závorka. Za další alespoň jednou mezerou následuje hodnota makra – text, ve kterém se mohou vyskytovat parametry. Je-li text makra dlouhý, lze jej rozdělit pomocí znaku obrácené lomítko a pokračovat na další řádku. Pokud se v textu programu vyskytne řetězec shodný se jménem makra následovaný argumenty v závorce, preprocesor dosadí (textově), argumenty z volání makra za argumenty z definice a místo volání makra vloží text z definice. Vzhledem k tomu, že hodnoty parametrů mohou být libovolné posloupnosti znaků (tedy libovolné výrazy), je nutné v textu makra uzavírat každý parametr do závorek, a totéž udělat i s celým textem makra (aby nedošlo k problémům způsobeným různou prioritou operátorů).
Titulní strana Obsah
JJ
II
J
I
Strana 69 z 89 Zpět Celá obrazovka Zavřít Konec
Použití maker – heapsort Následující příklad ukazuje, jak pomocí maker zpřehlednit třídicí algoritmus heapsort. V tomto algoritmu se na tříděné hodnoty pohlíží, jako by byly uspořádány do binárního stromu (s hodnotou v každém uzlu) tak, že hodnota otce každého uzlu je větší nebo rovna hodnotě obou jeho potomků. Algoritmus se skládá ze dvou částí: vytvoření heapu, a postupného odebírání největších prvků z heapu. Heap se vytváří postupným přidáváním prvků; jednoprvkový strom je vždy heap. Pokud přidáním dalšího prvku dojde porušení podmínky, je prvek prohozen se svým otcem, což může vyvolat potřebu dalšího prohození (otce s jeho otcem) atd. .
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 70 z 89
Odebírání prvků z heapu se provádí tak, že se odebere prvek z vrcholu a vloží se na první místo již setříděné části pole (setříděné pole se vytváří odzadu). Na jeho místo se dá nejpravější prvek z heapu, čímž se heap zmenší o jeden prvek. Prvek, který byl umístěn do vrcholu, může porušit podmínku pro heap, a pak je nutné jej prohodit s větším z jeho synů, atd. až prvek, který byl umístěn do vrcholu heapu, klesne tam, kde už neporušuje podmínku heapu. Pak se odebere další prvek atd. . Heap je realizován v poli tak, že vrchol je nultý prvek, a následují další vrstvy odshora, takže synové vrcholu jsou první a druhý prvek, synové levého syna vrcholu jsou třetí a čtvrtý prvek, synové pravého syna pátý a šestý prvek atd. .
Zpět Celá obrazovka Zavřít Konec
Makra LEFT(i), RIGHT(i) a PARENT(i) vracejí po řadě index levého syna, pravého syna, resp. otce prvku, který má v poli index i. #include <stdio.h> Úvodní strana
#define LEFT(i) (2*(i)+1) #define RIGHT(i) (2*(i)+2) #define PARENT(i) (((i)-1)/2)
Titulní strana Obsah
void heapsort (double a[], int n) {
JJ
II
int z, i; double temp;
J
I
Strana 71 z 89
/* Vytváření heapu; jednoprvkové pole je vždy heap */ for (z=1; z0 && temp>a[PARENT(i)]) { a[i]=a[PARENT(i)]; i=PARENT(i); } a[i]=temp; } /* Postupné odebírání vždy jednoho největšího prvku z heapu */
Zpět Celá obrazovka Zavřít Konec
for (z=n-1; z>0; z--) { temp=a[z]; /* Posledni prvek zkusím umístit do kořene a bublat dolů */ a[z]=a[0]; /* Odebrání prvku; z je už za heapem */ i=0; /* Je-li některý z následníků větší, je třeba bublat dolů */ while (LEFT(i)temp || RIGHT(i)temp) { /* Který z následníků je větší? Oba existují, je-li RIGHT(i)
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 72 z 89 Zpět Celá obrazovka Zavřít Konec
Knihovna conio.h • Pro práci s obrazovkou a klávesnicí v MS-DOSu. • Zavedeno v Turbo-C (analogie jednotky Crt z Turbo Pascalu). • Není standardní knihovnou jazyka C (např. v DJGPP je z důvodu kompatibility)
Úvodní strana Titulní strana Obsah
Funkce pro umístění kursoru a zjištění jeho souřadnic: void gotoxy(int _x, int _y); int wherex(void); int wherey(void);
JJ
II
J
I
Strana 73 z 89 Zpět
x vodorovně, y svisle, (1,1) je levý horní roh obrazovky. Pokud je definováno okno, jsou souřadnice v rámci něj a relativní vůči němu. Funkci pro výpis a čtení znaku s echem posouvají kursor.
Celá obrazovka Zavřít Konec
Podporuje jednoduchá okénka: void window(int _left, int _top, int _right, int _bottom); Úvodní strana
– definuje (neviditelný) obdélník na obrazovce, všechny funkce z conio.h, které pracují s obrazovkou používají tento obdélník. Při startu programu je okno přes celou obrazovku. Není žádná podpora pro obnovování překrytých částí oken apod. – lze použít gettext() a puttext().
Titulní strana Obsah
JJ
II
J
I
Strana 74 z 89 Zpět Celá obrazovka Zavřít Konec
Analogie běžných funkcí pro vstupy a výstupy: int putch(int _c); int cputs(const char *_str); int cprintf(const char *_format, ...); int getch(void); int getche(void); int ungetch(int); int kbhit(void); char * cgets(char *_str); int cscanf(const char *_format, ...);
/* /* /* /* /* /* /* /* /*
Výpis znaku */ Výpis řetězce */ Formátovaný výstup */ Vstup znaku (bez echa) */ Vstup znaku (s echem) */ Vrácení přečteného znaku */ Byla stisknuta klávesa? */ Vstup řetězce */ Formátovaný vstup */
Funkce cgets očekává v prvním bytu řetězce hodnotu udávající maximální délku načítaného řetězce (včetně koncové nuly), po návratu je v _str[1] skutečná délka načteného řetězce – na rozdíl od gets je bezpečná. Pokud se výpis dostane do pravého dolního rohu okna, obrazovka odskroluje o jeden řádek nahoru. Po nastavení proměnné _wscroll na 0 se scrollovat nebude.
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 75 z 89 Zpět Celá obrazovka Zavřít
Smazání okna a smazání řádku v okně od pozice kursoru k pravému okraji okna: void clrscr(void); void clreol(void);
Konec
Barvy: BLACK BLUE GREEN CYAN RED MAGENTA BROWN LIGHTGRAY
černá tmavě modrá zelená modrozelená červená fialová hnědá bílá (světle šedá)
#define BLINK
DARKGRAY LIGHTBLUE LIGHTGREEN LIGHTCYAN LIGHTRED LIGHTMAGENTA YELLOW WHITE
šedá světle modrá světle zelená světle modrozelená světle červená světle fialová žlutá jasně bílá
0x80 /* Přičíst k parametru funkce textcolor() pro blikání */
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 76 z 89 Zpět Celá obrazovka Zavřít Konec
Nastavování barev: void void void void void void void void
textattr(int _attr); textcolor(int _color); textbackground(int _color); normvideo(void); highvideo(void); lowvideo(void); blinkvideo(void); intensevideo(void);
/* /* /* /* /* /* /* /*
Nastaví barvu písma i pozadí */ Nastaví barvu písma (spodní 4 bity + bit 7) */ Nastaví barvu pozadí (bity 4-6) */ Úvodní strana Nastaví barvy, které byly při startu */ Titulní strana Nastaví jasnější barvy písma */ Nastaví tmavší barvy písma */ Obsah Blikání */ Jasné barvy pozadí */ JJ II J
Scrollování textu v okně (uplatňuje se od řádku, na kterém stojí kursor, až do posledního řádku v okně):
I
Strana 77 z 89 Zpět
void delline(void); /* Smaže řádek s kursorem, zbytek okna posune nahoru */ void insline(void); /* Vloží prázdný řádek, zbytek okna posune dolů */
Celá obrazovka Zavřít Konec
Načtení nastavení hodnot knihovny conio.h (poloha a velikost okna, poloha a viditelnost kursoru, atd.): void gettextinfo(struct text_info *_r); Úvodní strana
struct text_info { unsigned char winleft; unsigned char wintop; unsigned char winright; unsigned char winbottom; unsigned char attribute; unsigned char normattr; unsigned char currmode; unsigned char screenheight; unsigned char screenwidth; unsigned char curx; unsigned char cury; };
/* /* /* /* /* /* /* /* /* /* /*
levý okraj okna */ horní okraj okna */ pravý okraj okna */ spodní okraj okna */ aktuální barevné atributy */ normální barevné atributy */ aktuální videorežim */ šířka obrazovky (znaků) */ výška obrazovky (řádků) */ x-ová pozice kursoru */ y-ová pozice kursoru */
Titulní strana Obsah
JJ
II
J
I
Strana 78 z 89 Zpět Celá obrazovka Zavřít
Nastavení vzhledu kursoru: void _setcursortype(int _type); /* Nastavení vzhledu kursoru */ #define _NOCURSOR #define _SOLIDCURSOR #define _NORMALCURSOR
0 1 2
Konec
Nastavení textového režimu videoadaptéru (přičtením C4350 dojde k přepnutí na 50 řádků na VGA nebo 43 na EGA): void textmode(int _mode); /* Nastaví textový režim z následujících: */ enum text_modes { LASTMODE=-1, BW40=0, C40, BW80, C80, MONO=7, C4350=64 };
Úvodní strana Titulní strana
Nastavení počtu řádek na obrazovce (používají se zvláštní znakové sady s výškou znaku 8, 14 nebo 16 bodů): void _set_screen_lines(int _nlines);
Uložení, obnovení a kopie obdélníku na obrazovce (2 byty na pozici – první je zobrazený znak, druhý barevné atributy):
Obsah
JJ
II
J
I
Strana 79 z 89 Zpět Celá obrazovka
int gettext(int _left, int _top, int _right, int _bottom, void *_destin); Zavřít int puttext(int _left, int _top, int _right, int _bottom, void *_source); int movetext(int _left, int _top, int _right, int _bottom, int _destleft, int _desttop); Konec
Deklarace složitých typů int *fnc[20](int n)
je totéž jako
Úvodní strana Titulní strana
int *((fnc[20])(int n));
pole dvaceti funkcí s parametrem typu int, které vracejí ukazatel na int, ale něco jiného než
Obsah
JJ
II
J
I
Strana 80 z 89
int (*fnc[20])(int n);
co je totéž jako
Zpět Celá obrazovka Zavřít
int (*(fnc[20]))(int n);
pole dvaceti ukazatelů na funkci, která má parametr typu int a vrací hodnotu typu int, a to je je něco jiného než
Konec
int (*fnc)[20](int n);
což je totéž jako int ((*fnc)[20])(int n);
Úvodní strana Titulní strana
ukazatel na pole dvaceti funkcí, které mají parametr typu int a vrací hodnoty typu int
Obsah
JJ
II
J
I
Strana 81 z 89 Zpět Celá obrazovka Zavřít Konec
Vlastnosti proměnných, funkcí, návěští a dalších pojmenovaných entit • doba trvání (existence, duration) – jakou část doby běhu programu proměnná existuje • oblast platnosti (výskytu, scope) – kde ve zdrojovém textu je možné používat určitý identifikátor pro odkazování na týž objekt
Úvodní strana Titulní strana Obsah
• způsob spojování – za jakých podmínek znamenají dva stejné identifikátory tutéž věc
JJ
II
J
I
věci (proměnné) mohou být z hlediska doby trvání (duration) Strana 82 z 89
• statické – existují po celou dobu běhu programu; proměnné deklarované vně funkcí a proměnné deklarované uvnitř funkcí s klíčovým slovem static nebo extern • automatické – lokální proměnné funkcí (deklarované bez static i extern) a formální parametry funkcí; existují po dobu vyvolání funkce; je-li funkce vyvolána rekurzivně, existují ve více exemplářích • řízené (controled) – vznikají voláním malloc a zanikají voláním free (nebo ukončením programu); pokud se provede ptr=malloc(4), je řízená ta paměť, která byla alokována, ne proměnná ptr – ta na ni pouze ukazuje
Zpět Celá obrazovka Zavřít Konec
způsob spojování (linkage): • žádný – každá oblast platnosti identifikátoru se vztahuje k jinému objektu; tento způsob spojování mají proměnné a deklarované uvnitř funkce; pokud jsou ale deklarovány s klíčovým slovem extern, mají interní linkage • interní – různé oblasti platnosti identifikátoru v jednom zdrojovém souboru se vztahují k jednomu objektu; proměnné deklarované vně funkcí mají interní linkage; pokud jsou ale deklarovány s klíčovým slovem extern, mají externí linkage • externí – různé oblasti platnosti identifikátoru v různých zdrojových souborech se vztahují k jednomu objektu
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 83 z 89 Zpět
jmenné prostory Celá obrazovka
Objekt je identifikovatelná oblast paměti, která může obsahovat v čase proměnnou nebo konstantní hodnotu nebo sadu hodnot. (Objekt zde nemusí objektem ve smyslu objektově orientovaného programování.) Entita je procedura, návěští, typ anebo objekt ve smyslu uvedeném výše. L-hodnota je výraz, který je odkazem na objekt. Objekt může být konstantní, pak mluvíme o konstantní l-hodnotě. Na levé straně přiřazovacího příkazu musí být l-hodnota, která není konstantní.
Zavřít Konec
Program se skládá z jednoho nebo více zdrojových souborů, které se překládají samostatně. Oblast výskytu identifikátoru (scope) je souvislá část programu, ve které lze identifikátor použít pro přístup k jedné určité entitě. Úvodní strana
Různé entity mají různé oblasti výskytu. Oblast výskytu Titulní strana
blok mají identifikátory deklarované uvnitř bloku a parametry procedur (lokální identifikátory). Oblastí výskytu je u parametrů procedur hlavička procedury a blok, který je jejím tělem, u ostatních identifikátorů nejvnitřnější blok obklopující deklaraci. procedura mají návěští, která se deklarují uvedením návěští a dvojtečky před příkazem. Příkaz goto label ; lze použít pouze uvnitř procedury, kde je návěští label deklarováno. prototyp procedury mají parametry prototypů procedur. Oblast výskytu je omezena na příslušný prototyp (tj. seznam parametrů v deklaraci procedury).
Obsah
JJ
II
J
I
Strana 84 z 89 Zpět Celá obrazovka Zavřít Konec
soubor mají identifikátory deklarované mimo všechny bloky (globální identifikátory), například identifikátory funkcí. Oblasti výskytu dvou různých entit označených týmž identifikátorem se mohou překrývat jestliže
• Identifikátory mají různé jmenné prostory (name space). • Identifikátory mají stejné jmenné prostory, ale oblast výskytu identifikátoru jedné entity je blok, procedura nebo prototyp procedury, který je vnořen do oblasti výskytu druhé entity, čímž dočasně zakrývá tuto druhou entitu. Jmenné prostory označují skutečnost, že identifikátory určitých entit si vzájemně nekonkurují, protože mohou být použity pouze v přesně stanovených disjunktních případech. Jednotlivé jmenné prostory: Návěští mohou být použity pouze v deklaraci návěští a v příkazu goto. Jména struktur, unionů a výčtových typů se používají vždy ve spojení struct ident, union ident nebo enum ident. Jména položek struktur nebo unionů musí být jednoznačná pouze v rámci jedné struktury nebo unionu. Kromě deklarace se používají pouze pro přístup k položce struktury nebo unionu, na pravé straně operátoru tečka (.) nebo šipka (->). Ostatní identifikátory proměnných, procedur, konstant a typů (typedef jména). Viditelnost identifikátoru (visibility) je rovna oblasti jeho výskytu zmenšené o vnořené oblasti výskytu téhož identifikátoru se stejným jmenným prostorem, kde je první identifikátor zakryt.
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 85 z 89 Zpět Celá obrazovka Zavřít Konec
Trvání objektu (duration) je doba, po kterou objekt existuje. Rozeznáváme objekty s trváním statickým, které existují po celou dobu běhu programu. automatickým, které existují pouze po dobu provádění bloku, ve kterém mají výskyt. dynamickým, které se vytvářejí vyvoláním funkce (například malloc()) a existují až do svého zrušení vyvoláním další funkce (free()) nebo do konce běhu programu. Způsob spojování (linkage) entit rozhoduje o tom, zda dva výskyty entity s týmž identifikátorem budou považovány za odkaz na tutéž entitu. Rozeznáváme následující způsoby spojování:
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 86 z 89 Zpět
externí – entity se stejným jménem a jmenným prostorem se považují za tutéž entitu ve všech souborech a knihovnách, ze kterých je sestavován program. interní – entity téhož jména, patřící do stejného jmenného prostoru se považují za tutéž entitu v rámci souboru v němž se vyskytují. žádný – každý výskyt je považován za jinou entitu. Pravidla pro určení způsobu spojování jsou dosti složitá.
Celá obrazovka Zavřít Konec
Další třídy paměti • register – rada pro překladač, aby proměnnou umístil do registru; přístup k registrům je obvykle rychlejší než do paměti; překladač se touto radou může ale nemusí řídit (může do registru umístit i jinou proměnnou, než která je deklarována s register); na takto deklarovanou proměnnou nelze použít operátor získání adresy (&); lze použít pouze u automatických proměnných • auto – proměnná má být automatická; prakticky nemá žádný význam, lze použít pouze u proměnných, které už automatické jsou
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 87 z 89 Zpět Celá obrazovka Zavřít Konec
Zacházení s proměnnými • const – hodnotu proměnné nelze (kromě inicializace) měnit: const double pi = 3.14159265358979; double r, plocha; scanf("%lf", &r); plocha=pi*r*r; printf("Plocha kruhu je %lG\n", plocha); pi=22.0/7.0;
Poslední příkaz způsobí při překladu chybu nebo alespoň výpis varování. • volatile – hodnota proměnné se může měnit i jiným způsobem než programem; překladač musí při každém použití skutečně pracovat s proměnnou; používat například pro hardwarové registry nebo sdílené proměnné
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 88 z 89 Zpět Celá obrazovka Zavřít Konec
Použití typedef Jestliže deklarace obsahuje specifikátor typedef, není deklarovaný identifikátor proměnnou, ale typem. Takto deklarovaný identifikátor je možné použít v dalších deklaracích jako specifikátor typu: typedef unsigned char byte; typedef unsigned short word; byte b; word w;
– v prvním řádku je deklarován typ byte jako unsigned char, ve druhém typ word jako unsigned short; v dalších dvou řádcích jsou pomocí těchto nových typů deklarovány proměnné b a w. Použitím typedef lze zpřehlednit zejména používání složitějších typů:
Úvodní strana Titulní strana Obsah
JJ
II
J
I
Strana 89 z 89 Zpět Celá obrazovka Zavřít
struct listitem { struct listitem *next; int value; } titem, *pitem; pitem seznam; p1=malloc(sizeof(titem));
Konec