Prezentace se nahrává, počkejte prosím

Prezentace se nahrává, počkejte prosím

Základy jazyka C. Charakteristika jazyka: Univerzální programovací jazyk Nízkoúrovňový jazyk (obsahuje standardní datové typy-znaky,celá čísla,reálná.

Podobné prezentace


Prezentace na téma: "Základy jazyka C. Charakteristika jazyka: Univerzální programovací jazyk Nízkoúrovňový jazyk (obsahuje standardní datové typy-znaky,celá čísla,reálná."— Transkript prezentace:

1 Základy jazyka C

2 Charakteristika jazyka: Univerzální programovací jazyk Nízkoúrovňový jazyk (obsahuje standardní datové typy-znaky,celá čísla,reálná čísla) Úsporné vyjadřování Strukturovaný Efektivní překlad, rychlý kód Navržen pro operační systém UNIX, celý Unix je v C napsán V současnosti většina systémového SW je v C napsána

3 Umožňuje snadné napsání překladače jazyka Dosahuje vysokou efektivitu překladu blížící se efektivitě jazyka Assembler HISTORIE jazyka C První standard jazyka (K&R) v roce 1978 [ Brian W.Kernighan,Denis M.Ritchie ] Z něho vychází standard ANSI C (1988), který obsahuje navíc i specifikaci knihovních funkcí a hlavičkových souborů, které implementace C musí obsahovat

4 V současnosti byl standard ANSI C rozšířen (1990) Jazyk je přenositelný na libovolný operační systém a libovolný počítač Modernější programovací prostředky: konec devadesátých let: C++, JAVA začátek 21.stol.: C#

5 Způsob zpracování programu v jazyku C : Proces editace zdrojového kódu, překladu do OBJECT kódu, sestavení do výsledného EXE-kódu, proces ladění programu:

6 Textový editor (nízkoúrovňový) – pokud je C součástí integrovaného prostředí, pak zpravidla obsahuje i tento editor Preprocesor (součást kompilátoru) –Upravuje/opravuje zdrojový soubor Vynechává komentáře Vkládá hlavičkové soubory (.H) Zajišťuje makrosubstituce –Výsledkem jeho činnosti je opět textový soubor, který je předán ke zpracování přímo kompilátoru Kompilátor (překladač) –Transformuje (překládá) textově napsaný program do relativního kódu (tzv.Object-kód)

7 (soubor s příponou.OBJ). Každá programová jednotka = relativní modul –Produkuje na požádání výpis překládaného programu – tzv. listing (soubor s příponou.LST) LINKER (sestavovací program) –Vyřeší reference na externí podprogramy pomocí standardních systémových event. uživatelských knihoven (soubory s příponou.LIB). –Produkuje výsledný spustitelný modul (soubor s příponou.EXE)

8 DEBUGER (prostředek pro ladění) –Pomáhá při procesu ladění, zobrazuje během výpočtu hodnoty určených proměnných, dokáže výpočet krokovat apod. Toto je princip jakéhokoliv překladače libovolného jazyka. Prostředí BORLAND C++

9 Základní pojmy v jazyce C Zdrojové a hlavičkové soubory –Zdrojový soubor (.C) obsahuje text programu –Hlavičkový soubor (.H) je vložen ( #include) k vlastnímu programu před jeho překladem po- mocí tzv. preprocesoru. Direktiva #include řídí tento proces. Protože program používá např. i knihovní funkce, hlavičkové soubory umožňují jejich správné volání. Zpřehlednění programu –„štábní kultura“, časté komentování –Strukturování jmen souborů:

10 edi.main.c edi.sub1.c Bílé znaky ASCII kódová tabulka, dolní/horní část Identifikátory –C jazyk je „case sensitive“ – rozlišuje malá a velká písmena, jména objektů psát malými –Klíčová slova musí být psána malými písmeny jinak se berou jako identifikátory ( for, while ) –Délka identifikátoru není omezena,ale rozezná prvních 31 znaků (ANSI C),ostatní neuvažuje –Možnost užití podtržítka _ mezi slovy, ne na začátku (syst.identifikátor), ne na konci

11 –Nerozlišovat 2 identifikátory jen typem písma –Dodržovat konvence (např.: i,j,k – prom.cyklu) Komentáře /* ….. */ ANSI C nedovoluje komentáře hnízdit Jméno autora programového modulu a datum poslední aktualizace,číslo verze Okomentovat ucelené logické části hned při tvorbě programu – po odladění se už na to zpravidla zapomene Možnost víceřádkových komentářů

12 Základy Jednoduché datové typy PascalC INTEGERint, short int,short long int, long CHARchar REALfloat, double, float double –Typy char, int, short int, long int mohou být signed nebo unsigned, implicitní je signed (mimo char) –Rozsahy pro unsigned : 0 až 2 n – 1, pro signed : - 2 n-1 až +2 n-1 – 1 –unsigned char (8 bitů): 0 až 255, pro signed char (7 bitů):-128 až 127 –C neposkytuje typ Boolean, logické hodnoty jsou však representovány pomocí celočíselných hodnot ( int ) ( 0=false, nenulová hodnota=true ) –Typ double má přesnost 20 desetinných míst

13 Definice proměnných –definice přidělí proměnné jméno a paměť –deklarace udává typ a jméno proměnné PascalC VAR i : INTEGER;int i ; c, ch : CHAR;char c, ch ; f, g : REAL;float f, g ; –doporučeno komentovat proměnné –definice se vyskytují buď vně (globální), nebo uvnitř (lokální) programové jednotky: int i ;/* globální proměnná od začátku řádky */ int main() { int j;/* lokální proměnná je odsazena od začátku */ }

14 Celočíselné: (signed) int (signed) short int(short) (signed) long int(long) unsigned int(unsigned) Rozsah znaménkových proměnných je : Reálné: float double (20 des.míst) Logické (C je přímo neposkytuje) – vyjadřuje se pomocí celočíselných int: 0 … false <>0 (1) … true Znakové char: délka vždy 1 byte (8 bit) signed char – rozsah -128 až +128 unsigned char – rozsah 0 až 255

15 Přiřazení –l-hodnota (l-value) představuje adresu – to, co může být na levé straně přiřazovacího příkazu ( konstanta 123 nebo výraz (x+3) není adresa, ale hodnota, proměnná x je l-hodnotou ) –Pravá strana přiřazovacího příkazu musí být vždy vyčíslitelná (hodnota) výrazvýrazi*2 + 3 přiřazeníl-hodnota=výrazj=i*2 + 3 příkazl-hodnota=výraz;j=i*2 + 3; Př.: PASCALC j := 5;j = 5; d := ‘z’ ;d = ‘z’; f := f *i ; f = f *i ; –Existuje možnost násobného přiřazení i = j = k = x + 5; Vyhodnocení: i = ( j = ( k=x+5) ) )

16 terminologie: česky:symbolicky:prakticky: výrazvýrazi*2+3 přiřazeníl-hodnota = výrazj=i*2+3 příkazl-hodnota = výraz ; j=i*2+3 ;

17 Hlavní program Hlavní programový modul se jmenuje povinně main a musí být uveden (zpravidla za definicemi podprogramů / funkcí ). Je volán po spuštění programu. Př.: PASCAL C Program Pokus(input,output); int main() /*bez středníku*/ var i, j : integer ; { int i, j ; Begin i:=5 ; i = 5 ; j:= -1 ; j = -1 ; j:= j + 2*i ; j = j + 2*i ; End. return 0; }

18 Složené závorky otevírají / uzavírají : { /* blok */ { /* složený příkaz */ int i; i=5; i=5; j=6; j=6; } } Jazyk C umožňuje inicializaci proměnné přímo v definici : int i = 5;

19 Konstanty Celočíselné konstanty : –desítkové15, 0, 1 –Osmičkové 065, 015, 01 –Šestnáctkové0x3A, 0xCD, 0x1 Pro konstanty typu long se použije přípona L Pro unsigned konstanty se použije přípona U Záporné konstanty jsou uvozeny znaménkem -

20 Reálné konstanty : –Jsou implicitně double a jsou tvořeny podle běžných pravidel: 15., 56.8,.84, 5e6 –Konstanta typu float má příponu F ( 56.8F ) –Konstanta typu long má příponu L ( 5e6L ) Znakové konstanty : –Jsou stejně jako v Pascalu uzavřeny do apostrofů: 'a', '*' –Hodnota znakových konstant je odvozena z použité kódové tabulky –Potřebujeme-li konstantu z neviditelného znaku, pak použijeme zápis šestnáctkový (/X0A) nebo osmičkový (/012)

21 –Lze zdvojovat /“ (zobrazení úvozovek) –Lze použít i znakový ekvivalent (escape sekvence) sekvencehodnotavýznam \n0x0Anová řádka (LF) \r0x0Dnávrat na začátek řádky (CR) \f0x0Cnová stránka (FF) \t0x09tabulátor (HT) \b0x08posun doleva (BS) \a0x07písknutí (BELL) \\0x5Czpětné lomítko (backslash) \’ 0x2Capostrof (single quote) \00x00nulový znak (NUL)

22 Řetězcové konstanty (literály) –Jsou uzavřeny mezi uvozovky a mohou obsahovat všechny způsoby zápisu znakových konstant Příklad:” Tohle je znakový řetězec ” –ANSI C možňuje dlouhé řetězcové konstanty zřetězovat, jednotliné subřetězce mohou být odděleny mezerami, nebo novými řádky Příklad:” Tohle je ” ”znakový řetězec ” ” Tohle je ” ”znakový řetězec ”

23 Aritmetické výrazy Výraz ukončený středníkem se stává příkazem Př.: j = 5 … výraz j = 5; … příkaz Unární operátory Binární operátory PascalC sčítání++ odečítání-- násobení** reálné dělení// celočíselné děleníDIV/ dělení moduloMOD%

24 To zda bude dělení celočíselné, nebo reálné záleží na operandech – pouze int/int je celočíselné,ostatní reálné. Speciální unární operátory – incrementální 1) ++výraz… incrementování před užitím Výraz je zvětšen o jedničku a pak je nová hodnota vrácena výrazu. 2)výraz++… incrementování po užití Je vrácena původní hodnota výrazu a teprve pak je výraz zvětšen o jedničku. Výraz musí být proměnná (l-hodnota), nikoli konst.nebo výraz !! Př.: int i = 5, j = 1, k ; i++;… i = 6 j = ++i;… j = 7, i = 7 j = i++;… j = 7, i = 8 k = --j + 2 ;… k = 8, j = 6

