72
Osnove računarstva 2015/2016 Čudnovate stvari Čudnovate stvari (sve što vam niko nije rekao o (sve što vam niko nije rekao o pokazivačima i stringovima) pokazivačima i stringovima) Doc. dr Vedran Ljubović Univerzitet u Sarajevu Elektrotehnički fakultet Sarajevo

P17 Cudnovate Stvari-expanded

Embed Size (px)

DESCRIPTION

C Program

Citation preview

Page 1: P17 Cudnovate Stvari-expanded

Osnove računarstva 2015/2016

Čudnovate stvariČudnovate stvari(sve što vam niko nije rekao o (sve što vam niko nije rekao o

pokazivačima i stringovima)pokazivačima i stringovima)

Doc. dr Vedran Ljubović

Univerzitet u SarajevuElektrotehnički fakultet Sarajevo

Page 2: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 2

Deklaracije stringova

● Koja je razlika između:

char s[10] = "Test";

char s[] = "Test";

char* s = "Test";

Page 3: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 3

Deklaracije stringova

● Niz od 10 elemenata:

char s[10] = "Test";

... 250 251 252 253 254 255 256 257 258 259 260 ...

... T e s t \0 ...

Page 4: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 4

Deklaracije stringova

● Niz od 5 elemenata:

char s[] = "Test";

... 250 251 252 253 254 255 256 257 258 259 260 ...

... T e s t \0 ...

Page 5: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 5

Deklaracije stringova

● Pokazivač na literal:

char* s = "Test";

... 250 251 252 253 254 255 256 257 258 259 260 ...

... 256 T e s t \0 ...

Page 6: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 6

Deklaracije stringova

● Pokazivač na literal:

char* s = "Test";● Ovo je jedini način u C-u da deklarišemo pokazivač na

literal.

● Bitno je da se ovakav string ne može mijenjati! Npr. želimo da spojimo dvije riječi sa razmakom između:

printf("%s", spoji(rijec1, spoji(" ", rijec2)));

Page 7: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 7

Deklaracije stringova

● Pokazivač na literal:

char* s = "Test";● Ovo je jedini način u C-u da deklarišemo pokazivač na

literal.

● Bitno je da se ovakav string ne može mijenjati! Npr. želimo da spojimo dvije riječi sa razmakom između:

printf("%s", spoji(rijec1, spoji(" ", rijec2)));

Page 8: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 8

Deklaracije stringova

● Pokazivač na literal:

char* s = "Test";● Ovo je jedini način u C-u da deklarišemo pokazivač na

literal.

● Bitno je da se ovakav string ne može mijenjati! Npr. želimo da spojimo dvije riječi sa razmakom između:

printf("%s", spoji(rijec1, spoji(" ", rijec2)));

Krahiranje, jerje " " literal

Page 9: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 9

Deklaracije stringova

● Pokazivač na literal:

char* s = "Test";● Ovo je jedini način u C-u da deklarišemo pokazivač na

literal.

● Bitno je da se ovakav string ne može mijenjati! Npr. želimo da spojimo dvije riječi sa razmakom između:

printf("%s", spoji(rijec1, spoji(" ", rijec2)));

treba ovako:char razmak[100] = " ";printf("%s", spoji(rijec1, spoji(razmak, rijec2)));

Page 10: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 10

Višestruki pokazivači

● Dvostruki pokazivač je pokazivač koji pokazuje na pokazivač:

int broj=5;int* p = &broj;int** dp = &p;

... 250 251 252 253 254 255 256 257 258 259 260 ...

... 5 251 254 ...

p dpbroj

Page 11: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 11

Višestruki pokazivači

● Trostruki pokazivač je pokazivač koji pokazuje na dvostruki pokazivač itd.

int broj=5;int* p = &broj;int** dp = &p;int*** tp = &dp;

... 250 251 252 253 254 255 256 257 258 259 260 ...

... 5 251 259 254 ...

p dpbroj tp

Page 12: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 12

Da li je niz isto što i pokazivač?

● Ime niza nije isto što i pokazivač na prvi element niza!

● Ali ime niza se po potrebi konvertuje u pokazivač na prvi element niza:

int niz[3];int* p = niz;

