47
Programski jezik C - pokazivači

Programski jezik C - pokazivači

  • Upload
    others

  • View
    17

  • Download
    3

Embed Size (px)

Citation preview

Page 1: Programski jezik C - pokazivači

Programski jezik C -pokazivači

Page 2: Programski jezik C - pokazivači

Pokazivači i adrese Memorija računara organizovana je u niz uzastopnih bajtova Memoriji se pristupa preko adresa Adrese su brojevi koji se najčešće zapisuju u heksadekadnom sistemu Uzastopni bajtovi memorije mogu da se tretiraju kao jedinstven podatak Na primer, dva (ili četiri, u zavisnosti od sistema) uzastopna

bajta mogu da se tretiraju kao jedinstveni podatak celobrojnogtipa

2

Page 3: Programski jezik C - pokazivači

Pokazivači i adrese Pokazivači (engl. pointer) predstavljaju tip podataka u C-u čije

su vrednosti memorijske adrese Pokazivačka promenljiva (promenljiva pokazivačkog tipa) sadrži

adresu memorijske lokacije neke (druge) promenljive Na 16-bitnim sistemima adrese zauzimaju dva bajta, na 32-

bitnim sistemima četiri, na 64-bitnim osam Iako su pokazivačke vrednosti (adrese) celi brojevi, pokazivački

tipovi se razlikuju od celobrojnih

3

Page 4: Programski jezik C - pokazivači

Primer#include <stdio.h>void f(int a[]) {

printf("f: %d\n", sizeof(a));}int main() {

int a[] = {1, 2, 3, 4, 5};printf("main: %d\n", sizeof(a));f(a);return 0;

}

4

Page 5: Programski jezik C - pokazivači

Pokazivači C razlikuje više pokazivačkih tipova Za svaki tip podataka (i osnovni i korisnički – int, float, double,

struct tacka, enum karta itd.) postoji odgovarajući pokazivačkitip

Na primer, tip pokazivača koji ukazuje na podatak tipa int zapisuje se

int * Slično važi i za druge tipove, npr float *, double *, char *...

ALI: zvezdica (*) vezuje se za ime (identifikator) pokazivača, ne za sam tip (bez obzira na razmake tj. položaj zvezdice)

5

Page 6: Programski jezik C - pokazivači

Pokazivači - primeri

int *p1; /* pokazivac na int */ int* p2; /* pokazivac na int */ int* p3, p4; /* p3 je pokazivac na int, p4 je int */

6

Page 7: Programski jezik C - pokazivači

Pokazivači - sadržaj Pokazivačka promenljiva može da sadrži adrese promenljivih ili

elemenata niza Adresa promenljive tj. elementa niza dobija se operatorom &

primenjenim na tu promenljivu tj. element niza

Operator & je unaran, naziva se i operatorom referenciranja ili adresnim operatorom

Adresni operator vraća adresu svog operanda Adresni operator može da se primeni samo na promenljive i

elemente niza, a ne i na izraze ili konstante

7

Page 8: Programski jezik C - pokazivači

Primer int a=10; int *p; p = &a;

Kako izgleda memorija?

8

Page 9: Programski jezik C - pokazivači

Operator dereferenciranja

Unarni operator * (koji zovemo „operator dereferenciranja“) primenjuje se na pokazivačku promenljivu i vraća sadržaj sa adrese koja je vrednost te promenljive, vodeći računa o tipu

Dereferencirani pokazivač može biti l-vrednost

Dereferencirani pokazivač nekog tipa može da se pojavi u bilokom kontekstu u kojem može da se pojavi podatak tog tipa

9

Page 10: Programski jezik C - pokazivači

Primer

int a=10, *p; p = &a; *p = 5; *p = *p+a+3;

Kako izgleda memorija i koja je vrednost promenljive a?

10

Page 11: Programski jezik C - pokazivači

Pokazivači i celi brojevi

Pokazivački i celobrojni tipovi su različiti pa je naredni kodneispravan:

int *pa, a;pa = a;a = pa;pa = 1234;

11

Page 12: Programski jezik C - pokazivači

Pokazivači i celi brojevi (0), NULL

Pokazivač može da ima vrednost 0; Nije ga moguće dereferencirati („segmentation fault“)

Ćešće se koristi simbolička konstanta NULL Definisana u zaglavlju <stdio.h>

Na primer, int* p = NULL;

12

Page 13: Programski jezik C - pokazivači

NULL, primer

int* a = NULL, b = 2; a = &b; *a = 3; b++;

Koja je vrednost promenljive b?

13

Page 14: Programski jezik C - pokazivači

Konverzije

Pokazivači mogu da se konvertuju iz jednog u drugi pokazivački tip, na primer:

int a; char* p = (char*)&a;

Vrši se samo prosta dodela adrese, bez konverzije podataka na koje pokazivač ukazuje

Često dovodi do neželjenih efekata Oprez!

14

Page 15: Programski jezik C - pokazivači

Konverzije - primer

int* p = NULL;float f = 5;p = &f;printf("%d\n", *p);

15

Page 16: Programski jezik C - pokazivači

Konverzije - primer

int* p = NULL;float f = 5;p = (int *)&f;printf("%d\n", *p);

Program će ispisati 1084227584 - broj koji odgovara celobrojnoj vrednosti zapisa u pokretnom zarezu broja 5

16

Page 17: Programski jezik C - pokazivači

Pokazivači na void U nekim slučajevima, poželjno je imati mogućnost „opšteg“

pokazivača, tj. pokazivača koji može da ukazuje na promenljiverazličitih tipova

Za to se koristi tip void*void* p = NULL;int a = 3, b = 5, c;float f = 3.0, g;p = &a;c = *(int*)p + b;p = &f;g = *(float*)p + 1;

17

Page 18: Programski jezik C - pokazivači

const I na pokazivače može da se primeni ključna reč const

/*promenljiva i*/int i;

/*vrednost od a je 5 i ne moze se menjati*/const int a = 5;

/*pokazivac na konstantan int, npr p=&a; */const int* p = &a;

/*vrednost p1 ne moze se menjati*/int* const p1 = &i;

/*p2 se ne moze menjati, pokazuje na const int*/const int* const p2 = &a;

18

Page 19: Programski jezik C - pokazivači

Kopiranje pokazivača

Vrednost pokazivača može da se dodeli pokazivaču istog tipa Kako izgleda memorija? Taj način kopiranja nekada se naziva plitkim kopiranjem Duboko kopiranje podrazumeva da se napravi kopija sadržaja

koji se nalazi na adresi na koju pokazivač pokazuje, a da se pokazivač usmeri ka kopiji tog sadržaja

19

Page 20: Programski jezik C - pokazivači

Kopiranje pokazivača - primerint a = 5;int *p = NULL, *q = NULL;p = &a;q = p;*p = 2;*q = *p + 5;

Koja je vrednost promenljive a? Kako izgleda memorija?

20

Page 21: Programski jezik C - pokazivači

Pokazivači i argumenti funkcija Već smo napomenuli da C prenosi argumente funkcija po vrednosti,

tj. ne omogućuje direktnu promenu vrednosti argumenata od stranepozvane funkcije.

Na primer, funkcija za razmenu vrednosti x, y (swap):void swap(int x, int y){ int temp;

temp =x;x = y;y = temp;

} i njen poziv swap(a, b); neće razmeniti vrednosti argumenata a i b (zbog prenosa

argumenata po vrednosti, funkcija swap razmenjuje samo sopstvenekopije promenljivih a i b iz svog "stek okvira") 21

Page 22: Programski jezik C - pokazivači

Pokazivači i argumenti funkcijavoid swap(int x, int y){ int temp;

temp =x;x = y;y = temp;

}main() {

int a = 3, b = 5;swap(a, b);printf("a = %d, b = %d\n", a, b);

}

22

Page 23: Programski jezik C - pokazivači

Pokazivači i argumenti funkcija Željeni efekat može se postići prenosom pokazivača na argumente

umesto samih argumenata, tj. pozivom funkcije swap(&a, &b) definisane sledećom definicijom (parametri funkcije su pokazivači na celobrojne promenljive):

void swap(int *px, int *py) / razmena *px i *py /{ int temp;

temp = *px;*px = *py;*py = temp;

} deklaracija (prototip): void swap(int *, int *) poziv swap(&a, &b)

23

Page 24: Programski jezik C - pokazivači

Pokazivači i argumenti funkcija

24

Page 25: Programski jezik C - pokazivači

Pokazivači i argumenti funkcija -primer

#include <stdio.h>void deljenje(unsigned a, unsigned b, unsigned* pk, unsigned* po) {

*pk = 0; *po = a;while (*po >= b) {

(*pk)++;*po -= b;

}}int main() {

unsigned k, o;deljenje(14, 3, &k, &o);printf("%d %d\n", k, o);return 0;

}25

Page 26: Programski jezik C - pokazivači

Pokazivači i strukturestruct razlomak *pa = &a;(*pa).imenilac = 2;(*pa).brojilac = 1;

Zagrade su neophodne zbog prioriteta operatora Umesto kombinacije operatora * i ., moguće je koristiti operator

-> koji je najvišeg prioriteta