25 Operátory přiřazení základní přiřazení : PASCALC :== ostatní přiřazovací příkazy dostupné pouze v C : l-hodnota += výraz l-hodnota = l-hodnota + výraz l-hodnota -= výraz l-hodnota = l-hodnota – výraz l-hodnota *= výraz l-hodnota = l-hodnota * výraz l-hodnota /= výraz l-hodnota = l-hodnota / výraz l-hodnota %= výraz l-hodnota = l-hodnota % výraz…celoč.dělení l-hodnota >>= výraz l-hodnota = l-hodnota >> výraz…bit. posuny l-hodnota <<= výraz l-hodnota = l-hodnota << výraz…bit. posuny l-hodnota &= výraz l-hodnota = l-hodnota & výraz…bit.součin l-hodnota ^= výraz l-hodnota = l-hodnota ^ výraz..bit.exkl.suma l-hodnota |= výraz l-hodnota = l-hodnota | výraz…bit.součet

26 Terminálový vstup a výstup Hlavičkový soubor stdio.h –I/O operace nejsou v C součástí jazyka,ale jsou řešeny voláním knihovních funkcí –Aby bylo možné tyto funkce vyvolat, je třeba připojit popis těchto funkcí v hlavičkovém souboru stdio.h pomocí příkazu: #include Vstup a výstup znaku getchar(), putchar() –vstup zajišťuje getchar() … píšeme znaky tak dlouho, dokud nestiskneme ENTER, pak se přečte první znak a ostatní se ignorují

27 –výstup znaku zajišťuje putchar() Př.: { int c; c = getchar(); putchar(c); putchar(‘\n’); return 0; } Formátovaný vstup a výstup –Analogie funkcí Read a Write v Pascalu jsou v jazyku C funkce scanf() a printf() Příkazy: scanf( “%d”, &i ); %d znamená dekadický formát čtení znak & znamená adresu proměnné printf( “%d”, i ); –Řídící řetězec formátu Formátové specifikace začínají znakem % Znakové specifikace se používají jen u printf()

28 –Některé formátové specifikace c … znak (při čtení i „white spaces“) d … číslo int zobrazené desítkově (signed) u … číslo int zobrazené desítkově (unsigned) x … číslo int zobrazené šestnáctkově (mal.) X … číslo int zobrazené šestnáctkově (vel.) o … číslo int zobrazené oktalově ld … číslo long desítkově lx … číslo long šetnáctkově malými písmeny lX … číslo long šetnáctkově velkými písmeny f … čtení float / tisk float i double lf … načítání double (nepoužívat pro tisk) Lf … long double s … řetězec

29 Příklady: printf(“ Znak ‘%c’ má ASCII kód %d (%XH) \n ”,c,c,c); Vypíše: Znak ‘A‘ má ASCII kód 65 (41H) printf(“ Je presně %2d: %2d\n “,hodiny,minuty); Vypíše: Je presně 13:30 (Formátování je podobné jako u stejnojmenných příkazů v Matlabu.)

30 Kódy pro printf: Kódy pro scanf:

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48 Řídící struktury Pro zpřehlednění programu dodržujte grafická členění hnízdění cyklů a úrovní závorkování { }. Závorkujte pro zpřehlednění výrazů i když to není nutné Každý neřídící příkaz by měl být na vlastní řádce Pokud se výraz nevejde na řádku a musí se pokračovat, pak začínejte na stejné pozici, kde začíná výraz

49 Logické výrazy (Booleovské) Operátory PascalC rovnost= == nerovnost<> != logický součinAND && logický součetOR|| negaceNOT! relace: menší< < menší nebo rovno<= <= větší> > větší nebo rovno>= >=

