Programování v jazyce C

Slides:



Advertisements
Podobné prezentace
A1PRG - Programování – Seminář Ing. Michal Typová konverze, oblast platnosti, paměťové třídy 9 Verze
Advertisements

Standardní knihovní funkce pro práci s textovými řetězci
Programování v C jazyku - SEMINÁŘ
Dynamické dokumenty na straně klienta Informatika pro ekonomy II.
Programovací jazyk C++
Přednáška 11 Jiří Šebesta
Programování 2 Cvičení 5.
VISUAL BASIC Práce se soubory.
PHP Práce se soubory v PHP - 13
C# pro začátečníky Mgr. Jaromír Osčádal
Programování v C++ Cvičení.
Principy překladačů Běhová podpora Jakub Yaghob. Běhová podpora Statická podpora jazyka Překladač Interface na knihovny Hlavičkové soubory Dynamická podpora.
Principy překladačů Mezikód Jakub Yaghob.
Algoritmizace a programování
Programování v Pascalu Přednáška 7
David Bednárek Filip Zavoral.  Vývoj ◦ první verze C, společný vývoj s UNIXem, jádro v C ◦ 1978Kerninghan, Ritchie: The C Programming Language.
Materiály k přednášce Úvod do programování Ondřej Čepek.
Generování mezikódu Jakub Yaghob
Informatika I 3. přednáška
Práce se soubory. * soubory patří k základním datovým prvkům v počítači * převážná většina programovacích jazyků má podporu určité formy práce se soubory.
A1PRG - Programování – Seminář Ing. Michal Standardní knihovní funkce pro práci se soubory 13 Verze
Vyučovací hodina 1 vyučovací hodina: Opakování z minulé hodiny 5 min Nová látka 20 min Procvičení nové látky 15 min Shrnutí 5 min 2 vyučovací hodiny: Opakování.
OSNOVA: a) Řetězce v C b) Funkce stdio.h pro řetězce c) Funkce string.h pro řetězce d) Příklad Jiří Šebesta Ústav radioelektroniky, FEKT VUT v Brně Počítače.
A1PRG - Programování – Seminář Ing. Michal Operátory (2. část) 4 Verze
Seminář C cvičení STL, Trolltech Ing. Jan Mikulka.
PHP – Základy programování
Sémantická analýza Jakub Yaghob
A1PRG - Programování – Seminář Ing. Michal Ukazatele a pole 10 Verze
Počítače a programování 1
OSNOVA: a)Programování se soubory b)Záloha databáze v souboru c) Příklady Jiří Šebesta Ústav radioelektroniky, FEKT VUT v Brně Počítače a programování.
Návrh a tvorba WWW Přednáška 5 Úvod do jazyka PHP.
Dokumentace informačního systému
7. Typ soubor Souborem dat běžně rozumíme uspořádanou množinu dat, uloženou mimo operační paměť počítače (na disku). Pascalský soubor je abstrakcí skutečného.
OSNOVA: a) Úvod a klasifikace b) Funkce main() s argumenty c) Souborový vstup a výstup d) Programování WAV Jiří Šebesta Ústav radioelektroniky, FEKT VUT.
Gymnázium prof. Jana Patočky Jindřišská Praha 1 „Praha & EU: Investujeme do vaší.
Algoritmizace a programování Textové soubory - 13 Mgr. Josef Nožička IKT Algoritmizace a programování
1 Počítače a programování 1 13.přednáška. 2 Obsah přednášky Vstupy a výstupy – 1.část.
Problémy s češtinou České znaky se standardně nepovažují za alfanumerické znaky (\w) Vadí to při třídění vyhodnocování regulárních výrazů Je třeba použít.
Počítače a programování 1 7.přednáška. Základy Pole ve třídách a metodách Pole Arrays.
Pokročilé programování v C++ (část B)
Ukazatele, řetězce Přednáška č. 3. Ukazatele  Ukazatel (pointer) – typ o velikosti 4 bajty (v 32bit. systémech) pro uložení adresy objektu na který ukazuje.
Systém souborů. Množina souborů různých typů – Data – Spustitelné programy – Konfigurační a pomocné informace – I/O zařízení Způsob organizace množiny.
Soubory BI-PA1 Programování a algoritmizace 1, ZS Katedra teoretické informatiky © Miroslav Balík Fakulta informačních technologií České vysoké.
Jazyk C A0B36PRI - PROGRAMOVÁNÍ Část II.
Jazyk C A0B36PRI - PROGRAMOVÁNÍ Část I.
Vícerozměrná pole (1) Jazyk C povoluje, aby pole mělo více rozměrů (dimenzí) než jeden Z vícerozměrných polí bývá nejčastěji použí-váno pole dvourozměrné.
Pokročilé datové typy (struktury, unie, dynamické proměnné)
Jazyk C++ Přednáška 1.. Přednáška C++ č.12 Název C++ –Starší verze jazyka, společně označované jako „C with Classes“ (česky C s třídami), byly používány.
Programování v jazyce C++
Kontakty Webpage přednášky: – Slajdy (MS PowerPoint): –ftp://ulita.ms.mff.cuni.cz/predn/PRG017 Technické.
Programování KONSTANTY, ČTENÍ PO JEDNOM ZNAKU GETCHAR() FORMÁTOVANÝ VÝSTUP POMOCÍ PRINTF, VÝVOJOVÉ DIAGRAMY, CYKLY.
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.
Překladače 6. Sémantická analýza
Programování ÚVOD, PROMĚNNÉ, OPERÁTORY A PODMÍNĚNÝ PŘÍKAZ ERIK KRÁL.
Programování OPERÁTOR SIZEOF, FUNKCE, POLE JAKO PARAMETRY FUNKCÍ ERIK KRÁL.
Počítače a programování 2
Programování ENUM, SWITCH,pole jednorozměrná a vícerozměrná, deklarace, inicializace, kopírování, porovnání Erik Král.
Vícerozměrná pole (1) Jazyk C povoluje, aby pole mělo více rozměrů (dimenzí) než jeden Z vícerozměrných polí bývá nejčastěji použí-váno pole dvourozměrné.
Výukový materiál zpracován v rámci projektu
Y36PJC Programování v jazyce C/C++
Překladače Syntaktická analýza
Programovací jazyk C Autorem materiálu a všech jeho částí, není-li uvedeno jinak, je Ing. Jitka Vlčková. Dostupné z Metodického portálu ISSN.
Programování 2. hodina RNDr. Jan Lánský, Ph.D.
Programování v jazyce C++
Programování v jazyce C++
Operační systémy 9. Spolupráce mezi procesy
Funkce výstupu (2) Funkce printf: deklarována v: stdio.h
Databázové systémy a SQL
Oblast platnosti identifikátoru (1)
C# přehled vlastností.
Transkript prezentace:

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 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

Obsah předmětu C++ C++ C C ZS LS Programování v jazyce C OOP (v C++) Nejdůležitější: vlastní praxe Na přednáškách se nikdo nikdy programovat nenaučil

Obsah přednášky Přednáška Cvičení 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?

Pascal vs. C++ Úvod do Programování, Programování  výuka (v) Pascalu 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é........

'Vše' již bylo naprogramováno 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áno

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)

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++

Historie 1970-73 první verze C, společný vývoj s UNIXem 1973 přepsání jádra UNIXu do C 1978 Kerninghan, Ritchie: The C Programming Language 1980 standardy – ANSI X3J11, od r. 1999 ISO 9899 1980 AT&T - "C with Classes" 1983 poprvé název C++ (Rick Mascitti) 1985 Stroustrup: The C++ Programming Language 1989 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ět Implementace novinek často nekorektní nebo neefektivní (STL)

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

hello.c #include <stdio.h> #include <conio.h> direktiva preprocesoru vložení souboru deklarace knihovních funkcí #include <stdio.h> #include <conio.h> int main( int argc, char ** argv) { printf( "Hello\n"); getch(); return 0; } hlavička funkce název funkce typ návratové hodnoty formální parametry tělo funkce skutečné parametry příkaz volání funkce bez parametrů složené závorky BEGIN END

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

Překlad jednoho modulu a sestavení knihovny standardní i jiné knihovní headery .h .obj .obj .obj .obj .obj .lib spustitelný program .cpp CC .obj Link .exe spojování (linkování) objektový modul (přeložený kód) kompilace

Oddělený překlad - dělení na moduly Modul - ucelená funkčí jednotka modul.cpp (.c) - implementace modul.h - definice rozhraní rozdělení projektu do modulů a vytváření headerů je umění, nedá se to naučit na přednášce fotbal.h hriste.h hrac.h mic.h fotbal.cpp hriste.cpp hrac.cpp mic.cpp

Překlad více modulů – oddělený překlad vlastní headery knihovní headery knihovny .h .h .obj .obj .obj .obj .obj .lib .c CC .obj Link .exe kompilace jednoho modulu .obj .obj .c .obj .c .c další moduly

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

Integrované vývojové prostředí .h .h .obj .obj .obj .obj .obj .lib .c .obj .c CC .obj .obj Link .exe .c editor debugger projekt

Make .h .h .obj .obj .obj .obj .obj .lib .c .obj .c CC .obj .obj Link .exe .c makefile make

Program a modul Program v C++ nemá (vnořovanou) blokovou strukturu Neexistuje "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

argumenty z příkazové řádky Funkce vnořené funkce nelze! Základní programová jednotka je funkce Neexistují vnořené funkce Začátek programu – funkce main int fce2( int a) { int fce1( int x, int y) return x+y; } return fce1( 2*a+17); hlavička funkce 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) ... tělo funkce začátek programu argumenty z příkazové řádky později