● Izuzetak je prototip funkcije gdje int niz[] je zaista isto što i int* niz (samo druga sintaksa).

Page 13: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 13

Niz pokazivača

● Moguće je deklarisati niz elemenata bilo kojeg tipa, pa i pokazivača:

float* niz[10];

● Primjer:

char* datum[3] = {"19.", "Januar", "2016."};printf("%s", datum[1]);

... 250 251 252 253 254 255 256 257 258 259 260 ...

... 253 257 264 1 9 . \0 J a n u ...

... 261 262 263 264 265 266 267 268 269 270 271 ...

... a r \0 2 0 1 6 . \0 ...

Page 14: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 14

Niz pokazivača

● Moguće je deklarisati niz elemenata bilo kojeg tipa, pa i pokazivača:

float* niz[10];

● Primjer:

char* datum[3] = {"19.", "Januar", "2016."};printf("%s", datum[1]);

... 250 251 252 253 254 255 256 257 258 259 260 ...

... 253 257 264 1 9 . \0 J a n u ...

... 261 262 263 264 265 266 267 268 269 270 271 ...

... a r \0 2 0 1 6 . \0 ...

Ispisaće: Januar

Page 15: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 15

Niz pokazivača

● Moguće je deklarisati niz elemenata bilo kojeg tipa, pa i pokazivača:

float* niz[10];

● Primjer:

char* datum[3] = {"19.", "Januar", "2016."};printf("%s", datum[1]);

... 250 251 252 253 254 255 256 257 258 259 260 ...

... 253 257 264 1 9 . \0 J a n u ...

... 261 262 263 264 265 266 267 268 269 270 271 ...

... a r \0 2 0 1 6 . \0 ...

Niz pokazivača "datum"

Ispisaće: Januar

Page 16: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 16

Niz pokazivača

● Moguće je deklarisati niz elemenata bilo kojeg tipa, pa i pokazivača:

float* niz[10];

● Primjer:

char* datum[3] = {"19.", "Januar", "2016."};printf("%s", datum[1]);

... 250 251 252 253 254 255 256 257 258 259 260 ...

... 253 257 264 1 9 . \0 J a n u ...

... 261 262 263 264 265 266 267 268 269 270 271 ...

... a r \0 2 0 1 6 . \0 ...

Niz pokazivača "datum"

Literali se nalaze"negdje" u memoriji

Ispisaće: Januar

Page 17: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 17

Niz pokazivača vs. matrica

● Ovako deklarisan niz pokazivača nije isto što i matrica:

char mat[3][10] = {"19.", "Januar", "2016."};printf("%s", mat[1]);

... 250 251 252 253 254 255 256 257 258 259 260 ...

... 1 9 . \0 J ...

... 261 262 263 264 265 266 267 268 269 270 271 ...

... a n u a r \0 2 0 ...

Page 18: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 18

Niz pokazivača vs. matrica

● Ovako deklarisan niz pokazivača nije isto što i matrica:

char mat[3][10] = {"19.", "Januar", "2016."};printf("%s", mat[1]);

... 250 251 252 253 254 255 256 257 258 259 260 ...

... 1 9 . \0 J ...

... 261 262 263 264 265 266 267 268 269 270 271 ...

... a n u a r \0 2 0 ...

Nema nizapokazivača

Page 19: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 19

Niz pokazivača vs. matrica

● Ime niza pokazivača konvertuje se u dvostruki pokazivač:

char* datum[3] = {"19.", "Januar", "2016."};char** dp = datum;printf("%s", dp[1]);

● Ime matrice se konvertuje u "pokazivač na niz":

char mat[3][10] = {"19.", "Januar", "2016."};char (*ap)[10] = mat;printf("%s", ap[1]);

char** dp = mat;

Page 20: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 20

Niz pokazivača vs. matrica

● Ime niza pokazivača konvertuje se u dvostruki pokazivač:

char* datum[3] = {"19.", "Januar", "2016."};char** dp = datum;printf("%s", dp[1]);

● Ime matrice se konvertuje u "pokazivač na niz":

char mat[3][10] = {"19.", "Januar", "2016."};char (*ap)[10] = mat;printf("%s", ap[1]);

char** dp = mat;