50 POZOR na rozdíl mezi = a == ! ! Priorita vyhodnocování výrazů: Operátory směr vyhodnocení ! zprava doleva * / %zleva doprava + -zleva doprava = >zleva doprava == != zleva doprava &&zleva doprava ||zleva doprava ( ? :)zprava doleva = += -= *=zprava doleva,zleva doprava

51 Pozor: Nejsme-li si jisti, prioritu vyhodnocení výrazu upravíme závorkováním ! ! Podmíněný výraz, ternární operátor Syntaxe: podmínka ? Výraz1 : Výraz2 a má význam (Pascalovsky zapsáno): if podmínka then výraz1 else výraz2 Příklad: int i, k, j = 2 ; i = ( j == 2) ? 1 : 3 ; … i nabude hodnoty 1 k = ( i > j ) ? i : j ; … k nabude hodnoty 2 Ternární operátor nemusí být použit jen pro přiřazení: ( i == 1 ) ? i++ : j++ … increment buď i nebo j

52 Operátor čárky Pouze 4 operátory && || ( ? : ) a oper. čárky zaručují přednostní vyhodnocení levého operandu před pravým. Syntaxe: výraz1, výraz2 Výraz1 je vyhodnocen, výsledek zapomenut, pak se vyhodnotí výraz2 a to je závěrečný výsledek. Není to l-hodnota. Používá se jen v řídících příkazech for a while. Příklad: int i = 2, j = 4 ; j = ( i++, i – j ) ; /* i bude 3 a j bude -1 */

53 Neúplný a úplný podmíněný příkaz syntaxe: PASCAL C IF podmínka if (podmínka) THEN příkaz1 příkaz1; ELSE příkaz2; else příkaz2; Př.: Program čte znak. Pokud je to velké písmeno, pak vypíše znak jako dekadické číslo: #include int main() { int c ; c=getchar(); if (c >= ‘A’ && c <= ‘Z’) printf(“%d\n”,c); return 0 ; }

54 Příklady na IF: PASCAL C IF i > 3 if (i > 3 ) THEN j := 5 ;j = 5; IF i > 3 if (i > 3 ) THEN j := 5 j = 5; ELSE j := 1 ; else j = 1; _____________________________________ IF i > 3 if (i > 3 ) THEN BEGIN { j := 5 ; j = 5 ; i := 7 ;i = 7 ; END } ELSE j := 1; else j = 1 ;

55 Přepínač – příkaz SWITCH Pro mnohonásobné větvení programu existuje v C příkaz switch. ( Je to analogie pascalovského příkazu CASE ). PASCAL C CASE výraz switch výraz OF { hodnota 1 : příkaz 1; case hodnota 1 : příkaz 1; break; … hodnota n : příkaz n; case hodnota 1 : příkaz 1; break ELSE příkaz def; default : příkaz def; break; END }

56 Odlišnosti: Nelze napsat více hodnot pro jednu větev,ale prázdné bez break postupují řízení na další větev Logický výraz musí být typu int Každá větev musí být ukončena příkazem break V každé větvi může být více příkazů, které není nutno závorkovat Příklad na switch : (pro zadané a b c vypíše 1,pro d 2 jinak 3) switch ( getchar() ) { case ‘a’ : case ‘b’ : case ‘c’ : putchar(‘1’); break ; case ‘d’ : putchar(‘2’); break ; default : putchar(‘3’); break ; }

57 Příkazy cyklu V C existují 3 druhy: while, for, do-while Pomocné příkazy break a continue : break – okamžitě opouští cyklus a jde na první příkaz za příkazem cyklu continue – ukončí pouze nejvnitřnější neuzavřenou smyčku, ale příkaz cyklu neukončí – Příkaz while Příkaz testuje podmínku před průchodem cyklu (nemusí proběhnout ani jednou). Podmínka je závislá na tom, co se děje v tělu cyklu. Nekonečná smyčka má podm.=1 PASCALC WHILE podmínka DOwhile (podmínka) příkaz ; příkaz ;

58 Příklady na while: PASCAL C WHILE x < 10 DO while ( x < 10 ) x := x + 1 ; x++ ; Program přečte a vytiskne viditelné znaky a pokud načte znak ‘z’, pak skončí s cyklem načítání znaků: #include int main() { int c ; while (c = getchar() != ‘z’ ) { if ( c >= ‘ ‘ ) putchar(c); printf ( “Načítání znaku bylo ukončeno … \n” ); return 0 ; }

59 – Příkaz do-while Je to ekvivalent pascalovského REPEAT-UNTIL. syntaxe : PASCALC REPEAT do { příkazy ; příkazy ; UNTIL NOT podmínka ; } while (podmínka ) ; Příklad na do while: ( cyklus odečítá jedničku tak dlouho, dokud se neznuluje ) PASCALC REPEAT do { i := i - 1 ; i-- ; UNTIL i 0 ) ;

60 Program přečte a vytiskne viditelné znaky a pokud načte znak ‘z’, vytiskne ho a pak skončí s načítáním znaků: #include int main() { int c ; do { if ( ( c = getchar() ) >= ‘ ‘ ) putchar(c); } while ( c != ‘z’ ) printf ( “Načítání znaku bylo ukončeno … \n” ); return 0 ; }

61 –Příkaz for Je to ekvivalent pascalovského FOR. syntaxe : PASCAL C FOR prom:=start TO stop for ( výraz_start ; [ STEP krok ]výraz_stop ; DO výraz_iter ) příkaz ; příkaz ; Příklad na for: FOR i :=1 TO 10 DO for ( i=1 ; i<=10; i++ ) writeln(i) ; printf(“%d\n”,i) ; Nechá se přepsat pomocí cyklu while takto: výraz_start ; while ( výraz_stop ) { příkaz ; výraz_iter ; }

62 Příkaz skoku - goto Ve strukturovaném programu ho lze vždy nějak obejít a proto je dobré se mu vyhnout. Na rozdíl od Pascalu není nutné návěští předem definovat definují se svým výskytem. Příklad: goto cast2; cast1: ….. ….. goto konec; cast2: ….. ….. konec: …..

