Vezbe iz Osnova programiranja – pokazivaci (uvod)


 

98. Šta je rezultat rada sledećeg programa? Primer koji ilustruje operator &

prikaz adrese i sadrzaja u memoriji


/* broj karaktera u nizu */
#define MAX 10
 char niz[MAX] = "012345678";    /* niska znakova*/


main()
{
   int index;   /* brojac u petlji  */

  /* stampanje clanova niza prema zahtevu */
  for (index = 0; index < MAX; index++)
     {
        printf( "&niz[index]=0x%x (niz+index)=0x%x niz[index]=0x%x\n", &niz[index], (niz+index), niz[index]);
     }


 return (0);
}

99. Sta je rezultat rada sledećeg programa?
Primer koji ilustruje rad sa pokazivacima

#include <stdio.h>

main()

{

int x = 3;


/* Adresu promenjive x zapamticemo u novoj promenljivoj.

Nova promenljiva je tipa pokazivaca na int (int*) */

int* px;

printf("Adresa promenljive x je : %p\n", &x);

printf("Vrednost promenljive x je : %d\n", x);


px = &x;

printf("Vrednost promenljive px je (tj. px) : %p\n", px);

printf("Vrednost promenljive na koju ukazuje px (tj. *px) je : %d\n", *px);


/* Menjamo vrednost promenljive na koju ukazuje px */

*px = 6;

printf("Vrednost promenljive na koju ukazuje px (tj. *px) je : %d\n", *px);


/* Posto px sadrzi adresu promenljive x, ona ukazuje na x tako da je

posredno promenjena i vrednost promenljive x */

printf("Vrednost promenljive x je : %d\n", x);

}




Izlaz (u konkretnom slucaju):

Adresa promenljive x je : 0012FF88

Vrednost promenljive x je : 3

Vrednost promenljive px je (tj. px) : 0012FF88

Vrednost promenljive na koju ukazuje px (tj. *px) je : 3

Vrednost promenljive na koju ukazuje px (tj. *px) je : 6

Vrednost promenljive x je : 6



100. Sta je rezultat rada sledećeg programa?
Primer koji ilustruje prenos argumenata preko pokazivaca – funkcija koja vrsi trampu vrednosti dva cela broja.

Podsetimo se:
U programskom jeziku C parametri se mogu predati funkciji po _______________ i po ______________.
Kada god je potrebno da funkcija menja vrednost svojih stvarnih parametara i tako izmenjene ih vrati pozivajucoj jedinici, onda se ti parametri predaju funkciji po ____________________.
Kada god je potrebno da funkcija svoje stvarne parametre vrati pozivajucoj jedinici nepromenjene, onda se ti parametri predaju funkciji po ____________________.
Kada god je potrebno da funkcija vrati pozivajucoj jedinici vise rezultata, onda se ti rezultati prenose kao parametri funkcije i predaju funkciji po ____________________.

 

#include <stdio.h>


/* Pogresna verzija funkcije swap. Zbog prenosa po vrednosti, funkcija

razmenjuje kopije promenljivih iz main-a, a ne samih promenljivih */

void swap_sa_greskom(int x, int y)

{

int tmp;

printf("swap_sa_greskom: ");

printf("Funkcija menja vrednosti promenljivim na adresama : \n");

printf("x : %p\n", &x);

printf("y : %p\n", &y);

tmp = x;

x = y;

y = tmp;

}




/* Resenje je prenos argumenata preko pokazivaca */

void swap(int* px, int* py)

{

int tmp;

printf("swap : Funkcija menja vrednosti promenljivim na adresama : \n");

printf("px = %p\n", px);

printf("py = %p\n", py);

tmp = *px;

*px = *py;

*py = tmp;

}


main()

