You are on page 1of 48

PB071 Programovn v jazyce C

Vcerozmrn pole, hlavikov soubory, etzce, const

vod do C, 8.10.2013

PB071

Organizan

vod do C, 8.10.2013

PB071

Organizan
Studentt poradci vyuvejte
mstnost B011 asy na hlavnm webu

Odevzdn prvnho pkladu


konec odevzdvn 8.10.2013 (dnes, plnoc) je nutn odevzdat NAOSTRO! Pokud nemte zznam do ISu od cvicho do 4 dn, ozvte se!

vod do C, 8.10.2013

PB071

Prce s poli

vod do C, 8.10.2013

PB071

Jednorozmrn pole - opakovn


Jednorozmrn pole lze implementovat pomoc ukazatele na souvislou oblast v pamti
int array[10];

Jednotliv prvky pole jsou v pamti za sebou Promnn typu pole obsahuje adresu prvnho prvku pole
int *pArray = array; int *pArray = &array[0];

Indexuje se od 0
n-t prvek je na pozici [n-1]

Pole v C nehld pmo meze pi pstupu!


int array[10]; array[100] = 1;

pro kompiltor OK, me nastat vjimka pi bhu (ale nemus!)


vod do C, 8.10.2013

PB071

Jednorozmrn pole promnn dlka


Dynamick alokace bude probrno pozdji
promnn typu ukazatel int* pArray; msto na pole alokujeme (a odebrme) pomoc specilnch funkc na hald
malloc(), free()

Deklarace pole s variabiln dlkou


variable length array (VLA) int arraySize = 20; scanf("%d", &arraySize); a od C99 int arrayLocal[arraySize]; arrayLocal[10] = 9; alokuje se na zsobnku nen nutn se starat o uvolnn (lokln promnn) nedoporuuje se pro pli velk pole (pout haldu)
PB071

vod do C, 8.10.2013

Ukazatelov aritmetika
Aritmetick opertory provdn nad ukazateli Vyuv se faktu, e array[X] je definovno jako *(array + X) Opertor + pit k adrese na rovni prvk pole
nikoli na rovni bajt! obdobn pro -, *, /, ++ ...

Adresu potku pole lze piadit do ukazatele

vod do C, 8.10.2013

PB071

Ukazatelov aritmetika - ilustrace


int myArray[10]; for (int i = 0; i < 10; i++) myArray[i] = i+10; int* pArray = myArray + 5; *(myArray+2) (hodnota) myArray[6] (hodnota) 15 16 17

myArray[0] (hodnota)

myArray+2 (adresa)

myArray (adresa)

10

11

12

13

14

pArray (adresa)

18

19

vod do C, 8.10.2013

PB071

Demo ukazatelov aritmetika


