Бочни ефекти функција

Често је потребно да у програму користимо посебне логичке целине – потпрограме који не дају само једну излазну вредност већ неколико вредности (резултата) или уопште не дају резултате већ обављају неки посебан задатак, попут штампе…

Видели смо да параметри функција садрже копије одговарајућих аргумената. Због тога није могуће променом вредности параметара унутар функције створити додатне резултате, односно променити вредност аргумената у главном програму, поред вредности функције. Програмски језик C дозвољава изношење резултата из функције посредством параметара, али је то могуће извести искључиво индиректним адресирањем параметара.

Да вас подсетим:

Променљиве у програмском језику су објекти који имају неку вредност, која се може мењати у току извршавања програма. Име променљиве се повезује са адресом меморијске локације у којој је уписана текућа вредност променљиве. Овакав приступ подацима, где се на адреси у меморији чува ВРЕДНОСТ податка назива се директно адресирање.

Са друге стране, постоји и индиректно адресирање, код кога се у меморији чува адреса на којој је уписана вредност траженог податка. Индиректно адресирање се у програмском језику C реализује помоћу показивача. Показивач (енгл. pointer) представља променљиву која чува адресу меморијске локације неког другог податка.

Дакле, применом индиректног адресирања код параметара функције ми, у ствари, користимо показиваче. То другим речима значи да се параметри у функцију не уносе помоћу вредности, него помоћу адресе. Због тога се такви параметри називају параметри показивачки типова или краће показивачки параметри.

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

Функције у језику C могу истовремено да дају вредност функције и да стварају бочне ефекте. Могуће је чак да функције не дају вредност функције и тада се за ознаку типа вредности функције користи службена реч void. Такве функције своје резултате стварају искључиво кроз бочне ефекте. Пошто не враћају вредност функције у њима не постоји наредба return. Повратак из функције наступиће при доласку до краја тела функције. Ове функције могу се позивати искључиво засебним наредбама у програму, не могу бити део неког аритметичког израза!

Параметри наведени при позиву функције називају се стварни, а параметри наведени у опису функције називају се формални. Стварни параметри се другачије називају аргументи!

Параметар показивачког типа може се сматрати само средством за долажење до податка који је предмет обраде. Суштински аргумент функције је тај обрађивани податак чија се адреса доставља преко показивача. Због тога се каже да се показивачким параметрима аргументи преносе у функције помоћу адресе.

Ако је параметар показивач на податке неког типа, аргумент може да буде само показивач на податке истог типа. Показивачки аргумент је најчешће адресни израз којим се формира адреса неке променљиве (&prom). Другим речима – у дефиницији функције која враћа бочне ефекте за показивачке параметре користе се показивачи (*p), а при позиву те функције за показивачке параметре користе се адресни изрази (&prom).

Пример:

Нека су улазне вредности два цела броја m и n, а резултат цели бројеви p и q. Резултат p треба да буде збир квадрата бројева од m до n, а резултат q збир кубова од m до n. Уместо увођења две функције kv (за израчунавање збира квадрата) и kub (за израчунавање збира кубова) написаћемо један потпрограм који ћемо назвати KvKub у којој се израчунавају вредности резултата p и q. Тај програм је функција која враћа бочне ефекте. Њен тип је void, а параметри p и q треба да буду дефинисани као показивачки параметри (*pKv, *pKub).

#include<stdio.h>
void KvKub(int m, int n, int *pKv, int *pKub)
{
int i;
*pKv=0;*pKub=0;
for (i=m;i<=n;i++)
{
*pKv=*pKv+i*i;
*pKub=*pKub+i*i*i;
}
}
main()
{
int m,n,k,l,p,q,r;
KvKub(2,4,&p,&q);
printf("zbir kvadrata od 2 do 4 iznosi:%d, a zbir kubova: %d\n",p,q);
printf("unesi 4 cela broja");
scanf("%d%d%d%d",&m,&n,&k,&l);
KvKub(m,n,&p,&q);
printf("zbir kvadrata od %d do %d iznosi:%d, a zbir kubova: %d\n",m,n,p,q);
KvKub(m-k,n+l,&p,&r);
printf("zbir kvadrata od %d-%d do %d+%d iznosi:%d, a zbir kubova: %d\n",m,k,n,l,p,r);
}

Прва два параметра су „улазни подаци”: Они се у функцију преносе помоћу вредности. На месту позива функције у променљиве m и n уписују се копије вредности аргумената. Наш потпрограм израчунава вредности збира квадрата и збира кубова. Ови параметри су дефинисани као показивачки параметри (*pKv, *pKub), да би се омогућило да се помоћу њих резултати врате у главни програм. Показивачки параметри се у функцију преносе помоћу адресе. На месту позива функције у променљиве *pKv и *pKub (а то су показивачи, чија вредност је адреса!) уписују се адресе променљивих у које желимо да упишемо израчунате вредности!

