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); }
/* 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
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 |