Дефинисање показивача¶
Оперативна меморија рачунара је заправо низ меморијских локација у којој су смештени подаци који су дефинисани у програму. Број меморијске локације је њена адреса.
На пример, наредбом int
a резервисан је меморијски простор величине 4 бајта (32 бита). Најмања величина меморијске локације која може да се адресира је 1 бајт (8 бита), па ће ова променљива заузети 4 меморијске локације (1000-1003).
Меморијски простор неопходан за смештање једне променљиве типа int a:

Бинарни систем због прегледности није погодан за престављање адресе меморијских локација. Оне се обично означавају у декадном и хексадекадном кодном систему. На почетку ћемо због једноставности и разумљивости користити једноставне декадне вредности, а касније ћемо користити хексадекадне вредности које могу да представљају стварне адресе у рачунару.
Хексадекадни систем је бројни систем код кога је основа 16. Зато је за представљање цифара хексадекадног система поред 10 децималних цифара потребно још 6 симбола. Цифрама децималног система: 10, 11, 12, 13, 14, 15, 16 одговарају симболи A, B, C, D, E, F. Свака хексадекадна цифра замењује 4 бинарне цифре. На пример, хексадекадни број 62fe0c, који представља адресу неке меморијске локације у рачунару, у декадном систему је 6.487.564, а у бинарном систему би гласио 0110 0010 1111 1110 0000 1100. Предности представљања адреса хексадекадним кодом су очигледне, пре свега због компактности записа.
Даље, на пример наредбом а = 5, у резервисане меморијске локације смештамо вредност 5. Вероватно знаш да ће се она у меморији наћи у бинарном облику.
Наредбом а=5 у резервисани меморијски простор уносимо вредност променљиве а у бинарном облику:

Такође, у првом разреду учио си да променљиве одређеног типа заузимају простор у меморији, и то:
char
1 бајт,short int
2 бајта,float
4 бајта,double
8 бајтова.
Међутим, у меморији се могу наћи не само вредности променљивих, већ и њихове адресе. Ту долазимо до дефиниције показивача.
Показивач (енгл. pointer) је податак у који може да се смести адреса неке локације у меморији у којој се налази нека друга променљива.

Показивач р садржи адресу променљиве а
Већ смо се подсетили да показивачи спадају у изведене типове података.
Показивачи се дефинишу као и сви остали подаци у програму, с тим што се испред идентификатора податка додаје симбол *
. Општи облик наредбе за дефинисање показивача је тип *ime
. Тип означава тип податка на који показивач указује. Најчешће се показивач дефинише са *p
, али то не мора да буде правило.
Пример декларисања променљивих:
int a, d;
int b[20];
int *c, *p;
Овом наредбом смо дефинисали две целобројне променљиве а
и d
, низ b
од 20 целих
бројева, као и два показивача на целе бројеве – c
и p
.
Ове променљиве смо могли декларисати и на следећи начин:
int a, b[20], *c, d, *p;
Међутим, због прегледности, у нашим примерима и задацима користићемо први начин.
Када видиш испред имена променљиве знак *
, знај да је у питању
показивачка променљива, односно да она садржи адресу, а не вредност.
Питаш се, сигурно, чему све ово, зашто компликујемо, чему сад све ове адресе, показивачи, анализа меморије.
За сада схвати да показивачи имају значајну улогу у језику С, јер се многи сложенији или комплекснији програми не би могли написати без њихове употребе. Употребом показивача се добија ефикаснији и читљивији кôд од било ког другог начина, а врло често је то једини пут за решавање неког проблема. Зато се потруди да овде схватиш основе рада са показивачима – то ће ти помоћи у даљем учењу језика С.
Па да наставимо нашу причу.
Раније си научио да се адреса неког податка смештеног у меморији може добити употребом унарног оператора &
. Операнд оператора &
мора бити неки податак смештен у меморији.
Где си користио овај оператор? Па наравно, код наредбе scanf.

Шта заправо ради следећи кôд, а који врло често користиш?
int x;
scanf("%d", &x);
Првом наредбом, када декларишеш променљиву x
, у меморији се одваја меморијски простор од 4 бајта.
Стање оперативне меморије после наредбе int x
:

Са scanf(“%d”, &x)
на адресу која је додељена променљивој x
смешташ вредност коју уносиш
са тастатуре. Овај корак смо раније објаснили.
Показивачима се може доделити почетна вредност у облику:
tip *ime = adresa
на пример, можемо декларисати променљиве на следећи начин:
int a = 7;
int *p = &a;
int *b;
Као што смо навели ово је прегледнија варијанта декларисања променљивих од:
int a = 7,*p = &a, *b;
Анализирајмо све ово на још једном примеру!
Дефинисаћемо две променљиве, и то скаларну променљиву b
и показивачку променљиву p
.
double *p, b = 12.52;
Овде смо нагласили да резервишемо простор за смештање променљиве b
двоструке тачности, истовремено јој додељујући вредност. Такође, видимо да ће показивачка променљива указивати на променљиву типа double.
Наредбом p = &b
показивачкој променљивој p доделио си адресу променљиве b
. Тек сада показивач p
заправо добија своју праву улогу, јер си му доделио адресу неке друге променљиве, у нашем примеру променљиве b
. Он сада упућује на променљиву b
.
Изглед меморије после наредби double *p, b=12.52; p=&b;
:

Обрати пажњу да ће променљива b
заузети 8 бајтова у меморији.
И показивач, као и било која друга променљива, има своју адресу, али за сада њена вредност није од важности.
Сврха рада са показивачима је да се на индиректан начин приступи одређеним меморијским локацијама и вредностима које се налазе у њима. Приступ подацима на овај начин, помоћу адресе, назива се индиректно адресирање.
Шта ово заправо значи? Све време причамо о адресама и адресирању, али оно што је основни смисао показивача јесте да адресирање и показиваче искористимо као средство да на посредан начин дођемо до вредности променљивих које се налазе на тим меморијским локацијама.

Како постићи ово?
Рекли смо раније да се адреса неког податка додељује показивачу помоћу адресног оператора &
.
p = &a;
Показивачу p
показује на променљиву а наредбом p = &a
:

Локацији (вредности) на коју показивач указује приступа се помоћу оператора за индиректан приступ (дереференцирање) *.
*p = 1;
На индиректан начин приступамо локацији на коју указује показивач р и додељујемо јој вредност 1, заправо на посредан начин смо приступили променљивој а и доделили јој нову вредност, односно сада је a = 1.
Вредност променљиве а после наредбе *p = 1
:

Дакле, овде важи једнакост a = *p
, што значи да вредност променљиве а можемо изнети на два
начина. Из наведеног можеш да закључиш да су &
и *
инверзни оператори, односно да важе
следеће једнакости: y = *(&x)
или y = *&x
или y = x
.
Илуструјмо следећим примером:
Декларисати променљиву x
целобројног типа, као и показивач px
који ће упућивати на њу.
Приказати вредност и адресу променљиве x
на оба начина.
За приказ адреса ћемо надаље користити хексадекадне вредности уз коришћење
конверзије %x
.
#include <stdio.h>
int main(void)
{
int x = 100, *px;
px = &x;
printf("Vrednost promenljive x je %d\n", x);
//indirektno preko pokazivača:
printf("Vrednost promenljive x je: %d\n", *px);
printf("Adresa promenljive x je: %x\n", &x);
//indirektno preko pokazivača:
printf("Adresa promenljive x je: %x\n", px);
return 0;
}
Резултат извршавања програма:
Vrednost promenljive x je 100
Vrednost promenljive x je: 100
Adresa promenljive x je: 62fe1c
Adresa promenljive x je: 62fe1c
Вредност адресе је јединствена за сваки рачунар. Ако будеш тестирао овај задатак на свом рачунару, вероватно ћеш добити другу вредност адреса.
Изглед оперативне меморије:

Једна од битних карактеристика показивача је да се једном показивачу може доделити адреса другог показивача, што ћемо детаљније анализирати у следећем поглављу.
Изменићемо претходни пример увођењем новог показивача py
.

Шта се добија следећим кодом?
int x = 100, *px, *py;
px = &x;
py = px;
Овом наредбом смо показивачу py доделили вредност px
, што заправо представља адресу
променљиве x
. Сада и показивач py
показује на x
.
Сада имамо право да параметре променљиве x, вредност и адресу, прикажемо на оба начина.
#include<stdio.h>
main()
{
int x = 100;
int *px, *py;
px = &x;
py = px;
printf("Vrednost promenljive x je %d\n", x);
//indirektno preko pokazivača py:
printf("Vrednost promenljive x (preko pokazivaca py) je: %d\n", *py);
printf("Adresa promenljive x je: %x\n", &x);
//indirektno preko pokazivača py:
printf("Adresa promenljive x (preko pokazivaca py) je: %x\n", py);
}
Резултат извршавања програма:
Vrednost promenljive x je 100
Vrednost promenljive x (preko pokazivaca py) je: 100
Adresa promenljive x je: 62fe0c
Adresa promenljive x (preko pokazivaca py) je: 62fe0c
Изглед оперативне меморије:
