Бочни ефекти функције¶
Нагласили смо да функције могу да врате само једну вредност наредбом return
.
Како сада решити проблем ако у функцији треба да израчунамо више вредности и њих
предамо главном програму? У претходном поглављу смо нешто рекли о преносу параметара
по референци. Такође смо споменули да се могу користити и показивачи на податке.
Резултат је сличан – промене се дешавају над стварним параметрима на које показују
показивачи дефинисани у функцији.
Дакле, основна идеја јесте да се у функцију проследи адреса стварне променљиве. Тако
ћемо на индиректан начин, користећи знање које смо раније стекли о показивачима, приступити
стварним параметрима и мењати њихове вредности. Функције које стварају бочне ефекте су углавном
типа void
, али не морају бити. У нашим наредним примерима су типа void
.
Ово ћемо најлакше схватити ако анализирамо следеће задатке:

Креирати функцију којом се за задате вредности отпора R
и струје I
рачунају вредности
напона U
и снаге P
на отпорнику.
Из задатка видимо да треба да израчунамо две вредности користећи познате улазне параметре. Користићемо познате формуле за:
Омов закон: \(U=R*I\) и
Закон снаге: \(P=R*I^2\).
Како функција napon_snaga
резултате даје преко бочних ефеката, за тип функције користимо void
.
#include<stdio.h>
void napon_snaga(float R, float I, float *pU, float *pP)
{
*pU = R * I;
*pP = R * I * I;
}
main()
{
float R, I, U, P;
printf("Unesi vrednost otpora R[Om] = ");
scanf("%f", &R);
printf("Unesi vrednost struje I[A] = ");
scanf("%f", &I);
napon_snaga(R, I, &U, &P);
printf("Vrednost napona U[V] = %.2f\n", U);
printf("Vrednost snage P[W] = %.2f\n", P);
}
Резултат извршавања програма:
Unesi vrednost otpora R[Om] = 23.55
Unesi vrednost struje I[A] = 17.36
Vrednost napona U[V] = 408.83
Vrednost snage P[W] = 7097.25
А сада да детаљно погледамо:
Како функција треба да дâ два резултата, користићемо бочне ефекте. Функција има четири параметра.
Улазни параметри R
и I
се у функцију преносе помоћу вредности.
Параметри *pU
и *pP
су показивачи у које смештамо адресе променљивих U
и P
.
Префикс p
користимо јер су у питању показивачке променљиве. Променљиве U
и P
су дефинисане у главном програму, тако да добијене вредности напона и снаге смештамо у њих.
Пренос параметара у функцију napon_snaga
:
main() napon_snaga(float R, float I, float *pU, float *pP)

У самој функцији се рачунају вредности напона и снаге изразима:
*pU = R * I;
*pP = R * I * I;
Да се подсетимо значења ових израза.
Резултат израза се смешта у меморијску локацију на коју показивачка променљива указује.
У нашем случају показивач pU
указује на стварни параметар U
у главном програму јер садржи
његову адресу.
Показивач pP
указује на параметар P
. У ова два параметра ће бити смештени резултати израза.
Вредности параметара U и P представљају бочне ефекте функције napon_snaga:
main() napon_snaga(float R, float I, float *pU, float *pP)


Креирати функцију max_min
која проналази највећи и најмањи од три броја. У
главном програму за три унета броја исписати производ највећег и најмањег.
void max_min(int a, int b, int c, int *max, int *min)
{
*max = a;
*min = a;
if (b > *max)
*max = b;
if (b < *min)
*min = b;
if (c > *max)
*max = c;
if (c < *min)
*min = c;
}
int main(void)
{
int a, b, c;
int max, min;
scanf("%d%d%d", &a, &b, &c);
max_min(a, b, c, &max, &min);
printf("Proizvod max i min je: %d", max * min);
return 0;
}
Резултат извршавања програма:
20
7
12
Proizvod max i min je: 140
Пренос параметара у функцију max_min
:
main() max_min(int a, int, b, int c, int *max, int *min)