struct razlomak *pa = &a;pa->imenilac = 2;pa->brojilac = 1;

26

Page 27: Programski jezik C - pokazivači

Pokazivači, strukture i funkcije Strukture se kao argumenti u funkciju prenose po vrednosti Često zauzimaju veliki prostor Umesto struktura u funkcije mogu da se proslede njihove adrese

- pokazivači na strukture

void saberi_razlomke(const struct razlomak *pa, const struct razlomak *pb, struct razlomak *pc)

{pc->brojilac = pa->brojilac*pb->imenilac +

pa->imenilac*pb->brojilac;pc->imenilac = pa->imenilac*pb->imenilac;

}27

Page 28: Programski jezik C - pokazivači

Pokazivačka aritmetika Razlikuje se od običnog izračunavanja

Izraz p+1 označava dodavanje dužine jednog objekta tipa na koji ukazuje p

NE označava dodavanje vrednosti 1 na p

Primer: int* p; p+1 i p mogu da se razlikuju za dva ili četiri, tj za sizeof(int)

Ako p sadrži adresu 100, i ako je sizeof(int) jednako 4, vrednost p+3 je adresa 100 + 3*4 = 112

28

Page 29: Programski jezik C - pokazivači

Pokazivačka aritmetika Izraz p-n označava oduzimanje n dužina objekta tipa na koji

pokazuje p

Prefiksni i postfiksni operatori ++ i - – (slično značenje)

Dva pokazivača je moguće oduzimati- vrši se deljenje razlike veličinom tipa pokazivača

Dva pokazivača ne mogu da se sabiraju

29

Page 30: Programski jezik C - pokazivači

Operatori poređenja

Ako su pokazivači istog tipa: relacijski operatori

Npr. p1 < p2, p1 == p2, . . . (značenje)

30

Page 31: Programski jezik C - pokazivači

Prioriteti operatora

Unarni operatori & i * imaju viši prioritet nego binarni aritmetičkioperatori

Na primer, *p+1 je zbir sadržaja lokacije na koju ukazuje p i vrednosti 1 (ne sadržaj na adresi p+1)

Unarni operatori &, *, i prefiksni ++ se primenjuju zdesna nalevo, pa naredba

++*p; inkrementira sadržaj lokacije na koju ukazuje p

Postfiksni operator ++ se primenjuje sleva nadesno ali ima viši prioritet od drugih unarnih operatora koji se primenjuju zdesnanalevo

*p++ vraća sadržaj na lokaciji p kao bočni efekat p se inkrementira

31

Page 32: Programski jezik C - pokazivači

Primer

int a = 3, *p; p = &a; *p = *p+1; ++*p; Koja je vrednost promenljive a?

32

Page 33: Programski jezik C - pokazivači

Nizovi

Postoji tesna veza između pokazivača i nizova int a[10]; deklariše niz od 10 elemenata tipa int Izraz sizeof(a) ima istu vrednost kao izraz 10*sizeof(int)

Početni element niza je a[0], a deseti element je a[9] i oni su u memoriji poređani uzastopno

U fazi kompilacije, imenu niza a pridružena je informacija o adresi početnog elementa niza, o tipu elemenata niza i o broju elemenata niza

33

Page 34: Programski jezik C - pokazivači

Pokazivači i nizovi

Ime niza (vrednost) a nije pokazivačkog tipa Nije l-vrednost, ne može mu se promeniti vrednost

int a[50]; int b[50]; a = b; /*neispravna dodela*/

34

Page 35: Programski jezik C - pokazivači

Pokazivači i nizovi

a <=> &a[0] *a <=> a[0] a+1 <=> &a[1] *(a+1) <=> a[1] ... a+i <=> &a[i] *(a+i) <=> a[i] ... a+n-1 <=> &a[n-1] *(a+n-1) <=> a[n-1] Nema provere granica niza, pa je dozvoljeno pisati (tj. prolazi fazu

prevođenja) i a[100], *(a+100), a[-100], *(a-100), iako je veličina niza samo 50

35

Page 36: Programski jezik C - pokazivači

Pokazivači i nizovi Elementima niza može se pristupati korišćenjem pokazivačke

aritmetike Na pokazivač može da se primeni nizovski indeksni pristup Na primer, int* p; p[3]... Vrednost izraza p[3] poklapa se sa elementom p[3] niza koji bi

počinjao na adresi p (bez obzira što p nije niz nego pokazivač)

Na primer, ako je sizeof(int) 4 i ako pokazivač p ukazuje na adresu 100 na kojoj počinje niz celih brojeva, tada je p[3] ceo broj koji se nalazi u memoriji počevši od adrese 112

Isto: *(p+3) (korišćenje pokazivačke aritmetike)