Први позив ове функције је наредба:

KvKub(2,4,&p,&q);

На том месту процедура се извршава са улазним подацима 2 и 4. Резултати ће бити уписани на адресе променљивих p и q. Због тога потпрограм, односно функција која враћа бочне ефекте има директан приступ овим локацијама (иако оне физички припадају меморијском простору намењеном за променљиве које припадају главном програму), тако да у њих може уписати резултате кад их израчуна.

Advertisements

Низови – задаци

Да се подсетимо:

Низ је структура података истог типа који имају заједничко име а појединачним елементима се приступа на основу редног броја. За дефинисање низа и за приступ елементима низа користе се []. Редни бројеви (индекси) крећу се од 0 до n-1. Елементима низа може се приступати и помоћу показивача:

#include<stdio.h>
main()
{
 int a[20],*p,zbir,n,i;

printf("unesi n");scanf("%d",&n);
 for (p = a; p < a + n; p++)scanf("%d", p);
 zbir=0;
 for(p=a;p<a+n;p++)zbir=zbir+(*p);
 printf("zbir=%d",zbir);

}

За рад са низовима могу се дефинисати функције за унос елемената низа, за приказивање елемената низа, за нека израчунавања над елементима низа. За пренос елемената низа у функцију и у програм низ се дефинише преко показивача, јер функција не формира локалну копију низа (као што је случај са појединачним подацима) већ се директно ради са елементима низа. Због тога се при дефинисању функције за низ користи само име низа, а не наводи се његова димензија, тако да заглавље функције за унос елемената целобројног низа има следећи изглед:

void unesi(int a[], int n)

1. Написати програм који израчунава средњу вредност оних елемената низа целих бројева који су дељиви са 3.

#include<stdio.h>
main() 
{
 int a[20],i,k,n;
 float s,as;
 printf("unesi n"); scanf("%d",&n);
 printf("unesi elemente niza");
 for(i=0;i<n;i++)scanf("%d",&a[i]);
 s=0;k=0; 
for(i=0;i<n;i++)if(a[i]%3==0){s=s+a[i];k++;}
 if(k!=0)
{
as=s/k;
 printf("srednja vrednost elemenata deljivih sa 3 je %8.2f",as);
}
 else printf("nema elemenata deljivih sa 3");
 }

2. Написати програм који обрће редослед елемената низа, односно мења места првог и последњег, другог и претпоследњег…

#include<stdio.h>
main()
 {
 float a[20],b;
 int n,i,j; 
printf("unesi n"); scanf("%d",&n);
 printf("unesi elemente niza");
 for(i=0;i<n;i++)scanf("%f",&a[i]); 
for(i=0,j=n-1;i<j;i++,j--){b=a[i];a[i]=a[j];a[j]=b;} 
printf("novodobijeni niz:\n"); 
for(i=0;i<n;i++)printf("%8.2f\t",a[i]);
 }

3. Написати програм који саставља нови низ који се састоји од елеманата унетог низа при чему су изостављени елементи једнаки задатој вредности k.

#include<stdio.h>
main() 
{
 int i,j,k,n,a[20];
 printf("unesi n"); scanf("%d",&n);
 printf("unesi elemente niza"); 
for(i=0;i<n;i++)scanf("%d",&a[i]); 
printf("unesi broj koji treba izbaciti iz niza");scanf("%d",&k); 
for(i=0,j=0;i<n;i++)if(a[i]!=k)a[j++]=a[i];
 n=j;
 printf("novodobijeni niz:\n"); 
for(i=0;i<n;i++)printf("%d\t",a[i]); 
}

 

4. Написати програм који у уређени низ бројева умеће нови елеменат, али тако да низ остане уређен. Задатак решити тако да се уносе елементи низа, након тога сортирати низ, и тек онда у сортирани низ уметнути нови елеменат.

#include<stdio.h>
main() 
{
 int i,n,b,a[20],j,pom;
 printf("unesi n"); scanf("%d",&n);
 printf("unesi elemente niza");
 for(i=0;i<n;i++)scanf("%d",&a[i]);
 /* sortiranje niza */ 
for(i=0;i<n-1;i++) 
for(j=i+1;j<n;j++) 
if(a[i]>a[j]) { pom=a[i]; a[i]=a[j]; a[j]=pom; }
 printf("unesi broj koji treba dodati u niz");scanf("%d",&b);
 /* umetanje elementa u niz */ 
for(i=n-1;i>=0&&a[i]>b;i--)a[i+1]=a[i];
 a[i+1]=b;
 n++;
 printf("novodobijeni niz:\n");
 for(i=0;i<n;i++)printf("%d\t",a[i]);
 }

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