void demoPointerArithmetic() { const int arrayLen = 10; int myArray[arrayLen]; int* pArray = myArray; // value from variable myArray is assigned to variable pArray int* pArray2 = &myArray; // wrong, address of variable array, //not value of variable myArray (warning) for (int i = 0; i < arrayLen; i++) myArray[i] = i; myArray[0] = 5; // OK, first item in myArray *(myArray + 0) = 6; // OK, first item in myArray //myArray = 10; // wrong, we are modifying address itself, not value on address pArray = myArray + 3; // pointer to 4th item in myArray //pArray = 5; // wrong, we are modifying address itself, not value on address *pArray = 5; // OK, 4th item pArray[0] = 5; // OK, 4th item *(myArray + 3) = 5; // OK, 4th item pArray[3] = 5; // OK, 7th item of myArray pArray++; // pointer to 5th item in myArray pArray++; // pointer to 6th item in myArray pArray--; // pointer to 5th item in myArray int numItems = pArray - myArray; // should be 4 (myArray + 4 == pArray) } PB071 vod do C, 8.10.2013

Ukazatelov aritmetika - otzky


int myArray[10]; for (int i = 0; i < 10; i++) myArray[i] = i+10; int* pArray = myArray + 5;

Co vrt myArray[10]? Co vrt myArray[3]? Co vrt myArray + 3? Co vrt *(pArray 2) ? Co vrt pArray - myArray ?

vod do C, 8.10.2013

PB071

Typick problmy pi prci s poli


Zpis do pole bez specifikace msta
int array[10]; array = 1;

promnnou typu pole nelze naplnit (rozdl oproti ukazateli)

Zpis tsn za konec pole, ast N+1 problm


int array[N]; array[N] = 1; v C pole se indexuje od 0

Zpis za konec pole


nap. dsledek ukazatelov aritmetiky nebo chybnho cyklu int array[10]; array[someVariable + 5] = 1;

Zpis ped zatek pole


mn ast, ukazatelov aritmetika

ten/zpis mimo alokovanou pam me zpsobit pd nebo nedouc zmnu jinch dat (kter se zde nachz)
int array[10]; array[100] = 1; // runtime exception

vod do C, 8.10.2013

PB071

Tutoril v etin
Programovn v jazyku C
http://www.sallyx.org/sally/c/

vod do C, 8.10.2013

PB071

Multipole

vod do C, 8.10.2013

PB071

Jednorozmrn pole - opakovn


Jednorozmrn pole lze implementovat pomoc ukazatele na souvislou oblast v pamti
int array[10];

Jednotliv prvky pole jsou v pamti za sebou Promnn typu pole obsahuje adresu prvnho prvku pole
int *pArray = array; int *pArray = &array[0];

Indexuje se od 0
n-t prvek je na pozici [n-1]

Pole v C nehld pmo meze pi pstupu!


int array[10]; array[100] = 1;

pro kompiltor OK, me nastat vjimka pi bhu (ale nemus!)


vod do C, 8.10.2013

PB071

Vcerozmrn pole
Pravohl pole N x M

int array[2][4];
[0][0] [0][1] [0][2] [0][3] [1][0] [1][1] [1][2] [1][3]

stejn poet prvk v kadm dku int array[N][M]; (pole ukazatel o dlce N, v kadm adresa pole int o dlce M)

Pstup pomoc opertoru [] pro kadou dimenzi


array[7][5] = 1;

Lze i vcerozmrn pole


v konkrtnm rozmru bude stejn poet prvk int array[10][20][30][7]; array[1][0][15][4] = 1;
vod do C, 8.10.2013

PB071

Reprezentace vcerozmrnho pole jako 1D


Vce rozmrn pole lze realizovat s vyuitm jednorozmrnho pole Fyzick pam nen N-rozmrn
=> peklada mus rozloit do 1D pamti

Jak implementovat pole array[2][4] v 1D?


indexy v 0...3 jsou prvky array2D[0][0...3] indexy v 4...7 jsou prvky array2D[1][0...3]
array2D[row][col] array1D[row * NUM_COLS + col]
NUM_COLS je poet prvk v dku (zde 4)

int array2D[2][4]; int array1D[8];


[0][0] [0][1] [0][2] [0][3] [0][0] [0][1] [0][2] [0][3] [1][0] [1][1] [1][2] [1][3] [1][0] [1][1] [1][2] [1][3] vod do C, 8.10.2013

PB071

Pro zamylen
Lze takto realizovat trojrozmrn pole?
int array3D[NUM_X][NUM_Y][NUM_Z];

array3D[x][y][z] ?
int array1D[NUM_X*NUM_Y*NUM_Z]; array1D[x*(NUM_Y*NUM_Z) + y*NUM_Z + z]];

Pro?

vod do C, 8.10.2013

PB071

int* pArray;

int array1D[4];
[0] [1] [2] [3]

Nepravohl pole

0x...

Pole, kter nem pro vechny dky stejn poet prvk


dosahovno typicky pomoc dynamick alokace (pozdji) lze ale i pomoc statick alokace int* pArray1D[4];

Ukazatel na pole
adresa prvnho prvku
int array[4]; int* pArray = array;

0x...

0x...

0x...

0x...

Pole ukazatel
pole poloek typu ukazatel
int* pArray1D[4]; int* pArray1D[4];
0x... 0x... 0x... 0x...

