programov ání v jazyce c

Post on 11-Jan-2016

46 Views

Category:

Documents

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

Programov ání v jazyce C. RNDr. Jan Lánský, Ph.D. Katedra softwarového inženýrství MFF UK Katedra informatiky V Š FS (Autor původní verze slajd ů : RNDr. Filip Zavoral, Ph.D.) zizelevak@gmail.com http://kocour.ms.mff.cuni.cz/~lansky/. Studijní povinnosti. Zápočet - PowerPoint PPT Presentation

TRANSCRIPT

Programování v jazyce C

RNDr. Jan Lánský, Ph.D.Katedra softwarového inženýrství MFF UK

Katedra informatiky VŠFS

(Autor původní verze slajdů: RNDr. Filip Zavoral, Ph.D.)

zizelevak@gmail.com

http://kocour.ms.mff.cuni.cz/~lansky/

2

Studijní povinnosti

Zápočet aktivní účast na cvičeních během semestru 'domácí úkoly' (krátké prográmky)

2 povinné 2 dobrovolné (nejsou podmínkou zápočtu, ale lze je použít u zkoušky)

Zkouška Musíte mě přesvědčit o vašich znalostech Ústní na základě přípravy napsání programu

na PC s možností použít domácí úkoly (povinné i dobrovolné) žádná další literatura (s výjimkou nápovědy) není povolena

3

Programování v jazyce C OOP (v C++) ZS LS

Obsah předmětu

C++

C C

C++

Nejdůležitější: vlastní praxeNa přednáškách se nikdo nikdy programovat

nenaučil

4

Obsah přednášky

Přednáška Překlad programů, spojování Základní vlastnosti C a C++, odlišnosti od jiných prog. jazyků Datové typy, operátory a řídící konstrukce Pole a ukazatele Standardní knihovny Programování není zápis algoritmů

Cvičení Praktické programování Microsoft Visual Studio .NET 2008 Ladění programů (!)

Prosíím, já jsem napsal program a ono to řeklo 'Váš program provedl neplatnou instrukci a bude ukončen '. Co mám dělat?

5

Pascal vs. C++

Úvod do Programování, Programování heslo: programování = zápis algoritmů algoritmické myšlení, algoritmizace problému soustředění se na řešení problému formulace algoritmu a jeho zápis v nějakém formalismu (jazyku) základní datové a řídící struktury nedůležité: kontrola vstupů, uživatelské rozhraní, obedněnost, vazba

na OS a HW, přenositelnost, optimalizace, udržovatelnost

výuka (v) Pascalu dobrý jazyk pro zápis algoritmů nezatěžuje technickými detaily (alokace paměti, vazba na OS, ...) slabá podpora pro kontrolu vstupů, uživatelské........

6

Pascal vs. C++

Programování v jazyce C++, OOP heslo: programování = vývoj software důležité: kontrola vstupů, uživatelské rozhraní, obedněnost, vazba na

OS a HW, přenositelnost, optimalizace, udržovatelnost zvládnutí knihoven a vývojových nástrojů

