Vezbe iz Osnova programiranja

Studentima se preporučuje da samostalno urade i testiraju rešenja zadataka koji se mogu pogledati na stranici vezba.html




41. NCP koji tekst sa standardnog ulaza prepisuje na standardni izlaz pretvarajući početna slova rečenice u velika. Pretpostaviti da se u tekstu znaci .?! pojavljuju samo kao znaci završetka rečenica. Dakle, u tekstu nema rednih brojeva koji bi se završavali tačkom,... Tekst se završava markerom kraja datoteke. /*tekst sastavljen od recenica.  Tacka , upitnik,uzvicnik se pojavljuju samo kao oznake kraja  recenice  */




/* Velika slova na pocetku recenice */
#include <stdio.h>
#include <ctype.h>

main()
{
enum {F,T};   /*false,true;0,1*/
int znak,prvi=T; /* znak sa ulaza, indikator pojavepocetka recenice */
 

/* ucitavanje ulaza do markera kraja (EOF) i pretvaranje pocetnih slova recenice u velika i pretvaranje velikih slova iz sredine recenice u mala slova. */
while ( (znak=getchar() ) != EOF)
{
  if (isupper(znak) )
   { if ( !prvi)            /* if (prvi==0)  */
       znak=tolower(znak);    /*u sredini recenice veliko slovo->malo slovo */
     else prvi=F;           /*napusta se pocetak recenice */
   }
  else  if (islower(znak) )
    { if(prvi)                /*recenica pocinje */
       { znak=toupper(znak);  /*  velikim slovom */
         prvi=F;              /*napusta se pocetak recenice */
       }
     }
  else  /*nije slovo */
   if (znak =='.' || znak=='!' || znak =='?')
      prvi=T;     /*novi pocetak */
  putchar(znak); /*slanje rezultata obrade naizlaz */
}
 

return 0;
}

42.
/* Sa standardnog ulaza se unose linije teksta limitirane dužine. Ispisati na standardni izlaz linije koje sadrže dati obrazac- nisku HTML. */
/* Za one koji preferiraju  MS  "hungariannotation" */
#include <stdio.h>
#include <ctype.h>
 

/* limit duzine ulazne linije */
#define cMAXLINE 1000
 

/* ucitava liniju limitirane duzine sa ulaza i vracanjenu duzinu */
int getline( char szLine[], int iLimit);
 

/* vraca ili
-1 ako se druga niska ne nalazi u prvoj
ili poziciju prve pojave druge niske u prvoj */
int strindex( char szSource[], char szSearchFor[]);

char gszPattern[]="HTML"; /* obrazac za kojim se traga*/

/* glavni program */
main()
{
  char szLine[cMAXLINE]; /* linija sa ulaza limitiraneduzine*/
   int iFound=0; /* signal pojave pattern-a:ako je iFound==0 =>
niti jedna linija se ne ispisuje, jer niti jedna linijane sadrzi obrazac*/

/*ucitavanje linija sa ulaza do markera kraja (EOF)uz pretragu obrasca u svakoj ucitanoj liniji */
while( getline(szLine, cMAXLINE)>0 )

/*ako je indeks(pozicija) nadjenog obrasca(pattern-a)u liniji veci ili jednak nuli, onda odstampati tu liniju */
  if( strindex(szLine, gszPattern)>=0 )
  {
   printf("%s", szLine);
   iFound++;
  }
  else  printf("\n");
/* ako pozicija obrasca nije veca ili jednaka nuli,preci u novi red */
 
 

return iFound;
}