Do poloek pArray1D piadme pole


pArray1D[0] = array0; pArray1D[2] = array1;
int array0[3]; vod do C, 8.10.2013 [0] [1] [2] int array1[5]; [0] [1] [2] [3] [4]

PB071

Hlavikov soubory

vod do C, 8.10.2013

PB071

Modulrn programovn
Program typicky obsahuje kd, kter lze pout i v jinch programech
nap. vpoet faktorilu, vpis na obrazovku... sname se vyhnout cut&paste duplikaci kdu

Opakovan pouiteln sti kdu vylenme do samostatnch (knihovnch) funkc


nap. knihovna pro prci se vstupem a vstupem

Logicky souvisejc funkce meme vylenit do samostatnch soubor


deklarace knihovnch funkc do hlavikovho souboru (*.h) implementace do zdrojovho souboru (*.c)

vod do C, 8.10.2013

PB071

Hlavikov soubory rozhran (*.h)


Obsahuje typicky deklarace funkc
me ale i implementace
#include <stdio.h> int main(void) { printf("Hello world"); return 0; }

Uivatelv program pouv hlavikov soubor pomoc direktivy preprocesoru #include


#include <soubor.h> - hled se na standardnch cestch #include soubor.h hled se v aktulnch cestch #include ../tisk/soubor.h hled se o adres ve

Zpracovno bhem 1. fze pekladu


(preprocessing -E) obsah hlavikovho souboru vlo namsto #include ochrann makro #ifndef HEADERNAME_H
stdio.h

#ifndef _STDIO_H_ #define _STDIO_H_ int fprintf (FILE *__stream, const char *__format, ...)

// ...other functions
vod do C, 8.10.2013

#endif /* MYLIB_H_ */

PB071

Implementace funkc z rozhran


Obsahuje implementace funkc deklarovanch v hlavikovm souboru Uivatel vkld hlavikov soubor, nikoli implementan soubor
dobr praxe oddlen rozhran od konkrtnho proveden (implementace)

Dodaten soubor je nutn zahrnout do kompilace


gcc std=c99 .... o binary file1.c file2.c ... fileN.c hlavikov soubory explicitn nezahrnujeme, pro?
jsou ji zahrnuty ve zdrojku po zpracovn #include

vod do C, 8.10.2013

PB071

main.c #include " library.h" int main() { foo(5); } gcc E main.c main.i int foo(int a); int main() { foo(5); }

library.h int foo(int a);

library.c #include "library.h" int foo(int a) { return a + 2; }

gcc E, gcc-S, as library.s assembler code implementace funkce foo()

gcc S, as main.o assembler code adresa funkce foo() zatm nevyplnna

gcc main.o library.s main.exe spustiteln binrka


PB071

vodstd=c99 do C, 8.10.2013 gcc .... o binary main.c library.c

Poznmky k provazovn soubor


Soubory s implementac se typicky nevkldaj
tj. nepeme #include library.c pokud bychom tak udlali, vlo se cel implementace stejn jako bychom je napsali pmo do vkldajcho souboru

Principiln ale s takovm vloenm nen problm


preprocesor nerozliuje, jak soubor vkldme

Hlavikovm souborem slbme pekladai existenci funkc s danm prototypem


implementace v separtnm souboru, provazuje linker

Do hlavikovho souboru se snate umisovat jen opravdu potebn dal #include


pokud nkdo chce pout v hlavikov soubor, mus zrove pout i vechny ostatn #include

vod do C, 8.10.2013

PB071

Textov etzce

vod do C, 8.10.2013

PB071

Pole znak, etzce


Jak uchovat a tisknout jeden znak?
(umme, char) jak uchovat a tisknout cel slovo/vtu?

Nepraktick monost nezvisl znaky


char first = E; char second = T; printf(%c%c, first, second);

Praktitj monost pole znak


char sentence[10]; for (int i = 0; i < sizeof(sentence); i++) printf(%c, sentence[i]);

Jak ukonit/zkrtit existujc vtu?


\0 binrn nula - speciln znak jako konec

