Vezbe iz Osnova programiranja

74. Bez upotrebe standardnih f-ja za alokaciju memorije sortirati iz jedne datoteke do 1000 linija zbirne duzine do 40000, tako da u novoj datoteci je na pocetku svake linije njen redni broj pre sortiranja.
  

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

#define UKUPAN_BROJ_LINIJA 1000
#define ZBIRNA_DUZINA 40000L
struct datoteka {	  int rbr;	  char *s;	  } niz[UKUPAN_BROJ_LINIJA];

int brlin=0;  /*broj linija <= UKUPAN_BROJ_LINIJA   */
long ukupna_duzina=0;
char heap[ZBIRNA_DUZINA+UKUPAN_BROJ_LINIJA];
 char *rec=heap;

int getline(FILE *f,char *line)
  /*ucitavanje linije iz datoteke i cuvanje '\n' u nisci line; vraca duzinu linije*/ 
 {int c,i=0;
     while((c=fgetc(f))!=EOF && c!='\n') line[i++]=c;
     if(c=='\n') line[i++]=c;
      line[i]='\0';
       return i;
}

void greska(int n)  /*rutina za obradu greske u slucaju preobimnog ulaza */
     {switch(n) 
           {case 0 : fprintf(stderr,"prevelik ukupan broj linija\n");
	 exit(1);
	 break;
           case 1 : fprintf(stderr,"prevelika ukupna duzina linija\n");
  	 exit(1);
	 break;
	 }
}

void predstavi(char *imedat)    /*predstavlja sadrzaj datoteke po imenu  polju linija */
{
   FILE *f;int d;   /*duzina tekuce linije */

 /*pokusaj otvaranja datoteke za citanje */
 if((f=fopen(imedat,"r"))==NULL) {
   fprintf(stderr,"greska : otvaranje fajla %s\n",imedat);   exit(1);
}

/*ucitavanje linija do markera kraja i prekid ucitavanja u slucaju preobimnog ulaza */
while((d=getline(f,rec))>0) {
   if(brlin>=UKUPAN_BROJ_LINIJA) greska(0);   niz[brlin].rbr=brlin+1;

   /*uvecava se redni broj linije */
      niz[brlin++].s=rec;

   ukupna_duzina+=d;

   if(ukupna_duzina>=ZBIRNA_DUZINA) greska(1);   rec+=strlen(rec)+1;
   }

fclose(f);
}


int uporedi(const void *a,const void *b) 
{
   return strcmp( ((struct datoteka *)a)->s,((struct datoteka *)b)->s );
}



void ucetiri(int n,char *s) { 
    /*formiranje rednog broja linije  sa vodecim nulama */
       int i=0,j;  /*brojaci u petljama */
          while(n>0) {
               s[i++]=(n % 10) +'0';                     n/=10;
             }

  for(j=i;j<4;j++,i++) s[i]='0';   /*dopuniti  nulama*/
  s[i]='\0';
  strrev(s);
;}

main(int argc,char *argv[]) 
{
  FILE *f;  int i;   /*brojac u petlji */
  /*redni broj linije */  char broj[5];
        //char *broj;

  /*imena datoteka se zadaju kao argumenti komandne linije */
if(argc!=3) {     fprintf(stderr,"poziv : %s <ulazna dat> <izlazna dat> \n",argv[0]);     exit(1);   }   

if((f=fopen(argv[2],"w"))==NULL) { 
        fprintf(stderr,"greska : otvaranje datoteke %s\n",argv[2]);      exit(1);   
     }


predstavi(argv[1]);

qsort(niz,brlin,sizeof(struct datoteka),uporedi);  /*zeljeno sortiranje */

for(i=0;i<brlin;i++) {   
ucetiri(niz[i].rbr,broj);  /*upisu sadrzaja linije prethodi redni broj */   
fputs(broj,f);   

fputs(". ",f);            /*znak tacka kao zavrsetak rednog broja linije */   
fputs(niz[i].s,f);       /*upis sadrzaja linije rednog broja broj */

}

putchar('\n');

fclose(f);}



75.
a) Napisati funkciju double sr_duz_rec_1 (FILE *dat) koj ce citati tekst datoteke znak po znak i vratiti kao rezultat srednju duzinu reci u tekstualnoj datoteci. Smatrati da rec je ma koja niska sa ne vise od 80 karaktera koja ne sadrzi beline (razmak, tabulator, znak prelaza u novi red,...).
b) Napisati funkciju double sr_duz_rec_2 (FILE *dat) koj ce citati tekst datoteke rec po rec i vratiti kao rezultat srednju duzinu reci u tekstualnoj datoteci. Smatrati da rec je ma koja niska ne vise od 80 karaktera koja ne sadrzi beline (razmak, tabulator, znak prelaza u novi red,...).
c) NCP koji prihvata ime datoteke iz komandne linije i koristeci prethodne dve funkcije ispisuje na standardni izlaz srednju duzinu reci u datoteci.



#include <stdio.h>
#include <ctype.h>
#include <string.h>