/* getline: ucitava liniju i vraca njenu duzinu */
int getline( char szLine[], int iLimit)
{
 int CharCurr, iCur;
 iCur=0;
 while( --iLimit>0 && (CharCurr=getchar())!=EOF&& CharCurr!='\n')
  szLine[iCur++]=CharCurr;
 if( CharCurr=='\n' )
 {
  szLine[iCur]=CharCurr;
  ++iCur;
 }
 szLine[iCur]='\0';
 return iCur;
}
/* strindex: vraca indeks druge niske u prvoj, odnosno-1 ako se ne sadrzi*/
int strindex( char szSource[], char szSearchFor[])
{
  int iSub, iFirst, iSecond; /* pozicija karakterau nisci u kojoj se vrsi pretraga,
pozicija pocetka pretrage u svakom prolazu,
pozicija karaktera u niski obrasca */
 

/*pretraga pocinje od pocetka prve niske
i ako je odatle neuspesna, onda se povecava iSub svedo kraja prve niske */
 for( iSub=0; szSource[iSub]!='\0'; iSub++ )
 {

/* pocev od tekuce pozicije prve niske (iSub) poredi se znak prve idruge niske i to sve do kraja druge niske ili do pojave prvog znaka u komse niske razlikuju */
  for( iFirst=iSub, iSecond=0;
szSearchFor[iSecond]!='\0' && szSource[iFirst]==szSearchFor[iSecond];
      iFirst++, iSecond++)    ;
 

/* u slucaju uspesne pretrage vraca se pozicija prve niske od koje pocinjeprva pojava druge niske */
  if( iSecond>0 && szSearchFor[iSecond]=='\0')
   return iSub;
 }

 return -1;

}
 

43.
/* Izracunati sumu brojeva u pokretnom zarezu. Nije unapred poznato koliko
ima brojeva, sem da  je svaki sadrzan u po jednoj liniji, a sve linije ulaza su limitirane duzine.
Smatracemo na dalje da se ovakav ulaz podrazumeva,cak i ako ga ne opisemo detaljno*/
#include <stdio.h>
#include <ctype.h>

#define LINELIMIT 1000

int getline( char linija[], int lim);
/* na osnovu sadrazaja niske vraca broj u pokretnomzarezu */
double atofd (char [] );
/* glavni program */
main()
{double dSum;   /* suma brojeva */
 char linija[LINELIMIT];    /*tekucibroj kao niska cifara */
dSum=0;
while( getline(linija, LINELIMIT)>0 )   dSum+= atofd(linija);
printf("Suma: %f \n", dSum);
 return 0;
}
/* getline: ucitava liniju i vraca njenu duzinu */
int getline( char linija[], int lim)
{
  int znakk, indeks;
  indeks=0;
  while( --lim>0 && (znakk=getchar())!=EOF&& znakk!='\n')  linija[indeks++]=znakk;
  if( znakk=='\n' )
 { linija[indeks]=znakk;
      ++indeks;
  }
  linija[indeks]='\0';
  return indeks;
}

/* atof: na osnovu sadrzaja niske vraca broj u pokretnomzarezu */
double atofd( char sBroj[])
{
 double dVal, dPower;
 int indeks, iSign;

/*preskok escapespace */
 for( indeks=0; isspace(sBroj[indeks]); indeks++) ;

/*odrediti predznak */
 iSign = ( sBroj[indeks]=='-' ) ? -1 : 1;

if( sBroj[indeks]=='+' || sBroj[indeks]=='-' ) indeks++;

/*vrednost celobrojnog dela */
for( dVal=0.0; isdigit(sBroj[indeks]); indeks++) dVal=10.0*dVal+(sBroj[indeks]-'0');

if( sBroj[indeks]=='.' )   indeks++;

/* razlomljenog dela */
for( dPower=1.0; isdigit(sBroj[indeks]); indeks++)
{dVal=10.0*dVal+(sBroj[indeks]-'0');
 dPower *= 10;
}

return iSign*dVal/dPower;
}