Upozorenje: initialization from incompatible pointer type

Page 21: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 21

Niz pokazivača vs. matrica

● Ime niza pokazivača konvertuje se u dvostruki pokazivač:

char* datum[3] = {"19.", "Januar", "2016."};char** dp = datum;printf("%s", dp[1]);

● Ime matrice se konvertuje u "pokazivač na niz":

char mat[3][10] = {"19.", "Januar", "2016."};char (*ap)[10] = mat;printf("%s", ap[1]);

char** dp = mat;

Upozorenje: initialization from incompatible pointer type

Tip promjenljive ap je"pokazivač na niz od

10 elemenata tipa char"

Page 22: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 22

Niz pokazivača vs. matrica

● Ime niza pokazivača konvertuje se u dvostruki pokazivač:

char* datum[3] = {"19.", "Januar", "2016."};char** dp = datum;printf("%s", dp[1]);

● Ime matrice se konvertuje u "pokazivač na niz":

char mat[3][10] = {"19.", "Januar", "2016."};char (*ap)[10] = mat;printf("%s", ap[1]);

char** dp = mat;

Upozorenje: initialization from incompatible pointer type

Tip promjenljive ap je"pokazivač na niz od

10 elemenata tipa char"Takav tip nam je potrebanda bismo znali da je ap+1

za 10 bajta veće od ap

Page 23: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 23

Niz pokazivača vs. matrica

● Ime niza pokazivača konvertuje se u dvostruki pokazivač:

char* datum[3] = {"19.", "Januar", "2016."};char** dp = datum;printf("%s", dp[1]);

● Ime matrice se konvertuje u "pokazivač na niz":

char mat[3][10] = {"19.", "Januar", "2016."};char (*ap)[10] = mat;printf("%s", ap[1]);

char** dp = mat;

Upozorenje: initialization from incompatible pointer type

Tip promjenljive ap je"pokazivač na niz od

10 elemenata tipa char"Takav tip nam je potrebanda bismo znali da je ap+1

za 10 bajta veće od ap

Zagrade su potrebnekako bi se razlikovalo

od niza od 10 pokazivača

Page 24: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 24

Slanje matrice u funkciju

● Kada šaljemo niz u funkciju mi ustvari šaljemo pokazivač na prvi član niza (adresu).

● A kada šaljemo matricu, ustvari šaljemo pokazivač na niz koji predstavlja jedan red matrice.

● Mora se navesti jedna dimenzija matrice!

– Dakle funkcije koje rade sa matricama ne mogu biti potpuno univerzalne.

– Zbog toga radije koristimo nizove pokazivača.

Page 25: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 25

Slanje matrice u funkciju

● Primjer:

#include <stdio.h>int primimatricu(int (*mat)[10], int redova) {

printf("%d", mat[0][0]);}int main() {

int matrica[10][10] = {{15}};primimatricu(matrica, 10);return 0;

}

Page 26: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 26

Parametri funkcije main

● Funkcija main ima dva oblika. Do sada smo uvijek koristili oblik bez parametara. Pored toga postoji oblik sa dva parametra:

int main(int argc, char** argv)

● Svakom programu se mogu poslati parametri putem komandne linije.

● argc je broj parametara, a argv je pokazivač na prvi član niza pokazivača na stringove koji predstavljaju tekst parametara.

Page 27: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 27

Parametri funkcije main

● Primjer:

int main(int argc, char** argv) {int i;printf("Program ima %d parametara.\n", argc);printf("Ti parametri su:\n");for (i=0; i<argc; i++)

printf("%s\n", argv[i]);return 0;

}

● Prvi parametar je uvijek ime samog programa.

Page 28: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 28

Primjer: sortiranje

● Napisati funkciju koja abecedno sortira niz stringova.

– Najprije moramo definisati: da li funkcija prima matricu tipa char ili niz pokazivača tipa char?

– Deklaracija funkcije bi izgledala:void sortiraj(char** niz, int n)

void sortiraj(char(*mat)[100], int n)

● Koristićemo Selection sort koji smo obradili na kraju poglavlja 10.

Page 29: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 29

Primjer: sortiranje

● Selection sort (Predavanje 10):