double sr_duz_rec_1 (FILE *dat) {       
  int br_rec=0, zb_duz=0, prvi=1, znak;  /*brojac reci, brojac znakova u reci, indikator nailaska na pocetak reci, tekuci znak*/

  fseek (dat, 0, SEEK_SET);  /* pozicionirati se na pocetak tekstualne datoteke */

/* Citanje tekstualne datoteke znak po znak do nailaska na EOF   */
  while ((znak = fgetc (dat)) != EOF) {
    if (isspace (znak))    prvi = 1;  /*van reci */
    else {
      zb_duz++;  
      if (prvi) { br_rec++; prvi = 0; } /*pocetak reci, uveca se brojac reci */
    }
  }


  return (double) zb_duz / br_rec;  /*srednja duzina reci = broj karaktera u recima/broj reci */
}




double sr_duz_rec_2 (FILE *dat) {      
  int br_rec=0, zb_duz=0;  /*brojac reci, brojac karaktera u reci */
  char rec[80]; /*tekuca rec*/

  fseek (dat, 0, SEEK_SET); /* pozicionirati se na pocetak tekstualne datoteke */

  /* Citanje  tekstualne datoteke  rec po rec do nailaska na EOF     */
  while ((fscanf (dat, "%s", rec)) != EOF) {
    zb_duz += strlen (rec); 
    br_rec++;
  }


  return (double) zb_duz / br_rec;   /*srednja duzina reci = broj karaktera u recima/broj reci */
}

void main (int argc, char *argv[]) {

  FILE *dat = fopen (argv[1], "r");

  if (dat)
    printf ("Srednja duzina reci u datoteci \"%s\" je %.2f (%.2f)\n",
            argv[1], sr_duz_rec_1(dat), sr_duz_rec_2 (dat));
 else fprintf(stderr,"Nemoguce otvoriti datoteku %s za citanje\n", argv[1]);

}



76.
NCP koji iz datoteke ulaz.txt ucitava dva datuma u obliku dd.mm.gggg. i ispisuje na standardni izlaz veci od njih. U slucaju jednakosti oba datuma, ispisati tacno jedan od njih uz poruku da datumi jesu jednaki.

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

int veci(int d1, int m1, int g1, int d2, int m2, int g2); 
/*vraca 1, ako je prvi datum d1.m1.g1 veci od drugog d2.m2.g2.
   vraca 2, ako je drugi datum veci
  vraca 0, ako su datumi jednaki */

void poruka(int d, int m, int g);
/*stampa rezultat u formi d.m.g. */

main()
{ 
    FILE *f;
    int d1,m1,g1;  /* 1.datim d1.m1.g1. */
    int d2,m2,g2;  /* 2.datim d2.m2.g2. */

    f=fopen("ulaz.txt", "r");
    if (f==NULL) {fprintf(stderr, "Greska u citanju datoteke\n"); exit(1);}
  
    fscanf(f, "%d.%d.%d.", &d1, &m1, &g1);
    fscanf(f, "%d.%d.%d.", &d2, &m2, &g2);
  if (veci(d1,m1,g1,d2,m2,g2)==0) printf("Oba datuma su jednaka\n");
   
   fclose(f);

}

void poruka(int d, int m, int g)
{
       printf("\n%d.%d.%d.\n",d,m,g);
}


int veci(int d1, int m1, int g1, int d2, int m2, int g2)
{
    int status; 
 /* status = 0,1,2 u zavisnosti da li prvi datum je jednak drugom, veci od drugog, manji od drugog */

    if (g1 > g2) status=1; /*jer prvi datum je tada veci od drugog*/
   else if (g1 < g2) status=2;
   else /* ako su godine u oba datuma jednaka, porede se meseci */
       if (m1 > m2) status=1;
       else if (m1 < m2) status=2;
       else  /*porede se dani ako su meseci u oba datuma jednaki */
            if (d1 > d2) status =1;
            else if (d1 < d2) status =2;
            else status=0;

  if (status < 2) poruka(d1,m1,g1); /* prvi datum se stampa ako je veci ili jednak od drugog */
  else poruka(d2,m2,g2);

 return status;
}

77.
NCP koji iz datoteke ulaz.txt ucitava datume u obliku dd.mm.gggg. (do nailaska na oblezje kraja datoteke) i ispisuje na standardni izlaz najveci datum. U slucaju da postoji vise takvih ispisati tacno jedan od njih.

Napomena pre resavanja: U tekstu zadatka nisu date nikakve pretpostavke o ukupnom broju datuma u datoteci !!! Dakle, Vi kao programer ne znate da li ih ima 30 ili 300. Vodite racuna da ne upotrebite strukturu podataka koja cuva datume i zahteva od Vas da u programu navedete pretpostavljeni broj clanova strukture.


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

int veci(int d1, int m1, int g1, int d2, int m2, int g2); 
/*vraca 1, ako je prvi datum d1.m1.g1 veci od drugog d2.m2.g2.
   vraca 2, ako je drugi datum veci
  vraca 0, ako su datumi jednaki */

void poruka(int d, int m, int g);
/*stampa rezultat u formi d.m.g. */