У првом разреду си решавао задатке у којима се пореде три броја. Један од
начина је да се на почетку претпостави да је први број и највећи-max и најмањи-min.
Остатак програма је поређење тренутне вредности са max
и min
. Управо је та идеја
искоришћена у овом задатку.
На почетку извршавања функције наредбама *max = a
и *min = a
вредности променљивих
на које указују показивачи *max
и *min
добијају вредност прве променљиве a
. Шта
смо заправо урадили? На посредан начин смо приступили стварним параметрима max
и min
и доделили им вредност.
max=a, min=a;
Вредности променљивих после наредбе *max = a
и *min = a
:
main() max_min(int a, int, b, int c, int *max, int *min)

У наставку извршавања функције max_min
, после наредбе if (b > *max)
, односно
if (7 > 20)
, вредности се неће мењати.
Међутим, услов if (b < *min)
, односно if (7 < 20)
је испуњен, па ће се извршити
наредба *min = b;
.
Вредности променљивих после наредбе *min = b
:
main() max_min(int a, int, b, int c, int *max, int *min)

Последња два услова c > *max
и c < *min
нису испуњена – наредбе се неће извршити,
вредност променљивих се неће мењати.
Вредности променљивих на крају извршења програма:
main() max_min(int a, int, b, int c, int *max, int *min)

Покушај да исти задатак урадиш са измењеним вредностима, нпр. а = 17
, b = 12
, с = 5
.
Анализирај детаљно вредности променљивих током извршавања програма.
Обрати пажњу! Функција scanf
је пример функције која даје бочне ефекте. Зато су
параметри у њој адресе променљивих у које се смештају учитане вредности.
Погледајмо кôд:
int a, b;
scanf("%d%d", &a, &b);
У првом реду резервисали смо меморијске локације за променљиве а
и b
.
У наредби scanf
навели смо адресе ових променљивих у које смештамо унете вредности.
Вежбање:¶
Дата је функција void funkcija(int k, int* n)
.
Који од следећих позива функције су нетачни и зашто? Целобројне променљиве k, m и n су декларисане у главном програму.
funkcija(&k, &n);
funkcija(k, n);
funkcija(k, m, n);
funkcija(2 * m + 1, &n);
Позив функције под 1 је неисправан, јер се као први параметар преноси адреса, а не вредност.
Позив функције под 2 је неисправан, јер се као други параметар преноси вредност, а не адреса.
Позив функције под 3 је неисправан, јер се при позиву функције наводи један аргумент више.
Једини тачан одговор је под 4.

Шта се исписује по извршењу програма за наведене улазне вредности?
#include<stdio.h>
void funkcija(int* n)
{
*n += 5;// *n = *n + 5;
}
int main(void)
{
int m, n;
scanf("%d", &n);
funkcija(&n);
printf("n = %d", n);
return 0;
}
За n = -13 излаз је |blank|.
За n = 5 излаз је |blank|.
За n = 21 излаз је |blank|.

Шта се исписује по извршењу програма за наведене улазне вредности?
#include<stdio.h>
void funkcija(int* n)
{
*n++;
}
int main(void)
{
int m, n;
scanf("%d", &n);
funkcija(&n);
printf("n = %d", n);
return 0;
}
За n = 21 излаз је |blank|.
За n = -29 излаз је |blank|.
За n = 0 излаз је |blank|.
Излаз је исти као улазна вредност, јер се у функцији вредност показивача увећава
за један, а не вредност параметра n
. Овде мораш бити обазрив – сада показивач у
функцији показује на недозвољени део меморије.

Шта се исписује по извршењу програма за наведене улазне вредности?
#include<stdio.h>
void funkcija(int* n)
{
(*n)++;
}
int main(void)
{
int m, n;
scanf("%d", &n);
funkcija(&n);
printf("n = %d", n);
return 0;
}
За n = 51 излаз је |blank|.
За n = -29 излаз је |blank|.
За n = 0 излаз је |blank|.
С обзиром да заграда има већи приоритет, наредбом *n
се прво приступа променљивој
n
, а затим се њена вредност увећа за 1
.
Дата је функција
void funkcija(int x, int *y, int *z)
{
x = *y + *z;
(*z)--;
(*y)--;
}
У главном програму су декларисане променљиве:
int a = 5, b = 10, c = 15
Које вредности ће имати променљиве a, b, c после позива функције у главном програму funkcija(a, &b, &c)? |blank|,|blank|,|blank|.