for (i=0; i<n; i++) {min=i;for (j=i+1; j<n; j++) {

if (niz[j] < niz[min])min = j;

}

temp = niz[i];niz[i] = niz[min];niz[min] = temp;

}

Page 30: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 30

Primjer: sortiranje

● Selection sort (Predavanje 10):

for (i=0; i<n; i++) {min=i;for (j=i+1; j<n; j++) {

if (niz[j] < niz[min])min = j;

}

temp = niz[i];niz[i] = niz[min];niz[min] = temp;

}

Ne možemo ovakoporediti stringove

Page 31: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 31

Primjer: sortiranje

● Selection sort (Predavanje 10):

for (i=0; i<n; i++) {min=i;for (j=i+1; j<n; j++) {

if (niz[j] < niz[min])min = j;

}

temp = niz[i];niz[i] = niz[min];niz[min] = temp;

}

Ne možemo ovakoporediti stringove

Dodjela nizova neradi znakom =

Page 32: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 32

Primjer: sortiranje

● Selection sort (Predavanje 10):

for (i=0; i<n; i++) {min=i;for (j=i+1; j<n; j++) {

if (niz[j] < niz[min])min = j;

}

temp = niz[i];niz[i] = niz[min];niz[min] = temp;

}

Ne možemo ovakoporediti stringove

Dodjela nizova neradi znakom =

Trebamo koristitifunkcije strcmp

i strcpy

Page 33: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 33

Primjer: sortiranje

void sortiraj(char** niz, int n) {int i, j, min, temp;for (i=0; i<n; i++) {

min=i;for (j=i+1; j<n; j++) {

if (strcmp(niz[j],niz[min]) < 0)min = j;

}

temp = niz[i];niz[i] = niz[min];niz[min] = temp;

}}

Page 34: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 34

Primjer: sortiranje

void sortiraj(char** niz, int n) {int i, j, min, temp;for (i=0; i<n; i++) {

min=i;for (j=i+1; j<n; j++) {

if (strcmp(niz[j],niz[min]) < 0)min = j;

}

temp = niz[i];niz[i] = niz[min];niz[min] = temp;

}}

???

Page 35: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 35

Primjer: sortiranje

● U slučaju niza pokazivača možemo samo razmijeniti pokazivače:

D a n a s \0

j e \0

b i o \0

l i j e p \0

d a n \0

Page 36: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 36

Primjer: sortiranje

● U slučaju niza pokazivača možemo samo razmijeniti pokazivače:

D a n a s \0

j e \0

b i o \0

l i j e p \0

d a n \0

Page 37: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 37

Primjer: sortiranje

void sortiraj(char** niz, int n) {int i, j, min; char* temp;for (i=0; i<n; i++) {

min=i;for (j=i+1; j<n; j++) {

if (strcmp(niz[j],niz[min]) < 0)min = j;

}

temp = niz[i];niz[i] = niz[min];niz[min] = temp;

}}

Page 38: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 38

Primjer: sortiranje

void sortiraj(char** niz, int n) {int i, j, min; char* temp;for (i=0; i<n; i++) {

min=i;for (j=i+1; j<n; j++) {

if (strcmp(niz[j],niz[min]) < 0)min = j;

}

temp = niz[i];niz[i] = niz[min];niz[min] = temp;

}}

Razmijenili smopokazivače u nizu

Page 39: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 39

Ključna riječ const

● Pored simboličkih konstanti koje smo deklarisali preprocesorskom direktivom #define postoje i konstante koje se deklarišu tako što prije tipa navede ključna riječ const

const int x=5;● Pošto je x konstantno ne može se mijenjati.

● Ipak treba napomenuti da x iznad ustvari nije konstanta! U programskom jeziku C to je promjenljiva koja se ne može mijenjati direktno (ali može preko pokazivača).

Page 40: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 40

Usporedba konstanti

● #define konstante se bukvalno zamjenjuju u kodu prije kompajliranja, tako da ne zauzimaju nikakvu memoriju. S druge strane, dobar kompajler će isto napraviti i sa const promjenljivim ako je moguće.

● #define konstante su uvijek globalne, a const imaju opseg.

● #define konstante nemaju eksplicitno definisan tip. Njihov tip ovisi od vrijednosti koja im je dodijeljena.