63 Příkaz return Narazí-li běh programu na příkaz return, ukončí stávající pro- gramovou jednotku a navrátí se za příkaz svého volání do nad- řazené programové jednotky. Často se používá také k předání ( funkční ) hodnoty volající jednotce. Příklad: int nasobeni() { int i, j, k ; for ( i=0 ; i<10 ; i++ ) { for ( j=0 ; j<10 ; j++ ) { for ( k=0 ; k<10 ; k++ ) { if ( x[k] == 0 ) return 0; /* chyba */ a[i] = a[i] + b[j] / x[k] ; } return 1 /* správně */ }

64 Souborové vstupně-výstupní operace ANSI C dovoluje rozlišit při otevírání soubory textové a binární Základní datový typ pro práci se soubory je FILE. Proměnná typu FILE je ukazatel na soubor (píše se s * na začátku). Identifikátor FILE musí být velkými písmeny ! ! ! Př.: FILE *fr, *fw Je dobré mnemotechnicky rozlišit, která proměnná slouží pro soubor pro čtení ( *fr ) a která pro zápis ( *fw ) (Od slova read-číst nebo write-psát)

65 Otevření souboru pro čtení PascalC VAR t : TEXT;FILE *f ;… ASSIGN( f, ‘a.txt’);f = fopen( “a.txt”, “r” ) ; RESET(f); Otevření souboru pro zápis PascalC VAR t : TEXT;FILE *f ;… ASSIGN( f, ‘a.txt’);f = fopen( “a.txt”, “w” ) ; REWRITE(f); Udáváme-li se souborem i cestu, pak pozor na znak \, musíme ho zdvojit : f = fopen( “C:\\a.txt”, “w” ) ;

66 Některé kompilátory vyžadují ještě specifikovat typ souboru, tj. textový ( t ), nebo binární ( b ). f = fopen( “a.txt”, “wt” ) ; resp. f = fopen( “a.txt”, “wb” ) ; Základní operace s otevřeným souborem Čtení ze souboruc = getc(f) Zápis do souboruputc( c, f ) Formátované čtení ze souborufscanf(f,“formát“,argumenty) Formátovaný zápis do souborufprintf( f,“formát“,argumenty) Základní operace se std.vstupem/výstupem Čtení z klávesnicec = getchar() Zápis na obrazovkuputchar(c) Formátované čtení z klávesnicescanf(“formát“,argumenty) Formátovaný zápis na obrazovku printf( “formát“,argumenty)

67 Ukončení práce se souborem Aby bylo možné ukončit práci se souborem, je třeba uvolnit použitou vyrovnávací paměť. To zajišťuje knihovní funkce, která se jmenuje fclose as jediným parametrem určujícím jméno souborové proměnné : fclose( f ) ; Příklady: (pro práci se soubory) #include Int main() { FILE *fw ; int i ; fw = fopen( “pokus.txt”, “w” ) ; for ( i=1 ; i<=10 ; i++ ) fprintf( fw, “%d\n”, i ); fclose( fw ); return 0 ; }

68 Testování konce řádky V textových souborech se často přečte najednou celá řádka. K tomu slouží funkce fgets(), která uloží obsah řádky do řetězce. Pokud ale čteme řádku znak po znaku, pak je třeba zjistit, který znak je konec řádky ( EOLN – end of line ). K tomu existují 3 možnosti: –Samostatný znak CR ( 0xD ) –Samostatný znak LF ( 0xA ) –Dvojznak CRLF ( 0x0D0A ) V C se uvažuje za konec řádky standardně znak “nový řádek” \ n ( 0x0A ) Příklad: #include Int main() { FILE *fw ; int c ; fr = fopen( “dopis.txt”, “r” ) ; while ( ( c = getc( fr ) ) != ’\n’ ) putchar( c ); fclose( fw ); return 0 ; }

69 Testování konce souboru V textových souborech se testuje konec souboru buď pomocí makra feof(), nebo předdefinované konstanty EOF. Čtení všech znaků do konce souboru: if ((c=getchar(fr))!= EOF ) Proměnná nesmí být char, protože konstanta EOF je typu int. Příklad: (na kopírování souboru ) #include Int main() { FILE *fr, *fw ; int c ; fr = fopen( “orig.txt”, “r” ) ; fw = fopen( “kopie.txt”, “w” ) ; while ( ( c = getc( fr ) ) != EOF ) putc( c, fw ); fclose( fr ); fclose( fw ); return 0 ; }

70 Příklad: (na kopírování souboru – test pomocí feov() ) #include Int main() { FILE *fr, *fw ; int c ; fr = fopen( “orig.txt”, “r” ) ; fw = fopen( “kopie.txt”, “w” ) ; while ((c = getc(fr)), feof( fr ) == 0 ) { putc(c, fw); putchar(c); /* Kontrolni vypis kopirovaneho souboru. */ } fclose( fr ); fclose( fw ); return 0 ; }

71 Testování správnosti otevření a uzavření Operace otevírání a uzavírání jsou funkce, které vrací hodnotu obsahující návratový kód informující o úspěchu či neúspěchu operace. Např.udáme-li chybné neexistující jméno souboru, či cesty, nebo otevíráme příliš mnoho souborů, nebo při uzavírání se zjistí, že chybí místo na disku apod. Při nesprávné činnosti těchto funkcí je návratový kód nulový při otevření souboru, či je roven konstantě EOF při uzavření if ( ( fr = fopen( “TEST.TXT”, ”r” )) == NULL ) printf(“Soubor se nepodařilo otevřít …\n”) ; if ( fclose( fr ) == EOF ) printf(“Soubor se nepodařilo uzavřít …\n”) ;

72 Standardní vstup a výstup C jazyk ve skutečnosti pracuje s obrazovkou a klávesnicí, jako se souborem. Existují pro to standardní deklarace, FILE *stdin, *stdout které tyto proměnné definují. Tyto standardní proudy je možné zpravidla ještě prostředky operačního systému (parametry při vyvolání programu, vytvořeného v C) někam přesměrovat (redirecting). Např.: tiskni.exe > C:\user\tiskni.txt getc(stdin)… je ekvivalentem funkce … getchar() putc(c,stdout)… je ekvivalentem funkce … putchar()

73 Preprocesor jazyka C Příkazová řádka určená pro zpracování v preprocesoru začíná znakem #. Za ní nesmí být mezera. Preprocesor rozeznává následující konstrukce : –Definování makra: #define –Zrušení definice makra: #undefine –Podmíněný překlad textu v závislosti na konst_výraz : #if konst_výraz #elif #else #endif –Vložení textu ze specifikovaného souboru: #include

74 –Podmíněný překlad textu v závislosti na tom, zda je makro definováno/nedefinováno: #ifdef #elif #else #endif –Podmíněný překlad textu v závislosti na tom, zda je makro nedefinováno/definováno: #ifndef #elif #else #endif –Výpis chybových zpráv během preprocesingu: #error Chybová zpráva Příklad definice makra: #define DVE_PI (2 * 3.14) #define je_velke(c) ( (c) >= ‘A’ && (c) <= ‘Z’ )

75 Vkládání souborů: Jakýkoliv soubor (i text programu) lze vložit pomocí direktivy #include.Jako příklad použití je uveden způsob překladů více programových modulů najednou versus oddělený překlad:

76 Řízení překladu: #if WINDOWS #define SOUBOR “D:\\data\\senzor.txt” #else #define SOUBOR “/data/senzor.txt” #endif Pokud budeme překládat na windowsových počítačích, pak na začátku nastavíme konstantu na: #define WINDOWS 1 jinak (např.pro unixové počítače) nastavíme: #define WINDOWS 0 Potom se mám nadefinuje soubor podle horní nebo dolní definice.

77 Funkce a práce s pamětí Jazyk C je založený na funkcích, které tvoří vlastní programové jednotky – uživatelských a systémových (knihovních). Jednoduchý program se může napsat do jednoho hlavního programového modulu ( main ). Většina programů však obsahuje větší počet funkcí Pojmy : –Definice identifikátoru: kompletní specifikace včetně alokace paměti pro danný typ –Pole působnosti identifikátoru: v programové jednotce v níž je definován –Doba života identifikátoru: časový interval během kterého program pracuje v poli působnosti identifikátoru –Oddělený překlad

78 –Dynamická alokace paměti: místo v paměti ( Heap- hromada / Stack-zásobník ), které se alokuje za běhu programu –Statická alokace paměti: místo je alokováno v datové oblasti programu už během překladu –Globální proměnná: je definována vně jakékoliv funkce a její existence začíná se spuštěním programu a končí s jeho ukončením –Lokální proměnná: její existence začíná se vstupem do funkce v níž je definována a končí s ukončením této funkce. Překladač ji uloží do zásobníku –Statická globální proměnná: jako globální proměnná, ale klíčové slovo static omezuje její viditelnost na část programu –Statická lokální proměnná: existence začíná se vstupem do programové jednotky a končí výstupen. Překladač ji uloží do datové části programu

79 Alokace paměti –Statická: používá se nejčastěji a to tehdy, pokud jsme schopni překladači sdělit konečné programové nároky.(Pozor na rekursivní volání). Globální proměnné mohou být alokovány pouze staticky. –Dynamická – na hromadě: alokaci provádíime pomocí volání knihovní funkce, kdy za běhu programu volíme velikost paměti. Paměť je dostupná přes ukazatele (pointery). Fragmentace – čistič paměti. –Dynamická – v zásobníku: alokaci provádíme jako běžnou definici lokální proměnné. Paměť využívá symbolického jména proměnné Pro naprostou většinu lokálně definovaných proměnných uvnitř funkce je použit tento druh alokace. Existence takovéto proměnné je pouze, po dobu zpracovávání funkce, při výstupu se její obsah ztrácí.

80 Funkce POZOR: Abychom odlišili jméno proměnné od jména funkce, uvádíme na jménem funkce důsledně kulaté závorky ! Funkce se nemohou hnízdit – tj.uvnitř jedné funkce nemůže být definována jiná funkce. Všechny funkce v C jsou skutečné – čili vrací hodnotu, ale existuje možnost, jak funkci použít jako proceduru: funkce je definována jako funkce vracející typ void, nebo funkce sice hodnotu vrací, ale nikdo ji nechce. Definice funkce: Definice: specifikace hlavičky a těla funkce Deklarace:specifikace hlavičky PASCAL C_____________ FUNCTION max(a,b:INTEGER): int max(int a, int b) INTEGER;

81 Hlavička není ukončena středníkem Všechny parametry jsou volány hodnotou Parametry uvnitř závorek se nazývají formálními parametry funkce Typ funkce (její návratová hodnota) mohl být ve starších překladačích vynechán – implicitně byl int Tělo funkce je uzavřeno do složených závorek { } Na rozdíl od Pascalu, kdy se jménu funkce přiřadí návratová hodnota se v C používá příkaz return výraz či return (výraz) Funkce bez parametrů musí být definována i volána s () PASCAL C_____________ FUNCTION max(a,b:INTEGER): int max(int a, int b) INTEGER; { BEGIN return ( a>b ? a : b ); IF a > b THEN max := a } ELSE max := b END;

82 Procedury a datový typ void Pokud nechceme využít předání funkční hodnoty, pak můžeme toto obejít: a) necháme vrátit návratovou hodnotu, ale nevyužijeme ji (nepřiřadíme l-hodnotě funkci – necháme ji bez přiřazení) b) typ funkce se definuje jako void (prázdný) void tisk1(int i) { printf(“%d”,i); } Vyvolání pak může vypadat jen takto: tisk1(a+b);