výuka (v) C++ standardní jazyk pro vývoj software další jazyky vycházejí z C++ (Java, C#, ...) dobrá podpora pro kontrolu vstupů, uživatelské........ nutnost zvládnout technické detaily (alokace paměti, vazba na OS..) velké množství hotového kódu (knihovny, komponenty, ...)

'Vše' již bylo naprogramován

o

7

Literatura

Základní učebnice a popis jazyka Miroslav Virius: Programování v C++ (ČVUT, 2. vydání 2004)

Miroslav Virius: Pasti a propasti jazyka C++ (Brno, 2. vydání 2005) Bjarne Stroustrup: The C++ Programming Language (3rd ed.) Bruce Eckel: Myslíme v jazyku C++ (Thinkinkg in C++ 2nd ed.)

C++ In-depth aneb Jak správně C++ používat - pro ty, kdo již C++ nějak znají Scott Meyers: Effective C++ (2nd ed.), More Effective C++ Herb Sutter: Exceptional C++, More Exceptional C++ Andrew Koenig, Barbara E. Moo: Accelerated C++ Practical Programming by

Example Nicolai Josuttis: The C++ Standard Library – A Tutorial and Reference James Coplien: Advanced C++ Programming Styles and Idioms Que: ANSI/ISO C++ Professional Programmer's Handbook Andrei Alexandrescu: Modern C++ Design Generic Programming and Design

Patterns Applied

Normy ISO/IEC 9899: Programming languages - C (1999) ISO/IEC 14882, ANSI: Programming languages - C++ (1998, 2003)

8

Nevhodná literatura - nepoužívat!

Martin Beran: Učebnice Borland C++ - hrubé chyby

Jan Pokorný: Rukověť uživatele Borland C++ - staré, BC 3.1

Vladimír Rudolf: ABC programátora v C++ - neúplné, zastaralé

Dirk Louis: C und C++ — Programierung und Referenz - chyby

Dalibor Kačmář: Jazyk C — učebnice pro střední školy – chyby

Brodský, Skočovský: Operační systém Unix a jazyk C – neúplné, zastaralé

Eric Gunnerson: Začínáme programovat v C# – C# není C++

9

Historie

1970-73 první verze C, společný vývoj s UNIXem1973 přepsání jádra UNIXu do C1978 Kerninghan, Ritchie: The C Programming Language1980 standardy – ANSI X3J11, od r. 1999 ISO 98991980 AT&T - "C with Classes"1983 poprvé název C++ (Rick Mascitti)1985 Stroustrup: The C++ Programming Language1989 ANSI X3J16 norma C++2003 nejnovější ISO/ANSI norma C++

Normy se vyvíjí, aktuální překladače o několik let zpětImplementace novinek často nekorektní nebo neefektivní (STL)

10

hello.c

#include <stdio.h>#include <conio.h>

int main( int argc, char ** argv){ printf( "Hello\n"); getch(); return 0;}

11

hello.c

#include <stdio.h>#include <conio.h>

int main( int argc, char ** argv){ printf( "Hello\n"); getch(); return 0;}

tělo funkce

hlavička funkce

příkaz

deklarace knihovních funkcí

direktiva preprocesoru

vložení souboru

formální parametr

y

název funkce

typ návratové hodnoty

skutečné parametr

yvolání funkce

bez parametr

ůsložené

závorky BEGIN END

12

Struktura programu

Program se skládá z modulů Překládány samostatně kompilátorem Spojovány linkerem

Modul z pohledu programátora Soubor s příponou .cpp (.c)

Hlavičkové soubory Soubory s příponou .h Deklarují (a někdy i definují) identifikátory používané ve více

modulech Vkládány do modulů direktivou include

Direktivu zpracovává preprocesor čistě textově Preprocesor je integrován v kompilátoru jako první fáze překladu

Modul z pohledu kompilátoru Samostatná jednotka překladu Výsledek práce preprocesoru

13

Překlad jednoho modulu a sestavení

.cpp

.h

CC .obj Link .exe

.obj.obj.obj.obj.obj.lib

kompilacespojování(linkování

)

knihovnystandardní i

jiné

knihovní headery

objektový modul

(přeložený kód)

spustitelný

program

14

Modul - ucelená funkčí jednotkamodul.cpp (.c) - implementacemodul.h - definice rozhraní

Oddělený překlad - dělení na moduly

fotbal.cpp

fotbal.h

hriste.cpp hrac.cpp mic.cpp

hriste.h hrac.h mic.h

rozdělení projektu do modulů

a vytváření headerů je umění,

nedá se to naučit na přednášce

15

Překlad více modulů – oddělený překlad

.c

.h .h

CC .obj Link .exe

.obj.obj.obj.obj.obj.lib

.obj.obj.obj

kompilace jednoho modulu

knihovnyknihovní headery

vlastní headery

.c

.c.c

další moduly

16

Překladače a vývojová prostředí

Windows - překladač součástí integrovaného prostředí MS Visual Studio - Visual C++ (VC6.0, .Net, .Net2008) integrovaný make, linker, debugger klikabilní konfigurace další překladače - Borland C++ Builder, Intel, Watcom

Unix (Linux) - samostatné programy, příkazová řádka gcc make - pro 'opravdové' programátory pokusy o vývojová prostředí (kDevelop)

raději nepoužívat

17

Integrované vývojové prostředí

.c

.h .h

CC Link .exe

.obj.obj.obj.obj.obj.lib

.obj.obj.obj.c

.c

debugger

projekt

editor

18

Make

.c

.h .h

CC Link .exe

.obj.obj.obj.obj.obj.lib

.obj.obj.obj.c

.c

makemakefile

19

Program a modul

Program v C++ nemá (vnořovanou) blokovou strukturuNeexistuje "hlavní blok"

Běh programu začíná vyvoláním funkce main Před funkcí main běží inicializace běhového prostředí, po ní úklid Funkce main musí mít tuto hlavičku:

int main( parametry příkazové řádky)

Modul: posloupnost globálních deklarací a definic Deklarace

Oznámení překladači, že identifikátor existuje Určení některých vlastností (typ, parametry)

Definice Doplnění zbývajících vlastností (kód funkce, obsah struktury) Překladač vygeneruje kód funkce, vyhradí místo pro proměnnou

20

Funkce

Základní programová jednotka je funkceNeexistují vnořené funkceZačátek programu – funkce main

int fce1( int x, int y){ return x+y;}

int fce2( int a){ return fce1( 1, 2*a+5);}

int main( int argc, char** argv){ ...}

int fce2( int a){ int fce1( int x, int y) { return x+y; }

return fce1( 2*a+17);}

vnořené

funkce nelze!

začátek programu argumenty z příkazové řádky

později

hlavička funkce

tělo funkce

21

Funkce - návratový typ

Typ funkce = typ návratové hodnotyHodnota se vrací pomocí klíčového slova return

Speciální typ void - 'prázdný' typ ekvivalent procedury Pascalu

int fce1( int x, int y){ return x+y;}

void fce2( char* text){ printf( text);}

void fce3( char* text){ if( ! text) return; printf( text);}návrat celočíselné

hodnoty

návrat z funkce

typ funkce

22

Parametry funkce

Pevný počet, pevný typ možnost proměnného počtu parametrů - printf

Parametry jsou odděleny čárkouU každého parametru musí být uveden jeho typFunkce bez parametrů - void

int fce1( int x, int y, float z){ ...}

int fce2( double a, char* str){ ...}

int fce3( void){ ...}

int fce4( int x, y){ ...}

int fce5{ ...}

každý parametr musí

mít typ

23

Volání funkce

Shoda počtu formálních a skutečných parametrůKompatibilita typů formálních a skutečných parametrůI funkce bez parametrů musí obsahovat operátor ()Návratová hodnota - lze ignorovat

int fce1( int x, int y, float z){ ... }

int fce3( void){ ... }

int fce2( int a){ fce1( a, 1, a); fce3(); return 0;}

int fce4( int x, int y, float z){ ... }

int fce5( int a){ fce4; fce4( a, 1); fce4( a, 1, "ahoj");}

24

Lokální proměnné

Definice lokálních proměnných C: na začátku těla funkce (přesněji: na začátku bloku) C++: kdekoliv v těle funkce

Možná inicializace – při každém běhu funkce neinicializovaná proměnná – náhodná hodnota !!!

int fce( void){ int x, y; int z = 0; return z + x;}

deklarace celočíselných proměnných

deklarace s inicializací

náhodná hodnota !!!

25

Příklad - malá násobilka

#include <stdio.h>

int vynasob( int c){ int i = 1, v; if( c < 1 || c > 10) return -1; while( i <= 10) { v = i * c; printf( "%d * %d = %d\n", i, c, v); i = i + 1; } return 0;}

int main(){ int cislo = 7; vynasob( cislo); return 0;}

inicializovaná

celočíselná proměnná

neinicializovaná proměnná

hlavička funkce, formální parametr

definice knihovních

funkcí

konec cyklu

začátek cyklu

kontrola parametrů

okanžitý návrat z funkce

2 * 7 = 14

i++

konec, OK

konec, OK

hlavní program

ignorování návratové hodnoty volání funkce

se skutečným

parametremThe END

26

Předávání parametrů hodnotou

Všechny parametry se předávají hodnotou'Výstupní' parametry pouze přes ukazatele nebo reference

vymění se jen lokální proměnné

funkce

předají se pouze hodnoty (1, 2), nikoliv 'proměnné'

void swap( int x, int y){ int pom; pom = x; x = y; y = pom;}

void fce( void){ int a = 1; int b = 2; int c = 0; swap( a, b); c = 2 * a + b;}

27

Globální proměnné

Definice mimo tělo funkceViditelné v jakékoliv funkciMožná inicializace – při startu programuPoužívat s rozvahou!!

pouze pro sdílená dataint g = 1;

void fce( int x){ int z = 2; g = g + z * x;}

int main( void){ fce( 2); fce( 3); return g;}

globální proměnná

formální parametr

skutečný parametr

lokální proměnn

á

co vrátí main ??

28

Výraz

Norma: "Výraz je posloupnost operací a operátorů specifikující výpočet hodnoty"Přiřazovací 'příkaz' je také výraz

jeho hodnotou je přiřazovaná hodnotaVýrazy mohou mít vedlejší efekty

1

a+b*sin(x)

printf( "Ahoj")

q = &b[17]+*p++

"retezec"

a = b = 0;

if( (x = fnc()) != 0) ...

užitečné:test přiřazované

hodnoty

29

Příkaz

Příkaz je výraz ukončený ';' (středníkem) složený příkaz - posloupnost příkazů mezi '{' a '}' programová konstrukce

if, if-else, switch, while, do-while, for, break, continue, return, goto

1;a+b*sin(x);printf( "Ahoj");q = &b[17]+*p++;"retezec";

{ 1; a+b*sin(x); printf( "Ahoj"); q = &b[17]+*p++; "retezec";}

jeden složen

ý příkaz

30

Podmíněný příkaz

if (výraz) příkazif (výraz) příkaz else příkaz

if( a > 1) printf( "OK");

if( a > 1) b = 0; printf( "OK");

if( a > 1) b = 0; printf( "OK");else printf( "nee");

if( a > 1){ b = 0; printf( "OK");}else{ printf( "nee");}

if( a > 1) printf( "OK");else printf( "nee");

syntakticky správně, ale dělá

něco jiného

syntakticky špatně

if( a > 1) { b = 0; printf( "OK");} else { printf( "nee");}

31

Vnořené podmíněné příkazy

if( a > 1) { if( b > 0) printf( "OK");} else { printf( "nee");}

Syntakticky správně, ale nepřehledné

Na pohled nejasné párování

if( a > 1) { if( b > 0) printf( "OK"); else printf( "nee");}

U vnořených podmínek

vždy používat { }

if( a > 1) if( b > 0) printf( "OK");else printf( "nee");

32

Vícenásobné větvení – konstrukce switch

switch (výraz) { case konstanta: posloupnost příkazů break; case konstanta: case konstanta: posloupnost příkazů break; default: posloupnost příkazů}

switch( errc) {case 0: b = 0; printf( "OK"); break;case -1: printf( "trochu spatne"); break;case -2:case -3: printf( "hodne spatne"); break;default: printf( "jina chyba"); break;}

switch( ch) {case '0'..'9': x += ch - '0'; break;case 'A'..'F': x += ch - 'A'; break;}

switch( errc) {case 0: b = 0; printf( "OK");case -1: printf( "spatne"); break;}

zapomenutý break syntakticky

OK,ale dělá něco

jiného

interval nelze

celočíselný výraz

ukončení větve

pokud výraz není roven žádné z

konstant

33

Cyklus – konstrukce while a do-while

while (výraz) příkaz podmínka na začátkudo příkaz while (výraz) ; podmínka na konci

while( a > 1) { fce( a); a = a / 2;}

while( a > 1) a = a / 2;

do { fce( a); a = a / 2;} while( a > 1);

tělo se vždy alespoň jednou

provede

Pozor! cyklus pokračuje pokud je podmínka

platná

34

for (výraz1 ; výraz2 ; výraz3 ) příkaz

je ekvivalentem

výraz1;while (výraz2 ) { příkaz výraz3 ;}

Cyklus – konstrukce for

i=0;while( i<=9) { fce( i); i=i+1;}

inicializace

for( i=0; i<=9; i=i+1) { fce( i);}

podmínka inkrement

tělo cyklu

FOR I := 0 TO 9 DO FCE(I)

ekvivalent v jiném jazyce

for( init(a); i<9 && a[i] >0; a[i++]=i*2) { fce( i);}

for v C++: obecnější, širší

možnosti použití

jako inicializaci, podmínku i inkrement lze libovolný

výraz

35

break okamžité ukončení celého cyklu cyklus s podmínkou uprostřed ošetření chybových stavů

continue ukončení (jednoho) běhu těla cyklu

Ukončení cyklu - break, continue

for(;;) { errc = fce(); if( errc < 0) break; jinafce();}

n = 1;while( n<1000) { val = get(); if( val == 0) continue; n = n * val;}

36

Nepoužívat! .... pokud k tomu není dobrý důvodKdyž už, tak pouze dopředu (skok dozadu = cyklus)Dobrý důvod: výskok z vícenásobně vnořených cyklů

Goto

for( i=0; i<10; i++) { for( j=0; j<10; j++) { if( fnc( i, j) == ERROR) goto konec_obou_cyklu; } }konec_obou_cyklu: dalsi_funkce();

nelze break -ukončil by pouze vnitřní cyklus, vnější cyklus by

pokračoval

labelnávěští

37

Celočíselné typy

typ 8 bit 16 bit 32 bit

64 bit

char 8 8 8 8

short 8 / 16 16 16 16 / 32

int 16 16 32 32

long 16 32 32 32 / 64

long long

- - 64 64

Základní celočíselné typy jsou znaménkovéPro každý typ existuje unsigned varianta

možné využití unsigned: unsigned char, pole bitů, modulová aritmetika pokud není dobrý důvod, unsigned raději nepoužívat

char short int long long longsize_t, ptrdiff_t, wchar_t

-2GB .. +2GB

38

Logické a znakové hodnoty a typy

C: Až do r. 1999: neexistuje typ 'boolean'Porovnání a logické operátory jsou celočíselné výrazy

FALSE (nepravda) 0 TRUE (pravda) 1 (libovolná hodnota různá od 0)

důsledek: if( x != 0) if( x) if( x == 0) if( !x)

C++, C99 celočíselný typ bool (C99: _Bool) hodnoty true (=1), false (=0)

char norma neurčuje signed / unsignedkorektní porovnání na nerovnost pouze 0 .. 127'a' < 'ž' ?

signed char -128 .. 127unsigned char 0 .. 255 - 'byte'wchar_t stddef.h: znak rozšířené sady (Unicode)

časté použití:test

(ne)nulovostinapř. ukazatelů

záleží na implementaci

většinou char = signed

40 > 200 !!!

200 -56

39

enum pohlavi { p_muz, p_zena };

pohlavi p = p_muz;int pp = p_zena;pohlavi q = 0;

enum flags { f1 = 1, f2 = 2, f3 = 4, f4 = 8 };if( x & f1)

...

enum porty { pop3 = 111, ftp = 21, smtp = 80 };

Výčtový typ

C: celočíselné konstanty - OK

C++: samostatný typ - nelze

test bitů

hodnoty doplnípřekladač (od 0)

explicitní hodnoty

40

'Reálné' typy

float double long double

malá přesnost -

nepoužívat!standard pro

'reálné' výpočty

zvýšená přesnost

double x = 1;double y = x / 3;if( x == 3 * y) printf( "Presne");else printf( "Nepresne");

Pozor!Reálné výpočty

jsou vždy nepřesné

raději nepoužívatpouze pro fyzikální

nebo numerické veličiny

double zustatek = 15.60;

long zustatek_v_halerich = 1560;

pro přesné hodnoty

používejte přesné typy

41

Celočíselné konverze

Automatické konverze (integral promotions)Výpočty výrazů a předávání parametrů vždy v šíři alespoň int

signed char, unsigned char, signed short signed int unsigned short signed int (pokud je int delší) / unsigned int

Automatické konverze u binárních operací signed int unsigned int signed long unsigned long

float double long double

vždy když je použit menší typ

než int

při nestejných operandech

42

Přehled operátorů, asociativita a priorita

postfi

x

++ --( )[ ]-> .::

post-in/de-krementacevolání funkceindexpřístup k položce strukturykvalifikace identifikátoru

pre

fix

++ --! ~+ -& *sizeof( )newdelete

pre-in/de-krementacebooleovská a bitová negaceunární +/-reference, dereferenceměření velikostipřetypovánídynamická alokacedynamická dealokace

L .* ->* dereference member-ptru

L * / % multiplikativní operátory

L + - aditivní operátory

L << >>

bitové posuny

L < <=> >=

uspořádání

L == != rovnosti

L & bitové AND

L ^ bitové XOR

L | bitové OR

L && booleovské AND

L || booleovské OR

L ? : podmíněný výraz

P =*= /= %= +=-= &=^= |= <<= >>=

přiřazeníkombinované přiřazení

L , sekvence

43

Základní aritmetické operátory

+ - * / % podle typu operandů automatická konverze na větší typ % - modulo

x / y 1 x / b 1.666

x % y 2 x % b Error

a / b 1.666 a / y 1.666

a % b Error a % y Error

int x=5, y=3;

double a=5, b=3; modulo je pouze celočíselná

operaceceločíselné dělení

reálné dělení

44

Bitové a logické operátory

& | ^ ~ - bitové operace AND, OR, XOR, NOT&& || ! - logické operace AND, OR, NOT

5 & 3 1 5 && 3 1

5 | 3 7 5 || 3 1

5 ^ 3 6 5 ^^ 3 Error

5 ^ 15 10

5 & 0 0 5 && 0 0

5 | 0 5 5 || 0 1

neexistuje

5 = 01012

3 = 00112

1 = 00012

7 = 01112

9 = 10012

15 = 11112

10 = 10102

oba op. 0

alespoň jeden

operand 0

alespoň jedenoperand = 0

45

Zkrácené vyhodnocování, relační operátory

a && b - je-li a=0, b se nevyhodnocuje, výsledek = false (0)a || b - je-li a=1, b se nevyhodnocuje, výsledek = true (1)

< <= >= >== !=

výraz typu int (bool) - výsledek vždy 0 nebo 1 (false, true) porovnávání na (ne)rovnost float/double ! porovnání vs. přiřazení !

int x[10]; // pole 0..9

if( i < 10 && x[i] != 0) y = y / x[i];

test mezí pole předpřístupem k prvku

pole

if( x==y && *x++) ...

Pozor! operátory s vedlejšími efekty se

nemusí provést !

if( x = 1) ...

POZOR!!! Přiřazení!(zde hodnota vždy =

1)

46

Přiřazení, inkrementace, bitový posun

=+= -= *= /= %= &= |= ^= <<= >>=

kombinované přiřazení a op= b a = a op b

++ -- a++ a = a + 1, výsledkem je stará hodnota a ++a a = a + 1 , výsledkem je nová hodnota a přesněji: a++ (tmp = a, a = a + 1, tmp)

<< >> bitový posun C++ - časté použití pro jiné účely (streams) - přetěžování

i += 2;x[ i+=1] /= 3;

int sum = 0;int i, x[10];

...for( i=0; i<9; sum += x[i++]) ;

pozor - vždy si uvědomit, zda jde

o pre- nebo post- inkrementaci

47

Podmíněný výraz, sekvence

a ? b : c po vyhodnocení podmínky a se vyhodnotí buď b (je-li a != 0) nebo c (je-li a

== 0)

a , b po úplném vyhodnocení a se vyhodnotí b

x = (y>0 ? y : 0);

x = (tmp = y, y = y + 1, tmp);

ekvivalentx = y++;

ternární operátor

operátor sekvence

('zapomnění')

48

i = 0;p[ i++] = i++;

Pravidla vyhodnocování

a( b,c)vedlejší efekty parametrů jsou vyhodnoceny před zavoláním fcea && b je-li a nulový, b se nevyhodnocujea || b je-li a nenulový, b se nevyhodnocujea ? b : c po vyhodnocení a se vyhodnotí buď b nebo ca , b po úplném vyhodnocení a se vyhodnotí b

Žádná další pravidla nejsou ostatní operátory jsou vyhodnocovány v libovolném pořadí vedlejší efekty se mohou projevit kdykoliv během výpočtu

možné výsledky:

p[0] = 0; p[1] = 0; p[0] = 1;

49

Fungující triky vs. chyby

Fungující triky Test ukazatele

while ( p && p->v < v )

p = p->next;

Volání funkce s vedlejším efektem

while ( (c = getchar()) != EOF && c != '\n' );

Kopie řetězce

while ( *a++ = *b++ );

Chyby Vícenásobný výskyt modifikované proměnné

p[ i++] = i++;

Nadbytečné volání funkce s vedlejším efektem

if ( getchar() == 'A' && getchar() == 'B' )

nevím, jestli se provede

50

Pole

Indexy polí vždy začínají od 0 !Při přístupu se nikdy nekontrolují meze !!!Deklarace: t x[n] - pole x o n prvcích (0..n-1) typu t

Vícerozměrné pole je pole políDeklarace: t x[m][n];Přístup: x[m][n] = a;

int x[5];for( i=1; i <=5; i++) x[i] = i;

0 1 2 3 4 ???

? 1 2 3 4 5

Přepis náhodného místa v paměti !

Nepředvídatelné následky !!

int x[8][8];

for( i=0; i < 8; i++) for( j=0; j < 8; j++) x[ i ] [ j ] = i * j;

Pozor! x[m,n] není prvek dvojrozměrného

poleo souřadnicích m a n

čárka = operátor sekvence

význam:m-prvkové pole

typu(n-prvkové pole

typu t)

51

Inicializace pole

Při deklaraci pole lze obsah pole inicializovat Nejde o přiřazení, lze pouze při deklaraci Deklarace inicializovaného pole nemusí obsahovat velikost

překladač dopočítá z inicializace u vícerozměrných polí pouze "vnější" rozměr

Při nesouhlasu velkosti pole a počtu inicializátorů velikost > inicializátory: inicializace začátku, obsah zbytku nedefinován velikost < inicializátory: kompilační chyba (Too many initializers)

int cisla[] = { 1, 2, 3, 4 };char* jmena[] = { "Josef", "Karel", "Jana" };int matice[][3] = { { 11, 12, 13 }, { 21, 22, 23 } };

52

Ukazatele

Co to je proměnná?místo v paměti, typ (-> velikost), hodnota

hodnota se dá číst a většinou i zapisovat

Co to je ukazatel (pointer)?něco, čím si můžu ukazovat na proměnnou(nebo na jiné paměťové místo – pole, položka struktury, dynamická

alokace)

K čemu jsou ukazatele dobré:zpracování řetězců, dynamické datové struktury,předávání parametrů odkazem, práce s buffery, ...

Pro C++ je práce s ukazateli typická

1někde bydlí

je nějak velká (typ)

má hodnot

u

53

Ukazatele

Deklarace:t x – proměnná x typu tt *p - ukazatel p na typ t

Operátor reference: p = &xOperátor dereference: x = *p

Neinicializovaný ukazatel vs. nulový ukazatel C: #define NULL 0 C++: 0

17x:

p:

54

Ukazatele - příklad

int x = 1, y = 3;int * px, * py;*px = 5;py = NULL; *py = 7;if( ! py) etwas();px = &x; py = &y;(*py)++;px = py; y = x;py = &x; *py = 9;

přepsání náhodného místa v

paměti

1x: :px

3y: :py

?

? 5

jaký zde bude obsah x a y?

55

Ukazatele - příklad

int x = 1, y = 3;int * px, * py;*px = 5;py = NULL; *py = 7;if( ! py) etwas();px = &x; py = &y;(*py)++;px = py; y = x;py = &x; *py = 9;

typicky 'segmentation fault'váš program bude ukončen

pro pokus o porušení ochrany paměti

1x: :px

3y: :py

0: 7

umožní test

56

Ukazatele - příklad

int x = 1, y = 3;int * px, * py;*px = 5;py = NULL; *py = 7;if( ! py) etwas();px = &x; py = &y;(*py)++;px = py; y = x;py = &x; *py = 9;

přístup k hodnotě proměnné přes

ukazatel

1x: :px

4y: :pyPozor na prioritu!

*py++ *(py++)

1x: :px

3y: :py

57

Ukazatele - příklad

int x = 1, y = 3;int * px, * py;*px = 5;py = NULL; *py = 7;if( ! py) etwas();px = &x; py = &y;(*py)++;px = py; y = x;py = &x; *py = 9;

1x: :px

1y: :py

9x: :px

1y: :pyjaký zde bude obsah x a y?

58

Pole a ukazatele, aritmetika ukazatelů

int a[5];int *p;

a[2] = 20;p = &a[2];

a[0] = *p - 15;p++;*p = 30;

0 1 2 3 4

? ? 20 ? ?

5 ? 20 30 ?

p

p

reference na prvek pole

inkrementace ukazatele

posun na daší prvek

a

59

Pole a ukazatele, aritmetika ukazatelů

p = &a[1];*(p+3) = 40;

Operátor []

p[i] *(p+i)

&p[i] p+i

a &a[0]

5 ? 20 30 40

p

přičtení čísla k ukazateli posun o n prvků

identifikátor pole je ukazatel na svůj nultý

prvek

indexování pole (ukazatele) je jen jiný zápis přístupu přes

ukazatel

Automatické konverze pole-ukazatelJe-li výraz typu pole na místě, kde typ pole nemůže být, automaticky se konvertuje na ukazatel na nultý prvek tohoto pole.

Pole nelze přiřazovat ani předávat hodnotou (ukazatel na nultý prvek)

p = a je ekvivalentní p = &a[0]

60

Pole a ukazatele, aritmetika ukazatelů

int a[5];int *p;

identifikátor pole je konstantní nelze do něj přiřazovat

0 10 20 30 40

p = &a[0];p = a;*p = a[1];*(p+2) = a[2] – 1;p = a + 2;p[1] = *(a+1);a[3] = p[2];*(a+2) = p[-1];3[a] = 2[p];

a[4] = p + 1;p = a[0];p[1] = a;

a = p + 2;

nekompatibilní typynestejná úroveň

indirekce

p[i] *(p+i) *(i+p) i[p]

61

Řetězce

Jazyk C++ nezná pojem řetězec (!) – konvence, knihovnyŘetězec je pole znaků (char) zakončené nulou

"Ahoj"

X proměnná'X' znaková konstanta - celočíselná hodnota"X" řetězec - ukazatel

'A' 'h' 'o' 'j' '\0'

Každý řetězec musí být vždy

ukončen nulou

'A' 'h' 'o' 'j' '\0'

vždy myslet na koncovou nulu !

pozor na uvozovky a apostrofy !

char buffer[4];strcpy( buffer, "Ahoj");

'\0' = 0

kód znaku v použitém kódování

(ASCII, CP1250, ISO08859-2, EBCDIC, ...)když chcete říct mezera, napište

mezeru (' ')ať vás ani nenapadne napsat 32

přestože to na VAŠEM počítačí funguje

62

'Řetězcové proměnné'

char s1[] = "Uno";

const char *s2 = "Due";

'U' 'n' 'o' '\0'

'D' 'u' 'e' '\0'

s1:

s2:

Inicializovaná proměnnátypu ukazatel

s2++ se přesune na další znak

Inicializované pole(konstantní ukazatel)

s1++ nelze!

anonymní globální proměnná

const char[]

63

Řetězce – knihovní funkce, délka řetězce

v C neexistují 'řetězcové operace' (C++: třída string) přiřazení, zřetězení, porovnání, podřetězec, ... vše standardní knihovní funkce

#include <string.h>

int strlen( const char* s);

A h o j \0 ? ? ?pole:

počet znaků(bez koncové

nuly)

char pole[8] = "Ahoj";x = strlen( pole); // 4

skutečný počet znaků (4)

nikoliv velikost pole

deklarace řetězcových funkcí

inicializované pole typu char

64

Délka řetězce – různé způsoby implementace

int i = 0;while ( *s != '\0') { i++; s++;}return i;

int strlen ( const char* s){ int i = 0; while ( s[i] != '\0') { i++; } return i;}

char *p = s;while (*p++) ;return p-s-1;

for( i=0; *s != '\0'; i++) s++;

for( i=0; *s != '\0'; i++, s++) ;

int i=0;while ( *s++ != '\0') i++;

int i=0;while ( *s++) i++;

přístup přes index

přístup přes ukazatel

podmínka for cyklu může být

libovolná

více inkrementací prázdné tělo

nezapomenout na ';' !!

složitější podmínka:test nenulovostiinkrementace

ukazatele

while(a!=0) while(a)

podmínka je splněnapokud je nenulová

rozdíl ukazatelů = počet prvků mezi

nimi pozor na ± 1 !

65

Řetězce - kopírování

char* strcpy( char* d, const char* s);

zkopíruje obsah sdo místa začínajího od

dchar buf[8];char pozdrav[] = "Ahoj";strcpy( buf, pozdrav);

A h o j \0pozdrav

A h o j \0 ? ? ?buf

kopíruje pouze do koncové '\0'

66

Řetězce – chyby při kopírování

D o b r y d e n \0pozdrav

buf

char buf[6];char pozdrav[] = "Dobry den";strcpy( buf, pozdrav);

D o b r y d e n \0

vždy pozor na dostatek místa

funkce nic nekontroluje !!!váš program provedl...

char *ptr;char pozdrav[] = "Ahoj";strcpy( ptr, pozdrav);

kopírování na neinicializovaný ukazatel !!!

váš program provedl...

A h o j \0pozdrav

ptr?

A h o j \0

ptr neinicializovaný !!!

67

Řetězce – zřetězení, vyhledávání

char* strcat( char* d, const char* s); připojí s za dchar* strchr( const char* s1, int c); vyhledá první pozici c v s1char* strstr( const char* s1, const char* s2); vyhledá podřetězec s2 v s1

char buf[10];char* bp;strcpy( buf, "Ahoj");strcat( buf, "Babi");bp = strstr( buf, "oj");

A h o j \0

? ? ? ? ?po strcpy

A h o j B a b i \0

?po strcat

buf

bp

A h o j B a b i \0

?pozor na dostatek

místa !

68

Řetězce – porovnávání a další funkce

int strcmp( const char* s1, const char* s2);s1 < s2 -1s1 = s2 0s1 > s2 +1

lexikografické uspořádání (jako ve slovníku)

další řetězcové funkce:strncat, strncmp, strncpy strrchr Find last occurrence of given character in string strpbrk Find first occurrence of character from one string in another string strspn Find first substring from one string in another string strtok Find next token in string sprintf Write formatted data to a string

co znamená 's1 < s2'? A B C E

= = =

A B C D E

výsledek podle prvního rozdílného

znaku

69

Funkce printf

int printf( const char *format [, argument]... ) Vytiskne na standardní výstup text definovaný formátovacím řetězcem Formátovací řetězec určuje počet a typy dalších parametrů (symbolem %)

Výjimka z pravidla, že funkce v C má přesně daný počet a typy parametrů. Kompilátor nemá možnost ověřit zda parametry jsou správné časté pády

programu Vrací počet skutečně vytisknutých znaků

#include <stdio.h>double r = 2.6;int c = 65;char * buf = "Ahoj";

printf ("Soucet cisel %d + %.2f = %.2f \n", 7, r, r + 7);

printf ("Retezec %s zacina na %c \n", buf, buf[0]);

printf ("ASCII kód znaku %c je %i \n", c, c);

%s – řetězec%d, %i – celé číslo%c – znak%f – reálné číslo%08d – zarovná na 8 míst, doplní 0%5.2f – zarovná na 5 míst, 2 desetinná místa\n – odřádkuje\t – tabulátor\\ – \ (cesta k souborům)

printf ("%s", r);

printf ("%i + %i = %i", c, c);

70

Parametry příkazové řádky

C:\> myprog.exe -n -w a.txt b.txt

0

m y p r o g . e x e \0

- n \0

- w \0

a . t x t \0

b . t x t \0

argv

5argc

int main( int argc, char** argv)

pole řetězců(ukazatelů na char)

Počet parametrůvčetně názvu programu !

= počet ukazatelů v argv

71

Zpracování příkazové řádky – výpis parametrů

int main( int argc, char** argv){ while( *argv) { printf( "%s\n", *argv); argv++; }}

C:\> myprog.exe -n -w a.txt b.txt

myprog.exe-n-wa.txtb.txt

výstup řetězce a

odřádkováníposun na další

parametr

72

Zpracování příkazové řádky

int main( int argc, char** argv){ while( *argv) { printf( "%s\n", *argv); argv++; }}

m y p r o g . e x e \0

- n \0

- w \0

a . t x t \0

b . t x t \0

argv

0

argvtyp:

char**

**argv argv[0][0]

typ: char

argv[4][1]

*argv argv[0]

typ: char*

argv[4]

73

Zpracování příkazové řádky

int main( int argc, char** argv){ while( *argv) { printf( "%s\n", *argv); argv++; }}

m y p r o g . e x e \0

- n \0

- w \0

a . t x t \0

b . t x t \0

argv

0

argv++ **argv

74

Zpracování příkazové řádky

int main( int argc, char** argv){ while( *argv) { printf( "%s\n", *argv); argv++; }}

m y p r o g . e x e \0

- n \0

- w \0

a . t x t \0

b . t x t \0

argv

0

*argv == 0

75

Zpracování příkazové řádky

int main( int argc, char** argv){ int n=0, w=0; while( *++argv && **argv=='-') { switch( argv[0][1]) { case 'n': n = 1; break; case 'w': w = 1; break; default: error(); } } if( !argv[0] || !argv[1]) error(); doit( argv[0], argv[1], n, w); return 0;}

options

usage: myprog [-n] [-w] fileA fileB

nastavení přepínače

zbývající parametry

výkonná funkce

p r g . e x e \0

- n \0

- w \0

a . t x t \0

b . t x t \0

0

argv

76

Dynamická alokace paměti

C: standardní knihovny <malloc.h> void* malloc( int size); void free( void* p);

C++: součást jazyka (podrobně později)

new T new T[ n] delete p delete[] p

char* s;s = malloc( 20);if( ! s) error();strcpy( s, "ahoj");*s = 'X';

s:

X h o j \0

C++ nutnost přetypování

s = (char*) malloc( 20);lépe new

vždy ověřit !!!váš program

provedl...

int * pole;pole = malloc(20 * sizeof(int));

Velikost datového typusizeof(char) = 1 vždy

77

Velikost pole určena za běhu programu

int main( int argc, char** argv){ char* buf; ... buf = malloc( strlen(argv[1]) + strlen(argv[2]) + 1))); if( ! buf) error(); strcpy( buf, argv[1]); strcat( buf, argv[2]);