● #define se ne može promijeniti preko pokazivača.

Page 41: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 41

Konstantni pokazivači

char* const a = s;

● Ovim je deklarisan konstantni pokazivač p koji sada može pokazivati samo na s i ni na šta drugo (ne može se pomjerati).

const char* b = s;

● Pokazivač koji pokazuje na konstantne podatke. Pokazivač se može usmjeriti negdje drugo, ali se ono na šta on pokazuje ne može mijenjati. Primjer:

*a = x; /* Moze */a = &x; /* Ne moze */*b = x; /* Ne moze */b = &x; /* Moze */

Page 42: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 42

Konstantni pokazivači

const char* const c = s;

● Sa ovakvom deklaracijom ne može se mijenjati ni adresa pohranjena u pokazivaču ni ono što je na toj adresi.

● Pokazivač na konstante podatke se često koristi kada se u funkciju šalje niz ali se želi zabraniti da se niz mijenja u funkciji. Npr.

int dajmax(const int* niz, int vel)

Na ovaj način autori funkcije nas obavještavaju da se u funkciji neće promijeniti članovi niza.

● Ova ograničenja se mogu zaobići konverzijom (cast).

Page 43: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 43

Konstantni pokazivači

● U nekim kompajlerima možete dobiti upozorenje ako pridružujete string literal pokazivaču koji nije konstantan:

char* s = "Test";

Konkretno ovo se dešava sa C++ kompajlerom. Treba pisati:

const char* s = "Test";

● Također ako očekujete da se funkcija može pozivati sa literalom trebali biste navesti const char* kao tip parametra.

Page 44: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 44

Pokazivači na funkcije

● Moguće je deklarisati pokazivač koji pokazuje na funkciju. To je korisno kako bi se funkciji mogla proslijediti druga funkcija kao parametar.

Page 45: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 45

void pokazivač

● Moguće je definisati pokazivače na sve poznate tipove u C-u, pa i nizove (što smo vidjeli ranije).

● Pored toga moguće je definisati generički pokazivač void* za koji nije poznat tip vrijednosti na koju pokazuje.

void* p;

● Koristi se kada tip nije unaprijed poznat nego će kasnije biti određen.

● Nad void* nije moguće primjenjivati pokazivačku aritmetiku jer se ne može znati za koliko bajta treba pomjeriti pokazivač.

Page 46: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 46

void pokazivač

● Primjer:

void* p;...if (tip == INT_TIP)

printf("%d", *(int*)p);

● Prije upotrebe void* moramo pretvoriti (cast) u neki drugi tip.

Page 47: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 47

void pokazivač

● Primjer:

void* p;...if (tip == INT_TIP)

printf("%d", *(int*)p);

● Prije upotrebe void* moramo pretvoriti (cast) u neki drugi tip.

Konvertujemo upokazivač na int

Page 48: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 48

void pokazivač

● Primjer:

void* p;...if (tip == INT_TIP)

printf("%d", *(int*)p);

● Prije upotrebe void* moramo pretvoriti (cast) u neki drugi tip.

Tako dobiveni pokazivač dereferenciramo kako bismo

dobili cijeli broj

Page 49: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 49

Dinamička alokacija memorije

● Kako da dobijemo niz stvarno proizvoljne veličine? Pomoću dinamičke alokacije!

● Funkcija za dinamičku alokaciju je malloc i nalazi se u biblioteci stdlib.h

● Funkcija ima jedan parametar – broj bajta koliko treba zauzeti u memoriji, a vraća void pokazivač na zauzetu memoriju.

– Npr. ako nam treba niz od 10 vrijednosti tipa int, potrebno nam je 40 bajta.

– Da bi kod radio na različitim platformama pišemo 10*sizeof(int)

Page 50: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 50

sizeof operator

● Jedan od operatora u programskom jeziku C je sizeof unarni operator.

● Daje veličinu u memoriji vrijednosti sa desne strane

int niz[] = { 7, 5, 0, 3, 7, 2 };printf("%d", sizeof niz);

● Ako se u zagradama navede tip, daje veličinu tog tipa

printf("%d", sizeof(double));

