четвртак, 25 априла, 2024
Како да...?

Увод у програмски језик C (6. део)

Аутор: Вељко Симић

Показивачи

Меморију рачунара можемо да посматрамо као низ меморијских локација. Меморијске локације обележавамо бројевима од 0 па до капацитета меморије и називамо их меморијским адресама. Показивачи су променљиве које као вредност садрже адресу меморијске локације неке променљиве. Показивач такође има и тип. Тип показивача је тип вредности на коју показивач показује (референцира). Показивачи се дефинишу као и сви остали подаци, наводе се његов тип (тачније тип вредности на коју референцира) и назив, с тим што се пре његовог назива пише „*” – која означава да је нека променљива показивач. Дефинишимо показивач p типа int: int *p;

Меморијској локацији неког елемента приступа се навођењем знака „&” испред променљиве. Ако је x променљива типа int, следећом наредбом ћемо доделити показивачу p адресу x-а.

p=&x;

Уколико желимо да приступимо вредности која се налази на адреси коју референцира p, то ћемо учинити коришћењем „*”. Ако је променљива a типа int, следеће две наредбе ће учинити да вредност a има исту вредност као x.

p=&x;
a=*p;

Функција sizeof(x) за параметар прима променљиву или тип неког податка, а као резултат враћа величину меморијског простора коју заузима прослеђен параметар. Вероватно вам се намеће питање чему потреба за показивачима. Потреба показивача је огромна, а ми ћемо у овом броју навести основне и најкоришћеније примере. Нека је задатак да напишемо функцију која замењује вредности два броја.

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

Уколико тестирамо ову функцију, приметићемо да функција не ради оно што бисмо желели.

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

Као резулат рада ове три линије, добићемо испис на екрану: 5 7. Да бисмо објаснили ову појаву, најпре ћемо појаснити како ради функција. Функција заправо ради са копијама вредности својих аргумената и такво прослеђивање се назива прослеђивање аргумената по вредности. Вредности можемо променити унутар функције уколико као параметар наведемо њихову меморијску локацију, па би исправна верзија претходно написане функције изгледала овако:

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

У овом случају прослеђујемо меморијску локацију променљивих:

razmeni(&a, &b);

Низови

При дефиницији низа морамо навести број елемената тог низа. Мана тога је што морамо да скоро увек резервишемо више него што нам треба (за сваки случај), ако то не урадимо, веома лако можемо доћи у ситуацију да немамо довољан број елемената низа. У том случају програм изазива грешку segmentation fault – то је грешка која се јавља уколико покушамо да приступимо меморијској локацији којој није дозвољен приступ. На пример, затражимо вредност елемента n[5], где је n дефинисан као низ од три елемента.

У оваквим ситуацијама користи се динамичко алоцирање меморије, тачније додељивање више меморијских локација једном показивачу. Дефинисање низа од n елемената извршава следећи део кода:

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

Анализирајмо код. Као што видите, имамо две непознате функције malloc() и free(). Функција malloc алоцира простор тражене величине и враћа показивач на њега, у нашем примеру желимо да заузмемо простор за n података типа int. Функција free ослобађа заузету меморију. I-том члану низа приступамо тако што ћемо приступити i-тој меморијској локацији низа *(niz+i). Следећа два исказа су еквивалентна *(niz+0) и *niz. У следећем броју ћемо причати о сложеним типовима података, тј. о структурама података и имплементацији најпознатијих сложених структура: листа, стек, стабло и граф.

Наредни део овог серијала можете прочитати овде.

Претходни део овог серијала можете прочитати овде.