vod do C, 8.10.2013

PB071

etzce v C
etzce v C jsou pole znak ukonench binrn nulou "Hello world" H e l l o w o r l Dky ukonovac nule nemusme udrovat dlku pole
pole znak prochzme do vskytu koncov nuly etzec lze zkrtit posunutm nuly vznik riziko jejho pepsn (viz. dle)

\0

Deklarace etzc
char myString[100]; // max. 99 znak + koncov nula char myString2[] = Hello; // dlka pole dle konstanty, viz dle

Od C99 lze i irok (wide) znaky/etzce


wchar_t myWideString[100]; // max. 99 unicode znak + koncov nula
vod do C, 8.10.2013

PB071

etzcov konstanta v C
Je uzaven v vozovkch "" ("retezcova_konstanta") Je uloena v statick sekci programu Obsahuje koncovou nulu (binrn 0, zpis 0 nebo \0)
pozor, 0 NEN binrn nula (je to ascii znak s hodnotou 48)

Pklady
(pouze koncov 0) Hello (5 znak a koncov nula) Hello world Hello \t world

Konstanty pro irok (unicode) etzce maj pedazen L


L"Dsn avaouk" sizeof(L"Hello world") == sizeof("Hello world") * sizeof(wchar_t)

vod do C, 8.10.2013

PB071

Inicializace etzc
Pozor na rozdl inicializace etzec a pole
char answers[]={'a','y','n'}; nevlo koncovou nulu char answers2[]="ayn"; vlo koncovou nulu

Vimnte si rozdlu

Pozor na rozdl ukazatel a pole


char* myString = "Hello"; ukazatel na pozici etzcov konstanty char myString[50] = "Hello"; nov promnn typu pole, na zatku inicializovna na Hello

Pozor, etzcov konstanty nelze mnit


char* myString = "Hello"; myString[5] = 'y'; // patn vhodn pout const char* myString = "Hello";

vod do C, 8.10.2013

PB071

Inicializace etzc
Promnnou meme pi vytven inicializovat
doporuen postup, v opanm ppad je potenm obsahem pedchoz smet z pamti inicializace vrazem, nap. konstantou (int a = 5;)

Pole lze tak inicializovat


int array[5] = {1, 2}; zbvajc poloky bez explicitn hodnoty nastaveny na 0 array[0] == 1, array[1] == 2, array[2] == 0

etzec je pole znak ukonen nulou, jak inicializovat?


jako pole: char myString[] = {'W', 'o', 'r' , 'l' , 'd', 0}; pomoc konstanty: char myString2[] = "World";
sizeof(myString) == sizeof(Hello) == 6 x sizeof(char)

vod do C, 8.10.2013

PB071

Jak manipulovat s etzci?


1. Jako s ukazatelem
vyuit ukazatelov aritmetiky, opertory +, * ....

2. Jako s polem
vyuit opertoru []

3. Pomoc knihovnch funkc


hlavikov soubor <string.h> strcpy(), strcmp() ...

vod do C, 8.10.2013

PB071

Ukazatelov aritmetika s etzci


etzec ~ pole znak ~ ukazatel
char myString[] = Hello world; myString[4]; *(myString + 4) H myString + 6 => world
e l l o

myString (adresa) myString[3] (hodnota) w o r l d \0

Meme uchovvat ukazatel do prosted jinho etzce


char* myString2 = myString + 6; // myString2 contains world

myString2 (adresa)

Meme etzec ukonit vloenm nuly


myString[5] = 0;
H e l l o \0 w o r l d \0

Pozor, etzce v C nemn automatickou svou velikost


nedochz k automatickmu zvten etzce na potebnou dlku nekorektn pouit me vst k zpisu za konec pole

myString1 + myString2 je stn ukazatel etzc


nikoli jejich etzen (jak je nap. v C++ nebo Jav pro typ string)
vod do C, 8.10.2013

PB071

Knihovn funkce pro prci s etzci


Hlavikov soubor string.h
#include <string.h>

Kompletn dokumentace dostupn nap. na http://www.cplusplus.com/reference/clibrary/cstring/ Nejdleitj funkce