{

int x = 3, y = 5;

printf("Adresa promenljive x je %p\n", &x);

printf("Vrednost promenljive x je %d\n", x);

printf("Adresa promenljive y je %p\n", &y);

printf("Vrednost promenljive y je %d\n", y);


/* Pokusavamo zamenu koristeci pogresnu verziju funkcije */

swap_sa_greskom(x, y);

printf("Posle swap_sa_greskom:\n");

printf("Vrednost promenljive x je %d\n", x);

printf("Vrednost promenljive y je %d\n", y);


/* Vrsimo ispravnu zamenu. Funkciji swap saljemo adrese promenljvih x i y, a ne njihove vrednosti */

swap(&x, &y);

printf("Posle swap:\n");

printf("Vrednost promenljive x je %d\n", x);

printf("Vrednost promenljive y je %d\n", y);

}




Izlaz u konkretnom slucaju:

Adresa promenljive x je 0012FF88

Vrednost promenljive x je 3

Adresa promenljive y je 0012FF84

Vrednost promenljive y je 5

swap_sa_greskom: Funkcija menja vrednosti promenljivim na adresama :

x : 0012FF78

y : 0012FF7C

Posle swap_wrong:

Vrednost promenljive x je 3

Vrednost promenljive y je 5

swap : Funkcija menja vrednosti promenljivim na adresama :

px = 0012FF88

py = 0012FF84

Posle swap:

Vrednost promenljive x je 5

Vrednost promenljive y je 3


 

101. Šta je rezultat rada sledećeg programa? Primer koji ilustruje visestruko referenciranje.

pointer na pointer


#include <stdio.h>
char * c[]={"html","\\a","HEAD","a\thref","\\body"};
char **cp[]={c+3,c+4,c,c+1,c+2};
char ***cpp=cp;
main()
{   printf("1 %s\n", **++cpp);
    printf("2 %s\n", **++cpp+1);
   printf("3 %s\n", *((--cpp)[-1]) );
    printf("4 %s\n", **cpp+1);
    printf("5 %s\n", **++cpp);
    return 0;
 }


102. Napisati C potprogram div_and_mod koji kao rezultat vraca celobrojni deo kolicnika i ostatak pri deljenju dva cela broja x i y. NCP koji ilustruje rad sa potprogramom.


Primer koji ilustruje rad sa vise povratnih vrednosti funkcije koristeci prenos argumenata preko adrese (tj. pokazivace).


/* Funkcija istovremeno vraca dve vrednosti - kolicnik i ostatak dva data broja.

Ovo se postize tako sto se funkciji predaju vrednosti dva broja (x i y) koji se dele

i adrese dve promenljive na koje ce se smestiti rezultati */


void div_and_mod(int x, int y, int* div, int* mod)

{

printf("Kolicnik postavljam na adresu : %p\n", div);

printf("Ostatak postavljam na adresu : %p\n", mod);

*div = x / y;

*mod = x % y;

}


main()

{

int div, mod;

printf("Adresa promenljive div je %p\n", &div);

printf("Adresa promenljive mod je %p\n", &mod);


/* Pozivamo funkciju tako sto joj saljemo vrednosti dva broja (5 i 2)

i adrese promenljvih div i mod na koje ce se postaviti rezultati */

div_and_mod(5, 2, &div, &mod);


printf("Vrednost promenljive div je %d\n", div);

printf("Vrednost promenljive mod je %d\n", mod);

}


Izlaz u konkretnom slucaju:

Adresa promenljive div je 0012FF88

Adresa promenljive mod je 0012FF84

Kolicnik postavljam na adresu : 0012FF88

Ostatak postavljam na adresu : 0012FF84

Vrednost promenljive div je 2

Vrednost promenljive mod je 1


 

103. NCP koji ispisuje broj argumenata komandne linije i parametre komandne linije.

argumenti komandne linije


#include <stdio.h>

/*argumenti komandne linije */
main(int argc, char *argv[] )
{  int i;  /*brojac u petlji */
   printf("Broj argumenata je %d\n", argc);
   /*stampanje svakog argumenta u zasebnom redu */
  for(i=0;i<argc;i++)
     printf( "argv[%d] = %s\n", i , argv[i] );
}



104.
NCP koji na izracunava i na standardni izlaz ispisuje sumu brojeva koji se zadaju u komandnoj liniji. Celi brojevi se zadaju posle imena programa i opcije -d. Realni brojevi se zadaju posle imena programa i opcije -f.