83 Rekurzivní funkce Rekurzivní funkce – (tj.funkce, které volají samy sebe) vypadají, jako všechny ostatní. Př.: (Výpočet faktoriálu) #include int fakt(int n) { return ( ( n <= 0 ) ? 1 : n * fakt( n – 1 ) ) ; } int main() { int i ; printf( “Zadej cele celé číslo: “ ) ; scanf(“%d”, %i ) ; printf( “Faktoriál je: %d \n“, fakt(i) ) ; return 0 ; }

84 Umístění definice funkcí Funkce nesmí být definována uvnitř jiné funkce. Jednotlivé funkce jsou definovány postupně (za sebou). Z toho plyne možný problém s pořadím definic. Pokud první funkci v druhé funkci vyvoláváme a nebyla dosud definována, nemá překladač dosud informaci o typu funkce,počtu a typu parametrů (tzv.hlavičkové informace). Jak sdělit překladači tyto informace dopředu ? –Deklarací návratového typu a jména funkce (nepoužívá se, protože nepodává informaci o eventuálních parametrech – K&R). Deklarace je umístěna v deklarační části programové jednotky –Pomocí funkčního prototypu (přináší verze ANSI C) Jedná se o uvedení celé hlavičky funkce. Deklarace je umístěna v před jednotlivými programovými jednotkami (je globální). Lze též použít i klíčové slovo EXTERN.

85 Konverze návratové hodnoty Pokud není typ návratové hodnoty totožný s typem výsledku, provede se automatická konverze int konverze(double n) { return ( d ) ; } Např.je-li d=4.5, pak je návratová hodnota oříznuta na 4 Parametry funkcí Parametry: formální při definici,skutečné při vyvolání. C-jazyk umožňuje předávání parametrů pouze jedním způsobem a to „volání hodnotou“. Výhoda: pokud je parametr aritmetický výraz, před předáním se napřed vyčíslí Nevýhoda:skutečné parametry nemohou být ve funkci změněny a předány zpět Automatická typová konverze skutečných parametrů.

86 Pointery (ukazatele) a funkce Pokud chceme trvale změnit hodnotu skutečného parametru (volání odkazem), pak musíme použít ukazatel jako parametr. void vymen(int *p_x, int *p_y) { int pom; pom=*p_x; *p_x=*p_y; *p_y=pom; } void main() { int i=5; j=3; vymen(&i,&j); printf(“\n\n\i=%d j=%d\n\n”,i,j); }

87 Lokalita a globalita proměnných Lokální proměnné jsou dostupné jen v programové jednotce, v jejíž deklarační části jsou definovány. Globální proměnné jsou dostupné od místa definice do konce.C-souboru a definovány jsou před jednotlivými programovými jednotkami - funkcemi. Globální proměnné jsou automaticky inicializovány na nulu. Lokální proměnné nejsou automaticky inicializovány, obsah je náhodný. Některé globální stejnojmenné proměnné mohou být stejně jako v Pascalu zastíněny proměnnými lokálními. Lokální definice jsou od místa definice do konce funkce.

88 Paměťové třídy Třídy určují, v které části paměti bude proměnná umístěna. Může být umístěna před typem proměnné. –auto –extern –static –register Třída auto je implicitní pro lokální proměnné a proměnná je uložená v zásobníku. Vzniká při vstupu do funkce a zaniká výstupem. Třída extern je implicitní pro globální proměnné a proměnné jsou umístěny v datové části. Používá se při odděleném překladu programových modulů chceme-li sdílet tutéž proměnnou.