main()
{ 
    FILE *f;
    int d1,m1,g1;  /* 1.datim d1.m1.g1. */
    int maxd=0,maxm=0,maxg=0;  /* najveci datum u obliku maxd.maxm.maxg. Polazna pretpostavka: 0.0.0. */

    f=fopen("ulaz.txt", "r");
    if (f==NULL) {fprintf(stderr, "Greska u citanju datoteke\n"); exit(1);}
  
    while (!feof(f))
   {  fscanf(f, "%d.%d.%d.", &d1, &m1, &g1);    
       if (veci(d1,m1,g1,maxd,maxm,maxg)==1) 
       {  /* postavi nove vrednosti za najveci datum, jer je d1.m1.g1. novi najveci datum */
            maxd=d1; maxm=m1; maxg=g1;
        }
  }
 
 poruka(maxd,maxm,maxg);
 fclose(f);

}


void poruka(int d, int m, int g)
{
       printf("\n%d.%d.%d.\n",d,m,g);
}


int veci(int d1, int m1, int g1, int d2, int m2, int g2)
{
    int status; 
 /* status = 0,1,2 u zavisnosti da li prvi datum je jednak drugom, veci od drugog, manji od drugog */

    if (g1 > g2) status=1; /*jer prvi datum je tada veci od drugog*/
   else if (g1 < g2) status=2;
   else /* ako su godine u oba datuma jednaka, porede se meseci */
       if (m1 > m2) status=1;
       else if (m1 < m2) status=2;
       else  /*porede se dani ako su meseci u oba datuma jednaki */
            if (d1 > d2) status =1;
            else if (d1 < d2) status =2;
            else status=0;

 return status;
}


78.
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 cele 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);
}

79.
NCP koji u binarnu datoteku ulaz.bin upisuje MAX parnih brojeva. MAX se zadaje u komandnoj liniji.