RESENJE:

Dakle, program mora da radi sa sledecom vrstom poziva iz komandne linije:

U slucaju da korisnik u komandnoj liniji zada samo naziv programa, dobro bi bilo da program obavestiti korisnika da nije uneo dovoljno argumenata za pokretanje programa i da program prekine dalji rad.
U slucaju da korisnik u komandnoj liniji izostavi znak horizontalne crte, dobro bi bilo da program program prekine dalji rad i obavestiti korisnika da nije uneo opcije na korektan nacin.
U slucaju da korisnik u komandnoj liniji nakon znaka horizontalne crte unese znak koji nije slovo d ili f, dobro bi bilo da program program prekine dalji rad i obavestiti korisnika da nije uneo opcije na korektan nacin.
U slucaju da korisnik u komandnoj liniji unese opciju -d, onda konvertovati argumente komandne linije u cele brojeve f-jom atoi.
U slucaju da korisnik u komandnoj liniji unese opciju -f, onda konvertovati argumente komandne linije u realne brojeve f-jom atof.

#include <stdio.h>
#include <stdlib.h>

typedef enum {GR1, GR2, GR3} kodGreske;

char *greske[]=
{ "Nekorektno pokretanje programa. Morate navesti i opcije i konkretne brojeve\n",
   "Nekorektno zadavanje opcija -d ili -f\n",
   "Nekorektno slovo u opciji. MORATE uneti -d ili -f\n"
};

void ispisGreske(kodGreske broj);

main(int argc, char*argv[])
{
    int i; /*brojac u ciklusu*/
    int s1=0; /*suma celih brojeva */
    double s2=0; /*suma realnih brojeva*/

if (argc<2) ispisGreske(GR1);

if(*argv[1]!='-') ispisGreske(GR2);

/*analiza opcije, tj. slova iza - */
switch(*(argv[1]+1))
{
   case 'd': for (i=2;i<argc;i++)  s1+=atoi(argv[i]);
                 printf("\n Suma CELIH brojeva iz komandne linije: %d\n ", s1);
                 break;
  case 'f': for (i=2;i<argc;i++)  s2+=atof(argv[i]);
                 printf("\n Suma REALNIH brojeva iz komandne linije: %f\n ", s2);
                 break;
 default: ispisGreske(GR3);  break;
 }

}


void ispisGreske(kodGreske j)
{  fprintf(stderr,  greske[j]);
   exit(EXIT_FAILURE);
}

105.
NCP koji u datoteku prosti.txt upisuje proste brojeve zadatog intervala kojima je zbir cifara složen broj. Interval se zadaje učitavanjem gornje i donje granice (dva prirodna broja) u komandnoj liniji. Brojeve upisivati u datoteku u opadajućem poretku. U programu nije potrebno predvideti obradu greski nastalih usled nekorektnog pozivanja programa u komandnoj liniji ili greske u otvaranju datoteke... Program treba da radi sa preusmeravanjem standardnog izlaza.

gcc zad105.c -o zad105

POKRETANJE PROGRAMA: zad105 10 40
daje u izlaznoj datoteci prosti.txt IZLAZ

37 31 19 17 13
jer broj 37 je prost, a zbir cifara 3+7=10 je slozen broj
...

#include <stdio.h>
#include <stdlib.h>

int prost (int n);  /*testira da li je broj n prost broj */
/*Prirodni brojevi (sem 1) imaju najmanje dva delioca:jedinicu i samog sebe.
   Brojevi koji nemaju drugih delioca,sem ova dva, nazivaju se prostim */

int zbirCifara (int n);   /*vraca zbir cifara broja n */