návrat celočíselné hodnoty Funkce - návratový typ Typ funkce = typ návratové hodnoty Hodnota se vrací pomocí klíčového slova return Speciální typ void - 'prázdný' typ ekvivalent procedury Pascalu void fce2( char* text) { printf( text); } void fce3( char* text) if( ! text) return; typ funkce int fce1( int x, int y) { return x+y; } návrat z funkce návrat celočíselné hodnoty

každý parametr musí mít typ Parametry funkce Pevný počet, pevný typ možnost proměnného počtu parametrů - printf Parametry jsou odděleny čárkou U každého parametru musí být uveden jeho typ Funkce bez parametrů - void každý parametr musí mít typ int fce1( int x, int y, float z) { ... } int fce2( double a, char* str) int fce3( void) int fce4( int x, y) { ... } int fce5

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"); }

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 !!! deklarace celočíselných proměnných int fce( void) { int p; int q, r; int s = 5; int x, z = 0, y; return z + x; } deklarace s inicializací náhodná hodnota !!!

Příklad - malá násobilka definice knihovních funkcí hlavička funkce, formální parametr #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); neinicializovaná proměnná inicializovaná celočíselná proměnná okanžitý návrat z funkce kontrola parametrů 2 * 7 = 14 začátek cyklu i++ konec cyklu konec, OK hlavní program konec, OK ignorování návratové hodnoty volání funkce se skutečným parametrem The END

Předávání parametrů hodnotou Všechny parametry se předávají hodnotou 'Výstupní' parametry pouze přes ukazatele nebo reference 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; vymění se jen lokální proměnné funkce předají se pouze hodnoty (1, 2), nikoliv 'proměnné'

Globální proměnné Definice mimo tělo funkce Viditelné v jakékoliv funkci Možná inicializace – při startu programu Používat s rozvahou!! pouze pro sdílená data globální proměnná formální parametr int g = 1; void fce( int x) { int z = 2; g = g + z * x; } int main( void) fce( 2); fce( 3); return g; lokální proměnná co vrátí main ?? skutečný parametr

test přiřazované hodnoty 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á hodnota Vý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

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

syntakticky správně, ale dělá něco jiného Podmíněný příkaz if (výraz) příkaz if (výraz) příkaz else příkaz if( a > 1) { b = 0; printf( "OK"); } else printf( "nee"); syntakticky správně, ale dělá něco jiného if( a > 1) printf( "OK"); if( a > 1) b = 0; printf( "OK"); if( a > 1) printf( "OK"); else printf( "nee"); if( a > 1) b = 0; printf( "OK"); else printf( "nee"); if( a > 1) { b = 0; printf( "OK"); } else { printf( "nee"); } syntakticky špatně

Vnořené podmíněné příkazy Syntakticky správně, ale nepřehledné Na pohled nejasné párování if( a > 1) if( b > 0) printf( "OK"); else printf( "nee"); if( a > 1) { if( b > 0) printf( "OK"); } else { printf( "nee"); } if( a > 1) { if( b > 0) printf( "OK"); else printf( "nee"); } U vnořených podmínek vždy používat { }

Vícenásobné větvení – konstrukce switch zapomenutý break syntakticky OK, ale dělá něco jiného switch( errc) { case 0: b = 0; printf( "OK"); break; case -1: printf( "trochu spatne"); case -2: case -3: printf( "hodne spatne"); default: printf( "jina chyba"); } celočíselný výraz switch (výraz) { case konstanta: posloupnost příkazů break; default: } switch( errc) { case 0: b = 0; printf( "OK"); case -1: printf( "spatne"); break; } ukončení větve switch( ch) { case '0'..'9': x += ch - '0'; break; case 'A'..'F': x += ch - 'A'; } pokud výraz není roven žádné z konstant interval nelze

Cyklus – konstrukce while a do-while while (výraz) příkaz podmínka na začátku do příkaz while (výraz) ; podmínka na konci Pozor! cyklus pokračuje pokud je podmínka platná while( a > 1) a = a / 2; tělo se vždy alespoň jednou provede while( a > 1) { fce( a); a = a / 2; } do { fce( a); a = a / 2; } while( a > 1);

Cyklus – konstrukce for inicializace podmínka inkrement tělo cyklu for (výraz1 ; výraz2 ; výraz3 ) příkaz je ekvivalentem výraz1; while (výraz2 ) { příkaz výraz3 ; } ekvivalent v jiném jazyce for( i=0; i<=9; i=i+1) { fce( i); } FOR I := 0 TO 9 DO FCE(I) i=0; while( i<=9) { fce( i); i=i+1; } jako inicializaci, podmínku i inkrement lze libovolný výraz výrazy 1,2,3 lze vynechat vynechání podmínky - nekonečný cyklus for( init(a); i<9 && a[i] >0; a[i++]=i*2) { fce( i); } for v C++: obecnější, širší možnosti použití

Ukončení cyklu - break, continue 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 for(;;) { errc = fce(); if( errc < 0) break; jinafce(); } n = 1; while( n<1000) { val = get(); if( val == 0) continue; n = n * val; } C++ vyjimky - pozdeji