/* varijanta sa konverzijom koja podrzava format sa mantisom i eksponentom:npr: -2.85e-4 ili 5.146E18 */
/*double atofd( char szNumber[]){
       double dVal, dPower;
        int iCur, iSign;
        
  for(iCur=0;isspace(szNumber[iCur]);iCur++);
        
    iSign = ( szNumber[iCur]=='-' ) ? -1 : 1;
       
     if( szNumber[iCur]=='+' || szNumber[iCur]=='-') iCur++;
        
   for( dVal=0.0; isdigit(szNumber[iCur]); iCur++)
                       dVal=10.0*dVal+(szNumber[iCur]-'0');
       
    if( szNumber[iCur]=='.' )
        { iCur++;
                
for( dPower=1.0; isdigit(szNumber[iCur]); iCur++)
                {                        dVal=10.0*dVal+(szNumber[iCur]-'0');
                        
dPower *= 10;
                }
               
 dVal = iSign*dVal/dPower;
        
}        else
                
dVal = iSign*dVal;
        
if( szNumber[iCur]=='e' || szNumber[iCur]=='E' )
        {                
   int iExp;
                iCur++;
                
iSign = ( szNumber[iCur]=='-' ) ? -1 : 1;
                
if( szNumber[iCur]=='+' || szNumber[iCur]=='-')
                        
iCur++;
                
for( iExp=0.0; isdigit(szNumber[iCur]); iCur++)
                        iExp=10.0*iExp+(szNumber[iCur]-'0');
                if( iSign==-1)
                        
for(iCur=1; iCur<=iExp;iCur++)
                                
dVal /= 10.0;                else                        
for(iCur=1; iCur<=iExp;iCur++)
                                
dVal *= 10.0;
        
}        
return dVal;
}*/

 

 

O REKURZIJI

STEK POZIVA ZA FUNKCIJU printd

stek poziva za funkciju printd


Stekovi se koriste za praćenje niza poziva funkcija tokom izvršavanja programa (stek aktivacijskih slogova). Svaki put kada se pozove funkcija, u stek se umetne aktivacijski slog. Slog sadrži prostor za informacije koje su potrebne tokom izvršavanja poziva funkcije i informacije o nastavku pozivnog programa nakon što se završi sa izvršavanjem funkcije.

 

PRIMERI REKURZIVNIH IMPLEMENTACIJA

R1. NCP koji će implementirati iterativnu i rekurzivnu funkciju za izračunavanje n!, pozivati tu funkciju za pozitivan ceo broj n koji se unosi sa standardnog ulaza. Faktorijel se definiše n!= n * (n-1)!, ako je n >0. Inace 0!=1.
Ako primenimo ovakvu definiciju, onda program sa implementacijom funkcije faktorijel izgleda:
#include <stdio.h>
/*  Rekurzivna verzija funkcija za racunanje n!                           */

long fakt (int n) {
	if (n)
		return n*fakt(n-1);
	else
		return 1;
}
	
/*     KOMPAKTNIJI KÔD REKURZIVNE VERZIJE
long fakt (int n) {
  return (n == 0) ?  1 : n * fakt (n-1);
}
*/




/*      ITERATIVNA VERZIJA 

long fakt(int n)
{
	long f = 1;
	int i;
	for (i = 1; i<=n; i++)
		f *= i;
	return f;
}
*/

main()
{
        int n;
        printf("Unesite n: "); scanf("%d", &n);
        printf("%d! = %ld\n", n,  fakt(n));
}









R2. NCP koji će implementirati iterativnu i rekurzivnu funkciju za izračunavanje sume 1+2+3+...+n, pozivati tu funkciju za pozitivan ceo broj n koji se unosi sa standardnog ulaza. Suma se definiše 1+2+...+n= Sn=n + Sn-1, ako je n >0. Inače, S0=0.
Ako primenimo ovakvu definiciju, onda program sa implementacijom funkcije suma izgleda:
#include <stdio.h>
/*  Rekurzivna verzija funkcija za racunanje Sn                           */

long suma (int n) {
	if (n)
		return n + suma(n-1);
	else
		return 0;
}
	
/*     KOMPAKTNIJI KÔD REKURZIVNE VERZIJE
long suma (int n) {
  return (n ) ?  (n + suma(n-1)) : 0;
}
*/




/*      ITERATIVNA VERZIJA 

long suma(int n)
{
	long s = 0;
	int i;
	for (i = 1; i<=n; i++)
		s += i;
	return s;
}
*/

main()
{
        int n;
        printf("Unesite n: "); scanf("%d", &n);
        printf("S%d = %ld\n", n,  suma(n));
}









R3. NCP koji će implementirati iterativnu i rekurzivnu funkciju za izračunavanje sume članova (double) niza a sa n članova, pozivati tu funkciju za pozitivan ceo broj n koji se unosi sa standardnog ulaza i za n članova (double) niza a koji se unose sa standardnog ulaza.
Suma se definiše a[0]+a[1]+...+a[n-1]= Sn=a[0] + Sn-1, ako je n >0. Inače, S0=0. U formulaciji zadatka je rečeno da je n > 0.
Ako primenimo ovakvu definiciju, onda program sa implementacijom funkcije zbir izgleda:
#include <stdio.h>
#define MAX 10

