Vezbe iz Osnova programiranja – datoteke (uvod)




115. NCP koji u datoteku podaci.txt upisuje prvih 10 prirodnih brojeva, a zatim se iz iste datoteke citaju brojevi dok se ne stigne do kraja i ispisuju se na standardni izlaz .

/* Program demonstrira otvaranje datoteka ("r" - read i "w" - write mod) i osnovne tehnike rada sa datotekama */


#include <stdio.h>


/* Zbog funkcije exit */

#include <stdlib.h>


main()

{

int i; /* brojac u ciklusu */

int br; /* broj iz ulazne datoteke */


/* Otvaramo datoteku sa imenom podaci.txt za pisanje */

FILE* f = fopen("podaci.txt", "w");


/* Ukoliko otvaranje nije uspelo, fopen vraca NULL. U tom slucaju, prijavljujemo gresku i zavrsavamo program */

if (f == NULL)

{

printf("Greska prilikom otvaranja datoteke podaci.txt za pisanje\n");

exit(1);

}


/* Upisujemo u datoteku prvih 10 prirodnih brojeva (svaki u posebnom redu) */

for (i = 0; i<10; i++) fprintf(f, "%d\n", i);


/* Zatvaramo datoteku */

fclose(f);


/* Otvaramo datoteku sa imenom podaci.txt za citanje */

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


/* Ukoliko otvaranje nije uspelo, fopen vraca NULL. U tom slucaju, prijavljujemo gresku i zavrsavamo program */

if (f == NULL)

{

printf("Greska prilikom otvaranja datoteke podaci.txt za citanje\n");

exit(1);

}


/* Citamo brojeve iz datoteke dok ne stignemo do kraja i ispisujemo ih na standardni izlaz */


/* Pokusavamo da procitamo broj */

while(fscanf(f, "%d", &br) == 1)

/* Ispisujemo procitani broj */

printf("Procitano : %d\n", br);



/* Zatvaramo datoteku */

fclose(f);

}


NAPOMENA:


Citanje brojeve iz datoteke do kraja datoteke i ispis tih brojeva na standardni izlaz

odvija se u fragmentu:


while(fscanf(f, "%d", &br) == 1)

printf("Procitano : %d\n", br);


II nacin za citanje brojeve iz datoteke do kraja datoteke i ispis tih brojeva na standardni izlaz:

while(1)

{

fscanf(f, "%d", &br);

/* Ukoliko smo dosli do kraja datoteke (poziv f-je feof(f) ), prekidamo ciklus*/

if (feof(f)) break;


/* Ispisujemo procitani broj */

printf("Procitano : %d\n", br);

}



OPREZ:


/* Ako je datoteka iz koje se vrsi ucitavanja mozda i prazna, onda

funkciju feof ne bi trebalo pozivati pre pokusaja citanja.


Sledeci kod moze dovesti do greske:

while (!feof(f))

{

fscanf(f, "%d",&br);

printf("Procitano : %d\n", br);

}

*/




116. NCP koji demonstrira rad sa datotekom u rezimu "a" - append mod datoteka tj. nadovezivanje sadrzaja na kraj datoteke.


#include <stdio.h>


main()

{

FILE* datoteka;


/* Otvaramo datoteku za nadovezivanje i proveravamo da li je doslo do greske */

if ( (datoteka=fopen("dat.txt","a"))==NULL)

{

fprintf(stderr,"Greska : nisam uspeo da otvorim dat.txt\n");

return 1;

}


/* Upisujemo sadrzaj u datoteku */

fprintf(datoteka,"Zdravo svima\n");


/* Zatvaramo datoteku */

fclose(datoteka);

}



117. NCP koji kopira datoteku ulaz.txt u datoteku izlaz.txt. Uz svaku liniju se zapisuje i njen broj


#include <stdio.h>

#include <string.h>

#define MAX_LINE 256


/* Korisnicka funkcija getline iz K&R jednostavno realizovana preko bibliotecke funkcije fgets (iz stdio.h) */

int getline(char s[], int lim)

{

char* c = fgets(s, lim, stdin);

return c==NULL ? 0 : strlen(s);

}



main()