ukončil by pouze vnitřní cyklus, vnější cyklus by pokračoval Goto Nepoužívat! .... pokud k tomu není dobrý důvod Když už, tak pouze dopředu (skok dozadu = cyklus) Dobrý důvod: výskok z vícenásobně vnořených cyklů nelze break - ukončil by pouze vnitřní cyklus, vnější cyklus by pokračoval 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(); label návěští C++ vyjimky - pozdeji

Celočíselné typy 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 long size_t, ptrdiff_t, wchar_t typ 8 bit 16 bit 32 bit 64 bit char 8 short 8 / 16 16 16 / 32 int 32 long 32 / 64 long long - 64 -2GB .. +2GB

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 / unsigned korektní porovnání na nerovnost pouze 0 .. 127 'a' < 'ž' ? signed char -128 .. 127 unsigned char 0 .. 255 - 'byte' wchar_t stddef.h: znak rozšířené sady (Unicode) časté použití: test (ne)nulovosti např. ukazatelů záleží na implementaci většinou char = signed 40 > 200 !!! 200  -56

Výčtový typ 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 }; hodnoty doplní překladač (od 0) C: celočíselné konstanty - OK C++: samostatný typ - nelze test bitů explicitní hodnoty

'Reálné' typy float  double  long double Pozor! Reálné výpočty jsou vždy nepřesné float  double  long double zvýšená přesnost double x = 1; double y = x / 3; if( x == 3 * y) printf( "Presne"); else printf( "Nepresne"); malá přesnost - nepoužívat! standard pro 'reálné' výpočty pro přesné hodnoty používejte přesné typy raději nepoužívat pouze pro fyzikální nebo numerické veličiny double zustatek = 15.60; long zustatek_v_halerich = 1560;

Číselné konverze Automatické konverze (integral promotions) vždy když je použit menší typ než int 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 při nestejných operandech

Přehled operátorů, asociativita a priorita postfix ++ -- ( ) [ ] -> . :: post-in/de-krementace volání funkce index přístup k položce struktury kvalifikace identifikátoru prefix ++ -- ! ~ + - & * sizeof ( ) new delete pre-in/de-krementace booleovská a bitová negace unární +/- reference, dereference měření velikosti přetypování dynamická alokace dynamická dealokace L .* ->* dereference member-ptru * / % multiplikativní operátory + - aditivní operátory << >> bitové posuny L < <= > >= uspořádání == != rovnosti & bitové AND ^ bitové XOR | bitové OR && booleovské AND || booleovské OR ? : podmíněný výraz P = *= /= %= += -= &= ^= |= <<= >>= přiřazení kombinované přiřazení , sekvence

Základní aritmetické operátory + - * / % podle typu operandů  automatická konverze na větší typ % - modulo int x=5, y=3; double a=5, b=3; modulo je pouze celočíselná operace celočíselné dělení x / y 1 x / b 1.666 x % y 2 x % b Error a / b a / y a % b a % y reálné dělení