#include<stdio.h>
main() 
{ 
int a[20],b[20],c[20],na,nb,nc,i; 
printf("unesi n"); scanf("%d",&na); 
printf("unesi elemente niza"); 
for(i=0;i<na;i++)scanf("%d",&a[i]); 
nb=0;nc=0; 
for(i=0;i<na;i++)
 if(a[i]<0)b[nb++]=a[i];
 else c[nc++]=a[i]; 
printf("niz negativnih brojeva:"); 
for(i=0;i<nb;i++)printf("%d\t",b[i]);
 printf("\n");
 printf("niz pozitivnih brojeva:");
 for(i=0;i<nc;i++)printf("%d\t",c[i]); 
}

6. Написати програм који спаја два сортирана низа при чему новодобијени низ такође треба да буде сортиран. Задатак решити тако да се уносе елементи оба низа, након тога сортирати низове, и тек онда спојити два сортирана низа како би се добио нови, сортирани низ.

#include<stdio.h>
main()
 { 
int a[20],b[20],c[40],na,nb,nc,ia,ib,ic,j,pom;
printf("unesi n za niz a"); scanf("%d",&na);
 printf("unesi elemente niza a"); 
for(ia=0;ia<na;ia++)scanf("%d",&a[ia]);
 /* sortiranje niza a */ 
for(ia=0;ia<na-1;ia++)
 for(j=ia+1;j<na;j++)
 if(a[ia]>a[j]) { pom=a[ia]; a[ia]=a[j]; a[j]=pom; }
 printf("sortirani niz:");
for(ia=0;ia<na;ia++)printf("%d\t",a[ia]);
 printf("\n");
 printf("unesi n za niz b"); scanf("%d",&nb);
 printf("unesi elemente niza b"); 
for(ib=0;ib<nb;ib++)scanf("%d",&b[ib]);
 /* sortiranje niza b */
 for(ib=0;ib<nb-1;ib++)
 for(j=ib+1;j<nb;j++)
 if(b[ib]>b[j]) { pom=b[ib]; b[ib]=b[j]; b[j]=pom; }
 printf("sortirani niz:");
for(ib=0;ib<nb;ib++)printf("%d\t",b[ib]); 
printf("\n");
 for(ia=0,ib=0,ic=0;ia<na&&ib<nb;ic++)
 if(a[ia]<b[ib])c[ic]=a[ia++];
 else c[ic]=b[ib++]; 
while(ia<na)c[ic++]=a[ia++]; 
while(ib<nb)c[ic++]=b[ib++];
 nc=ic; 
printf("novodobijeni niz:");
 for(ic=0;ic<nc;ic++)printf("%d\t",c[ic]);
 }

функције – задаци

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

1. Дефинисати функцију која израчунава збир два цела броја. У главном програму, применом дате функције израчунати
а) збир првих n бројева

 #include<stdio.h>
 int zbir (int a, int b) /* definicija funkcije zbir */
 {
      int s; /* definisanje lokalne promenljive */
      s=a+b;
      return s; /* povratak u glavni program */
 }
 main()
 {
      int i,n,s;
      printf("unesi broj n");
      scanf("%d",&n);
      s=0;
      for(i=1;i<=n;i++)s=zbir(s,i); /* poziv funkcije */
      printf("zbir prvih n brojeva: %d",s);
 }

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

 #include<stdio.h>
 int zbir (int a, int b)
 {
      return a+b;
 }
 main()
 {
      int i,n,s;
      printf("unesi broj n");
      scanf("%d",&n);
      s=0;
      for(i=1;i<=n;i++)s=zbir(s,i);
      printf("zbir prvih n brojeva: %d",s);
 }

б) збир унетих n бројева

 #include<stdio.h>
 int zbir (int a, int b)
 {
      int s;
      s=a+b;
      return s;
 }
 main()
 {
      int i,n,s,a;
      printf("unesi broj n");
      scanf("%d",&n);
      s=0;
      for(i=1;i<=n;i++) 
      {
           printf("unesi broj");
           scanf("%d",&a);
           s=zbir(s,a);
      }
      printf("zbir prvih n brojeva: %d",s);
 }

2. Дефинисати функцију која израчунава растојање између две тачке задате координатама x и y. У главном програму унети координате три течке и израчунати површину троугла.

