Пренос параметара по референци

До сада смо користили функције у којима смо стварне параметре копирали у функцију. Рекли смо да се тај поступак назива предаја параметара по вредности. Овај поступак смо детаљно објаснили и видели да се овом приликом стварни параметри не мењају. Функције на овај начин могу да врате само једну вредност.

А шта да радимо када функција треба да врати више вредности? Или када треба да променимо стварне параметре?

У овом случају се користи друга техника предаје параметара – пренос параметара по референци.

Шта значи овај појам?

Посматрајмо следећи, једноставан пример, у коме желимо да изменимо вредност стварног параметра а у главном програму. Обрати пажњу да пратимо адресе стварних и формалних параметара:

void izmeni(int m)
{
    printf("Adresa parametra m = %x\n", &m);
    m = 100;
}

У главном програму учитавамо стварни параметар и читамо његову адресу.

int main(void)
{
    int a;
    printf("Unesi broj a: ");
    scanf("%d", &a);
    printf("Adresa stvarnog argumenta a = %x\n", &a);
    izmeni(a);
    printf("Vrednost promenljive a posle poziva funkcije izmeni je a = %d\n", a);
    return 0;
}

Резултат извршавања програма:

Unesi broj a: 3
Adresa stvarnog argumena a = 62fe1c
Adresa parametra m = 62fdf0
Vrednost promenljive a posle poziva funkcije izmeni je a = 3

Шта уочаваш?

Вредност стварног параметра се није променила, иако нам је то био циљ. Уочи да су вредности адреса различите, јер се предајом параметара по вредности резервише нова меморија.

Хајде да објаснимо сликовито.

Позивом функције izmeni() у главном програму прослеђује се вредност стварног параметра у функцију.

Позивом функције копира се вредност стварног параметра у функцију:

../_images/Picture71.png

Затим се та вредност мења наредбом m = 100.

Наредбом m = 100 локална променљива добија нову вредност:

../_images/Picture81.png

Видимо да су се све промене десиле само у функцији – вредност стварног параметра а је остала иста. А то нисмо хтели, зар не?

Изменићемо кôд функције:

void izmeni(int &m)
{
	printf("Adresa lokalnog parametra a = %x\n", &m);
	m = 100;
}
int main(void)
{
    int a;
    printf("Unesi broj a ");
    scanf("%d", &a);
    printf("Adresa stvarnog parametra a = %x\n", &a);
    izmeni(a);
    printf("Vrednost promenljive a posle poziva funkcije izmeni je a = %d\n", a);
	return 0;
}

Резултат извршавања програма:

Unesi broj a: 3
Adresa stvarnog parametra a = 62fe1c
Adresa lokalnog parametra a = 62fe1c
a = 100

У чему је разлика?

Приликом предаје параметара по референци не ствара се нова меморија. Параметри у функцији су заправо референце у којима се чувају адресе стварних параметара. На овај начин свака промена параметра у функцији (m = 100) узрокује промену стварног параметра a у главном програму.

Погледајмо још један карактеристичан пример:

Креираћемо функцију zameni која замењује вредности променљивим a и b.

Функцију ћемо реализовати користећи већ познати начин замене две вредности, користећи локалну, помоћну променљиву t.

void zameni(int m, int n)
{
    int t;
    t = m;
    m = n;
    n = t;
}

Главни програм:

int main(void)
{
    int a, b;
    printf("Unesi broj a: ");
    scanf("%d", &a);
    printf("Unesi broj b: ");
    scanf("%d", &b);
    zameni(a, b);
    printf("a = %d\n", a);
    printf("b = %d\n", b);
    return 0;
}

Резултат извршавања програма:

Unesi broj a: 3
Unesi broj b: 9
a = 3
b = 9

Примећујемо да се вредности стварних параметара нису промениле. Зашто? Као и у претходном примеру, све промене су се десиле унутар саме функције. Објашњење је слично као у претходном примеру:

Приликом позива функције zameni у главном програму копирају се вредности стварних параметара у функцију.

Наредбом zameni(3, 9) копирају се стварни параметри у функцију:

../_images/Picture91.png

Анализирајмо шта се дешава у функцији после следећих наредби:

t = m;

Вредности формалних параметара после наредбе t = m:

../_images/Picture101.png

m = n;

Вредности формалних параметара после наредбе m = n:

../_images/Picture111.png

n = t;

Вредности формалних параметара после наредбе n = t:

../_images/Picture121.png

На крају извршења главног програма стање меморије би било следеће:

Вредности стварних и формалних параметара после позива функције zameni:

../_images/Picture131.png

И ево још једног доказа да вредности променљивих a и b нису замениле вредности и да су се све промене десиле на нивоу функције.

Решење је, као и у претходном примеру, у преносу параметара по референци.

Изменићемо функцију zameni:

void zameni(int &m, int &n)
{
    int t;
    t = m;
    m = n;
    n = t;
}
int main(void)
{
    int a, b;
    printf("Unesi broj a: ");
    scanf("%d", &a);
    printf("Unesi broj b: ");
    scanf("%d", &b);
    zameni(a, b);
    printf("a = %d\n", a);
    printf("b = %d\n", b);
	return 0;
}

Свака промена параметара m и n биће заправо промена стварних параметара а и b у главној функцији.

Резултат извршавања програма:

Unesi broj a: 3
Unesi broj b: 9
a = 9
b = 3

Променљиве a и b су замениле вредности. А то је управо оно што смо и желели.

Поред референци, могу се користити и показивачи на податке. И код ове технике врши се промена стварних параметара. С обзиром да се показивани подаци налазе изван функције, у главном програму, њихова промена се назива бочни ефекти функције. Користи се када функција треба да врати више излазних вредности.