{

char line[MAX_LINE]; /* linija datoteke */

FILE *in, *out; /*tokovi: ulaz, izlaz*/

int line_num; /*redni broj linije */



if ((in = fopen("ulaz.txt","r")) == NULL)

{

fprintf(stderr, "Neuspesno otvaranje ulazne datoteke %s\n", "ulaz.txt");

return 1;

}



if ((out = fopen("izlaz.txt","w")) == NULL)

{

fprintf(stderr, "Neuspesno otvaranje datoteke %s\n","izlaz.txt");

return 1;

}


/* Prepisivanje karakter po karakter je moguce ostvariti preko sledeceg fragmenta:

int c;

while ((c=fgetc(in)) != EOF) putc(c,out);

*/


line_num = 1; /*redni broj polazne linije */


/* Citamo liniju po liniju sa ulaza*/

while (fgets(line, MAX_LINE, in) != NULL)

{

/* Ispisujemo broj linije i sadrzaj linije na izlaz */

fprintf(out, "%-3d :\t", line_num++);

fputs(line, out);

}


/* Zatvaramo datoteke */

fclose(in);

fclose(out);

}




118. U svakoj liniji tekstualne datoteke cd.dat nalaze se podaci o prodaji kompakt diskova. Linija se sastoji od više kolona međusobno razdvojenih dvotačkom.

U prvoj koloni se nalazi naziv žanra CDa koji može biti jedna od niski iz skupa { inostrana, novokomponovana, decija, klasicna }.

U drugoj koloni je zadat broj prodatih primeraka za tekuću prodaju.

U trećoj koloni dat je datum prodaje u obliku rednog broja između 1 (početni dan intervala prodaje) i 30 (dan obrade podataka).

Potom slede podaci o nabavnoj ceni. Ti podaci se sastoje od: cene po primerku, ali za inostranu muziku dodatno se zadaje i iznos carine PO UKUPNOJ KOLIČINI, dok za novokomponovanu muziku dodatne se PO PRIMERKU zadaje i iznos poreza na šund.

Potom slede podaci o prodajnoj ceni


BROJ LINIJA U DATOTECI NIJE UNAPRED POZNAT.


NCP koji će odštampati na standardni izlaz ukupne prihode od prodaje u intervalima od 15 dana i formirati datoteku podaci.dat koja će biti u istom formatu kao datoteka cd.dat, ali će sadržati podatke o prodaju diskova koji nisu iz žanra novokomponovane muzike.

TEST PRIMER

cd.dat

standardni izlaz

podaci.dat

inostrana:20:1:400:20:500
novokomponovana:100:1:200:80:500
decija:5:1:100:200
klasicna:1:1:200:250
novokomponovana:100:2:200:80:500
inostrana:10:2:400:20:500
decija:3:2:100:200
novokomponovana:120:3:200:80:500
inostrana:28:3:400:20:500
inostrana:12:4:400:20:500
novokomponovana:80:4:200:80:500
decija:8:4:100:200
klasicna:3:4:200:250
Prihodi po intervalima dana:
[1,15]: 96720.00
[16,30]: 0.00
inostrana:20:1:400.000000:20.000000:500.000000
decija:5:1:100.000000:200.000000
klasicna:1:1:200.000000:250.000000
inostrana:10:2:400.000000:20.000000:500.000000
decija:3:2:100.000000:200.000000
inostrana:28:3:400.000000:20.000000:500.000000
inostrana:12:4:400.000000:20.000000:500.000000
decija:8:4:100.000000:200.000000
klasicna:3:4:200.000000:250.000000



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