#include<stdio.h>
#include<math.h>
 double duzina(double x1, double y1, double x2, double y2) 
{
      double r;
      r=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
      return r;
 }
 main()
 {
      double x1,x2,x3,y1,y2,y3,a,b,c,s,P; 
      printf("unesi koordinate tri tacke"); 
      scanf("%lf%lf%lf%lf%lf%lf",&x1,&y1,&x2,&y2,&x3,&y3);
      a=duzina(x1,y1,x2,y2);
      b=duzina(x2,y2,x3,y3);
      c=duzina(x3,y3,x1,y1);
      if((a+b>c)&&(b+c>a)&&(c+a>b))
      {
           s=(a+b+c)/2;
           P=sqrt(s*(s-a)*(s-b)*(s-c));
           printf("P=%8.2f",P);
      }
      else printf("pogresni podaci");
 }

3. Написати функцију која одређује максимум два цела броја. У главном програму одредити максимум 3 цела броја.

 #include<stdio.h>
 int max(int a, int b)
 {
      if (a>b)return a;
      else return b;
 }
 main()
 {
      int x,z,y,m;
      printf("unesi tri cela broja");
      scanf("%d%d%d",&x,&y,&z);
      m=max(x,y);
      m=max(z,m);
      printf("najveci od tri uneta broja je: %d",m);
 }

4. Написати функцију која израчунава обим круга полупречника r. У главном програму израчунати суму обима n унетих кругова.

 #define PI 3.14159
 #include<stdio.h>
 float obim(float r)
 {
      return 2*r*PI;
 }
 main()
 {
      float r,s;
      int i,n;
      printf("unesi n");
      scanf("%d",&n);
      s=0;
      for(i=1;i<=n;i++)
      {
           printf("unesi poluprecnik kruga");
           scanf("%f",&r);
           s=s+obim(r);
      }
      printf("zbir obima unetih krugova je: %8.2f",s);
 }

5. Написати функцију која израчунава реципрочну вредност броја (1/x). У главном програму израчунати

%d1%84%d0%be%d1%80%d0%bc%d1%83%d0%bb%d0%b01

#include<stdio.h>
 float rec(float x)
 {
      return 1/x;
 }
 main()
 {
      float x,s;
      int i,n;
      printf("unesi n");
      scanf("%d",&n);
      printf("unesi x");
      scanf("%f",&x);
      s=1;
      for(i=1;i<=n;i++)s=s+rec(i*x);
      printf("s=%8.2f",s);
 }

6. Написати функцију која израчунава n-ти степен броја x. У главном програму израчунати

%d1%84%d0%be%d1%80%d0%bc%d1%83%d0%bb%d0%b02

#include<stdio.h>
 float stepen(float x, int n)
 {
      int i;float p;p=1;
      for(i=1;i<=n;i++)p=p*x;
      return p;
 }
 main()
 {
      float x,s;
      int i,n;
      printf("unesi n");
      scanf("%d",&n);
      printf("unesi x");
      scanf("%f",&x);
      s=1;
      for(i=1;i<=n;i++)s=s+i/stepen(x,i);
      printf("s=%8.2f",s);
 }

7. Написати функцију која израчунава tgx. У главном програму израчунати%d1%84%d0%be%d1%80%d0%bc%d1%83%d0%bb%d0%b03

#include<stdio.h>
 #include<math.h>
 double tg(double x)
 {
      return sin(x)/cos(x);
 }
 main()
 {
      double x,y;
      printf("unesi x");
      scanf("%lf",&x);
      y=2*tg(2*(x/3)+7)-sin(sqrt(x*x+1));
      printf("y=%8.2f",y);
 }

 

Алгоритми

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

Другим речима, алгоритам је упутство како решити неки задатак или проблем. Тако се и упутство за полетање авиона и упутство за прављење руске салате састоји од низа корака, поступака, које треба урадити и који воде испуњењу циља или решавању проблема. Упутство може садржати кораке који се понављају више пута или кораке када треба донети неку одлуку, на основу неког критеријума. Добро упутство предвиђа и поступак када нису сви услови испуњени нпр. нема довољно горива у резервоарима авиона, или нема кромпира у фрижидеру а почели смо да спремамо жуманце за мајонез. Коректно извршавање сваког корака не решава задатак ако је алгоритам био погрешан.

Наставите са читањем

пример исправљања грешака у програму

Кроз један пример видећемо како могу да се исправљају грешке које се јављају у програмирању.

Задатак: Написати програм који уређује елементе k-те врсте од најмањег до највећег, и приказује новодобијену матрицу.

Наставите са читањем