89 Třída static není pro žádý implicitní případ. Proměnné této třídy jsou uloženy v datové oblasti. U globálních proměnných nebo funkcí: jsou viditelné pouze v modulu, kde jsou definovány. U lokálních proměnných – kdy si nechávají hodnotu i po opuštění funkce, kde jsou definovány. Třída register umožňuje definovat, že některá proměnná může být z důvodu rychlosti umístěna nikoliv v operační paměti, ale přímo v registru počítače. (C = nízkoúrovňový jazyk) Typové modifikátory const – říká, že po inicializaci proměnné již nesmí být měněna jení hodnota. volatile – upozorňuje, že udaná proměnná může být modifikována nějakou blíže nespecifikovanou činností mimo náš program.

90 Pointery (ukazatele) Definice: Pointer představuje proměnnou v paměti, která obsahuje adresu paměti, v níž se skrývá vlastní obsah. Operátor * se nazývá dereferenční operátor a získáme pomocí něho obsah paměti na adrese, na níž ukazuje příslušný pointer. Pointer je vždy svázán s nějakým datovým typem.

91 Každý ukazatel musí mít svůj typ – tj typ proměnné (objektu) na něž ukazuje. Operátor & vrací adresu proměnné, před kterou stojí. Operátor * vrací hodnotu uloženou na adrese před níž stojí. Příklad: #include int main(void) { int q, *p_q ; q = 199; /* přiřadí proměnné q hodnotu 199 */ p_q = &q; /* přiřadí p_q adresu proměnné q */ printf(“%d \n”, *p_q ) ; /* vypíše hodnotu q pomocí ukazatele */ while( ! kbhit() ) ; return ; }

92 Definice dat typu „pointer na typ“. Uvažujeme pointer na typ int. PASCAL C VAR p_i : ^INTEGER; int *p_i Jak získat adresu proměnné, která již existuje? Pomocí tzv. referenčního operátoru & (je možné ho použít pouze na proměnné). int i, *p_i = &i ; Inicializační příkaz, který v programu provede naplnění proměnné p_i hodnotou adresy proměnné i : p_i = &i Před práci s hodnotou je nutné vždy přiřadit pointeru adresu ! ! Přiřazení hodnoty do oblasti paměti, kam ukazuje pointer: *p_i = 1 ;

93 Přiřazení hodnoty pointerům: –Každá pointerová proměnná je l-hodnota a je tedy možné napsat: *p_i = 1; –Referenční operátor & je možné aplikovat pouze na pro- měnné (mají vždy adresu na rozdíl od konstant a výrazů) p_i = &i; /* v proměnné p_i je adresa proměnné i */ Přiřazení hodnoty pointerům: –2 typy přiřazení: statické – přiřazení je správné v době překladu (levá strana musí být stejného typu jako pravá) dynamické – je správné jak během překladu, tak během výpočtu (levá strana musí být stejného typu jako pravá) (přiřazovat jen přes inicializované nebo nastavené pointery)

94 Příklady: statickydynamicky i = 3;p_i = &i ; *p_i = 3 ; *p_i = 4; je totožné s *p_i = i;i = 3 ; i = *p_i ; p_i=&i ;

95 Pozor na stejný typ pointeru a objektu, na který pointer ukazuje: int q ; double *p_f; p_f = &q; *p_f = ; /* CHYBA */ Ukazateli p_f, který je typu double je přiřazena adresa na prvek int. Tato adresa je pak použita na levé straně přiřazovacího příkazu. Protože prvek int je obvykle kratší než double, může způsobit přepsání sousedící paměti.

96 Příklad: (načtení 2 čísel a zobrazení většího z nich) #include int main(void) { int i, j, *p_i ; scanf( “%d %d”, &i, &j ); p_i = ( i > j ) ? &i : &j ; printf(“%d je větší \n”, *p_i ) ; } Nulový pointer V Pascalu se tomuto pointeru říká nil, zatímco v C existuje podobná konstanta NULL definovaná v : #define NULL 0 NULL je možné bez přetypování přiřadit všem pointerům na libovolný typ dat

97 Zobrazení hodnot pointerů (~adres) Funkce printf() umožňuje zobrazit adresu obsaženou v ukazateli pomocí specifikátoru %p. Tuto schopnost printf() můžeme použít pro předvedení pointerové aritmetiky, jakým způsobem závisí na základním typu ukazatele Příklad: char *p_c, ch ; int *p_i, i ; float *p_f, f ; double *p_d, d ; p_c = &ch ; p_i = &i ; p_f = &f ; p_d = &d ; printf(“%p %p %p %p\n”, p_c, p_i, p_f, p_d ); p_c++; p_i++; p_f++; p_d++; /* incrementace ukazatelů */ printf(“%p %p %p %p\n”, p_c, p_i, p_f, p_d );

98 Zvětšení hodnoty, na kterou ukazuje ukazatel Pokud chceme incrementovat místo ukazatele samotnou hodnotu objektu, na něhož ukazuje ukazatel, pak je nutné použít ozávorkování ( *ukazatel )++ Příklad: int *p_q, q ; p_q = &q ; q=1; printf(“%p\n”, p_q ); /* zobrazení adresy ukazatele na q */ (*p_q)++ /* incrementace obsahu ukazatele – tedy prom. q */ printf(“%d %p\n”, q, p_q );

99 Vícenásobný nepřímý odkaz V jazyku C je možné, aby ukazatel ukazoval na jiný ukazatel. Nazývá se to vícenásobná dereference (tj. první ukazatel obsahuje adresu druhého ukazatele a ten teprve obsahuje adresu místa prvku). Při deklaraci se před jméno takového přidává další hvězdička navíc Příklad: char **mp_ch, *p_ch, ch ; p_ch = &ch ; /* získání adresy ch */ mp _ch = &p_pch; /* získání adresy adresy ch */ /* přiřazení hodnoty ‘A’ do proměnné ch pomocí vícenásobné dereference: */ **mp_ch = ‘A’;

100 V následujícím příkladu přiřaďte hodnotu pro proměnnou val pomocí vícenásobné dereference. Hodnotu zobrazte nejprve přímo a pak pomocí vícenásobné dereference. Příklad: float val, *p_val, **mp_val ; p_val = &val ; /* získání adresy proměnné val */ mp_val = &p_val ; /* získání adresy adresy val */ ** mp_val = ; printf(“ %f %f ”, val, **mp_val);

101 Konverze pointerů Při přidělování dynamické paměti je přeba občas konverzi pointerů využít. Pak používáne explicitní přetypování (protože implicitní není vhodné). Příklad: char *p_c; int *p_i ; p_c = (char *) p_i ; /* explicitní přetypování */ Zarovnání v paměti Pokud při přetypování dochází k neočekávané chybě, pak zkoušíme použít přetypování tam a zpět a vypsat adresu u obou.Při odlišných hodnotách to může být způsobeno automatickým zarovnáním určitých datových typů od sudé nebo od liché adresy bytu (memory alignment). Bez problémů je pouze konverze z vyšších datových typů na nižší.