Bitové a logické operátory & | ^ ~ - bitové operace AND, OR, XOR, NOT && || ! - logické operace AND, OR, NOT oba op.  0 5 & 3 1 5 && 3 5 | 3 7 5 || 3 5 ^ 3 6 5 ^^ 3 Error 5 ^ 15 10 5 & 0 5 && 0 5 | 0 5 5 || 0 5 = 01012 3 = 00112 1 = 00012 7 = 01112 9 = 10012 15 = 11112 10 = 10102 alespoň jeden operand  0 neexistuje ^ zobak nad '6' | 'bar' nad '\' ~ vlnka nad '`' alespoň jeden operand = 0

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í ! test mezí pole před přístupem k prvku pole int x[10]; // pole 0..9 if( i < 10 && x[i] != 0) y = y / x[i]; if( x==y && *x++) ... Pozor! operátory s vedlejšími efekty se nemusí provést ! POZOR!!! Přiřazení! (zde hodnota vždy = 1) if( x = 1) ...

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

Podmíněný výraz, sekvence ternární operátor 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 if (y>0) x =y; else x = 0; x = (y>0 ? y : 0); operátor sekvence ('zapomnění') x = (tmp = y, y = y + 1, tmp); ekvivalent x = y++;

Pravidla vyhodnocování a( b,c) vedlejší efekty parametrů jsou vyhodnoceny před zavoláním fce a && b je-li a nulový, b se nevyhodnocuje a || b je-li a nenulový, b se nevyhodnocuje a ? b : c po vyhodnocení a se vyhodnotí buď b nebo c a , 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; i = 0; p[ i++] = i++;

Fungující triky vs. chyby 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

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; Přepis náhodného místa v paměti ! Nepředvídatelné následky !! int x[5]; for( i=1; i <=5; i++) x[i] = i; 1 2 3 4 ??? ? 5 význam: m-prvkové pole typu (n-prvkové pole typu t) 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 pole o souřadnicích m a n čárka = operátor sekvence

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 } };

Ukazatele 1 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á je nějak velká (typ) má hodnotu 1 někde bydlí

Ukazatele p: x: 17 Deklarace: t x – proměnná x typu t t *p - ukazatel p na typ t Operátor reference: p = &x Operátor dereference: x = *p Neinicializovaný ukazatel vs. nulový ukazatel C: #define NULL 0 C++: 0 p: x: 17

přepsání náhodného místa v paměti 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 ? 5 x: 1 :px y: 3 :py ? jaký zde bude obsah x a y?

Ukazatele - příklad x: 1 :px y: 3 :py 0: 7 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; x: 1 :px y: 3 :py umožní test 0: 7 typicky 'segmentation fault' váš program bude ukončen pro pokus o porušení ochrany paměti

přístup k hodnotě proměnné přes ukazatel Ukazatele - příklad x: 1 :px 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; y: 3 :py x: 1 :px y: 4 :py Pozor na prioritu! *py++  *(py++) přístup k hodnotě proměnné přes ukazatel

Ukazatele - příklad x: 1 :px y: 1 :py x: 9 :px y: 1 :py 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; x: 1 :px y: 1 :py x: 9 :px jaký zde bude obsah x a y? y: 1 :py

Pole a ukazatele, aritmetika ukazatelů 1 2 3 4 ? 20 int a[5]; int *p; a[2] = 20; p = &a[2]; a[0] = *p - 15; p++; *p = 30; a p reference na prvek pole 5 ? 20 30 p inkrementace ukazatele posun na daší prvek

Pole a ukazatele, aritmetika ukazatelů 5 ? 20 30 40 p = &a[1]; *(p+3) = 40; Operátor [] p[i]  *(p+i) &p[i]  p+i a  &a[0] p přičtení čísla k ukazateli  posun o n prvků indexování pole (ukazatele) je jen jiný zápis přístupu přes ukazatel identifikátor pole je ukazatel na svůj nultý prvek Automatické konverze pole-ukazatel Je-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]

Pole a ukazatele, aritmetika ukazatelů int a[5]; int *p; 10 20 30 40 nekompatibilní typy nestejná úroveň indirekce 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; identifikátor pole je konstantní  nelze do něj přiřazovat p[i]  *(p+i)  *(i+p)  i[p]

Ř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 Každý řetězec musí být vždy ukončen nulou 'A' 'h' 'o' 'j' '\0' '\0' = 0 char buffer[4]; strcpy( buffer, "Ahoj"); 'A' 'h' 'o' 'j' '\0' pozor na uvozovky a apostrofy ! vždy myslet na koncovou nulu ! 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

'Řetězcové proměnné' char s1[] = "Uno"; const char *s2 = "Due"; Inicializované pole (konstantní ukazatel) s1++ nelze! s1: 'U' 'n' 'o' '\0' s2: 'D' 'u' 'e' '\0' Inicializovaná proměnná typu ukazatel s2++ se přesune na další znak anonymní globální proměnná const char[]

Ř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); deklarace řetězcových funkcí počet znaků (bez koncové nuly) char pole[8] = "Ahoj"; x = strlen( pole); // 4 inicializované pole typu char skutečný počet znaků (4) nikoliv velikost pole pole: A h o j \0 ?

Délka řetězce – různé způsoby implementace podmínka for cyklu může být libovolná přístup přes index int strlen ( const char* s) { int i = 0; while ( s[i] != '\0') { i++; } return i; více inkrementací prázdné tělo nezapomenout na ';' !! for( i=0; *s != '\0'; i++) s++; for( i=0; *s != '\0'; i++, s++) ; složitější podmínka: test nenulovosti inkrementace ukazatele int i=0; while ( *s++ != '\0') i++; int i = 0; while ( *s != '\0') { i++; s++; } return i; while(a!=0)  while(a) podmínka je splněna pokud je nenulová int i=0; while ( *s++) i++; rozdíl ukazatelů = počet prvků mezi nimi pozor na ± 1 ! char *p = s; while (*p++) ; return p-s-1; přístup přes ukazatel

Řetězce - kopírování buf pozdrav char* strcpy( char* d, const char* s); zkopíruje obsah s do místa začínajího od d char buf[8]; char pozdrav[] = "Ahoj"; strcpy( buf, pozdrav); kopíruje pouze do koncové '\0' buf A h o j \0 ? pozdrav A h o j \0

Řetězce – chyby při kopírování vždy pozor na dostatek místa funkce nic nekontroluje !!! váš program provedl... char buf[6]; char pozdrav[] = "Dobry den"; strcpy( buf, pozdrav); buf D o b r y d e n \0 pozdrav D o b r y d e n \0 kopírování na neinicializovaný ukazatel !!! váš program provedl... char *ptr; char pozdrav[] = "Ahoj"; strcpy( ptr, pozdrav); ? ptr A h o j \0 pozdrav ptr neinicializovaný !!! A h o j \0

Řetězce – zřetězení, vyhledávání char* strcat( char* d, const char* s); připojí s za d char* strchr( const char* s1, int c); vyhledá první pozici c v s1 char* 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"); po strcpy A h o j \0 ? po strcat A h o j B a b i \0 ? pozor na dostatek místa ! buf A h o j B a b i \0 ? bp

Řetězce – porovnávání a další funkce int strcmp( const char* s1, const char* s2); s1 < s2  -1 s1 = s2  0 s1 > 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 výsledek podle prvního rozdílného znaku co znamená 's1 < s2'? A B C E =  D

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 ("%+05d \n%.2f \n", 7, r + 7); printf ("Retezec %s zacina na %c \n", buf, buf[0]); printf ("Hodnota 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);

Parametry příkazové řádky C:\> myprog.exe -n -w a.txt b.txt pole řetězců (ukazatelů na char) int main( int argc, char** argv) argv 5 argc b . t x \0 a . t x \0 Počet parametrů včetně názvu programu ! = počet ukazatelů v argv - w \0 - n \0 m y p r o g . e x \0

Zpracování příkazové řádky – výpis parametrů C:\> myprog.exe -n -w a.txt b.txt int main( int argc, char** argv) { while( *argv) { printf( "%s\n", *argv); argv++; } myprog.exe -n -w a.txt b.txt výstup řetězce a odřádkování posun na další parametr

Zpracování příkazové řádky int main( int argc, char** argv) { while( *argv) { printf( "%s\n", *argv); argv++; } argv[4] typ: char* argv[4][1] typ: char b . t x \0 *argv  argv[0] typ: char* a . t x \0 - w \0 argv typ: char** - n \0 m y p r o g . e x \0 argv **argv  argv[0][0] typ: char

Zpracování příkazové řádky int main( int argc, char** argv) { while( *argv) { printf( "%s\n", *argv); argv++; } b . t x \0 a . t x \0 argv++ **argv - w \0 - n \0 m y p r o g . e x \0 argv

Zpracování příkazové řádky int main( int argc, char** argv) { while( *argv) { printf( "%s\n", *argv); argv++; } b . t x \0 a . t x \0 *argv == 0 - w \0 - n \0 m y p r o g . e x \0 argv

Zpracování příkazové řádky usage: myprog [-n] [-w] fileA fileB 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 nastavení přepínače zbývající parametry b . t x \0 a . t x \0 - w \0 výkonná funkce - n \0 argv p r g . e x \0

Dynamická alokace paměti Velikost datového typu sizeof(char) = 1 vždy 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 int * pole; pole = malloc(20 * sizeof(int)); C++ nutnost přetypování s = (char*) malloc( 20); lépe new char* s; s = malloc( 20); if( ! s) error(); strcpy( s, "ahoj"); *s = 'X'; s: X h o j \0 vždy ověřit !!! váš program provedl...

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'

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 R0 R1 ... SP

Organizace paměti procesu – 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 R0 R1 ... SP int fce( void) { ... } { int (*fp)( void); fp = fce; ...

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 R0 R1 ... SP int bigpole[ 1000]; { int* p = bigpole; char* s = "ahoj"; ...

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 R0 R1 ... SP { char* s; s = malloc( 256); ...

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 R0 R1 ... SP { char pole[100]; char s[] = "Ahoj"; int x = 1 + 2 * 3; ...

Statické proměnné globální proměnná neviditelná z jiných modulů C++: lepší řešení - namespace static int x; int fce( int a) { static int y = 0; return y += a; } de facto globální (!) proměnná neviditelná z jiných funkcí C++: raději skrýt do třídy inicializace: C: před vstupem do main C++: před prvním průchodem

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?

Struktury struct osoba { char jmeno[20]; char prijemni[30]; definice 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 = 1; položky struktury struktura, ukazatel na strukturu, pole struktur definice proměnné typu struktura s inicializací přístup k položkám (*x).y  x->y

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 * x const 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 & x const 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)

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 typicky se nepoužívá pole = ukazatel na 1. prvek čtení deklarací: od identifikátoru doprava, až to nepůjde, tak doleva

Kombinace typových kostrukcí - příklad int*(*pf[10])(void); int*(*maso(int*(*p1)(void),int*(*p2)(void)))(void); co to je za maso ???

Kombinace typových kostrukcí - typedef 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); použitím typedef se může výrazně zpřehlednit kód

Souborový vstup a výstup deskriptor souboru - deklaruje programátor struktura definovaná v <stdio.h> FILE * FILE Neznámý obsah Pro knihovní funkce OS 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)

(ukazatel na strukturu) Práce se soubory typ 'soubor' (ukazatel na strukturu) #include <stdio.h> FILE* fp; int c; if( !(fp = fopen("c:\\f.txt", "r"))) error(); while( (c = getc( fp)) != EOF) putchar( c); fclose( fp); otevření souboru pozor na '\\' !!! čtení ze souboru zavření souboru

r: soubor musí existovat Otevření souboru FILE* fopen( const char* fname, const char* mode); r open file for reading w truncate to zero length or create file for writing a append; open or create file for writing at end-of-file r+ open file for update (reading and writing) w+ truncate to zero length or create file for update a+ append; open or create f. for upd., writing at end-of-file rb binary file ... r: soubor musí existovat mode soubor ex. soubor neex. seek r R Error w Del, W W a End r+ R/W w+ Del, R/W a+ w: soubor se smaže a: otevřít na konci +: vždy čtení i zápis

Textové vs. binární soubory Textový soubor konverze konců řádek ('\n') na platformě 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

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); pro priste udelat obrazek na fread/fwrite

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); Nepoužívat! Nelze ohlídat přetečení bufferu všechny souborové funkce lze použít i pro std. v/v jednotný zápis na std výstup nebo do souboru

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, ungetc FILE, 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, ... pro priste udelat obrazek na fread/fwrite ... a mnoho mnoho dalších

Problém v C: české znaky, ale i jiné diaktické znaky 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í znaky isalpha – 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ísmeno toupper – k zadanému písmenu vrací příslušné velké písmeno Problém v C: české znaky, ale i jiné diaktické znaky pro priste udelat obrazek na fread/fwrite

Uživatelsky napsaná třídící funkce. Návratové 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. Ignore case Parametry: pole k setřídění, počet prvků pole, velikost 1 prvku, porovánací funkce pro priste udelat obrazek na fread/fwrite

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 makra raději vůbec nepoužívat, lépe inline funkce test na (ne)definovanost symbolu obrana před vícenásobným #include viz slajd Spojování modulů - #ifndef test konstantního výrazu - #if sizeof( int) == 4 'ouvozovkování' - #abc  "abc" spojení identifikátorů - a##b  ab

Spojování modulů – problém x.c double A() { return B( 7); } y.c double B() { return 3.14; } error: Undefined 'B'

Spojování modulů – externí deklarace x.c double B(); double A() { return B(); } y.c double B() { return 3.14; }

Spojování modulů – nekonzistence x.c double B(); double A() { return B(); } y.c int B( int q) { return q+1; } nekonzistence funkce B (počet a typy parametrů, návratová hodnota) x.obj import B export A y.obj export B app.exe C: nedefinované chování C++: linker error

Spojování modulů – header x.c #include "y.h" double A() { return B( 7); } y.h int B( int q); y.c int B( int q) { return q+1; } int B( int q); double A() { return B( 7); } preprocesor hlavičkový soubor (header)

Spojování modulů – nekonzistence x.c #include "y.h" double A() { return B( 7); } y.h int B( int q); y.c double B() { return 3.14; } nekonzistence int B( int q); double A() { return B( 7); }

Spojování modulů – řešení x.c #include "y.h" double A() { return B( 7); } y.h int B( int q); y.c #include "y.h" double B() { return 3.14; } int B( int q); double A() { return B( 7); } int B( int q); double B() { return 3.14; } error: Redefinition of 'B'

Spojování modulů – duplicitní data x.c #include "y.h" double A() {} y.h int c; y.c #include "y.h" int c; int c; double A() {} int c; int c; x.obj export c export A y.obj export c linker error: Duplicate symbol 'c'

Deklarace vs. definice x.c y.h y.c x.obj y.obj #include "y.h" double A() {} y.h extern int c; y.c #include "y.h" int c; extern int c; double A() {} extern int c; int c; Definice Definice Deklarace Deklarace x.obj import c export A y.obj export c

Spojování modulů - typy Příklad definice nového typu teď není nutné chápat přesný význam Deklarace proměnné tohoto typu x.c #include "y.h" double A() { return C; } y.h enum T { P, Q}; extern enum T C; y.c #include "y.h" 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;

Spojování modulů - duplicita typů Přes y.h a z.h je t.h vložen dvakrát x.c #include "y.h" #include "z.h" double A() { return C+D; } t.h enum T { P, Q}; y.h #include "t.h" extern enum T C; error: Type redefinition: 'T' enum T { P, Q}; extern enum T C; enum T { P, Q}; extern enum T D; double A() { return C + D; } z.h #include "t.h" extern enum T D;

Spojování modulů - #ifndef není-li symbol definován ... x.c #include "y.h" #include "z.h" double A() { return C+D; } t.h #ifndef _T_H #define _T_H enum T { P, Q}; #endif definice nového symbolu (makra) y.h #include "t.h" extern enum T C; #ifndef _T_H #define _T_H enum T { P, Q}; #endif extern enum T C; extern enum T D; symbol již definován z.h #include "t.h" extern enum T D; nepřekládá se

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í

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)

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 !!

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")

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!

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í

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 int x; char * p = (char *)&x; struct { char a; int b; } S; fwrite( &S, 1, sizeof( S), fp); #ifdef _MSC_VER // Microsoft typedef __int64 INT64; const char delimiter = '\\'; #else typedef long long INT64; #ifdef UNIX const char delimiter = '/'; #endif Ideál: Program přenositelný bez úpravy zdrojového textu

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

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

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;

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>

Dynamické seznamy ukazatel na další ukazatel na další hlava seznamu struct osoba { char jmeno[20]; int narozen; osoba *dalsi; }; osoba *zamestnanci; ukazatel na další ukazatel na další hlava seznamu hlava seznamu jmeno Novak narozen 1905 dalsi Jason 1948 Drson 1990 konec seznamu

Vyhledání prvku zamestnanci os přechod na další prvek pozor na konec! osoba *os; for( os=zamestnanci; os; os=os->dalsi) { if( os->narozen == 1972) return os; } return 0; přechod na další prvek pozor na konec! zamestnanci os lezu po krabicích Novak 1905 Jason 1948 Karel 1972 Drson 1990

Přídání prvku na začátek nový prvek osoba *zamestnanci; ... osoba *novy; if( ! (novy = malloc(sizeof(osoba)))) error(); strcpy( novy->jmeno, "Novak"); novy->narozen = 1905; novy->dalsi = zamestnanci; zamestnanci = novy; zařazení do seznamu zamestnanci Jason 1948 Drson 1990 novy Novak 1905

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; zamestnanci sem novy přepojení ukazatelů Karel 1972 Novak 1905 Jason 1948 Drson 1990

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); prvni: posledni: prvek prvek prvek 1 2 3 ukazatel na další poslední prvek nulový ukazatel

Další dynamické struktury obousměrně propojený lineární seznam binární strom, vyvážený strom obecný strom, obecný graf gumové pole asociativní pole mnoho DS ve standardních knihovnách - C++ STL

Oblíbené chyby – struktura programu 1. Chybějící nebo přebývající středník: for (i=0; i<n; i++); { ... } funkce(); { ... } 2. Přehozené parametry funkcí nebo části konstrukce: char text[20]; strcpy( "Chyba!", text); for( i=0; i++; i<20)... 3. Nezapomínat na break v konstrukci switch 4. 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 5. K čemu patří else? if(podmínka1)   if(podmínka2) /* akce */ else /* jiná akce */

Oblíbené chyby – výrazy 6. Celočíselné dělení: x=1/3; 7. Zaokrouhlovací chyby: for (x=0; x!=1.0; x+=0.1)... 8. Odporující si parametry u printf: printf("%d",1.25); 9. Záměna & | a && || a=1; b=2; if(a&b)... 10. Zkrácené vyhodnocování logických výrazů 11. Pozor na záměnu znaků: a=1; if (a<1,5)... 12. Pozor na prioritu operátorů. Závorka navíc nikdy neuškodí. 13. 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)...

Oblíbené chyby – ukazatele 14. Neinicializované proměnné, zvl. ukazatele: char *text; strcpy( text, "Chyba!"); 15. Ukazatel na proměnnou, která už neexistuje: char text[20]; strcpy( text, ....); return text; 16. Chybějící nebo naopak přebývající & u parametru předávaného ukazatelem: scanf( "%d %s", i, &text);

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() { _-_-_-_ _-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ _-_-_-_-_-_-_-_ }

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

Nepoužité slajdy

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

Typy souborů Microsoft Unix .c Zdrojový kód C .cpp .C .cc .cpp .h Hlavičkový soubor C .h .hpp nebo bez přípony .h .H .hh .hpp nebo bez přípony Hlavičkový soubor C++ .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

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čnost polymorphysm polymorfismus

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

Váňovo paradoxon čím vyšší jazyk tím méně přenositelný Zajímavé vlastnosti C Váňovo paradoxon čím vyšší jazyk tím méně přenositelný Přenositelnost velikost int, direktivy Zahození hodnoty Pří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

Přeložený kód - modul hello.obj Code Data ... push call ret Export _main Import _printf _getch

Spojování modulů cstart.obj hello.obj printer.obj Code Code Code ... call ... call ... Export Export Export entry point _main _printf moduly - pro knihovny malilinkate - aby linker bral jen to co potrebuje Import Import Import _main _printf _getch

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; } Globální buf: "abc" "ahoj" Lokální zásobník c: ??? s: Dynamická heap "ahoj" lokální ukazatel na dynamická data

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'); Globální buf: "abc" "ahoj" Lokální zásobník str: ??? c: 'X' s: Dynamická heap "Xhoj" str zatím není inicializované

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'); Globální buf: "abc" "ahoj" Lokální zásobník str: Dynamická heap "Xhoj" návrat ukazatele na dynamická data

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"); x->y  (*x).y Pozor! *x.y  *(x.y)

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); }

Next run podrobné spojování modulů až nakonec po direktivách typové konstrukce raději až po pointrech switch, for s příkladem systematicky bloky, vnořování, deklarace a inicializace, C / C++ / jazyky s bl. str. strlen postupně slajdy na argv int typy – size_t, ptrdiff_t, wchar_t Dvojrozměrné pole – jak ho alokovat Funkce printf Funkce random - pouziti Řetězce a argumenty příkazové řádky rozdělit do dvou přednášek 84-87, 109 – 116, 138-139 od Filipa pridat do slajdu callock