petak, 19 aprila, 2024
Kako da...?

Uvod u programski jezik C (6. deo)

Autor: Veljko Simić

Pokazivači

Memoriju računara možemo da posmatramo kao niz memorijskih lokacija. Memorijske lokacije obeležavamo brojevima od 0 pa do kapaciteta memorije i nazivamo ih memorijskim adresama. Pokazivači su promenljive koje kao vrednost sadrže adresu memorijske lokacije neke promenljive. Pokazivač takođe ima i tip. Tip pokazivača je tip vrednosti na koju pokazivač pokazuje (referencira). Pokazivači se definišu kao i svi ostali podaci, navode se njegov tip (tačnije tip vrednosti na koju referencira) i naziv, s tim što se pre njegovog naziva piše „*” – koja označava da je neka promenljiva pokazivač. Definišimo pokazivač p tipa int:int *p;

Memorijskoj lokaciji nekog elementa pristupa se navođenjem znaka „&” ispred promenljive. Ako je x promenljiva tipa int, sledećom naredbom ćemo dodeliti pokazivaču p adresu x-a.

p=&x; 

Ukoliko želimo da pristupimo vrednosti koja se nalazi na adresi koju referencira p, to ćemo učiniti korišćenjem „*”. Ako je promenljiva a tipa int, sledeće dve naredbe će učiniti da vrednost a ima istu vrednost kao x.

p=&x; a=*p;

Funkcija sizeof(x) za parametar prima promenljivu ili tip nekog podatka, a kao rezultat vraća veličinu memorijskog prostora koju zauzima prosleđen parametar. Verovatno vam se nameće pitanje čemu potreba za pokazivačima. Potreba pokazivača je ogromna, a mi ćemo u ovom broju navesti osnovne i najkorišćenije primere. Neka je zadatak da napišemo funkciju koja zamenjuje vrednosti dva broja.

void razmeni (int a, int b){ int tmp = a; a = b; b = a; }

Ukoliko testiramo ovu funkciju, primetićemo da funkcija ne radi ono što bismo želeli.

int a = 5, b = 7; razmeni(a,b); printf ("%d %d",a,b);

Kao rezulat rada ove tri linije, dobićemo ispis na ekranu: 5 7. Da bismo objasnili ovu pojavu, najpre ćemo pojasniti kako radi funkcija. Funkcija zapravo radi sa kopijama vrednosti svojih argumenata i takvo prosleđivanje se naziva prosleđivanje argumenata po vrednosti. Vrednosti možemo promeniti unutar funkcije ukoliko kao parametar navedemo njihovu memorijsku lokaciju, pa bi ispravna verzija prethodno napisane funkcije izgledala ovako:

void razmeni (int* a, int* b){ int tmp = *a; *a = *b; *b = tmp; }

U ovom slučaju prosleđujemo memorijsku lokaciju promenljivih:

razmeni(&a, &b);

Nizovi

Pri definiciji niza moramo navesti broj elemenata tog niza. Mana toga je što moramo da skoro uvek rezervišemo više nego što nam treba (za svaki slučaj), ako to ne uradimo, veoma lako možemo doći u situaciju da nemamo dovoljan broj elemenata niza. U tom slučaju program izaziva grešku segmentation fault – to je greška koja se javlja ukoliko pokušamo da pristupimo memorijskoj lokaciji kojoj nije dozvoljen pristup. Na primer, zatražimo vrednost elementa n[5], gde je n definisan kao niz od tri elementa.

U ovakvim situacijama koristi se dinamičko alociranje memorije, tačnije dodeljivanje više memorijskih lokacija jednom pokazivaču. Definisanje niza od n elemenata izvršava sledeći deo koda:

int *niz, n; scanf("%d",&n); niz = malloc(n*sizeof(int)); for (int i=0; i

Analizirajmo kod. Kao što vidite, imamo dve nepoznate funkcije malloc() i free(). Funkcija malloc alocira prostor tražene veličine i vraća pokazivač na njega, u našem primeru želimo da zauzmemo prostor za n podataka tipa int. Funkcija free oslobađa zauzetu memoriju. I-tom članu niza pristupamo tako što ćemo pristupiti i-toj memorijskoj lokaciji niza *(niz+i). Sledeća dva iskaza su ekvivalentna *(niz+0) i *niz. U sledećem broju ćemo pričati o složenim tipovima podataka, tj. o strukturama podataka i implementaciji najpoznatijih složenih struktura: lista, stek, stablo i graf.

Naredni deo ovog serijala možete pročitati ovde.

Prethodni deo ovog serijala možete pročitati ovde.