Адресна аритметика¶
Раније смо навели да се над показивачима могу изводити неке операције као што су:
додељивање вредности једног показивача другом,
поређење и одузимање два показивача,
поређење показивача са нулом,
сабирање и одузимање показивача и целобројног податка.
Додељивање вредности једног показивача другом¶
Да се подсетимо, када доделимо вредност једног показивача другом, оба показивача ће показивати на исти податак. Овде мораш водити рачуна да оба показивача морају бити истог типа, односно да указују на податке истог типа.
Анализирајмо детаљно пример (наредбе се извршавају сукцесивно, једна за другом):
int x = 100;
int *p1, *p2;
Овом наредбом дефинишемо скаларну променљиву x
и две показивачке променљиве p1
и p2
.
Изглед меморије након декларисања променљивих x
,*p1
,*p2
и доделе вредности
променљивој x
:

Наредбом p1 = &x, показивачу p1
се додељује адреса променљиве x
, сада он показује на x
.
Изглед меморије након доделе адресе променљиве x
показивачу р1
, p1 = &x
:

Изразом p2 = p1
другом показивачу се додељује вредност првог показивача. Та вредност заправо
представља адресу променљиве x
, што значи да сада и p2
указује на x
.
Изглед меморије након наредбе p2=p1
:

Већ смо причали о генеричким показивачима, па ћемо сада и њих укључити у причу. Ако је један показивач генеричког типа void
, а други негенерички, треба обратити пажњу на редослед доделе.
На пример:
double m = 18.37;
double *p1;
void *p2;
Обрати пажњу на следећа правила:
Дозвољено је p2 = p1, јер је објашњење логично - помоћу генеричког податка не можемо приступити податку, па није битно ког је типа.
Није дозвољено негенеричком показивачу доделити вредност генеричког показивача, односно p1 = p2.
Наравно, ово су општа правила када је један показивач генерички.
Проблем у програму би могао да
решиш кастовањем, поступком којим смо већ појаснили: p1 = (double*)p2;
Следећи код би се успешно извршио:
#include<stdio.h>
main()
{
double m = 18.37;
double *p1;
void *p2;
p2 = &m;
p1 = (double*)p2;
printf("Vrednost promenljive m (preko pokazivaca p1) je %.2lf", *p1);
}
Поређење два показивача¶
Програмски језик С дозвољава поређење два показивача коришћењем оператора ==
и !=
.
Поређење се врши да би се добио одговор да ли показивачи указују на исти податак у меморији или не.
У нашем примеру резултат израза if(p1 == p2)
био би потврдан (израз враћа вредност 1).
Наравно, израз p1 != p2
у овом случају враћа вредност 0.
Показивачи р1
и р2
имају исту вредност, односно указују на исту променљиву:

Поређење показивача са нулом¶
Могуће је показивачу произвољног типа, укључујући и показивач типа void
, доделити
нулу или га поредити са нулом. Уколико показивач има вредност нула, то значи да не
указује ни на који податак.
Врло често се за поређење користи симболичка константа NULL
која се налази у библиотеци
stdio.h
и stdlib.h
. Врло често ћеш ову константу користити у даљем изучавању програмирања,
а посебно у базама података.
Анализирајмо поново наш пример:
int x = 100;
int *p1, *p2;
p1 = &x;
Наредбе if (p2 == 0)
и if (p2 == NULL)
су заправо идентичне, јер испитују да ли показивач
указује на неки податак. У нашем случају показивач p2
не указује ни на један податак, за
разлику од показивача p1
.
Показивач р2 не показује ни на један податак:


Употреби претходни пример и слику и одговори које ће вредности вратити следећи изрази:
Израз поређења |
Решење |
---|---|
p2! = 0 |
0 |
p1 == NULL |
0 |
p1! = 0 |
1 |
p2 == NULL |
1 |
Сабирање и одузимање показивача и целобројног податка¶
Већ смо навели да је дозвољено сабирање и одузимање показивача и целобројног податка. Ово ћемо најлакше објаснити на примеру низа a[5]={7,12,36,4,18}.
Показивач p
позиционираћемо на трећи елемент низа и то наредбом p = &a[2]
.

Наредба p + 1
указује на следећи елемент, а p - 1
на претходни елемент низа:

Уопшено говорећи, важи да израз p + i
представља i-ти елемент иза елемента на који
указује показивач, а p - i
i-ти елемент испред елемента на који указује показивач.
Јединица мере при сабирању и одузимању показивача са целобројним податком јесте величина показиваног податка!
Уопштено говорећи, за израз p = p + х нова адреса р ће бити формирана као збир старе
адресе p и x * sizeof (pokazani_tip)
.
Нека су дефинисани низ a[10]
и показивач *p
(истог типа, наравно) и нека показивач p
упућује на a
(p = &а). Ако је вредност p = 6487574 (децимално), наредбом p = p + 1
добићемо следеће вредности показивача p
за различите типове података:
char: p = 6487575 – char заузима један бајт
short int: p = 6487576 – short int заузима два бајта
int, float: p = 6487578 – int, float заузимају четири бајта
double: p = 6487582 – double заузима осам бајтова
Анализирајмо сада следећи пример:
У низу путем показивача приступити елементима низа и у 4. елемент уписати вредност збира 2. и 5. елемента, а затим приказати измењене вредности низа.
На почетку треба одредити вредност показивача, на који елемент се позиционирамо. Нека
то буде први елемент, р = a
или p = &a[0]
.
Иако ће бити детаљније бити објашњено у лекцији „Показивачи и низови” запамти ове изразе:
&a[i]<=>a+i - адреса i-тог елемента низа
&a[0]<=>a - адреса првог елемента низа
a[i]=*(a+i) - вредност i-тог елемента низа
Већ си научио да вредности на тим позицијама добијамо са *(p + 1)
, односно *(p + 4)
.
Израз за наш задатак би гласио:
*(p + 3) = *(p + 1) + *(p + 4)
Вредности измењеног низа би износиле:

Решење:
#include<stdio.h>
main()
{
int a[] = {7, 12, 36, 4, 18};
int *p;
p = a;
*(p + 3) = *(p + 1)+ *(p + 4);
printf("Novi izgled niza:\n");
for (p = a; p < a + 5; p++)
printf("%d", *p);
}
Анализирајмо сада претходни програм:
После измена елемента низа наредбом *(p + 3) = *(p + 1)+ *(p + 4) приступамо елементима низа на следећи начин: Наредбом p = a показивач показује на први елемент низа, а са *p чита вредност са те локације. Показивач наредбом p++ показује на следећи елемент низа, чита и штампа вредност са те локације и тако редом, све до последњег елемента низа што се дефинише наредбом p < a + 5.
Резултат извршавања програма:
Novi izgled niza:
7 12 36 30 18
Када приступаш елементима у меморији, мораш водити рачуна да приступаш само дефинисаном делу меморије, где постоје вредности. Јасно ти је да у нашем примеру наредба p + 7, на пример, нема смисла, јер вредност на тој позицији не постоји.

Реши претходни пример, али тако да се на почетку позиционираш на трећи елемент
p = &a[2]
.
Pешење:
#include<stdio.h>
main()
{
int a[] = {7, 12, 36, 4, 18};
int *p;
p = a + 2;
*(p + 1) = *(p - 1) + *(p + 2);
printf("Novi izgled niza:\n");
for (p = a; p < a + 5; p++)
printf("%d", *p);
}