102 Pointery a funkce Volání parametru funkce odkazem Protože v C-čku existuje jen volání parametru hodnotou, pomocí pointeru lze umožnit i volání odkazem. ( V Pascalu je formální parametr funkce volaný odkazem uvozen klíčovým slovem var a tím je zajištěno předání adresy skutečného parametru do zásobníku.) V C-čku je proměnná opět volána hodnotou, ale je tam uložena adresa takovéhoto parametru.) void vymen(int *p_x, int *p_y) { int pom ; /* záměna 2 proměnných */ pom = *p_x ; *p_x = *p_y ; *p_y = pom ; }

103 Vyvolání funkce se provede následovně: int i = 5, j = 3 ; vymen( &i, &j ) ;

104 Jednorozměrná pole pole = datová struktura složená ze stejných prvků základní práce s pojem je v C-čku podobná Pascalu dolní mez indexu je vždy 0 ! ! ! ( v Pascalu je volitelná ) C-čko zásadně nekontroluje definované meze polí rozsah prvků pole je od 0 do počet-1 a musí být znám v době překladu – takového pole nazýváme statické Vždy když je pole definované pomocí [ ] jedná se o pole statické ( i když je definováno uvnitř funkce ) Definice pole: PascalC : VAR x : ARRAY [0..pocet-1]TYP x[pocet] ; OF TYP ;

105 Příklad definice pole: #define MAX 10 int x [ MAX ], y [ MAX * 2 ], z [MAX + 1 ] ; Definice nových typů pomocí typů známých: Pascal C : TYPE VEC5 = ARRAY [0..4] OF INTEGER; typedef int VEC5[5]; VEC3 = ARRAY [0..2] OF CHAR; typedef char VEC3[3]; VEC5 = ARRAY [0..4] OF INTEGER; typedef float FVEC[10]; Definice nových proměnných s využitím definovaných typů: Pascal C : VAR v5 : VEC5; VEC5 v5 ; v3 : VEC3; VEC3 v3 ; f : FVEC; FVEC f ; Syntaxe při použití indexované proměnné je stejná: tj. např.: v5[3] V C-čku jsou prvky pole l-hodnotami, tj. dají se měnit.

106 Příklad: (nasčítání počtu jednotlivých písmen v souboru) #include #define POCET ( ‘Z’ - ’A’ +1 ) int main(void) { FILE *fr; int c, i ; int pole[POCET] ; for ( i=0 ; i < POCET ; i++ ) pole[ i ] = 0 ; Fr = fopen( “TEXT.TXT”, ”r” ) ; while ( ( c = getc(fr) ) != EOF ) { if ( isalpha(c) ) pole [ toupper(c) – “A” ] ++ ; } printf ( “V souboru byl tento počet jednotlivých písmen: \n” ) ; for ( i=0 ; i < POCET ; i++ ) printf ( “ %c - %d \n ”, i + “A”, pole[i] ) ; fclose(fr) ; return 0 ; }

107 Jednorozměrná pole a pointery –Začíná-li první prvek od nuly a známe délku typu, pak lze lehce spočítat adresu i-tého prvku od začátku pole: &x[i] = bázová adresa x + i * sizeof(typ) ; –Indexování pole: x [ i ] je totožné s pointrovým zápisem *(x+i) ( pokud délka typu je 1)

108 Pointery a jednorozměrné pole Příklad: ( vytiskněte a 3. prvek pole a) indexy b) pointery ) int main() { int a[10]={10,20,30,40,50,60,70,80,90,100}; int *p_a; /* přiřadí p_a adresu začátku pole a : */ p_a = a; /* vytiskne prvek */ printf("%d %d %d ",a[0],a[1],a[2]); /* vytiskne prvek přes pointery*/ printf("%d %d %d ",*p_a, *(p_a+1), *(p_a+2)); while(!kbhit()); return 0; }

109 Dynamická jednorozměrná pole –Definice (vzniká při běhu programu): int *p_i ; –Přidělení dynamické paměti: p_i = ( int * ) malloc( 4 * sizeof(int) ) Ekvivalentní zápisy: p_i[0] == *p_i p_i[1] == *(p_i + 1) p_i[2] == *(p_i + 2) p_i[3] == *(p_i + 3)

110 Vícerozměrná pole Kromě polí jednorozměrných můžeme v C vytvářet pole se dvěma či více rozměry Příklad:( dvourozměrné pole celých čísel count 4 x 6 ) int count[4][6];

111 Pointery a vícerozměrné pole Příklad: Je definováno pole balance (5 řádků, 3 sloupce) jako typ float. Vytiskněte pomocí pointerové aritmetiky prvek [2][1] tohoto pole. int main() { float balance[5][3]={ 0,1,2, 3,4,5, 6,7,8, 9,10,11, 12,13,14 }; float *p_balance; /* priradi p_balance adresu zacatku pole balance : */ p_balance = (float *) balance; /* vytiskne prvek [2][1] */ printf("%.1f \n", balance[2][1] ); /* a) pres indexy */ printf("%.1f \n", *(p_balance+(2*3)+1) ); /* b) pres pointery */ while(!kbhit()); return 0; }

112 Dynamická alokace 2D-pole © Ing. P.Kropík

113 #include int main(int argc, char *argv[]) { double **p_pole; int i, radky = 10, sloupce = 4 ; /* Prideleni pameti pro 2D pole */ /* alokace vektoru ukazatelu na jednotlive radky */ p_pole = (double **) malloc(radky * sizeof(double *)); if (p_pole == NULL) { printf("\nNeni pamet..."); return(1); } /* alokace prvku jednotlivych radek */ for (i = 0; i < radky; i++) { p_pole[ i ] = (double *) malloc(sloupce * sizeof(double)); if (p_pole[ i ] == NULL) { printf("\nNeni pamet..."); return(1); } } /* Uvolneni pameti pro 2D-pole */ for (i = 0; i < radky; i++) free((void *) p_pole[ i ]); free((void *) p_pole); while(!kbhit()); return 0; }

114 Řetězce Řetězec (string) je speciální typ jednorozměrného pole Je to pole znaků ( složené z prvků typu char ), index začíná od 0 a je zakončen znakem \0. Jsou definované staticky (známe dopředu maximální délku pole) nebo dynamicky: statické: char a[10], b[20] = “inicializacni text” - aut.určením max.délky při překladu char s2[]=“….text….”

115 Pozor! Při statické definici nelze přiřadit ke jménu řetězce řetězec jako konstantu: char str[10]; str=“…retezec…” /* nelze */ Statická definice odkazem na pointer ukazujici na řetězcovou konstantu (není to dynamická deklarace): char *str=“Ahoj”; Dynamická deklarace (bere s hromady volné paměti ): char *s_dyn; s_dyn=(char *) malloc(10); strcpy(s_dyn,“…Text do 10 znaku …“); /* s_dyn=“…Text …”; je chybne ! ! ! */ Uvolnění dynamické paměti: free((void *) s_dyn); Nulový pointer … má hodnotu 0 Nulový řetězec … první znak řetězce je /0

116 Práce s řetězci #include Int main(void) { char str[11]; printf(“Zadejte retezec: “); scanf(“%s”, str); printf(“Retezec je %s\n\n”, str); return 0; } Přístup k jednotlivým znakům řetězce: char s[10]; for (i=0;i<10;i++) s[i]=‘*’; s[10]=‘\0’; /* Ukoncovaci znak – nutny !!! */

117 Standardní řetězcové funkce: délka řetězce: int strlen(char *s) -příklad: printf(“\n\n%d\n\n”,strlen(“Ahoj!”)); kopírování řetězce:char *strcpy(char *s1, char *s2) -příklad: strcpy(str,”Ahoj “); spojení řetězců:char *strcat (char *s1, char *s2) -příklad: strcat(str,”+ Nazdar “); nalezení znaku:char *strchr(char *s1, char c) -příklad: strchr(str,’z’); /* neexistuje-li vrati NULL */ porovnání řetězců:int strcmp(char *s1, char *s2) nalezení podřetězu:char *strstr(char *s1, char *s2)

118 Výčtové typy V C-čku lze definovat seznam pojmenovaných celočíselných konstant, nazývaný výčet (enumerace). Pro definici výčtového typu lze použít tento obecný formát: enum jméno výčtu { seznam položek } seznam proměnných ; Jednu z položek jméno výčtu nebo seznam proměnných lze vynechat Příklad: enum typ_barvy {červená, zelená, žlutá} barva

119 Standardně přiřazuje překladač konstantám výčtu celočíselné hodnoty. Konstanta ve výčtu stojící nejvíce vlevo má hodnotu 0, každá další napravo má hodnotu o 1 vyšší. Např.: (červená=0,zelená=1,modrá=2). Lze to explicitně změnit při definici výčtu (např. modrá=8). Máme-li už nadefinován výčet, lze definovat nové proměnné : enum typ_barvy mojebarva; Výčet je celočíselný typ a výčtová proměnná může obsahovat libovolnou celočíselnou hodnotu (nejen tu definovanou výčtem)

120 Příklad: #include enum computer {klavesnice, CPU, obrazovka, tiskarna }; int main() { enum computer comp; comp=CPU; printf(“%d”,comp); }

121 Struktury Struktura je sdružený datový typ, složený ze 2 a více proměnných – prvků struktury Každý prvek může mít svůj vlastní typ na rozdíl od pole struct jméno typu { typ prvek 1; typ prvek 2; : typ prvek N; } seznam proměnných ;

122 Položka seznam proměnných představuje konkrétní jména proměnných tohoto typu (nemusí být při definici typu uvedena). Jméno typu představuje konkrétní pojmenování definovaného typu (nemusí být uvedeno,pokud se struktura definuje jen pro proměnné uvedené v definici). Příklad : Struct katalog { char autor[40]; /* jmeno autora 40 byte */ char nazev[40]; /* jmeno knihy 40 byte */ char vydavatel[40]; /* vydavatel 40 byte */ unsigned datum; /* datum vydani 2 byte */ unsigned char vyd; /* cislo vydani 1 byte */ } karta Přistupujeme strukturovaným jménem: karta.datum=1776; Printf(“datum vydani: %u ”, karta.datum);

123 strcpy(karta.autor,“Victor Hugo“); strcpy(karta.nazev,“Bídníci“); strcpy(karta.vydavatel,“Olympia“); karta.vyd=2; Jakmile nadefinujeme strukturu, můžeme vytvořit další proměnné stejného typu: struct jméno typu seznam proměnných ; Příklad: struct katalog var1, var2, var3 ; Struktury lze ukládat také do pole jako jiné typy dat: struct katalog cat[100]; První strukturu z tohoto pole lze zpřístupnit následovně: cat[0] Přiřazení 33.-té položce katalogu – číslu vydání hodnotu 2: cat[33].vyd = 2;

124 Příklad na definici a použití struktury: #include struct s_type { int i; char ch; double d; char str[80]; } s; int main() { printf("Zadej cele cislo : "); scanf("%d",&s.i); printf("Zadej znak : "); scanf("%c",&s.ch); printf("Zadej cislo s pohyblivou radovou carkou : "); scanf("%lf",&s.d); printf("Zadej retezec : "); scanf("%s",s.str); printf ("%d %c %f %s", s.i, s.ch, s.d, s.str); while( ! kbhit() ); return 0; }

125 Zjištění velikosti struktury: #include struct s_type { int i; char ch; int *p; double d; } s; /* globalne definovana struktura */ int main() { printf("Struktura s_type ma delku : %d ", sizeof(struct s_type) ) ; printf("Struktura s_type ma delku : %d ", sizeof(s) ) ; while( ! kbhit() ); return 0; }

126 Jména prvků uvnitř struktury a lokální/globální proměnné: #include int main() { struct s_type { int i; int j; } s; /* lokalne definovana struktura */ int i; i = 10; /* stejnojmenne promenne uvnitr a */ s.i=100; /* vne struktury nejsou v konfliktu */ s.j=101; printf ("%d %d %d“, i, s.i, s.j ) ; while( ! kbhit() ); return 0; }

127 Ukazatele na struktury Ukazatel na proměnnou typu struktura je jako ukazatel na jiný typ dat : struct s_type { int i; char string[80]; } s, *p_s ; p_s = &s ; Místo tečkového operátoru používáme šipkový operátor: p_s->i = 1; strcpy(p_s->string,“.… textový řetězec ….“);

128 Vnořené struktury Dosud jsme pracovali se strukturami, kde základními stavebními prvky jsou typy jazyka C. Pokud jako prvky struktur figurují jiné struktury, říkáme jim vnořené struktury #define POCET_NA_LINCE 10 struct delnik {char jmeno[80]; int prum_pocet_jednotek_za_hodinu; int prum_pocet_chyb_za_hodinu; } ; struct vyrob_linka { int kod_vyrobku; double cena_materialu; struct delnik delnici[POCET_NA_LINCE]; } linka1, linka2 ; Přiřazení: linka1.delnici[1]. prum_pocet_jednotek_za_hodinu = 1 ;

129 Unie (Uniony) Unie se nazývá v jazyku C jedno místo v paměti, které je sdíleno dvěma nebo více proměnnými. Proměnné mohou být různého typu, současně lze však používat pouze jednu. Definují se podobně jako struktury: union jméno unionu { typ prvek 1; typ prvek 2; : typ prvek N; } seznam proměnných ;

130 Podobně, jako u struktur, může i jméno unie a seznam proměnných chybět Velikost unie musí být tak velká, aby se tam vešel největší prvek unie a je stanovená už při překladu ( sizeof( … ) ) Prvky mohou být libovolný datový typ jazyka C Příklad: union u_type {int i;/* 2 byty */ char c[2]; /* 2 byty c[0] a c[1] */ double d; /* 8 bytu */ } sample, *p_s ; p_s = &sample; Pro přístup k prvkům unie používáme jako u struktur tečkový operátor (přistupujeme-li pomocí ukazatele, pak šipkový operátor) : sample.d = ; p_s->i = 101 ;


Stáhnout ppt "Základy jazyka C. Charakteristika jazyka: Univerzální programovací jazyk Nízkoúrovňový jazyk (obsahuje standardní datové typy-znaky,celá čísla,reálná."

Podobné prezentace


Reklamy Google