● Operator sizeof vraća vrijednost tipa size_t koji je na PC-u ekvivalentan long unsigned int (zbog čega gornje naredbe daju upozorenje).

Page 51: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 51

sizeof operator

● Jedan od operatora u programskom jeziku C je sizeof unarni operator.

● Daje veličinu u memoriji vrijednosti sa desne strane

int niz[] = { 7, 5, 0, 3, 7, 2 };printf("%d", sizeof niz);

● Ako se u zagradama navede tip, daje veličinu tog tipa

printf("%d", sizeof(double));

● Operator sizeof vraća vrijednost tipa size_t koji je na PC-u ekvivalentan long unsigned int (zbog čega gornje naredbe daju upozorenje).

Ispisaće: 24

Page 52: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 52

Curenje memorije

● Sva memorija zauzeta funkcijom malloc mora se osloboditi funkcijom free.

● Ako se memorija ne oslobodi dolazi do curenja memorije (eng. memory leak)

– Program radi ispravno ali zauzima sve više i više memorije što izaziva postepeno usporenje računara.

● Po završetku programa memorija se oslobađa, ali treba se vježbati da se sva zauzeta memorija oslobodi zbog programa koji dugo stoje pokrenuti.

Page 53: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 53

Primjer dinamičke alokacije

#include <stdio.h>#include <stdlib.h>int main() {

int vel, i;int* niz;printf("Unesite velicinu niza: ");scanf("%d", &vel);niz = (int*)malloc(vel * sizeof(int));printf("Unesite clanove niza: ");for (i=0; i<vel; i++)

scanf("%d", niz[i]);/* ... radimo kao sa obicnim nizom */free(niz);return 0;

}

Page 54: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 54

Primjer 2

● Zadatak: Program omogućuje korisniku da unese niz od najviše 100 riječi pri čemu svaka riječ ima najviše 99 slova. Unos se završava sa dva minusa "--"...

char rijeci[100][100];

● Deklaracijom iznad smo zauzeli 10000 bajta od čega je većina neiskorišteno.

● Da bismo to izbjegli, koristimo niz pokazivača pri čemu svaki pokazuje na dinamički alocirani string koji je tačno onoliko velik koliko je potrebno.

Page 55: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 55

Primjer 2

#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {

int i, vel=0;char* rijeci[100];printf("Unesite rijeci (-- za kraj): ");do {

char rijec[100];unesi(rijec, 100);rijeci[vel] = (char*)malloc(strlen(rijec) + 1);strcpy(rijeci[vel++], rijec);

} while (strcmp(rijec, "--") != 0);/* ... */for (i=0; i<vel; i++)

free(rijeci[i]);return 0;

}

Page 56: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 56

Primjer 2

#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {

int i, vel=0;char* rijeci[100];printf("Unesite rijeci (-- za kraj): ");do {

char rijec[100];unesi(rijec, 100);rijeci[vel] = (char*)malloc(strlen(rijec) + 1);strcpy(rijeci[vel++], rijec);

} while (strcmp(rijec, "--") != 0);/* ... */for (i=0; i<vel; i++)

free(rijeci[i]);return 0;

}

Niz od 100 pokazivača tipa char

Page 57: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 57

Primjer 2

#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {

int i, vel=0;char* rijeci[100];printf("Unesite rijeci (-- za kraj): ");do {

char rijec[100];unesi(rijec, 100);rijeci[vel] = (char*)malloc(strlen(rijec) + 1);strcpy(rijeci[vel++], rijec);

} while (strcmp(rijec, "--") != 0);/* ... */for (i=0; i<vel; i++)

free(rijeci[i]);return 0;

}

Niz od 100 pokazivača tipa char

Unosimo riječ u nizod 100 elemenata

Page 58: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 58

Primjer 2

#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {

int i, vel=0;char* rijeci[100];printf("Unesite rijeci (-- za kraj): ");do {

char rijec[100];unesi(rijec, 100);rijeci[vel] = (char*)malloc(strlen(rijec) + 1);strcpy(rijeci[vel++], rijec);

} while (strcmp(rijec, "--") != 0);/* ... */for (i=0; i<vel; i++)

free(rijeci[i]);return 0;

}

Niz od 100 pokazivača tipa char

