Vezbe iz Osnova programiranja

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

 
  69. NCP koji ce odštampati na standardni izlaz izveštaj o broju redova, reči, karaktera u datoteci PROVERA.C. Pretpostaviti da tip lonf 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);
}

70. NCP koji će kopirati sadržaj jedne tekstualne datoteke u drugu tekstualnu datoteku. Nazivi datoteka se zadaju kao parametri komandne linije.
/*copy  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") ) == NUL) 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;
}
71. 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;
} 

72. NCP koji će obavljati čitanje binarne datoteke unazad (čije ime se zadaje u komandnoj liniji) i ispisati pročitan sadržaj na standardni izlaz u formi tabele sa 3 kolone čija su zaglavlja: ucitani karakter, vrednost karaktera, pozicija posle.

Bitna razlika između DOS-a i UNIX-a je u tretmanu kraju reda. U DOS-u su to 2 karaktera (CR LF ascii kodovi su: #13 #10), a u UNIX-u samo 1 (LF).
CR je Carriage Return (povratak na početak reda, vraćanje bubnja, tj. kolica na pisaćoj mašini ulevo).
LF je Line Feed (spuštanje za red niže).
ASCII (American Standard Code for International Interchange), DOS i kasniji OS-ovi koriste da je novi red CR LF.
Kod COMMODORE-u 64 je na primer novi red reprezentovan sa CR, dok u C-u i UNIX-u novi red je predstavljen sa LF.

Binarno prenošenje sadržaja je bit-po-bit. Ali ascii tekst tada ne bi bio dobro prenesen jer bi morao svaki LF da se zameni sa CR LF i obratno. Zato služi ascii prenos. Na primer, neki DOS fajl binarno ima 150 karaktera, a ascii 139.

ULAZ: 8abcd 9

PROVERITE IZLAZ OVOG zadatak za gore zadati ulaz pod DOS/Windows-om, pod UNIX/Linux-om. Uporedite sadržaje sve tri kolone. Ovaj zadatak ilustruje gore navedene razlike.


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



 #define BOF	-2		/* marker pocetka datoteke */
FILE *fp;

int get_and_print( void );     /*popunjavanje jedne vrste tabele */
int get_previous_char( void );    /*ocitavanje  karaktera pri citanju unazad */

main(int argc, char *argv[]){
       if( (fp = fopen( argv[1], "rb")) == NULL )	{
		fprintf( stderr, "Neuspeh pri  otvaranje  datoteke %s", argv[1]);
		exit( 1 );
	}	

/* kreiranje "tabele" za ispis */
	printf("\n ucitani\t vrednost\t pozicija");
	printf("\n karakter\t karaktera\t posle\n");	
                  fseek( fp, 0L, SEEK_END);	/* pozicioniranje na kraj datoteke */

	while( get_and_print( ) != BOF ) ;  /*ucitavanje do korisnickog markera pocetka */
	fclose( fp );
}


int get_and_print( void ){
     int c;  /*tekuci znak iz datoteke */ 
        c = get_previous_char( );
     if( isprint(c) ) printf("\t%c", c);                   /*"stampanje" ucitanog karaktera */
         else	if( c == '\n' ) printf("\tLF");
         else if( c == '\r' ) printf("\tCR");
         else if( c == EOF ) printf("\tEOF");
         else if( c == BOF ) printf("\tBOF");
        else if( c == 26 ) printf("\tALT26");
         else  printf("\t");

	printf("\t %3d", c);                         /*vrednost karaktera */
	printf("\t\t %2ld\n", ftell( fp ) );     /*pozicija */	          return( c );
}

int get_previous_char( void )
{  int c;
	if( ftell( fp ) > 0 )
	{
		fseek( fp, -1L, SEEK_CUR);	/* pomeranje za jedan unazad */
		c = getc( fp );                                   /* citanje */
 		fseek( fp, -1L, SEEK_CUR);    /* pripremanje za sledece citanje */
		return c;
	}
	else return BOF;
}
73. U svakoj liniji tekstualne datoteke cd.dat nalaze se podaci o prodaji komapkt diskova. Linija se sastojo od više kolona međusobno razdvojenih dvotačkom. U prvoj koloni sr nalazi naziv žanra CDa koji može biti jedna od niskiz skupa { inostrana, novokomponovana, decija, klasicna }. U drigoj 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. BROJ LINIJA U DATOTECI NIJE UNAPRED POZNAT. NCP koji će odštampati na standradni 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.
#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;
}


Jelena Grmusa Osnovi programiranja

e-mail: Jelena Grmuša


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