main ()
{  int i; /*brojac u petlji */ 
   FILE *cd;                    /*podaci o prodaji kompakt diskova se cuvaju u datoteci tako da svaka  
                                                            linija sadrzi podatke o jednoj prodaji;
                                                           Unutar linje kolone se razdvajaju dvotackama*/ 
 FILE *podaci;                            /*podaci o zanru inostrana, decija, klasicna */
  char naziv[17];                     /* zanr CD-a moze biti: inostrana, novokomponovana, decija, klasicna*/  
  int komada_prodato;                       /* broj prodatih  diskova pri tekucoj prodaji */
  int datum_prodaje;            /* datum prodaje za tekucu prodaju (1..30) */
  float nabavna_cena;           /* nabavna cena po jedinici  za tekucu prodaju. */ 
 float iznos_carine;            /*iznos carine za tekucu prodaju. */
  float iznos_poreza;           /* porez po jedinici za novokonponovanu muziku */
  float prodajna_cena;                         /* prodajna cena za tekucu prodaju. */
  float prihod_1_15, prihod_16_30;      /*prihod po svakom od intervala od po 15 dana*/
  float prihod;                    /*prihod od tekuce prodaje. */ 
   
     cd = fopen ("cd.dat", "r");
     podaci = fopen ("podaci.dat", "w");
     if ( (cd==NULL) || (podaci==NULL) )  
           {fprintf(stderr,"Greska pri otvaranju neke od datoteka\n");        exit(1);    }

  /* Inicijalizacije. */  
    prihod_1_15 = prihod_16_30  = 0;

  /* Obradjuje se jedna po jedna linija datoteke o svim prodajama, pazeci na dvotacku */
  for (; !feof (cd);)
    {
      /* Ucitava se naziv zanra */
      for (i = 0; (naziv[i] = fgetc (cd)) != ':'; i++)  ;
      naziv[i] = '\0';
          /* Ucitavaju se broj prodatih jedinica :datum prodaje:nabavna  cena za tekucu prodaju */ 
     fscanf (cd, "%d:%d:%f:", &komada_prodato, &datum_prodaje, &nabavna_cena);
      /* Za inostrani cd ucitava se iznos carine. */ 
     if (!strcmp (naziv, "inostrana"   ))
        fscanf (cd, "%f:", &iznos_carine);
      else      iznos_carine = 0;    

  /* Za cd novokomponovane  muzike ucitava se iznos poreza. */
      if (!strcmp (naziv, "novokomponovana"))
        fscanf (cd, "%f:", &iznos_poreza); 
     else       iznos_poreza = 0;

      /* Ucitava se prodajna cena po primerku */
      fscanf (cd, "%f\n", &prodajna_cena);   
   /* Izracunava se prihod od tekuce prodaje. */
      prihod =
        komada_prodato * (prodajna_cena - nabavna_cena - iznos_poreza) -  iznos_carine; 


     /* Uvecava se prihod u intervalu kome pripada prodaja. */ 
     if (datum_prodaje <= 15)   prihod_1_15 += prihod;
      else if (datum_prodaje <= 30)
        prihod_16_30 += prihod;
      
      /* Ako zanr cd nije novokomponovana muzika, prepisuje se tekuca prodaja u datoteku sa podacima o prodaji */
      if (strcmp (naziv, "novokomponovana") !=0)
        {  fprintf (podaci, "%s:%d:%d:%f:", naziv,      
           komada_prodato, datum_prodaje, nabavna_cena);
          if (!strcmp (naziv, "inostrana"))    fprintf (podaci, "%f:", iznos_carine);
          fprintf (podaci, "%f\n", prodajna_cena);
        }
    }

  /* Zatvaraju se datoteke. */ 
     fclose (cd);  fclose (podaci);  
/* Ispisuje se izvestaj o prodaji cd-a po intervalima */
  printf ("Prihodi po intervalima dana:\n");
  printf ("%s: %.2f\n", "[1,15]", prihod_1_15);
  printf ("%s: %.2f\n", "[16,30]", prihod_16_30);
  return 0;
}

119. NCP koji ispisuje na standardni izlaz spojeni sadržaj nekoliko datoteka čiji nazivi su dati kao parametri komandne linije. Ako se u komandnoj liniji ne nalazi naziv niti jedne datoteke, onda ispisati tekući sadržaj sa standardnog ulaza.


IDEJA:
U ovom zadatku potrebno je otvoriti datoteke čiji nazivi su sadržani u niskama argv[1], argv[2],..., argv[argc-1]
Ako otvaranje pojedinačne datoteka bude uspešno (fopen(...) != NULL), onda pozvati f-ju pisi(f,stdout) koja sadrzaj datoteke na koji pokazuje f ispisuje na stdout (standardni izlaz, tj. ekran dok ga ne preusmerimo komandom operativnog sistema)
Ako otvaranje datoteke ne uspe, potrebno je ispisati poruku o gresci na stderr(standardni tok za poruke o grešci) i prekinuti dalje izvršvanje programa (exit(1);)
U f-ju pisi(f,stdout) čita se karakter po karakter (sve do EOF) iz datoteke na koju pokazuje f (getc(f)) i ispisuje na standardni izlaz (putc(c,stdout)).
Nakon završetka ispisa sadržaja datoteke, datoteka se zatovori. (fclose(f))



#include <stdio.h>

void pisi(FILE *ulaz,FILE *izlaz);    /*prepisuje ulaznu datoteku u izlaznu datoteku */ 

main(int argc, char *argv[ ])
{ FILE *f;                           /* za citanje */
   int i;                                  /*brojac u petlji */
   char *imeprog=argv[0]; /*ime programa; nije obavezno pri ispisu*/


   if(argc==1) pisi(stdin,stdout);  /* kada se prenosi tekst sa glavnog ulaza,jer u komandnoj liniji nema imena ostalih datoteka */
   else                                           
/*inace ispisati "spojeni" sadrzaj (ako je moguce) onih  datoteka cija se imena cuvaju kao argv[1]...argv[argc-1] */ 
   for(i=1; i < argc;i++)    

/*pokusaj otvranja datoteke za citanje */ 
          if(  (f=fopen(argv[i],"r") ) ==NULL)      
            {  fprintf(stderr, "%s:  Ne mogu otvoriti fajl sa imenom %s\n",imeprog, argv[i]);
               exit(1);        }            
         else
             /*ispis sadrzaja upravo otvorene datoteke na standardni izlaz */
             { pisi(f,stdout);  fclose(f);}




     if (ferror(stdout) )
        { fprintf(stderr, "%s: greska pisanja u stdout\n",imeprog);   exit(2);}


      exit ( 0 );
}


void pisi(FILE *ulaz,FILE *izlaz)   /*kopira ulaz na izlaz */
  { int c; 
            while(   (c=getc(ulaz)  ) !=  EOF)  putc(c,izlaz);
}

120. NCP koji ce odštampati na standardni izlaz izveštaj o broju redova, reči, karaktera u datoteci PROVERA.C. Pretpostaviti da tip long je dovoljan za sve tri karakteristike iz izveštaja. Smatrati da reč je ma koja niska znakova koja ne sadrži znak razmak, horizontalni tabulator, znak za prelaz u novi red.



/* word count (UNIX komanda wc) za  file  "PROVERA.C", pogledati sličan zadatak u I glavi Kernighan-Ritchie */
#include <stdio.h>
#include <stdlib.h>

typedef enum {VAN, UNUTAR} STANJE;

main (){             STANJE ureci;  /*svojom vrednoscu signalizira VAN/UNUTAR  reci */
       long red_broj, rec_broj, znak_broj;   /*ukupan broj redova,reci,znakova */
       int zn;                                                /*tekuci ucitani znak */
       char ime[]="PROVERA.C" ;           /*ime datoteke koja se analizira */
       FILE *pf;

           pf = fopen(ime, "r");
           if (pf == NULL) {
                fprintf(stderr, "Otvaranje %s nije uspelo.\n", ime);exit (EXIT_FAILURE);                  
               }

/* analiza sadrzaja fajla  i prebrojavanje karaktera, reci, prelazaka u novi red*/
red_broj = rec_broj = znak_broj = 0;ureci = VAN;

while (( zn = fgetc(pf)) != EOF) {   
             ++znak_broj;
               if (zn == ' ' || zn == '\t' || zn == '\n')
                        ureci = VAN;
               else if (ureci == VAN) {
                        ++rec_broj;
                        ureci = UNUTAR;
                }
        if (zn == '\n')++red_broj;
     }

if (ferror(pf) != 0) {fprintf(stderr, "GRESKA PRI CITANJU: %s\n", ime); exit (EXIT_FAILURE); }

/* prikazati rezultate analize */
printf("%s: %ld %ld %ld\n",ime, red_broj, rec_broj, znak_broj);

return (EXIT_SUCCESS);
}

121. NCP koji će kopirati sadržaj jedne tekstualne datoteke u drugu tekstualnu datoteku. Nazivi datoteka se zadaju kao parametri komandne linije.

/*  POZIV programa: kopiraj dat1 dat2 */

#include <stdio.h>

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

   if (argc !=3)  printf("\nOblik komande je:  %s ulaz izlaz\n", argv[0]);
  else      if ( (ulaz=fopen(argv[1],"r") ) == NULL) printf("Datoteka %s se ne moze otvoriti za citanje\n",argv[1]);
  else         if   (  (izlaz=fopen(argv[2],"w") ) == NULL)
                printf("Datoteka %s se ne moze otvoriti za pisanje\n",argv[2]);
        else   {       /*izvrsiti kopiranje sadrzaja ulazne datoteke u izlaznu iscitavanjem ulaza do markera kraja */ 
                       while (  (znak=getc(ulaz) )  != EOF)  putc(znak, izlaz);
                       printf("\n");
                  }
    return 0;
}