/* Rekurzivna funkcija za racunanje zbira elemenata niza.       */

double zbir (const double a[], int n) {
  return (n > 0) ? a[0] + zbir (a+1, n-1) : 0;
}

/*ITERATIVNA VERZIJA 
double zbir (const double a[], int n) {
   double s;
   int i;
   s=a[0];
  for (i = 1; i<n; i++) s += a[i];
   return s;


}
*/

main()
{
        int n,i;
        double a[MAX];
        printf("Unesite n: "); scanf("%d", &n);
        printf("\nUnesite niz dimenzije %d: ", n);
        for(i=0; i <n; i++)  scanf("%lf", &a[i]);
        printf("\nS%d = %lf\n", n,  zbir(a,n));
}


R4. NCP koji će implementirati iterativnu i rekurzivnu funkciju za izračunavanje binomnog koeficijenta C(n,k) za dato n i k i ispisati Pascalov trougao do nivoa 10.
Znamo da C(k,k)=1, C(k,0)=1,
kao i da za 0 < k < n: C(n,k)= C(n-1,k-1) + C(n-1,k)
#include <stdio.h>
#define MAX 10

/* Rekurzivna funkcija za racunanje binomnog koeficijenta.     */

int binko (int n, int k) {
  return (0<k && k<n) ? binko (n-1, k-1) + binko (n-1, k) : 1;
}
/* Iterativno izracunavanje datog binomnog koeficijenta.                  

int binko (int n, int k) {
  int i, j, b;
  for (b=i=1, j=n; i<=k; b=b*j--/i++);
  return b;
}

*/

/* Ispisivanje Paskalovog trougla.                                        */



main () {
  int n, k, i;
  
  putchar ('\n');
  for (n=0; n<=MAX; n++) {
    for (i=0; i<MAX-n; i++) printf ("  ");
    for (k=0; k<=n; k++) printf ("%4d", binko (n, k));
    putchar ('\n');
  }
}


44.K&R zadatak: NCP koji sa standardnog ulaza unosi nisku znakova. Konvertovati unesenu liniju u ceo broj, duplirati vrednost celog broja, potom ga odštampati na standardni izlaz, uz upotrebu rekurzivne funkcije. Pretpostavka je da je ulazan sintaksno i semanticki korektan.

#include <stdio.h>
#include <stdlib.h>
/* zbog atoi */

#include <ctype.h>

#define LINELIMIT 1000

int getline( char linija[], int iLimit);
void printd( int n );
main()
{char linija[LINELIMIT];       /*tekuci ulaz */
int i;                 /*brojac u petlji */
/*ocitavanje ulaza */
while( getline( linija, LINELIMIT ) > 0 )
{  i=atoi( linija );
    i*=2;
    printd( i );              /*rekurzivna f-ja */
    putchar('\n');
}
  return 0;
}
/* getline: ucitava liniju i vraca njenu duzinu */
int getline( char linija[], int iLimit)
{int znakk, i;
for( i=0; i<iLimit-1 && (znakk=getchar())!=EOF&& znakk!='\n'; ++i)  linija[i]=znakk;
if( znakk=='\n' ){linija[i]=znakk;   ++i;}
linija[i]='\0';
return i;
}
/* printd: stampaj d decimalno */
void printd( int n )
{  if( n<0 )
       { putchar('-');
         n = -n;
        }
     if( n/10 )  printd(n/10 );
     putchar( n%10+'0' );
 }

 

R5. NCP koji će implementirati iterativnu verziju i rekurzivnu funkciju za izračunavanje skalarnog proizvoda, i za pozitivan ceo broj n i dva niza double brojeva, koji se unosi sa standardnog ulaza izračunati skalarni proizvod i ispisati na standardni izlaz.

/*  Skalarni proizvod dva vektora.                            */

#include <stdio.h>
#define DIM 10



/* Rekurzivna funkcija za racunanje
                skalarnog proizvoda dva vektora.                          */