Za cuvanje velike kolicine podataka cesto se koriste binarne datoteke (jer za istu kolicinu podataka zapis je <= zapisu u tekstualnoj datoteci.

Za otvaranje binarne datoteke za upis koristi se ista funkcija fopen kao kod tekstualne datoteke, ali rezim rada je "wb" (kod tekstualne datoteke "w", "wt").

Za upis podataka u binarnu datoteku koriste se standardna fukcija fwrite.


size_t fwrite(
   const void *buffer,
   size_t size,
   size_t count,
   FILE *stream 
);

Ova funkcija upisuje count elemenata (svaki velicine size) pocev od adrese buffer u datoteku na koju pokazuje stream. Povratna vrednost funkcije je broj uspešno upisanih podataka.

Uocite da velicina MAX nije poznata za vreme kompilacije. Niz brojeva cuvajmo u dinamickom nizu.

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

main(int argc, char *argv[])
{
    FILE *f;
    int i; /*brojacka promenljiva*/
    int MAX; /*broj clanova niza */
    int *niz;  /* dinamicki niz parnih brojeva */

   if (argc < 2) {fprintf(stderr, "Nekorektan poziv programa: naziv MAX\n"); exit(1);}
   
  MAX=atoi(argv[1]);
  
  niz=(int *)malloc(MAX*sizeof(int));
  /*niz=(int *)calloc(MAX, sizeof(int)); */  
 /* calloc ce sem alokacije izvrsiti i inicijalizaciju elemenata na 0 */
  if (niz==NULL)    {fprintf(stderr, "Nedovoljno memorije za malloc\n"); exit(2);}

  for(i=1; i<=MAX; i++)  niz[i-1]=2*i;

  f=fopen("ulaz.bin", "wb"); /*pokusaj otvaranja binarne datoteke za upis */
 if(f==NULL)  {fprintf(stderr, "Greska pri otvaranju datoteke za upis\n"); exit(3);}
 
 fwrite(niz, sizeof(int), MAX, f);

free(niz);

 fclose(f);


}




80.
NCP koji otvara za citanje binarnu datoteku ulaz.bin kreiranu u prethodnom zadatku i ispisuje na standardni izlaz element iz datoteke ciji redni broj se zadaje u komandnoj liniji.

Za citanje iz binarne datoteke koristi se <stdio.h> funkcija fread.
size_t fread( void *buffer, size_t size, size_t count, FILE *stream ); je funkcija koja iz datoteke na koju pokazuje stream ucitava count elemenata (svaki veličine size bajtova) i upisuje u operativnu memoriju počev od adrese buffer. Povratna vrednost funkcije je broj uspešno učitanih podataka.

Funkcije iz <stdio.h> fseek, ftell, rewind koriste se za pozicioniranja u datoteci. Kao što je već ilustrovano u primerima iz glave VII (sa vezbi, u knjzi K&R):

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

main(int argc, char *argv[])
{
    FILE *f;
    int N; /*redni broj clanova niza iz prethodnog zadatka, N=1,2,3,.... iako je niz indeksiran pocev od 0 */
    int broj; /*trazeni element sa rednim brojem N*/
    

   if (argc < 2) {fprintf(stderr, "Nekorektan poziv programa: naziv N\n"); exit(1);}
   
  N=atoi(argv[1]);
  
  
  f=fopen("ulaz.bin", "rb"); /*pokusaj otvaranja binarne datoteke za citanje */
 if(f==NULL)  {fprintf(stderr, "Greska pri otvaranju datoteke za citanje\n"); exit(2);}
 
if ( (fseek(f, (long)(N-1)*sizeof(int), SEEK_SET)) !=0)
  {fprintf(stderr, "Nekorektna pozicija %d u datoteci\n", N); exit(3);}

 fread(&broj, sizeof(int), 1, f);

if (broj < 0)  {fprintf(stderr, "Nekorektna pozicija %d u datoteci\n", N); exit(3);}

 printf("\n%d. clan niza je %d\n",N, broj);  


 fclose(f);


}




81.
NCP koji ulaznu datoteku ulaz.txt šifrira i prepisuje u datoteku tajna.txt tako da svaki znak datoteke se zameni znakom čiji ASCII kôd je rotaciono pomeran udesno za 1 bit.
Npr. znak z sa ASCII kôdom (dekadno) 122 se transformiše u znak = sa ASCII kôdom (dekadno) 61, jer rotacijom udesno za 1 bit ôda 01111010 dobija se kôd 00111011 (bit najmanje težine prelazi na poziciju najveće težine, a ostali bitovi pomeraju se udesno za 1 mesto).
#include <stdio.h>
#include <stdlib.h>

void greska(char *s); /*ispisuje nisku s na standardan izlaz za poruke o gresci */

main()
{
     FILE *ulaz, *izlaz;
     char znak; /*tekuci karakter ulazne datoteke koji ce se sifriran ispisati u izlaznu datoteku */
     unsigned short bit1; /* sifriran znak */
     unsigned short pom; /* pomocna promenljiva koja ce cuvati bit najmanje tezine u ASCII kodu znaka,
                                           znacajan pri rotaciji udesno*/
 
     ulaz=fopen("ulaz.txt", "r");
    if(ulaz==NULL) greska("\nGreska u otvaranju datoteke ulaz.txt");

     izlaz=fopen("tajna.txt", "w");
    if(izlaz==NULL) greska("\nGreska u otvaranju datoteke tajna.txt");

   /*ucitavanje karaktera po karakter ulazne datoteke sve do EOF i sifriranje svakog karaktera i upis u
    izlaznu datoteku */
    while  ( (znak=fgetc(ulaz)) != EOF)
    {  bit1=znak;
        pom=1;   /*maska za izdvajanje bita najmanje tezine */
         pom=bit1&pom;  /* pom cuva bit najmanje tezine */
       bit1=bit1>>1;  /* pomeranje ASCII bitova (sem bita najmanje tezine) udesno za 1 mesto */
      pom=pom<<7;   
      bit1=bit1|pom; /*pom bit postavljen u bit1 na mesto najvece tezine */
      znak=bit1;
      fputc(znak, izlaz);
    }

  fclose(ulaz);  fclose(izlaz);
}

void greska(char *s)
{
    printf("%s\n", s); exit(EXIT_FAILURE);
}

82.
NCP koji ulaznu datoteku tajna.txt (koja je dobijena šifriranjem ako u prethodnom zadatku) dešifrira i prepisuje u datoteku provera.txt .

IDEJA: svaki znak datoteke tajna.txt se zameniti znakom čiji ASCII kôd je rotaciono pomeran ulevo za 1 bit.
Npr. znak = sa ASCII kôdom (dekadno) 61 se transformiše u znak z sa ASCII kôdom (dekadno) 122, jer rotacijom ulevo za 1 bit ôda 00111011 dobija se kôd 01111010 (bit najvećlje težine prelazi na poziciju najmanje težine, a ostali bitovi pomeraju se ulevo za 1 mesto).

UPOREDITE datoteke ulaz.txt (prethodni zadatak) i provera.txt

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

void greska(char *s); /*ispisuje nisku s na standardan izlaz za poruke o gresci */

main()
{
     FILE *ulaz, *izlaz;
     char znak; /*tekuci karakter ulazne datoteke koji ce se desifriran ispisati u izlaznu datoteku */
     unsigned short bit1; /* desifriran znak */
     unsigned short pom; /* pomocna promenljiva koja ce cuvati bit najvece tezine u ASCII kodu znaka,
                                           znacajan pri rotaciji ulevo*/
 
     ulaz=fopen("tajna.txt", "r");
    if(ulaz==NULL) greska("\nGreska u otvaranju datoteke tajna.txt");

     izlaz=fopen("provera.txt", "w");
    if(izlaz==NULL) greska("\nGreska u otvaranju datoteke provera.txt");

   /*ucitavanje karaktera po karakter ulazne datoteke sve do EOF i desifriranje svakog karaktera i upis u
    izlaznu datoteku */
    while  ( (znak=fgetc(ulaz)) != EOF)
    {  bit1=znak;

        pom=1;  
        pom=pom<<7;    /*maska za izdvajanje bita najvece tezine */

         pom=bit1&pom;  /* pom cuva bit najvece tezine */

       bit1=bit1>>1;  /* pomeranje ASCII bitova (sem bita najvece tezine) ulevo za 1 mesto */
      
      pom=pom>>7;    
      bit1=bit1|pom; /*pom bit postavljen u bit1 na mesto najmanje tezine */

      znak=bit1;
      fputc(znak, izlaz);
    }

  fclose(ulaz);  fclose(izlaz);
}

void greska(char *s)
{
    printf("%s\n", s); exit(EXIT_FAILURE);
}

83.
NCP koji iz komandne linije prihvata naziv grada i formira datoteku izlaz.bin koja sadrzi podatke o studentima iz tog grada. Izlazna datoteka treba da sadrzi ime i prezime studenta, naziv zavrsene srednje skole, broj pena na prijemnom i adresu. Ovi podaci se vec nalaze u datotekama studiranje.bin kao delovi strukture
struct student{ char imePrezime[40]; long maticniBroj; int godinaStudija; char srednjaSkola[50]; double poeni; }
i datoteci licno.bin kao delovi strukture
struct licniDosije{ long maticniBroj; char adresa[50]; char grad[40]; long FiksniTelefon; long MobilniTelefon; char drzavljanstvo[20]; }


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


struct student{
  char imePrezime[40];
   long maticniBroj;
  int godinaStudija;
  char srednjaSkola[50];
  double poeni;
};



struct licniDosije{
  long maticniBroj;
  char adresa[50];
  char grad[40];
  long FiksniTelefon;
  long MobilniTelefon;
  char drzavljanstvo[20];
};


struct izlazniPodaci{
  char imePrezime[40];
  char adresa[50];
  char srednjaSkola[50];
  double poeni;
  };

void greska(char *s); /*ispisuje nisku s na standardan izlaz za poruke o gresci */

main(int argc, char *argv[])
{
      FILE *izlaz, *ulaz1, *ulaz2;
      struct student slog1;  /*slog prve ulazne datoteke */
      struct licniDosije slog2; /*slog sa podacima iz druge ulazne datoteke */
      struct izlazniPodaci slog; /* slog koji ce biti upisan u izlaznu datoteku */

      if (argc!=2) greska("Nekorektan poziv programa: nazivPrograma nazivGrada");
  
     ulaz1=fopen("studiranje.bin", "rb");
     ulaz2=fopen("licno.bin", "rb"); 
     izlaz=fopen("izlaz.bin", "wb");
     
    if (!ulaz1 || !ulaz2 || !izlaz) greska("Nekorektno otvaranje ili ulaznih ili izlazne datoteke");

    while (!feof(ulaz1))  /*sve dok ima slogova u studiranje.bin (tj. licno.bin) traziti polja koja se 
                                       odnose na studente iz zadatog grada */
    {
        /*citanje tekuceg sloga iz studiranje.bin */
            if (fread(&slog1, sizeof(struct student), 1, ulaz1) !=1) greska("Greska pri citanju sloga iz studiranje.bin");

       /*citanje tekuceg sloga iz licno.bin */
        if (fread(&slog2, sizeof(struct licniDosije), 1, ulaz2) !=1) greska("Greska pri citanju sloga iz licno.bin");   

       /*poredjenje zadatog grada sa vrednoscu polja grad u tekucem slogu iz datoteke licno.bin */
       if (strcmp(argv[1], slog2.grad)==0)
        {
             strcpy(slog.imePrezime, slog1.imePrezime);
             strcpy(slog.srednjaSkola, slog1.srednjaSkola);
             slog.poeni=slog1.poeni;
             strcpy(slog.adresa, slog2.adresa);

             /*upis slog(a) u izlaznu datoteku izlaz.bin */
             if (fwrite(&slog, sizeof(struct izlazniPodaci), 1, izlaz) != 1)
                 greska("Greska pri upisu sloga u datoteku izlaz.bin");
        }
     }

    fclose(ulaz1); fclose(ulaz2); fclose(izlaz);

}


void greska(char *s)
{
    printf("%s\n", s); exit(1);
}




84.
Binarna datoteka sadrži sliku. Prva četiri bajta čuvaju dužinu i širinu u pikselima, a ostatak podatke o pojedinačnim pikselima. Smatrati da pixel je određen RGB bojom pri čemu svaka komponenta (R=red, G=green, B=blue) ima 16 mogućih vrednosti, tj. staje u 4 bita (polubajt), tj. svakih 12 bitova definiše jedan pixel. Podaci su datoteci smešteni vrst apo vrsta. NCP koji se poziva sa
zumiraj ulaznadatoteka faktor izlaznadatoteka
koji siku smeštenu u ulaznadatoteka uvećava faktor puta i smešta u izlaznadatoteka. Izlazna datoteka čuva sliku na gore opisan ančin. Uvećanje slike se vrši na sledeći način: svaki pixel se zamenjuje kvadratom dimenzije faktor x faktor u kom svi pixeli imaju istu boju kao originalni pixel. Pretpostaviti da maksimalna dimenzija originalne slike je 1024 x 1024.

IDEJA:
Dakle, ako je program pozvan sa
zumiraj ulaz.bmp 3 izlaz.bmp
i ako je polazna slika bila dimenzije 10 x 20, onda će izlazna slika biti dimenzije 30 x 60.

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

#define MAX 1024

int uzmipixel(FILE *f); /*za svaki pixel ucitava 8+4 bita (bajt i polubajt) iz datoteke na koju pokazuje f i vraca brojcanu 12-bitnu vrednost */
void pisipixel(short p, FILE *f); /*upis pixela p u datoteku na koju ukazuje f */
void greska(char *s); /*ispisuje nisku s na standardan izlaz za poruke o gresci */


main(int argc, char *argv[])
{
    FILE * ulaz, *izlaz;
     short niz_pixela[MAX];  /*pixeli jednog reda u datoteci */
     short faktor, duzina, sirina;  /*faktor uvecanaj slike, duzina polazne slike, sirina polazne slike */     
     short i,j,k,n;  /*brojacke promenljive */

     if (argc!=4) greska("Greska u pozivu programa:zumiraj ulaz faktor izlaz");

     ulaz=fopen(argv[1],"rb");
     if (!ulaz) greska("Nekorektno otvaranje binarne ulazne datoteke za citanje");

     izlaz=fopen(argv[3],"wb");
     if (!ulaz) greska("Nekorektno otvaranje binarne izlazne datoteke za upis");

     faktor=atoi(argv[2]);
     if (faktor <0) greska("Nekorektna vrednost faktora");

   /*ucitavanje dimenzije slike iz ulazne datoteke */
    if (fread(&duzina, 2, 1, ulaz) !=1) greska("Nekorektna vrednost za duzinu slike u ulaznoj datoteci");
    if (fread(&sirina, 2, 1, ulaz) !=1) greska("Nekorektna vrednost za sirinu slike u ulaznoj datoteci");

   /*upis dimenzije slike u izlaznu datoteku */
      i=duzina*faktor; j=sirina*faktor;
    if (fwrite(&i, 2, 1, izlaz) !=1) greska("Nekorektno upisivanje vrednosti za duzinu slike u izlaznoj datoteci");
    if (fwrite(&j, 2, 1, izlaz) !=1) greska("Nekorektno upisivanje vrednosti za sirinu slike u izlaznoj datoteci");

    /*za svaku vrstu slike */
    for(i=0;i<duzina;i++)
    {

        /*ucitava se vrsta u niz*/
        for(j=0;j<sirina;j++)   niz_pixela[j]=uzmipixel(ulaz);

       /*u izlaznu datoteku se faktor puta ispisuje prosirena vrsta, tj. 
         vrsta u kojoj je svaki pixel umnozen uzastopno faktor puta */
       for (k=0;k<faktor; k++)
            for (j=0;j<sirina;j++)
              for (n=0; n<faktor; n++)  pisipixel(niz_pixela[j], izlaz);
    }

     fclose(ulaz);  fclose(izlaz);
   
}


int uzmipixel(FILE *f)
{
    static int stao_na_pola_bajta=0; /*indikator koji govori da li jeste ili nije zaostao polubajt na ulazu */
    static short pom;  /*sadrzi pixel i deo drugog pixel-a */

    if (stao_na_pola_bajta){
       stao_na_pola_bajta=!stao_na_pola_bajta; /*uzet je zaostali polubajt */
       return (   (getc(f) <<4) | (pom >> 12) ); 
   }
   else
    {
       pom=getc(f) | ( getc(f) << 8);
         stao_na_pola_bajta=!stao_na_pola_bajta; /*ostao je polubajt */
         return (pom & 0xfff);  /*vraca nizih 12 bita iz pom */
    }

}

void pisipixel(short c, FILE *f)
{
   static int stao_na_pola_bajta=0; /*indikator pristupa donjem ili gornjem polubajtu tekuceg bajta */
   static char pom2;  /* sadrzi deo pixel-a */

   if (stao_na_pola_bajta) {
       stao_na_pola_bajta=!stao_na_pola_bajta; 
       putc( ((c << 4) | pom2) & 0xff, f); 
       putc( c >> 8, f); /*nakupilo se 16 bitova (4 od ranije i novih 12 bitova) */
   }
   else
   {     stao_na_pola_bajta=!stao_na_pola_bajta; 
          putc (c & 0xff, f); /*upisuje donji bajt i ostaje jos 4 bita za upis */
          pom2=c >> 8;  /*koji se pamte u donja 4 bita promenljive pom2, zato je staticka*/
   }
}



void greska(char *s)
{
    printf("%s\n", s); exit(1);
}

85.
NCP koji ucitava iz (tekstualne) ulazne datoteke ulaz.txt prirodan broj n (manji ili jednak od 100), proverava korektnost učitane vrednosti i generiše prvih n članova skupa M koji se formiraju po zakonu
  1. 1 pripada M
  2. ako k pripada M, onda i 2k+1 i 3k+1 pripadaju skupu M
Ispisati prvih na članova skupa M na standardni izlaz. (NAPOMENA: M je skup, dakle nema duplikata među članovima).

Pogledajmo formiranje prvih n članova skupa M za neke vrednosti promenljive n:



#include <stdio.h>

#define MAX 100

main()
{
    FILE *f;
    int i2; /* indeks clana niza koji se generise granom 2k+1 */
    int i3;  /*indeks clana niza koji se generise granom 3m +1 */
   int n; /* broj clanova podskupa skupa M koji se ispisuje na stdout */
    int x[MAX]; /*niz koji sadrzi n <= MAX clanova skupa M */    
       int i;   /*indeks tekuceg clana niza x*/
    int ind; /*razlika vrednosti dva clana generisanog granom 2k+1, 3m +1 za tekuce k,m */

 
   f=fopen("ulaz.txt", "r");

 /*ucitavanje broja n sa proverom korektnosti*/
  do
   {
      fscanf(f, "%d", &n);
    } while (n < 1 || n > MAX);

  /*inicijalizacije*/
   i2=i3=0;
   x[0]=1; /* prvi clan skupa M */

  /*generisanje clanova podskupa na osnovu zakona */
   for (i=1; i <n; i++)
   {
        ind=x[i2]*2 - 3*x[i3]; /*razlika vrednosti dva clana generisanog granom 2k+1, 3m +1 za tekuce k,m  da bi se
                                                odlucilo koja grane daje manji clan*/

      if (ind < 0)  /*ako se generisanje vrsi granom 2k+1 */
        {
             x[i]=x[i2]*2+1;
             i2++;
        }
     else if (ind > 0)  /*ako se generisanje vrsi granom 3k+1 */
        {
             x[i]=x[i3]*3+1;
             i3++;
        }
     else   /*ako se isti clan dobija u obe grane */
       {   x[i]=x[i2]*2 +1;
            i2++;  i3++;
       }
   }

  printf("\nClanovi skupa M su:\n");
  for (i=0; i < n; i++)  printf("%d", x[i]);

 fclose(f);

 } 



86.
NCP koji u datoteku izlaz.txt upisuje n najmanjih prorodnih brojeva deljivih sa tačno dva broja iz skupa {2, 5, 7}. Proveru izvršiti bez upotrebe operatora / ili operatora %. Broj n se zadaje iz komandne linije.

IDEJA:
Program treba da n puta ispise

Kako poredak treba da bude rastući, onda proveru treba započeti od prvog kandidata i za svaki sledeći veći broj proveriti gore navedene uslove deljivosti. Prvi kandidat je 10=2*5 (i nema potrebe proveru uslova deljivosti vršiti za manje brojeve), a sledeći kandidati su 11, 12, 13,... Program okončava rad kada pronađe n brojeva počev od 10 koji zadovoljavaju uslov.

ULAZ program 12
IZLAZ 10 14 20 28 30 35 40 42 50 56 60 80
Uociti da broj 70=2*5*7 nije na izlaznom spisku



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

/* p1, p2, p3 su brojevi za koje proveravamo deljivost */
#define p1 2
#define p2 5
#define p3 7

int check (int a, int p); /* funkcija koja vraca negativnu vrednost ako a nije deljivo sa p, 
                                          ili 0 ako a jeste deljivo sa p*/

main (int argc, char * argv[])
{

    FILE *f;
    int j, k, l; /* u ove tri promenljive smestamo isti broj i posebno proveramo
                       da li je neki od njih deljiv sa 2, 5, 7 */
    int i;  /* brojac u petlji koji se uvecava za jedan i inicijalizuje j, k, l pri svakom
                    prolazu kroz petlju */
   int n;

    f=fopen("izlaz.txt", "w");
    n=atoi(argv[1]);

/* prvi kandidat je broj i=10=2*5; ispisuje se n brojeva koji ispunjavaju formulisanu uslov deljivosti */
   for(i=10;n>0; i++)
    {
        j=k=l=i;   /*inicijalizacija kandidata j,k,l*/
       j=check(j,p1);    /*ako je broj i deljiv sa 2 bice j==0 nakon poziva funkcije check */
       k=check(k,p2); /*ako je broj i deljiv sa 5 bice k==0 nakon poziva funkcije check */
       l=check(l,p3); /*ako je broj i deljiv sa 7 bice l==0 nakon poziva funkcije check */
   
      /*provera da li za vrednost promenljive  i vazi
          broj je deljiv sa 2 (j==0) i deljiv sa 5 (k==0) i nije deljiv sa 7 (l!=0)  ili
          broj je deljiv sa 2 (j==0) i deljiv sa 7 (l==0) i nije deljiv sa 5 (k!=0)  ili
          broj je deljiv sa 5 (k==0) i deljiv sa 7 (l==0) i nije deljiv sa 2 (j!=0)  */
      if (  (j==0 && k==0 && l!=0)
          || (j==0 && l==0 && k!=0)
          || (k==0 && l==0 && j!=0)  )      
           { fprintf(f, "%d ", i);  /*upis u datoteku broja i koji ispunjavaju formulisanu uslov deljivosti */
              n--;  /* kolicina brojeva za upis u datoteku je manja za jedan broj */
          }  /*if*/
    }  /*for*/

     fclose(f);

 }/*main*/


int check (int a, int p)
{
     do
         {   /*od promenljive a oduzimamo p sve dok je a strogo vece od nula,
                funkcija vraca kao rezultat poslednje izracunatu vrednost promenljive a.
                Ta vrednost ce biti tacno nula ako a deli p bez ostatka.*/
             a=a-p;
         } while (a>0);
           
      return a;
}     



87.
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...

gcc zad87.c -o zad87

POKRETANJE PROGRAMA: zad87 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*/
   FILE *f;


    f=fopen("prosti.txt", "w");

  /* "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) )  ) fprintf(f, "%d  ",i);

  fclose(f);
  
}


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;
}


88.
NCP koji će ulaznu datoteku prepisati u izlaznu tako da samo samoglasnici (a, e, i, o, u) budu prikazani velikim slovima. Nazivi ulazne i izlazne datoteke se zadaju u komandnoj liniji. U programu nije neophodno predvideti obradu greski nastalih usled nekorektnog pozivanja programa u komandnoj liniji ili greske u otvaranju datoteka...
#include <stdio.h>
#include <ctype.h>

int malisamogl(int znak); /* ako znak je malo slovo a,e,i,o,u funkcija vraca 1, inace 0 */

main(int argc, char *argv[])
{
   int znak; /*tekuci znak ulazne datoteke koji se kopira u izlaznu datoteku */
   FILE *ulaz, *izlaz;

   ulaz=fopen(argv[1], "r");
   izlaz=fopen(argv[2], "w");   
  /* kopirati sadrzaj ulazne datoteke u izlazne citanjem ulaza do markera kraja EOF i konvertovanjem malih samoglasnika */
      while( (znak=getc(ulaz)) != EOF)
     {   if (malisamogl(znak)) znak=toupper(znak); /*mali samoglasnik postaje veliki samoglasnik */
       else 
            /*veliko slovo koje nije samoglasnik postaje malo slovo;
               veliko slovo koje jeste samoglasnik se ne transformise */
           if( isupper(znak) && !malisamogl(znak + 'a'- 'A')) znak=tolower(znak);
       putc(znak, izlaz);
  }

}



int malisamogl(int znak)
{     if (znak=='a' || znak=='e' || znak=='i' || znak=='o' || znak=='u')
        return 1;
     else return 0;
}


89.
Svaki red datoteke, čije se ime unosi kao argument komandne linije, sadrži ime, prezime i korisničko ime studenta (Matematičkog fakulteta u Beogradu) na serveru ALAS. Iza imena i prezimena nalazi se po jedan blanko karakter, a korisnička imena su zapisana u formatu: dvoslovna oznaka smera, poslednje dve cifre godine upisa, četvorocifren broj indeksa. (npr. mr050007, ml040950, aa030034). Napisati program koji generiše HTML datoteku generacija05.htm koja sadrži tabelu sa podacima o studentima koji su upisani 2005. godine na Matematički fakultet. Zaglavlje tabele treba da sadrži polja: ime, prezime, username. Pretpostavka da ulazna datoteka je bez sintaksnih i semantičkih greški.
ULAZ
Marko Markovic ml020888
Branka Brankovic mr050012
Ana Petrovic mm040088
Petar Andric mv050700
Mika Lazic mn050701
Sanja Petrovic aa040500


IZLAZ  Generacija05.htm
ImePrezimeUsername
Branka Brankovic mr050012
Petar Andric mv050700
Mika Lazic mn050701

IDEJA i DISKUSIJA: Ucitava se rec po rec datoteke i nakon svake tri ucitane reci, proverava se vrednost niske username i njeni karakteri na drugoj i trecoj poziciji (jer nulta i prva pozicija cuvaju oznake smera, a druga i treca pozicija oznaku godine upisa u obliku poslednje dve cifre godine ).
Kako niske ime, prezime, username za svakog studenta ne sadrze beline, a kako separatori među niskama su blanko, a separator među podacima o studentima je znak za prelaz u novi red, to možemo koristiti bibliotečki funkciju formatiranog ulaza fscanf (tj. nije nužno da implementiramo korisničku funkciju za učitavanje reči). Uočite da implementacija korisničke funkciju za učitavanje reči sa ulaza je bilo potrebno kad god su te reči bile specifične forme (npr. tagovi - niske između uglastih zagrada ili alfanumeričke niske-niske koje sadrže samo slova ili cifre ili tagovi bez atributa - niske između uglastih zagrada i/ili belina,...)




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

#define MAXIME 20
#define MAXU 9



int main(int argc, char ** argv)
{
   FILE *ulaz, *izlaz;
   char ime[MAXIME], prezime[MAXIME], username[MAXU];

	ulaz=fopen(argv[1], "r");
	izlaz=fopen("generacija05.htm", "w");

               /*formiranje HTML zaglavlja i tela u izlaznoj datoteci generacija05.htm */
   	fprintf(izlaz,"<HTML><HEAD><TITLE>Generacija upisana 2005/06</TITLE></HEAD><BODY>");
	fprintf(izlaz, "<TABLE><TR><TH>Ime</TH><TH>Prezime</TH><TH>Username</TH>");
  
 
   while(!feof(ulaz))
   {
      /* Ucitavanje imena iz ulazne datoteke*/
      fscanf(ulaz, "%s", ime);

     /* Ucitava se prezime iz datoteke */
          fscanf(ulaz, "%s", prezime);
    
      /* Ucitava se username*/
            fscanf(ulaz, "%s", username);
	  
        /* provera da li ucitan potpun sadrzaj za sve tri niske */
	   if(strlen(ime) && strlen(prezime) && strlen(username))
		   /* provera da li korisnicko ime sadrzi cifre 05 na pozicijama godina upisa*/
		   if((username[2]=='0') && (username[3]=='5') )
			   /* upisi podataka u tabelu datoteke generacija05.htm */
	fprintf(izlaz,"<TR><TD>%s</TD> <TD>%s</TD> <TD>%s</TD></TR>", ime, prezime, username );
   }
   
   


   /*Upis tagovi za kraj tabele i HTML datoteke*/
   fprintf(izlaz,"</TABLE></BODY></HTML>");

   fclose(ulaz);
   fclose(izlaz);
}







Jelena Grmuša Osnovi programiranja

e-mail: Jelena Grmuša



Poslednja izmena: april 2006.
URL: http://www.matf.bg.ac.yu/~jelenagr/op/