122. NCP koji će prepisati sadržaj tekstualne datoteke (čije ime se zadaje kao argument komandne linije) na standardni izlaz tako da se učitava do 80 karaktera po liniji.

/* type datoteka */

#include <stdio.h>
#define LINE_LENGTH  81

main(int argc, char *argv[]){        char linija[LINE_LENGTH];  /*sadrzaj tekuce  linije datoteke */
    FILE *ulaz;
      if (argc !=2)  printf("\nFormat poziva: %s    imeUlazneDatoteke\n",argv[0]);
      else        if (  (ulaz=fopen(argv[1],"r") ) == NULL)
         printf("Datoteka %s se ne moze otvoriti \n", argv[1]);
       else    /*ispis teksta */
          while (fgets(linija,LINE_LENGTH,ulaz) != NULL) printf("%s",linija);    

   return 0;
} 

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

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

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

126.
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);

 } 

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

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

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





Zadaci za vezbu (zadaci su poredjani po tezini u rastucem poretku):


Zadatak 1. NCP koji iz komandne linije ucitava imena dve datoteke i ispisuje na standardni izlaz da li su jednake prva rec prve datoteke i prva rec druge datoteke. Smatrati da reci nemaju vise od 20 karaktera. U slucaju greske u otvaranju datoteka, prijaviti odgovarajuci komentar na stderr.


TEST primer

DAT1. txt

Programiranje 1 je moj omiljeni predmet.

DAT2.txt

Programiranje 1 nije moj omiljeni predmet.


IZLAZ

Prva rec 1. datoteke je Programiranje, prva rec 2. datoteke je Programiranje i te dve reci su jednake.



Zadatak 2. NCP koji iz komandne linije ucitava imena dve datoteke (ulazna i izlazna datoteka) i sabira sve realne brojeve u ulaznoj datoteci i ispisuje njihov zbir u izlaznu datoteku. U slucaju greske u otvaranju datoteka, prijaviti odgovarajuci komentar na stderr.

TEST primer

ULAZ.txt

1 5 8.3 -2.3

8

0

-6


IZLAZ.txt

Suma brojeva datoteke ULAZ.txt je 14.



Zadatak 3. NCP koji iz komandne linije ucitava imena dve datoteke (ulazna i izlazna datoteka) i iz ulazne datoteke kopira u izlaznu svaki drugi karakter polazeci od drugog procitanog karaktera. U slucaju greske u otvaranju i zatvaranju datoteka, prijaviti odgovarajuci komentar na stderr.

TEST primer

DAT1. txt

Programiranje.

IZLAZ

rgaiaj.


Zadatak 4. Napisati program koji broji pojavljivanja za svako od slova engleske abecede u datoteci ulaz i stampa rezultat na standardni izlaz.

TEST primer

ULAZ. txt

FE9 + 1 = FEA.

IZLAZ

Slovo A: 1

Slovo B: 0

Slovo C: 0

Slovo D: 0

Slovo E: 2

Slovo F: 2

Slovo G:0

....

Slovo Z: 0








Zadatak 5. NCP koji iz komandne linije ucitava naziv datoteke i ispisuje na standardni izlaz najduzu liniju. Ako ima vise linija najvece duzine, ispisati onu koja se najpre pojavila. Pretpostaviti da svaka linija datoteke nema vise od 80 karaktera. Broj linija datoteke NIJE unapred poznat!!! U slucaju greske u otvaranju datoteke, prijaviti odgovarajuci komentar na stderr.

TEST primer

DAT1. txt

Programiranje 1 je

moj omiljeni predmet. Ako

ne polozim

programiranje 1,

bice mi tesko da

savladam gradivo

na predmetu

Programiranje 2.

IZLAZ

moj omiljeni predmet. Ako





Zadatak 6. Opisati sve greške u sledećem C programu.