strcpy, strcat, strlen, strcmp, strchr, strstr... vpis etzce: puts(myString),printf(%s,myString);//stdio.h

Obecn pravidla
funkce pedpokldaj korektn C etzec ukonen nulou funkce modifikujc etzce (strcpy, strcat...) oekvaj dostaten pamov prostor v clovm etzci jinak zpis za koncem alokovanho msta a pokozen pi modifikaci vtinou dochz ke korektnmu umstn koncov nuly pozor na vjimky
vod do C, 8.10.2013

PB071

Jak st dokumentaci?
jmno funkce

deklarace funkce (funkn parametry, nvratov hodnota... popis chovn

detaily k parametrm, jejich oekvan tvar ukzka pouit, velmi pnosn pbuzn a souvisejc funkce, pnosn, pokud zobrazen funkce nespluje poadavky

Pevzato z http://www.cplusplus.com/reference/clibrary/cstring/strcpy/
vod do C, 8.10.2013

PB071

Nejdleitj funkce pro etzce


strlen(a) dlka etzce bez koncov nuly
strlen(Hello) == 5

strcpy(a,b) kopruje obsah etzce b do a


vrac ukazatel na zatek a a mus bt dostaten dlouh pro b

strcat(a,b) pipoj etzec b za a


nutn dlka a: strlen(a) + strlen(b) + 1; (koncov nula)

strcmp(a,b) porovn shodu a s b


vrac nulu, pokud jsou shodn (znaky i dlka), !0 jinak vrac > 0 pokud je a vt ne b, < 0 pokud je b > a
vod do C, 8.10.2013

PB071

Nejdleitj funkce pro etzce


strchr(a,c) hled vskyt znaku c v etzci a
pokud ano, tak vrac ukazatel na prvn vskyt c, jinak NULL

strstr(a,b) hled vskyt etzce b v etzci a


pokud ano, tak vrac ukazatel na prvn vskyt b, jinak NULL

Pro manipulaci se irokmi znaky jsou dostupn analogick funkce v hlavikovm souboru wchar.h
nzev funkce obsahuje wcs namsto str nap. wchar_t *wcscpy(wchar_t*, const wchar_t *);

vod do C, 8.10.2013

PB071

Testovn znak v etzci <ctype.h>

evzato z http://www.cplusplus.com/reference/clibrary/cctype/ a http://www.fi.muni.cz/usr/jkucera/pb071/sl4.htm PB071 vod doP C, 8.10.2013

ast problmy
nap. strcpy

char myString1[] = "Hello"; strcpy(myString1, "Hello world"); puts(myString1);

Nedostaten velk clov etzec Chybjc koncov nula


char myString2[] = "Hello"; myString2[strlen(myString2)] = '!'

nsledn funkce nad etzcem nefunguj korektn vznikne nap. nevhodnm pepisem (N+1 problm)

Nevloen koncov nuly


strncpy strlen
char myString3[] = "Hello"; strncpy(myString3, "Hello world", strlen(myString3));

Dlka/velikost etzce bez msta pro koncovou nulu if (myString4 == "Hello") { }


char myString4[] = "Hello"; char myString5[strlen(myString4)]; strcpy(myString4, myString5);

chybn, porovnv hodnotu ukazatel, nikoli obsah etzc nutno pout if (strcmp(myString, Hello) == 0) { }

Stn etzc pomoc + (st ukazatele namsto obsahu)


vod do C, 8.10.2013

PB071

Pole etzc
Pole ukazatel na etzce Typicky nepravohl (etzce jsou rzn dlouh) Pouit asto pro skupinu konstantnch etzc
nap. dny v tdnu char* dayNames[] = {"Pondeli", "Utery", "Streda"};

pole se temi polokami typu char* dayNames[0] ukazuje na konstantn etzec "Pondeli"

Co zpsob strcpy(dayNames[0], "Ctvrtek");?


zapisujeme do pamti s konstantnm etzcem pravdpodobn zpsob pd, je vhodn nechat kontrolovat pekladaem (klov slovo const viz. dle)

vod do C, 8.10.2013

PB071

Demo problmy s etzci


void demoStringProblems() { char myString1[] = "Hello"; strcpy(myString1, "Hello world"); puts(myString1);

char myString2[] = "Hello"; myString2[strlen(myString2)] = '!'; puts(myString2); char myString3[] = "Hello"; strncpy(myString3, "Hello world", sizeof(myString3)); char myString4[] = "Hello"; char myString5[strlen(myString4)]; strcpy(myString4, myString5); char myString6[] = "Hello"; if (myString6 == "Hello") { } char* dayNames[] = {"Pondeli", "Utery", "Streda"}; puts(dayNames[0]); strcpy(dayNames[0], "Ctvrtek"); } vod do C, 8.10.2013

PB071

Klov slovo const

vod do C, 8.10.2013

PB071

Klov slovo const


Zavedeno pro zven robustnosti kdu proti nezmrnm implementanm chybm Motivace:
potebujeme oznait promnnou, kter nesm bt zmnna typicky konstanta, nap. poet msc v roce

A chceme mt kontrolu pmo od pekladae! Explicitn vyznaujeme promnnou, kter nebude mnna
jej hodnota by nemla bt mnna argument, kter nem bt ve funkci mnn
vod do C, 8.10.2013

PB071

Klov slovo const - ukzka


void konstConstantDemo(const int* pParam) { //const int a, b = 0; // error, uninitialized const 'a' const int numMonthsInYear = 12; printf("Number of months in year: %d", numMonthsInYear); numMonthsInYear = 13; // error: assignment of read-only variable *pParam = 1; // error: assignment of read-only location }

vod do C, 8.10.2013

PB071

Klov slovo const


Pouvejte co nejastji
zlepuje typovou kontrolu a celkovou robustnost kontrola e omylem nemnme konstantn objekt umouje lep optimalizaci pekladaem dv dalmu programtorovi dobrou pedstavu, jak bude hodnota konstantn promnn v mst pouit

Promnn s const jsou lokln v danm souboru Pozor na const int a, b;


const je pouze a, nikoli b radji kad promnn na samostatnm dku
vod do C, 8.10.2013

PB071

etzcov literly
printf("ahoj");
etzec ahoj je uloen ve statick sekci je typu char*, ale zrove ve statick sekci
pi zpisu pravdpodobn pd programu
char* konstReturnValueDemo() {return "Unmodifiable string"; } const char* konstReturnValueDemo2() {return "Unmodifiable string"; } void demoConst() { char* value = konstReturnValueDemo(); // read-only memory write - problem value[1] = 'x'; char* value2 = konstReturnValueDemo2(); // error: invalid conversion }

Pouvejte tedy const char*


peklada hld pokus o zpis do statick sekce
const char* dayNames[] = {"Pondeli", "Utery", "Streda"};
vod do C, 8.10.2013

PB071

const ukazatel
Konstantn je pouze hodnota oznaen promnn
plat i pro ukazatel vetn dereference int value = 10; const int* pValue = &value;

Nen konstantn objekt promnnou odkazovan


const je plytk konstantn promnnou lze modifikovat pes nekonstantn ukazatel const int value = 10;
const int* pValue = &value; int* pValue2 = &value; value = 10; // error *pValue = 10; // error *pValue2 = 10; // possible
vod do C, 8.10.2013

PB071

Pedn const ukazatele do funkce


void foo(const int* carray) { carray[0] = 1; // error: assignment of read-only location '*carray' int* tmp = carray; //warning: initialization discards qualifiers //from pointer target type tmp[0] = 1; // possible, but unwanted! (array was const, tmp is not) } int main() { int array[10]; foo(array); return 0; }

vod do C, 8.10.2013

PB071

Shrnut
Pole nutn chpat souvislost s ukazatelem etzce pozor na koncovou nulu Pole a etzce pozor na nechtn pepis pamti const zlepuje itelnost kdu a celkovou bezpenost

vod do C, 8.10.2013

PB071

You might also like