Unosimo riječ u nizod 100 elemenata Dinamički alociramo onoliko

bajta koliko je dugačka riječ + 1

Page 59: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 59

Primjer 2

#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {

int i, vel=0;char* rijeci[100];printf("Unesite rijeci (-- za kraj): ");do {

char rijec[100];unesi(rijec, 100);rijeci[vel] = (char*)malloc(strlen(rijec) + 1);strcpy(rijeci[vel++], rijec);

} while (strcmp(rijec, "--") != 0);/* ... */for (i=0; i<vel; i++)

free(rijeci[i]);return 0;

}

Niz od 100 pokazivača tipa char

Unosimo riječ u nizod 100 elemenata Dinamički alociramo onoliko

bajta koliko je dugačka riječ + 1

Dodajemo pokazivač nanovu memoriju u niz

Page 60: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 60

Primjer 2

#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {

int i, vel=0;char* rijeci[100];printf("Unesite rijeci (-- za kraj): ");do {

char rijec[100];unesi(rijec, 100);rijeci[vel] = (char*)malloc(strlen(rijec) + 1);strcpy(rijeci[vel++], rijec);

} while (strcmp(rijec, "--") != 0);/* ... */for (i=0; i<vel; i++)

free(rijeci[i]);return 0;

}

Niz od 100 pokazivača tipa char

Unosimo riječ u nizod 100 elemenata Dinamički alociramo onoliko

bajta koliko je dugačka riječ + 1

Dodajemo pokazivač nanovu memoriju u niz

Kopiramo riječ iz privremenogstringa u alociranu memoriju

Page 61: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 61

Primjer 2

#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {

int i, vel=0;char* rijeci[100];printf("Unesite rijeci (-- za kraj): ");do {

char rijec[100];unesi(rijec, 100);rijeci[vel] = (char*)malloc(strlen(rijec) + 1);strcpy(rijeci[vel++], rijec);

} while (strcmp(rijec, "--") != 0);/* ... */for (i=0; i<vel; i++)

free(rijeci[i]);return 0;

}

Niz od 100 pokazivača tipa char

Unosimo riječ u nizod 100 elemenata Dinamički alociramo onoliko

bajta koliko je dugačka riječ + 1

Dodajemo pokazivač nanovu memoriju u niz

Kopiramo riječ iz privremenogstringa u alociranu memoriju

Po završetku rada trebaosloboditi zauzetu memoriju

Page 62: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 62

Primjer 2

#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {

int i, vel=0;char* rijeci[100];printf("Unesite rijeci (-- za kraj): ");do {

char rijec[100];unesi(rijec, 100);rijeci[vel] = (char*)malloc(strlen(rijec) + 1);strcpy(rijeci[vel++], rijec);

} while (strcmp(rijec, "--") != 0);/* ... */for (i=0; i<vel; i++)

free(rijeci[i]);return 0;

}

Niz od 100 pokazivača tipa char

Unosimo riječ u nizod 100 elemenata Dinamički alociramo onoliko

bajta koliko je dugačka riječ + 1

Dodajemo pokazivač nanovu memoriju u niz

Kopiramo riječ iz privremenogstringa u alociranu memoriju

Po završetku rada trebaosloboditi zauzetu memoriju

Mogli smo dinamički alocirati i sam niz pokazivača!

Page 63: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 63

Primjer 2

#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {

int i, vel=0;char** rijeci;printf ("Unesite broj rijeci: ");scanf("%d", &vel);rijeci = (char**)malloc(vel * sizeof(char*));printf("Unesite rijeci (-- za kraj): ");/* ... */for (i=0; i<vel; i++)

free(rijeci[i]);free(rijeci);return 0;

}

Page 64: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 64

Primjer 2

#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {

int i, vel=0;char** rijeci;printf ("Unesite broj rijeci: ");scanf("%d", &vel);rijeci = (char**)malloc(vel * sizeof(char*));printf("Unesite rijeci (-- za kraj): ");/* ... */for (i=0; i<vel; i++)

free(rijeci[i]);free(rijeci);return 0;

}

Prvo treba osloboditičlanove niza...

Page 65: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 65

Primjer 2

#include <stdio.h>#include <stdlib.h>#include <string.h>int main() {