float skalpro (const float a[], const float b[], int n) {
  return (n > 0) ? a[0] * b[0] + skalpro (a+1, b+1, n-1) : 0;
}

/*ITERATIVNA VERZIJA
float skalpro (const float a[], const float b[], int n) {
  float skal_pro;
  for (skal_pro=i=0; i<n; i++) skal_pro += a[i] * b[i];
  return skal_pro;
}
*/

main () {
  float a[DIM], b[DIM];
  int    i, n;
  while (1) {
    printf ("\nDuzina vektora (najvise %d)? ", DIM);
    scanf ("%d", &n);
  if (n <= 0 || n > DIM) break;
    printf ("\nUnesite vektor A: ");
    for (i=0; i<n; scanf ("%f", &a[i++]));
    printf ("\nUnesite vektor B: ");
    for (i=0; i<n; scanf ("%f", &b[i++]));
   
    printf ("\nSkalarni proizvod A*B= %10.3f\n", skalpro (a, b, n));
  }

}



 

45. NCP koji sa standradnog ulaza čita niz pozitivnih brojeva x, dok se ne pročita nula. Nije unapred poznat broj članova niza x, sem da ih neće biti više od 50. Od članova niza x formirati niz y, tako što iz niza x izbaci sve članove xk koji su deljivi nekim od brojeva x0, x1,..., xk-1. Odštampati sve članove niza y. Pri učitavanju razviti sopstvene funkcije za čitanje znakovne niske i konverziju u broj.
#include <stdio.h>
#include <ctype.h>

#define LINELIMIT 1000
#define MAXNIZ 50
unsigned atou( char s[] );
int getline( char line[], int lim);
int imaDelioce( unsigned  clan, unsigned clanovi[],int granica);
/* glavni program */
main()
{
char linija[LINELIMIT];      /*tekuci ulaz */
unsigned tekuciBr;           /*broj sa ulaza */
int xClanova=0;                 /*broj clanova niza x */
unsigned x[MAXNIZ];
int yClanova=0;                  /*broj clanova niza y */
unsigned y[MAXNIZ];
int i;                               /*brojac u petlji */
 

/*ucitavanje linija do markera kraja(0) i konverzija u broj */
xClanova=0;
do
{
  i = getline(linija,LINELIMIT);
  tekuciBr = atou(linija);
  if( tekuciBr )     x[xClanova++] = tekuciBr;
}
while( tekuciBr );
 

/*provera svojstva clana niza x i kreiranje niza yzavisno od rezultata provere*/
  yClanova = 0;
for( i=0; i<xClanova; i++ )
          if( !imaDelioce( x[i], x, i ) )   y[yClanova++] = x[i];
 
 

/*izdavanje niza y */
for( i=0; i<yClanova; i++ )    printf( "%u\t", y[i] );
printf("\n");
return 0;
}
 

/* getline: ucitava liniju i vraca njenu duzinu */
int getline( char line[], int lim)
{int znak, indeks;
for( indeks=0; indeks<lim-1 && (znak=getchar())!=EOF&& znak!='\n'; ++indeks)
line[indeks]=znak;
if( znak=='\n' ) line[indeks++]=znak;
line[indeks]='\0';
return indeks;
}
 

/* atou: ascii to unsigned */
unsigned atou( char s[] )
{
int poz;
unsigned rezultat=0;
/* preskociti escape znake */
 for( poz=0; isspace(s[poz]); poz++ )
  ;
/* preskociti  znak '+' */
if( s[poz]=='+')  poz++;

for( ; isdigit(s[poz]); ++poz) rezultat = 10*rezultat+(s[poz]-'0');
return rezultat;
}
 

/* provera da li niz clanovi do granice  sadrzi delioce broja clan */
int imaDelioce( unsigned  clan, unsigned clanovi[],int granica)
{
int i;
for( i=0; i<granica; i++ )
      if( clan % clanovi[i]== 0 )    return -1;
return 0;
}

 


Jelena Grmusa Osnovi programiranja

e-mail: Jelena Grmuša


Copyright © 2002, Jelena Grmusa
Poslednja izmena: februar 2006.
URL: http://www.matf.bg.ac.yu/~jelenagr/op/