36

Page 37: Programski jezik C - pokazivači

Pokazivači i nizovi Dakle, bez obzira da li je x pokazivač ili niz, važi

x[n] <=> *(x+n) i x+n <=> &x[n]

Ako funkcija prima pokazivač na prvi element niza, implementacijafunkcije može da koristi indeksni pristup kao da je u pitanju niz

Oprez! Mora da bude obezbeđen memorijski prostor!

Primer: int a[10]; int *b; a[3] = 5; b[3] = 8; // nije dobro

37

Page 38: Programski jezik C - pokazivači

Pokazivači i nizovi Izraz a ima vrednost adrese početnog elementa i tip int [10] Izraz &a ima istu vrednost (tj. sadrži istu adresu) kao i a, ali

drugačiji tip - tip int (*)[10] tip pokazivača na niz od 10 elemenata koji su tipa int

int a[10]; /*niz celobrojnih vrednosti*/ int *b[10]; /*niz pokazivaca*/ int (*c)[10]; /*pokazivac na niz sa 10 elemenata*/ c = &a; (*c)[0] = 0; /*a[0] = 0;*/

38

Page 39: Programski jezik C - pokazivači

Pokazivači i nizovi

Niz ne može da se prenese kao argument funkcije Kao argument funkcije može da se navede ime niza i time se

prenosi samo pokazivač koji ukazuje na početak niza Funkcija koja prihvata takav argument može da primi tip char [] ili

char * (npr. char a[] ili char * a) Ovim se u funkciju kao argument prenosi (po vrednosti) samo

adresa početka niza, ne i informacija o dužini niza

39

Page 40: Programski jezik C - pokazivači

Pokazivači i nizovi#include <stdio.h>int main() {int a[] = {8, 7, 6, 5, 4, 3, 2, 1};int *p1, *p2, *p3;/* Ispis elemenata niza */printf("%d %d %d\n", a[0], a[3], a[5]);/* Inicijalizacija pokazivaca -ime niza se konvertuje u pokazivac */p1 = a; p2 = &a[3]; p3 = a + 5;printf("%d %d %d\n", *p1, *p2, *p3);/* Pokazivaci se koriste u nizovskojsintaksi */printf("%d %d %d\n", p1[1], p2[2], p3[-1]);

40

Page 41: Programski jezik C - pokazivači

Pokazivači i nizovi/* Pokazivacka aritmetika */p1++; --p2; p3 += 2; /* a++ nije dozvoljeno */printf("%d %d %d %lu\n", *p1, *p2, *p3, p3 - p1);

*p1++; printf("%d ", *p1);*(p1++); printf("%d ", *p1);(*p1)++; printf("%d\n", *p1);return 0;} 8 5 3 8 5 3 7 3 4 7 6 1 6 6 5 6 41

Page 42: Programski jezik C - pokazivači

Pokazivači na funkcije Funkcije se ne mogu direktno prosleđivati kao argumenti drugim

funkcijama, vraćati kao rezultat funkcija i ne mogu se dodeljivati promenljivima

Moguće posredno korišćenjem pokazivača na funkcije

Više o tome u okviru kursa Programiranje 2

42

Page 43: Programski jezik C - pokazivači

Dinamička alokacija memorije

Više o tome u okviru kursa Programiranje 2

43

Page 44: Programski jezik C - pokazivači

Funkcije za rad sa stringovima -primeri

/ strcpy: kopira t u s; verzija sa indeksiranim nizovima /

char* strcpy(char *s, const char *t) // parametri mogu biti i char s[ ], const char t[ ]

{int i;i = 0;while ((s[i] = t[i]) != ‘\0')

i++;return s;

}

44

Page 45: Programski jezik C - pokazivači

Funkcije za rad sa stringovima -primeri

char *strcpy(char *s, const char *t){ char * temp=s;

while ((*s = *t) != ‘\0') {s++;t++;

}return temp;

}…while ((*s++ = *t++) != ‘\0');return temp;…while (*s++ = *t++);return temp;

45

Page 46: Programski jezik C - pokazivači

Funkcije za rad sa stringovima -primeri

/ strcmp: vraca <0 ako je s<t, 0 ako je s==t, >0 ako je s>t /int strcmp(char *s, char *t){

int i;for ( ; *s == *t; s++, t++)

if (*s == ‘\0')return 0;

return *s - *t;}

46

Page 47: Programski jezik C - pokazivači

Funkcije za rad sa stringovima -primeri

int strcmp(char *s, char *t){

int i;for (i = 0; s[i] == t[i]; i++)

if (s[i] == ‘\0')return 0;

return s[i] - t[i];}

47