spočítá potřebnou velikost

ze vstupních parametrů

pozor na koncovou '\0'

78

Organizace paměti procesu

Kódový segment Kód programu

Datový segment Globální proměnné

Heap Dynamicky alokovaná data

Zásobník Lokální proměnné a parametry

funkcí

IP

R0R1...

SP

79

Organizace paměti procesu – kódový segment

Kódový segment Připraven kompilátorem

součást spustitelného souboru

Kód uživatelských i knihovních funkcí

Obvykle chráněn proti zápisu Datový segment Heap Zásobník

IP

R0R1...

SP

int fce( void) { ... }

{ int (*fp)( void); fp = fce; ...

80

Organizace paměti procesu – datový segment

Kódový segment Datový segment

Připraven kompilátorem součást spustitelného souboru

Explicitně nebo implicitně (nulami) inicializované globální proměnné

Řetězcové konstanty Data knihoven

Heap Zásobník

IP

R0R1...

SP

int bigpole[ 1000];

{ int* p = bigpole; char* s = "ahoj"; ...

81

Organizace paměti procesu - heap

Kódový segment Datový segment Heap

Vytvářen startovacím modulem knihoven

Neinicializovaná dynamicky alokovaná data

malloc/free ( C++: new/delete ) Obsazené bloky různé velikosti

+ seznam volných bloků Zásobník

IP

R0R1...

SP

{ char* s; s = malloc( 256); ...

82

Organizace paměti procesu - zásobník

Kódový segment Datový segment Heap Zásobník

Připraven operačním systémem Lokální proměnné Pomocné proměnné generované

kompilátorem Návratové adresy Aktivační záznamy funkcí

IP

R0R1...

SP

{ char pole[100]; char s[] = "Ahoj"; int x = 1 + 2 * 3; ...

83

Statické proměnné

static int x;

int fce( int a){ static int y = 0; return y += a;}

globální proměnná neviditelná z jiných

modulů

de facto globální (!) proměnná neviditelná z

jiných funkcí

inicializace:C: před vstupem do mainC++: před prvním průchodem

C++: lepší řešení - namespace

C++: raději skrýt do třídy

84

Organizace paměti procesu – příklad

const int max = 100;char buf[max];

char* prefix( char* s){ static int n = 0; char* p = malloc( strlen( s) + 2); *p = '#'; strcpy( p + 1, s); return p;}

int main( int argc, char** argv){ char* p; strcpy( buf, argv[ argc – 1]); p = prefix( buf); p = prefix( p); ....}

co je v kterém segmentu?

85

Struktury

struct osoba {char jmeno[20];char prijemni[30];int rok_narozeni;int pohlavi;

};

osoba os, *po, zam[20];osoba beda = { "Béda", "Trávníček", 1980, p_muz };

strcpy( os.jmeno, "Venca");zam[3].rok_narozeni = 1968;po = &zam[3]; po->pohlavi = p_muz;

definice struktury

položky struktury

struktura, ukazatel na strukturu, pole

struktur

přístup k položkám(*x).y x->y

definice proměnné typu struktura s

inicializací

86

Typové kostrukce - přehled

A x[ n] pole n prvků typu A, n je konstantní výraz

A x[] pole neznámého počtu prvků typu A (pouze v některých kontextech)

A * x ukazatel na typ A

void * x ukazatel na neurčený typ *x ++x nelze

A const * xconst A * x

ukazatel na konstantní hodnotu typu A ++x lze ++*x nelze

A * const x konstantní ukazatel na typ A ++x nelze ++*x lze

A & x C++: reference na typ A

A const & xconst A & x

C++: reference na konstantní hodnotu typu A

A x() funkce vracející typ A - C: bez určení parametrů , C++: bez parametrů

A x( par) funkce s určenými parametry

A x( void) funkce bez parametrů

void x( par) funkce bez návratové hodnoty (procedura)

87

Kombinace typových kostrukcí

A * x[10] pole ukazatelů

A (* x)[10] ukazatel na pole

A * x() funkce vracející ukazatel

A (* x)() ukazatel na funkci

A x[10]() pole funkcí - zakázáno

A (* x[10])() pole ukazatelů na funkci

A x()[10] funkce vracející pole - zakázáno

A (* x())[10] funkce vracející ukazatel na pole

čtení deklarací: od identifikátoru doprava,

až to nepůjde, tak doleva

typicky se nepoužívápole = ukazatel na 1.

prvek

88

int*(*pf[10])(void);

int*(*maso(int*(*p1)(void),int*(*p2)(void)))(void);

Kombinace typových kostrukcí - příklad

co to je za maso ???

89

int*(*pf[10])(void);

int*(*maso(int*(*p1)(void),int*(*p2)(void)))(void);

typedef int* fce( void);

fce * pf [10];

fce * maso( fce* p1, fce* p2);

Kombinace typových kostrukcí - typedef

použitím typedef se může výrazně

zpřehlednit kód

90

Souborový vstup a výstup

struktura definovaná

v <stdio.h>

Neznámý obsah

Pro knihovní funkce

FILE *

FILE

deskriptor souboru -deklaruje

programátor

Otevření souboru: kontrola existence a práv vytvoření vnitřních knihovních struktur asociace s otevřeným souborem předání deskriptoru souboru (FILE*)

soubor(na disku)

OS

91

#include <stdio.h>

FILE* fp;int c;

if( !(fp = fopen("c:\\f.txt", "r")))error();

while( (c = getc( fp)) != EOF)putchar( c);

fclose( fp);

Práce se soubory

typ 'soubor'(ukazatel na strukturu)

otevření

souboru

čtení ze soubor

u

zavření souboru

pozor na '\\' !!!

92

Otevření souboru

FILE* fopen( const char* fname, const char* mode);

r open file for readingw truncate to zero length or create file for writinga append; open or create file for writing at end-of-filer+ open file for update (reading and writing)w+ truncate to zero length or create file for updatea+ append; open or create f. for upd., writing at end-of-file

rb binary file... mod

esoubor ex.

soubor neex.

seek

r R Error 0

w Del, W W 0

a W W End

r+ R/W Error 0

w+ Del, R/W R/W 0

a+ R/W R/W End

+: vždy čtení i zápis

a: otevřít na konci

r: soubor musí existovat

w: soubor se smaže

93

Textové vs. binární soubory

Textový soubor konverze konců řádek ('\n') na platformově závislou vnější reprezentaci typicky 0x0D 0x0A (Win) nebo 0x0A (Unix) konverze je automatická, programátor se o to nemusí starat vhodné pro ukládání lidsky čitelných dat getc/putc, fgets/fputs, fprintf, ... chování fseek/ftell na '\n' nedefinován - nepoužívat

Binární soubor žádné konverze se neprovádí v souboru je přesný binární obraz zapisovaných dat vhodné pro ukládání vnitřních datových struktur lidsky přímo nečitelné typicky fread/fwrite, lze i getc/putc (přístup po bajtech) fseek/ftell OK

94

Funkce pro práci se soubory

FILE* fopen( const char* fname, const char* mode);int fclose( FILE* fp);int fprintf( FILE* fp, const char* format, ...);int getc( FILE* fp);int putc( int c, FILE* fp);char* fgets( char* buffer, int limit, FILE* fp);int fputs( const char* buffer, FILE* fp);

int fread( void* ptr, int size, int n, FILE* fp);int fwrite( const void* ptr, int size, int n, FILE* fp);long ftell( FILE* fp);int fseek( FILE* fp, long offset, int whence);

whence: SEEK_SET, SEEK_CUR, SEEK_END

Zjištění velikosti souboru:

fseek( fp, 0, SEEK_END);

size = ftell( fp);

95

Souborový vs. standardní v/v

funkce pro práci se standardním vstupem/výstupem int getchar( void); int putchar( int c); int printf( const char* format, ...);

char* gets( char* buffer);

standardní vstup/výstup FILE* stand. otevřený na čtení/zápis před vstupem do main

FILE *stdin;FILE *stdout;

getchar() getc(stdin)putchar(c) putc(c, stdout)

FILE* fp = stdout;if( ...) fp = fopen( "...", "r");c = getc( fp);

jednotný zápisna std výstup nebo

do souboru

Nepoužívat!Nelze ohlídat přetečení

bufferu

všechny souborové

funkce lze použíti pro std. v/v

96

Základní knihovní (neobjektové) funkce

<string.h> <cstring>strlen, strcmp, strcpy, strncpy, strcat, strchr, strstr,memset, memcmp, memcpy, memchr<stdio.h> <cstdio>getchar, putchar, fopen, fclose, getc, putc, fgets, fputs, fread, fwrite, ftell, fseek, printf, fprintf, vfprintf, fflush, ungetcFILE, stdin, stdout, EOF, SEEK_SET, ...<stdlib.h> <cstdlib>malloc, free, atoi, atof, strtol, qsort, rand, exit<ctype.h> <cctype>isalpha, isdigit, isxdigit, isalnum, isspace, ispunct, iscntrl, islower, isupper, tolower, toupper<math.h> <cmath>abs, floor, sin, sqrt, exp, exp, log, ...<time.h> <ctime>time, gmtime, strftime, asctime, clock, ...

... a mnoho mnoho dalších

97

Typy znaků

<ctype.h> <cctype> Funkce vrací 0 nebo 1, podle toho zda zadaný znak je daného typu Parametrem funkce je jednotlivý ZNAK, ne celý řetězec

isdigit – číslice (0, ..., 9)isxdigit – hexadecimální číslice (0, ..., 9, a, ..., f, A, ..., F)isalnum – číslice nebo písmeno (0, ..., 9, a, ..., z, A, ..., Z)isspace – bílé znaky (mezera, tabulátor, konec řádku, ...)ispunct – interpunkční znaménka (?, !, ., ...) iscntrl – netisknutelné řídící znakyisalpha – písmeno (a, ..., z, A, ..., Z)islower – malé písmeno (a, ..., z)isupper – velké písmeno (A, ..., Z)tolower – k zadanému písmenu vrací příslušné malé písmenotoupper – k zadanému písmenu vrací příslušné velké písmeno

Problém v C: české znaky, ale i jiné diaktické znaky

98

Funkce qsort

#include <stdio.h>#include <stdlib.h>#include <string.h>

int compare( const void *arg1, const void *arg2 ){ return _stricmp( * ( char** ) arg1, * ( char** ) arg2 );}

void main( int argc, char **argv ){ int i; argv++; argc--; qsort( (void *)argv, (size_t)argc, sizeof( char * ), compare );

for( i = 0; i < argc; ++i ) printf( "%s ", argv[i] ); printf( "\n" );}

Uživatelsky napsaná třídící funkce. Návratové

hodnoty 0, < 0, a > 0.

Parametry: pole k setřídění, počet prvků pole, velikost 1 prvku, porovánací funkce

Ignore case

99

Direktivy preprocesoru

#include <stdio.h>#include <cstdio>#include <iostream>#include "mymodul.h"

#define KZR#define KZR 17#define KZR( pzr) ((pzr) * 2)#undef

#ifdef#ifndef#if#else#endif###

knihovní headery – C, C dle nových konvencí, C++

uživatelské headery

definice symbolu – viz slajd Spojování modulů - #ifndef

definice makra, lépe const int kzr = 17;

definice parametrického makraraději vůbec nepoužívat, lépe inline

funkcetest na (ne)definovanost symbolu

obrana před vícenásobným #includeviz slajd Spojování modulů - #ifndef

test konstantního výrazu - #if sizeof( int) == 4

'ouvozovkování' - #abc "abc"

spojení identifikátorů - a##b ab

100

x.c

double A() { return B( 7);}

Spojování modulů – problém

error:Undefined 'B'

y.c

double B() { return 3.14;

}

101

x.cdouble B();double A() { return B();}

Spojování modulů – externí deklarace

externí deklarace

y.c

double B() { return 3.14;

}

102

Spojování modulů – nekonzistence

C: nedefinované chování

C++: linker error

x.cdouble B();double A() { return B();}

y.c

int B( int q) { return q+1; }

x.obj

import Bexport A

y.obj

export Bapp.exe

nekonzistence funkce B

(počet a typy parametrů, návratová hodnota)

103

Spojování modulů – header

hlavičkový soubor (header)

x.c#include "y.h"double A() { return B( 7);}

y.c

int B( int q) { return q+1; }

y.h

int B( int q);

int B( int q);double A() { return B( 7);}

preprocesor

104

Spojování modulů – nekonzistence

nekonzistence

x.c#include "y.h"double A() { return B( 7);}

y.c

double B() { return 3.14;

}

y.h

int B( int q);

int B( int q);double A() { return B( 7);}

105

Spojování modulů – řešení

x.c#include "y.h"double A() { return B( 7);}

y.c#include "y.h"double B() { return 3.14;

}

y.h

int B( int q);

int B( int q);double A() { return B( 7);}

int B( int q);double B() { return 3.14;

}

error:Redefinition of 'B'

106

y.obj

export c

Spojování modulů – duplicitní data

x.c#include "y.h"double A() {}

y.c#include "y.h"int c;

y.h

int c;

int c;double A() {}

int c;int c;

x.obj

export c export A

linker error: Duplicate symbol 'c'

107

y.obj

export c

Deklarace vs. definice

x.c#include "y.h"double A() {}

y.c#include "y.h"int c;

y.h

extern int c;

extern int c;double A() {}

extern int c;int c;

x.objimport c export A

Deklarace

Definice

Deklarace

Definice

108

Spojování modulů - typy

x.c#include "y.h"double A() { return C; }

y.c#include "y.h"

enum T C;

y.henum T { P, Q};extern enum T C;

enum T { P, Q};extern enum T C;double A() { return C; }

enum T { P, Q};extern enum T C;

enum T C;

Příklad definice nového typuteď není nutné chápat přesný význam Deklarace proměnné tohoto typu

109

Spojování modulů - duplicita typů

x.c#include "y.h"#include "z.h"double A() { return C+D; }

t.henum T { P, Q};

enum T { P, Q};extern enum T C;

enum T { P, Q};extern enum T D;

double A() { return C + D; }

y.h#include "t.h"extern enum T C;

z.h#include "t.h"extern enum T D;

error:Type redefinition: 'T'

Přes y.h a z.hje t.h vložen dvakrát

110

Spojování modulů - #ifndef

x.c#include "y.h"#include "z.h"double A() { return C+D; }

t.h#ifndef _T_H#define _T_Henum T { P, Q};#endif

#ifndef _T_H#define _T_Henum T { P, Q};#endifextern enum T C;

#ifndef _T_H#define _T_Henum T { P, Q};#endifextern enum T D;

y.h#include "t.h"extern enum T C;

z.h#include "t.h"extern enum T D;

symbol již definován

nepřekládá se

není-li symbol definován ...

definice nového symbolu (makra)

111

Programování není zápis algoritmů

Běhové prostředí programu Vazba programu na operační systém Přenositelnost mezi platformami Typické chyby a ochrana proti nim Ladění programů debuggerem a bez debuggeru Udržovatelné programy, kultura programování

112

Vazba programu na operační systém

Proces je izolován od ostatních procesů a jádra OS Virtuální adresový prostor a/nebo ochrana paměti Přímá komunikace s I/O zařízeními není možná Přímá komunikace s jinými procesy by byla možná technikou sdílené paměti

Není ovšem všude dostupná a standardizována Použití efektivní ale obtížné a nebezpečné

Veškerá komunikace přes systémová volání Systémové volání zajišťuje:

Přechod z uživatelského režimu do privilegovaného a zpět Možnost suspendování procesu uvnitř systémového volání

Konkrétní technika systémového volání závisí na HW a OS Softwarové přerušení, brány, speciální volání, falešné výjimky Obvykle není možné volání přímo z C/C++ Relativně pomalé (změna kontextu, přeplánování)

Množina systémových volání je definována OS Může být přímo zpřístupněna knihovnou (Unix, "io.h") Nemusí být zveřejněna (Microsoft)

113

Zveřejněné rozhraní operačního systému

"C-API"Zpřístupněno knihovnami pro C (výjimečně C++)

Nejtypičtějsí část je standardizována Většina je závislá na OS

Knihovní funkce obvykle provádějí více než jedno systémové volání Některé knihovny mohou zcela změnit původní logiku systémových volání

Soubory: Buffering, překlad znakových sad, statefull/stateless Spouštění procesů: spawn = fork + exec

Vnitřek knihovních funkcí může záviset na verzi OS Připojovány jako DLL v okamžiku startu procesu (Microsoft)

Pozor na různé verze !!

114

Standardizovaná rozhraní OS

stdio.h - souborový vstup a výstup Přístup "s ukazovátkem" Sjednocení přístupu k souborům a rourám

stdin, stdout, stderr Buffering - snížení počtu systémových volání

Následky při pádu programu - fflush Textový/binární mód

Překlad do jednotné formy - oddělovač řádků "\n" Neřeší adresářové služby

signal.h, stdlib.h - řízení procesu Vyvolání/příjem signálu (podle Unixového vzoru) Ukončení procesu system( "winword my.doc")

115

Vlákna (threads)

Pro realizaci serverů i některých GUI aplikací Je-li třeba souběžně vykonávat více činností Nebo čekat na více událostí různých druhů

Proces může mít více vláken (threads) Všechna vlákna žijí uvnitř společného adresového prostoru Každé vlákno má vlastní zásobník (a tedy jiný SP) První vlákno je spuštěno při spuštění procesu Další vlákna vznikají na pokyn již existujících vláken Vlákna běží kvazi-paralelně, na multiprocesorech paralelně (!)

Všechny moderní OS vlákna podporují Způsoby implementace se mohou výrazně lišit Lze je též implementovat na úrovni knihoven bez vědomí OS

Norma C ani C++ o vláknech nehovoří Neexistuje přenositelný způsob práce s vlákny Existuje poměrně jednotná terminologie převzatá z teorie OS Existují pokusy o unifikaci prostřednictvím nestandardních knihoven

Programování s vlákny je obtížnější Nešikovná vzájemná komunikace vláken může zdržovat i zablokovat Využití vláken na multiprocesorech vyžaduje zvláštní opatrnost - Pozor na externí

knihovny!

116

Odlišnosti mezi platformami

Vlastnosti hardware Velikost adresového prostoru a velikostí ukazatelů Pořadí ukládání vícebajtových hodnot (little/big endian) Dostupné formáty celých a reálných čísel

Vlastnosti operačního systému Znaková sadou (ASCII/EBCDIC, Win/ISO), oddělovače řádků Konvence jmen souborů (oddělovače, povolené znaky, délka) Další vlastnosti souborového systému (sémantika delete, links, přístupová práva) Základní služby a konvence OS (environment, registry) Konvence (/usr/bin, .exe, $HOME)

Vlastnosti překladače Volba velikosti základních aritmetických typů Způsob zarovnání položek struktur Rozpoznávaná pod-/nad-množinou jazyka Chyby v diagnostice a generovaném kódu

Vlastnosti knihoven Dostupnost, pojmenování a sémantika funkcí

117

Přenositelnost mezi platformami

Zákaz konstrukcí závislých na vlastnostech hardware a překladače

Užívání základních typů prostředníctvím typedef

typedef unsigned long UINT32; Opatrné užívání pokročilých konstrukcí

(member-pointers, templates) Přednostní používání funkcí

definovaných normou jazyka Nelze-li jinak, užívání direktiv #ifdef

#ifdef _MSC_VER // Microsoft typedef __int64 INT64; const char delimiter = '\\'; #else typedef long long INT64; #ifdef UNIX const char delimiter = '/'; #else const char delimiter = '\\'; #endif#endif

int x; char * p = (char *)&x;struct { char a; int b; } S; fwrite( &S, 1, sizeof( S), fp);

Ideál: Program přenositelný bez úpravy zdrojového textu

118

Ladění programů debuggerem

Spustit program v ladicím režimu Některé zvládnou i připojení k již běžícímu procesu (JIT Debugging) Ladicí režim nemusí být (a typicky není) pro laděný program identický s

normálním Většina funkcí debuggeru je možná pouze pro programy přeložené v

ladicím nastavení překladače (bez optimalizací) Chybný program se může chovat při ladění jinak než finální verze

Krokovat a spouštět program Odchytit chybující program a zobrazit stav těsně před chybou Nedestruktivně zastavit běžící program Nastavovat breakpointy do kódu

Mohou být podmíněné Nastavovat breakpointy na data (změna či splnění podmínky)

Některé typy mohou o několik řádů zpomalit běh programu Zobrazovat zásobník volání Zobrazovat lokální i globální proměnné Zobrazovat paměť laděného procesu

119

Ladění programů bez debuggeru

Ladicí 'tisky' Co tisknout Kdy a kde tisknout Jak tisknout ('monitor', soubor, databáze, ...)

Automatické testování Testovací skripty Sady testovacích dat

Lokalizace chyby Minimalizace zdrojového textu, kde se chyba vyskytuje Prevence proti zavlečeným chybám

Ladicí implementace alokačních funkcí Obložit každý alokovaný blok prostorem vyplněným značkami Při dealokaci zkontrolovat neporušenost značek a změnit je

120

Bezpečné programování

Zapnout všechna varování, která je schopen kompilátor vydat Upravit program do podoby, která nezpůsobí žádné varování V odůvodněných případech lze varování vypnout pomocí #pragma

Dodržovat pravidla pro přenositelné a vícevláknové programy A to i když přenositelnost ani vícevláknovost zdánlivě nemá smysl

Minimum globálních proměnných, pokud možno pouze konstantní Procedura smí číst či měnit pouze objekty, které jsou přímo či nepřímo určeny jejími

parametry Důsledné užívání ochranných prostředků kompilátoru

const, private, ... Důsledná chybová diagnostika

Test úspěšnosti každého malloc, fopen, ... Testy proti interním chybám a špatným parametrům Ochrana proti užívání odalokovaných bloků Ochrana proti přetečením polí

Všechny funkce manipulující s polem dostávají velikost pole jako parametr Žádné strcat, gets a podobné nebezpečné funkce

Největší nepřítel je chyba, která není vždy a ihned smrtelná Dereference nulového ukazatele se pozná ihned Dereference neinicializovaného ukazatele způsobí pád později

void f( int* p){ assert( p); /*...*/ }

free(p); p=0;

121

Udržovatelné zdrojové texty Logické rozdělení do modulů a hlavičkových souborů

na nižší úrovni datové struktury a funkce, třídy

Jasné oddělení rozhraní od implementace Oddělení obsluhy uživatelského rozhraní od vlastní logiky aplikace Minimum globálních proměnných

ideálně žádné, příp. třída (struktura) app

Komentáře, zejména k rozhraním Indentace, omezená délka řádek Pojmenovávací konvence, logicky zvolené a dlouhé identifikátory

Buďto my_big_array nebo MyBigArray Obvykle typy a konstanty začínají velkými písmeny, proměnné malými GetX/SetX konvence pro metody v C++ apod.

Pojmenování všech smysluplných konstant Žádné int x[ 100] ani case 27: Jaké jiné konstanty než smysluplné by měly být ve zdrojových textech?

Nepoužívat deprecated features const a = 123; bool b; b++; char *s = "abcd"; <stdlib.h>

122

Dynamické seznamy

struct osoba { char jmeno[20]; int narozen; osoba *dalsi;};

osoba *zamestnanci;

hlava seznamu

jmeno Novak

narozen 1905

dalsi

Jason

1948

Drson

1990

ukazatel na další

konec seznam

u

hlava seznamu

ukazatel na další

123

Vyhledání prvku

osoba *os;for( os=zamestnanci; os; os=os->dalsi) { if( os->narozen == 1972) return os;}return 0;

zamestnanci os

Karel

1972

Novak

1905

Jason

1948

Drson

1990

přechod na další prvek

pozorna konec!

lezu po krabicích

124

Přídání prvku na začátek

osoba *zamestnanci;...

osoba *novy;if( ! (novy = malloc(sizeof(osoba)))) error();strcpy( novy->jmeno, "Novak"); novy->narozen = 1905;novy->dalsi = zamestnanci;zamestnanci = novy;

nový prvek

Novak

1905

Jason

1948

Drson

1990

zamestnancizařazení do seznamu

novy

125

Přídání prvku doprostřed

osoba *sem, *novy;if( ! (novy = malloc(sizeof(osoba)))) error();strcpy( novy->jmeno, "Karel"); novy->narozen = 1972;novy->dalsi = sem->dalsi;sem->dalsi = novy;

Novak

1905

Jason

1948

Drson

1990

zamestnanci sem Karel

1972

novy přepojení

ukazatelů

126

Dynamické datové struktury - fronta

struct prvek { int n; prvek *dalsi;};

struct fronta { prvek* prvni; prvek* posledni;};

init( fronta* f);put( fronta* f, int n);int get( fronta* f);

fronta f;init( &f);put( &f, 1);x = get( &f);

1

ukazatel na další

2 3

prvni:

posledni:

fronta

prvek prvek prvek

poslední prveknulový ukazatel

127

Další dynamické struktury

obousměrně propojený lineární seznambinární strom, vyvážený stromobecný strom, obecný grafgumové poleasociativní pole

mnoho DS ve standardních knihovnách - C++ STL

128

Oblíbené chyby – struktura programu

Chybějící nebo přebývající středník:for (i=0; i<n; i++);{ ... }funkce();{ ... }

Přehozené parametry funkcí nebo části konstrukce:char text[20];strcpy( "Chyba!", text);for( i=0; i++; i<20)...

Nezapomínat na break v konstrukci switch Pozor na define (raději takhle vůbec nepoužívat):#define uint int*uint p1,p2;#define N 100;int delka=N+1; /* rozvine se: int delka=100;+1; */#define square (x) x*x

K čemu patří else?if(podmínka1)  if(podmínka2) /* akce */else /* jiná akce */

129

Oblíbené chyby – výrazy

Celočíselné dělení:x=1/3;

Zaokrouhlovací chyby:for (x=0; x!=1.0; x+=0.1)...

Odporující si parametry u printf:printf("%d",1.25);

Záměna & | a && ||a=1; b=2; if(a&b)...

Zkrácené vyhodnocování logických výrazů Pozor na záměnu znaků:a=1; if (a<1,5)...

Pozor na prioritu operátorů. Závorka navíc nikdy neuškodí. Nespoléhat na pořadí vyhodnocování (následující výstupy nejsou definovány):printf("%d %d",i++,i--);

a[i++]=b[i++] může být přeloženo 3 způsoby if (0<x<1)...

130

Oblíbené chyby – ukazatele

Neinicializované proměnné, zvl. ukazatele:char *text;strcpy( text, "Chyba!");

Ukazatel na proměnnou, která už neexistuje:char text[20];strcpy( text, ....);return text;

Chybějící nebo naopak přebývající & u parametru předávaného ukazatelem:scanf( "%d %s", i, &text);

131

Co (a proč ) dělá tento program?

#define _ F-->00||F-OO--;

int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO()

{

_-_-_-_

_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_-_-_-_-_

_-_-_-_-_-_-_-_

_-_-_-_

}

132

==================

133

Nepoužité slajdy

134

Preprocesor

/*...*/int printf( const char *, ...);/*...*/

int getch();int putch();/*...*/

#include <stdio.h>#include <conio.h>int main( int argc, char ** argv){ printf( “Hello\n”); getch(); return 0;

/*...*/int printf( const char *, ...);/*...*/int getch();int putch();/*...*/int main( int argc, char ** argv){ printf( “Hello\n”); getch(); return 0;}

stdio.h

conio.h

hello.c

135

Typy souborů

Microsoft Unix

.c .c Zdrojový kód C

.cpp .C .cc .cpp Zdrojový kód C++

.h .h Hlavičkový soubor C

.h .hppnebo bez přípony

.h .H .hh .hppnebo bez přípony

Hlavičkový soubor C++

.i .i (Výstup preprocesoru)

.asm .s (Přeložený kód v assembleru)

.obj .o Objektový modul

.lib .a Knihovna

.dll .so Dynamicky linkovaná knihovna

.exe bez přípony Spustitelný program

136

C a C++

C++ nadstavba C (až na drobné výjimky) lepší C (reference, implicitní parametry, přetěžování funkcí) podpora pro datovou abstrakci objektově orientované programování zajímavé a pokročilé vlastnosti – výjimky, RTTI, šablony výborné objektové knihovny - STL

encapsulation zapouzdřeníinheritance dědičnostpolymorphysm polymorfismus

137

Výhody a nevýhody jazyka C

přenositelnost

standardní součást UNIXu dědictví UNIXu

úsporná syntaxe nepřehledná syntaxe

dostupnost a kvalita kompilátorů

slabá kontrola při kompilaci

využívání prostředků OS žádná kontrola za běhu

spojitelnost s jinými jazyky

použitelnost pro OS a I/O

použitelnost pro pračky

řezničiny řezničiny

138

Zajímavé vlastnosti C

Přenositelnost velikost int, direktivy

Zahození hodnotyPříkazem může být výraz (např. přiřazovací výraz)

Jazyk samotný nezná žádné 'standardní funkce' include - definice funkcí, typů, dat, ... bohaté knihovny, různá prostředí - různé knihovny

(pračky nepotřebují souborový výstup)

Neexistence automatických kontrol - chybové kódy C++ - mechanismus výjimek časté 'padání' nebo neočekávané chování programu

Váňovo paradoxon

čím vyšší jazyk tím méně

přenositelný

139

Přeložený kód - modul

hello.obj

...pushcall...call...ret

_main

_printf_getch

'H', 'e', 'l', 'l', 'o', 10, 0Data

Export

Import

Code

140

Spojování modulů

hello.ob

j...callcall...

_main

_printf_getch

Export

Import

Code cstart.o

bj...call...

entry point

_main

Export

Import

Code printer.o

bj...

_printfExport

Import

Code

141

Dynamická vs. lokální data

char buf[32] = "abc";

char* fce( int c){ char* s; s = malloc( 20); strcpy( s, "ahoj"); *s = c; return s;}

"abc""ahoj"

???

"ahoj"

Lokálnízásobník

Dynamickáheap

Globální

buf:

c:

s:

lokální ukazatelna dynamická data

142

Dynamická vs. lokální data

char buf[32] = "abc";

char* fce( int c){ char* s; s = malloc( 20); strcpy( s, "ahoj"); *s = c; return s;}

{ char* str = fce( 'X');

"abc""ahoj"

'X'

"Xhoj"

Dynamickáheap

Globální

buf:

c:

s:

str zatím není

inicializované

str:

Lokálnízásobník

???

143

Dynamická vs. lokální data

char buf[32] = "abc";

char* fce( int c){ char* s; s = malloc( 20); strcpy( s, "ahoj"); *s = c; return s;}

{ char* str = fce( 'X');

"abc""ahoj"

"Xhoj"

Dynamickáheap

Globální

buf:

návrat ukazatelena dynamická data

str:

Lokálnízásobník

144

Ukazatele na struktury

struct osoba { char jmeno[20]; int narozen;};

osoba ja, zamestnanci[1000];

osoba *novy;

if(!(novy = malloc(sizeof(osoba)))) error();novy->narozen = 1968;strcpy( novy->jmeno, "Novak");

Pozor! *x.y *(x.y)x->y (*x).y

145

Ladicí implementace alokačních funkcí

Obložit každý alokovaný blok prostorem vyplněným značkami

Při dealokaci zkontrolovat neporušenost značek a změnit je

void * my_malloc( size_t s){ char * p = (char *)malloc( s+sizeof(size_t)+2*AB_SIZE); if ( ! p ) return 0; *(size_t *)p = s; memcpy( p+sizeof(size_t), AB_FILL, AB_SIZE) memcpy( p+sizeof(size_t)+AB_SIZE+s, AB_FILL, AB_SIZE) return p+sizeof(size_t)+AB_SIZE;}

void my_free( void * vp){ char * p; if ( ! vp ) ERROR(); p = (char *)vp - (sizeof(size_t)+AB_SIZE); if ( memcmp( p+sizeof(size_t), AB_FILL, AB_SIZE) ) ERROR(); if ( memcmp( p+sizeof(size_t)+AB_SIZE+*(size_t *)p,

AB_FILL, AB_SIZE) ) ERROR(); /* ... zmenit znacky ... */ free( p); }

146

Next run

podrobné spojování modulů až nakonec po direktiváchtypové konstrukce raději až po pointrechswitch, for s příklademsystematicky bloky, vnořování, deklarace a inicializace, C / C++ / jazyky s bl. str.strlen postupněslajdy na argvint typy – size_t, ptrdiff_t, wchar_t

Dvojrozměrné pole – jak ho alokovatFunkce printfFunkce random - pouzitiŘetězce a argumenty příkazové řádky rozdělit do dvou přednášek84-87, 109 – 116, 138-139 od Filipa pridat do slajducallock

top related