int i, vel=0;char** rijeci;printf ("Unesite broj rijeci: ");scanf("%d", &vel);rijeci = (char**)malloc(vel * sizeof(char*));printf("Unesite rijeci (-- za kraj): ");/* ... */for (i=0; i<vel; i++)

free(rijeci[i]);free(rijeci);return 0;

}

Prvo treba osloboditičlanove niza...

...pa onda i sam niz!

Page 66: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 66

strncat i strncpy

● Funkcije iz biblioteke string.h strcat i strcpy smatraju se nesigurnim. Primjer:

void funkcija(char* s) {char pomocni[100];strcpy(pomocni, s); /* Primljeni string ce imati

najvise 100 znakova */...

● Šta ako primljeni string bude ipak imao više od 100 znakova???

● U C++ programskom jeziku ove funkcije se smatraju za prevaziđene (deprecated) i dobićete upozorenje ako ih koristite.

Page 67: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 67

strncat i strncpy

● Funkcije iz biblioteke string.h strcat i strcpy smatraju se nesigurnim. Primjer:

void funkcija(char* s) {char pomocni[100];strcpy(pomocni, s); /* Primljeni string ce imati

najvise 100 znakova */...

● Šta ako primljeni string bude ipak imao više od 100 znakova???

● U C++ programskom jeziku ove funkcije se smatraju za prevaziđene (deprecated) i dobićete upozorenje ako ih koristite.

Korisnik koji može funkcijiposlati više od 100 karaktera

može pisati po memoriji šta želi!

Page 68: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 68

strncat i strncpy

● Umjesto njih koristite strncat i strncpy. Primjer:void funkcija(char* s) {

char pomocni[100];strncpy(pomocni, s, 100);pomocni[99] = '\0';...

Iz stringa s u string pomoćni će biti kopirano najviše 100 karaktera. Primjer strncat:

void funkcija(char* s1, char* s2) {char pomocni[100];strncpy(pomocni, s1, 100);pomocni[99] = '\0';strncat(pomocni, s2, 99-strlen(s1));...

Page 69: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 69

strtok funkcija

● Još jedna korisna funkcija u biblioteci string.h je strtok (skraćeno od string tokenizer).

● Ova funkcija "sjecka" primljeni string po nekom iz niza karaktera.

● Kada prvi put pozovemo funkciju šaljemo joj string i niz delimitera (razdjelnika). Svaki sljedeći put šaljemo nul-pokazivač kao prvi parametar kako bismo označili da i dalje radimo sa istim stringom, a dobićemo pokazivač na sljedeći podstring.

– Ovo je primjer bibliotečne funkcije koja ne daje uvijek isti rezultat za iste parametre (koristi statičke promjenljive).

– Funkcija strtok uništava polazni string jer ubacuje \0 na mjestu svakog delimitera.

Page 70: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 70

strtok funkcija

● Primjer:

#include <stdio.h>#include <string.h>int main() {

char tekst[] = " Ovo, za pocetak,, je neki primjer.";

char* p;p = strtok(tekst, " .,");while (p != NULL) {

printf("Rijec: %s\n", p);p = strtok(NULL, " .,");

}return 0;

}

Page 71: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 71

strtok funkcija

● Primjer:

#include <stdio.h>#include <string.h>int main() {

char tekst[] = " Ovo, za pocetak,, je neki primjer.";

char* p;p = strtok(tekst, " .,");while (p != NULL) {

printf("Rijec: %s\n", p);p = strtok(NULL, " .,");

}return 0;

}

Cjepkamo string po znakovima razmak, tačka i zarez

Page 72: P17 Cudnovate Stvari-expanded

20.12.2015 Vedran Ljubović * OR15 * P17: Čudnovate stvari 72

strtok funkcija

● Primjer:

#include <stdio.h>#include <string.h>int main() {

char tekst[] = " Ovo, za pocetak,, je neki primjer.";

char* p;p = strtok(tekst, " .,");while (p != NULL) {

printf("Rijec: %s\n", p);p = strtok(NULL, " .,");

}return 0;

}

Cjepkamo string po znakovima razmak, tačka i zarez

Nakon posljednje riječidobićemo NULL