main(int argc, char **argv)
{ int donja,gornja;  /*granice intervala */
   int i;  /*brojac u petlji */
   int pom;   /*posrednik u eventualnoj trampi granica intervala*/
  

  /* "ucitavanje" granica intervala iz niski argv[1], argv[2] u komandnoj liniji i konverzija u cele brojeve*/
  sscanf(argv[1], "%d", &donja);  /*donja=atoi(argv[1]) */
  sscanf(argv[2], "%d", &gornja);  /*gornja=atoi(argv[2]) */


  if (donja > gornja)   /*obezbedjivanje relacije: donja <=gornja */
    { pom=donja;
      donja=gornja;
      gornja=pom;
    }

  /*brojevi ce se upisivati u datoteku u opadajucem poretku gornja - > donja*/
   for(i=gornja;i>=donja; i--)
    if (prost (i) && !prost(zbirCifara(i) )  ) printf("%d  ",i);

  
  
}


int prost(int n)  /*Ispituje se da li je broj n prost tako to se proverava da li ima delioce
medju brojevima od 2 do n/2.  Pri implementaciji se koristi tvrdjenje da je broj prost ako je jednak 2, ili 
ako je neparan i ako nema delitelja medju neparnim brojevima od 3 do n/2 */
{
  int prost;  /*indikator slozenosti broja n */
  int i;    /*potencijalni delitelj broja n */
  if (n==1) return 0;
  prost= (n%2!=0) || (n==2);    /*parni brojevi razliciti od  od dva nisu prosti brojevi */
  
  i=3;   /*najmanji potencijalni kandidat za delitelje medju neparnim brojevima razlicitim od jedan */
  while   ( (prost) && (i<=n/2) )
   { prost=n%i != 0;
     i=i+2; /*proveravamo kandidate za delitelje samo medju neparnim brojevma */ 
    }
 return prost;
}


int zbirCifara (int n)
{ int  Suma=0;  
   while (n>0)
  { Suma+= n%10;  /*dodavanje cifre tekuceg razreda,pocev od razreda jedinica ,
                   a iduci ka visim razredima cifara */
    n=n/10;      /*prelaz ka visem razredu */
  }
 return Suma;
}

106. NCP koji sa standardnog ulaza učitava 3x3 matricu i ispisuje je na standardni izlaz tako da centralno polje a[1][1] bude jednako sumi gornjeg levog (a[0][0]) i donjeg desnog polja (a[2][2]). Pre ucitavanja popuniti matricu proizvoljnim vrednostima.

#include <stdio.h>

main()

{

int a[3][3] = {{0, 1, 2}, {10, 11, 12}, {20, 21, 22}}; /* deklaracija i inicijalizacija matrice a */

int i, j; /*brojaci u ciklusu */



/* unos elemenata matrice */

for(i=0; i<3; i++)

for(j=0; j<3; j++)

{

printf("\na[%d][%d] = ", i, j);

scanf("%d", &a[i][j]);

}


printf("\n*************\n");


a[1][1] = a[0][0] + a[2][2]; /* 0 + 22 = 22 */


/*ispis matrice */


for(i=0; i<3; i++)

{

for(j=0; j<3; j++) printf("%d\t", a[i][j]);

printf("\n");

}


}


107. NCP koji sa standardnog ulaza učitava raspored 8 topova na šahovskoj tabli. Raspored se učitava u formi 8 linija sa po 8 brojeva po liniji. Ako na datom polju nema topa, učitava se 0, a inače 1. Program mora da ispita validnost unetog rasporeda ( da li su učitani brojevi ili 0 ili 1, da li ima 8 topova) i ispita da li se u datom rasporedu dva topa tuku.





#include <stdio.h>
#include <stdlib.h>