include <stdio.h>
define OFFSET 3;
define greska(msg) fprintf(stderr,#msg" %s\n",argv);
void processFile(pd1,pd2); /ucitavanja iz datoteke i obrada/
int length, width;
long area;
struct coord_p
{ int x,
int y }mypt
struct rectangle
{ coord_p topleft,
coord_p bottomrt } mybox

main(int argc, char argv**) {
FILE pd1, pd2;
if( argv = 3 ) /korektan broj argumenata /
if( pd1 = fopen( **++argv, 'r')== NULL ) {
greska(Ne moze da se otvori)
exit(1)
} else if( pd2 = fopen( **++argv, 'r')= NULL ) {
greska(Ne moze da se otvori)
exit(1)
} else { /ucitavanje koordinata/
processFile( pd1, pd2 ); free( pd1 ); free( pd2 );
exit(2)
}
return 3;
}
void processFile(pd1,pd2);
{boolean coord_test;
fscanf(pd1, "%d", mybox.topleft.x, mybox.topleft.y);
fscanf(pd1, "%d", mybox.bottomrt.x); fscanf(pd1, "%d", mybox.bottomrt.y);
coord_test=(bottomrt.x - topleft.x)*(bottomrt.y - topleft.y) > 0;
if (coord_test){ / izracunavanje duzine, visine i povrsine /
width = OFFSET+ bottomrt.x - topleft.x; length = OFFSET + bottomrt.y - topleft.y; Area = width * length;
printf(pd2,"\nPovrsina je %l\n", area); }
}



RESENJE:



#include <stdio.h>
#include <stdlib.h>
#
define OFFSET 3
#
define greska(msg) fprintf(stderr,#msg" %s\n", *argv);
void processFile( FILE * pd1, FILE *pd2 ); /*ucitavanje iz datoteke i obrada */

int length, width;
long area;
struct coord{
int x;
int y;
};
struct rectangle{
struct coord topleft;
struct coord bottomrt;
} mybox;

main(int argc, char **argv) {
FILE *pd1, *pd2;

if( argc == 3 ) /* korektan broj argumenata */
if( (pd1 = fopen( *++argv, "r" ) ) == NULL ) {
greska(Ne moze da se otvori)
exit(1);
} else if( ( pd2 = fopen( *++argv, "w" ) ) == NULL ) {
greska(Ne moze da se otvori)
exit(1);
} else { /* ucitavanje koordinata */

processFile( pd1, pd2 );
fclose( pd1 );
fclose( pd2 );
exit( 2 );
}

}
void processFile( FILE * pd1, FILE *pd2 ) {
int coord_test;
fscanf(pd1, "%d %d", &mybox.topleft.x, &mybox.topleft.y);
fscanf(pd1, "%d", &mybox.bottomrt.x);
fscanf(pd1, "%d", &mybox.bottomrt.y);
coord_test=(mybox.bottomrt.x - mybox.topleft.x)*(mybox.bottomrt.y - mybox.topleft.y) > 0;
if (coord_test) { /*izracunavanje duzine, visine i povrsine */
width = OFFSET + mybox.bottomrt.x - mybox.topleft.x;
length = OFFSET + mybox.bottomrt.y - mybox.topleft.y;
area = width * length;
}
fprintf(pd2,"\nPovrsina je %ld \n", area);
}



Zadatak 7*. Datoteka cije se ime unosi sa standardnog ulaza sadrzi podatke o proizvodima koji se prodaju u okviru odredjene prodavnice.

Svaki proizvod se odlikuje sledecim podacima :

bar-kod - petocifreni pozitivan broj

ime - niska karaktera

cena - realan broj zaokruzen na dve decimale

pdv - stopa poreza - realan broj zaokruzen na dve decimale

Pretpostavljamo da su podaci u datoteci korektno zadati.

Pretpostavljamo da se u prodavnici ne prodaje vise od 1000 razlicitih artikala. Na standardni izlaz ispisati podatke o svim proizvodima koji se prodaju.


Zadatak 8**. NCP koji iz komandne linije prihvata naziv grada i formira datoteku izlaz.txt 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.txt kao delovi strukture
struct student{ char imePrezime[40]; long maticniBroj; int godinaStudija; char srednjaSkola[50]; double poeni; }
i datoteci licno.txt kao delovi strukture
struct licniDosije{ long maticniBroj; char adresa[50]; char grad[40]; long FiksniTelefon; long MobilniTelefon; char drzavljanstvo[20]; }



Zadatak 9**.
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 datoteku generacija05.txt 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.txt

Ime

Prezime

Username

Branka

Brankovic

mr050012

Petar

Andric

mv050700

Mika

Lazic

mn050701



IDEJA:

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