main()
{ int tabla[8][8];  /*matrica nula i jedinica  cuva raspored  8  topova na  tabli */
   int suma;          /* pamti se suma reda/kolone kao test osobina iz zahteva zadatka */
    int i,j;               /*brojaci u petljama */

/*ucitavanje podataka o rasporedu topova  uz sumiranje broja topova i u slucaju greske
   stampa se odgovarajuca poruka i okoncava programa */
suma=0;
 for (i=0; i<8; i++ )
   for (j=0; j<8; j++)
     {  scanf("%d", &tabla[i][j]);

          /*test korektnosti ulaza */
          if (tabla[i][j] !=0 && tabla[i][j] !=1 )
             { printf ("\nNekorektni  ulazni podaci o rasporedu topova\n");
                 exit(EXIT_FAILURE);
             }
          suma=suma + tabla[i][j];
     }
 

/*greska je ako je broj topova na tabli razlicit od 8 */
if (suma !=8)
  { printf ("\nNekorektni  ulazni podaci o broju topova\n");
                 exit(EXIT_FAILURE);
    }

/*proveravanje da li se dva topa nalaze u istom redu , tj. da li je suma
   clanova nekog reda  veca od 1 */
for(i=0;i<8;i++)
  {
       suma=0;
       for (j=0;j<8;j++)  suma+=tabla[i][j];
       if (suma >1 )
        { printf ("\nTopovi se tuku\n");
                 exit(EXIT_SUCCESS);
         }
    }
 

/*proveravanje da li se dva topa nalaze u istoj koloni , tj. da li je suma
   clanova neke kolone    veca od 1 */
for(j=0;j<8;j++)
  {
       suma=0;
       for (i=0;i<8;i++)  suma+=tabla[i][j];
       if (suma >1 )
        { printf ("\nTopovi se tuku\n");
                 exit(EXIT_SUCCESS);
         }
    }
 

/*inace se topovi ne tuku */
printf ("\nTopovi se ne tuku\n");
exit(EXIT_SUCCESS);

}
 



Zadaci za vezbu:

Zadatak 1. Šta ispisuje sledeći kod:


#include <stdio.h>

main() {

int a[] = { 1, 2, 3, 4, 5, 6};

int * z=&a[2];

z-=3;

z+=2;

printf("%d\n",*z); }

2

 

 


Zadatak 2. Šta ispisuje sledeći kod


#include <stdio.h>

main()  {

int x=1,y=2,z=3,*p;

p=&x;

*p=y;

p=&y;

*p=x+z;

printf("x:%d y:%d z:%d\n",x,y,z);

}

  

x:2 y:5 z:3 

 

 


Zadatak 3. (prenos parametara funkcije po adresi) Napisati funkciju void minimax3 (int a, int b, int c, int *min, int *max) koja za date brojeve a,b,c odredjuje njihov max i njihov min. Napisati C program koji ucitava 3 cela broja i pozivajuci funkciju minimax3 ispisuje max i min za unete brojeve.

POMOC: *min=minimum(minimum(a,b), c); gde minimum(x,y) je f-ja koja racuna minimum dva broja

ili pomocu operatora ?:

*min= (a)<(b) ? ((a)<(c) ? (a) : (c)) : ((b)<(c) ? (b) : (c))



Zadatak 4. Napisati funkciju koja za dati celobrojni niz a[] vraca srednju vrednost i zbir niza i to srednju vrednost kao povratnu vrednost funkcije, a zbir kroz listu argumenata.


Zadatak 5. Napisati f-ju compare koja poredi dve niske a, i b i vraca 1 ako jesu jednake, vraca 0 ako nisu jednake. NCP koji unosi sa standardnog ulaza dve niske sa do 20 karaktera i koristeci funkciju compare ispisuje na standardni izlaz da li su date niske razlicite.


Zadatak 6. Napisati f-ju compare koja poredi dve niske a, i b i vraca 1 ako jesu jednake, vraca 0 ako nisu jednake. NCP koji koristeci funkciju compare ispisuje na standardni izlaz da li su razlicite dve niske koje se zadaju kao parametri (argumenti) komandne linije.

Zadatak 7. Popuniti sledecu tabelu:

zadatak sa II kolokvijuma 2005.

Zadatak 8. NCP koji ucitava sa standardnog ulaza najpre dimenziju kvadratne matrice, a potom i elemente te matrice. Na standardni izlaz ispisati zbir elemenata na glavnoj dijagonali.

Zadatak 9. NCP koji ucitava sa standardnog ulaza najpre dimenziju kvadratne matrice, a potom i elemente te matrice. Na standardni izlaz ispisati zbir elemenata na sporednoj dijagonali.