Sunteți pe pagina 1din 15

Caracterizarea posibilităţilor

de intrare/ieşire a informaţiei

În C nu există posibilităţi încorporate, adică instrucţiuni de intrare/ieşire a


informaţiei. Toate operaţiile de intrare/ieşire a informaţiei se realizează în baza
unor funcţii. Sunt 3 categorii mari de funcţii de intrare/ieşire a informaţiei:
1) funcţii ce realizazeă intrarea/ieşirea în baza fluxurilor de date;
2) funcţii care realizează intrarea/ieşirea la nivel jos;
3) funcţii care realizează intrarea/ieşirea la consoală (ecranul împreună cu
tastatura).
Vor fi caracterizate detaliat funcţiile din prima categorie, fiindcă informaţia
despre ele ne va permite o trecere simplă şi la funcţii din alte categorii, existând o
asemănare în modul lor de utilizare.
Un flux de date este o secvenţă de octeţi fără o oarecare structură internă,
asupra căreia pot fi efectuate o serie de operaţii admisibile. Un flux de date este
asociat cu un fişier sau cu un dispozitiv periferic. Din existenţa acestei legături
rezultă că operaţiile caracteristice unui flux de date sunt şi operaţii caracteristice
unui fişier sau unui dispozitiv periferic. Operaţiile admisibile unui flux de date
sunt:
a) deschiderea fluxului;
b) închiderea unui sau a tuturor fluxurilor;
c) citirea şi scrierea unui caracter;
d) citirea şi scrierea unui şir de caractere;
e) citirea şi scrierea formatată a datelor;
f) citirea şi scrierea neformatată a datelor;
g) fixarea poziţiei curente în cadrul fluxului;
h) operaţii cu buferul fluxului de date.
Toate operaţiile sunt realizate sub formă de funcţii. Pentru a putea utiliza aceste
funcţii, este necesară ataşarea fişierului antet stdio.h, unde sunt descrise
prototipurile funcţiilor date şi o serie de construcţii necesare pentru lucru cu
fişierele.
Când are loc citirea/scrierea informaţiei din/în fluxul de date (fişier sau alt
dispozitiv fizic), atunci are loc deplasarea automată a poziţiei curente în flux.
Poziţie curentă este poziţia de unde se va citi sau unde se va scrie informaţia.
Operaţia de deschidere a fluxului de date este prima operaţie care pregăteşte
fluxul pentru operaţiile ce urmează. Pentru a deschide un flux de date, este
necesară o variabilă adresă de tip FILE, care este o structură destinată memorării
informaţiei ajutătoare despre fişier. În caz general, această variabilă va avea
următoarea descriere
FILE *var_flux;
unde var_flux este numele variabilei care va fi asociată cu fluxul de date. De
exemplu:
FILE *cf;

La deschiderea fluxului de date se face asocierea dintre variabila de tip FILE


şi fişierul cu care vom lucra. Pentru această operaţie, este utilizată funcţia
fopen(), având următorul prototip:
FILE *fopen(const char *nume_fizic,
const char *mod);
unde variabila nume_fizic reprezintă adresa numelui fizic al fişierului, iar
variabila mod reprezintă adresa modului de deschidere, care descrie pentru ce tip
de operaţii este deschis fişierul, citire, scriere sau citire-scriere. Dacă fişierul este
deschis cu succes, funcţia returnează un pointer de tip FILE, în caz de eroare
valoarea returnată este o adresă nulă exprimată prin constanta NULL, descrisă în
fişierul antet stdio.h. Pentru a fi siguri că operaţiile care urmează după
deschidere vor fi efectuate cu succes, este necesar a testa succesul operaţiei de
deschidere prin compararea la egalitate a valorii variabilei fluxului de date cu
valoarea NULL. Urmează un exemplu schematic de deschidere şi testare a
succesului operaţiei de deschidere. Fişierele din exemplul de mai jos sunt deschise
unul pentru citire şi altul pentru scriere.
FILE *cit, *sc;
char numeFisier[]=”foto.jpg”, scriere[]=”w”;
.
.
cit = fopen (”f1.txt”, ”r”);
if(cit==NULL)
printf(”Eroare de deschidere pentru citire!!!”)
.
.
sc = fopen (numeFisier, scriere);
if(sc==NULL)
printf(”Eroare de deschidere pentru scriere!!!”)
.
.
Pentru descrierea modului de deschidere a fişierelor, sunt utilizate o serie de
simboluri, fiecare având o nuanţă de înţeles bine stabilită.
- simbolul r înseamnă că fişierul este deschis pentru operaţii de citire;
- simbolul w înseamnă că fişierul este deschis pentru operaţii de scriere;
- simbolul a înseamnă că fişierul este deschis pentru operaţii de adăugare la
sfârşitul fişierului;
- simbolul + înseamnă că fişierul este deschis atât pentru operaţii de citire, cât şi
pentru operaţii de scriere;
- simbolul t înseamnă că fişierul deschis va fi prelucrat ca un fişier textual;
- simbolul b înseamnă că fişierul deschis va fi prelucrat ca un fişier binar.
Dintre aceste simboluri primele trei sunt definitorii şi participă în orice
descriptor de deschidere. Aceste simboluri definesc ideea principală a operaţiei de
deschidere. De exemplu, simbolul ‘r’ din parametrul care descrie modul de
deschidere arată că operaţia principală este cea de citire şi operaţia de deschidere se
conformează întru totul operaţiei de citire. Deci următoarele moduri de deschidere
”r” ”r+” ”r+b”

se conformează operaţiei de citire.


Dacă modul de deschidere conţine simbolul ‘r’, atunci fişierul neapărat trebuie
să existe, în caz contrar, este generată eroare. Dacă este utilizat simbolul ‘w’ şi
dacă fişierul nu există el este creat, iar dacă există datele din el se trunchiază, adică
se şterg. La deschiderea fişierului cu oarecare dintre aceste simboluri poziţia
curentă este fixată în 0, adică la începutul fluxului. Dacă la deschidere este utilizat
simbolul ‘a’, atunci dacă fişierul nu există el este creat, iar dacă există datele din el
nu se şterg. La deschiderea fişierului cu acest simbol, poziţia curentă este fixată la
sfârşitul fluxului. Dacă la unul dintre aceste simboluri este ataşat simbolul ‘+’,
atunci fişierul va fi deschis atât pentru citire, cât şi pentru scriere, dar va păstra
particularităţile impuse de simbolurile ‘r’, ‘w’ şi ‘a’, descrise anterior. În
exemplul ce urmează
FILE *cit_sc;
cit_sc=fopen(”lab1.c”, ”a+”);
fişierul lab1.c va fi deschis atât pentru citire, cât şi pentru scriere; citirea va
putea fi efectuată din orice loc al fişierului, iar scrierea va fi posibilă doar la
sfârşitul fişierului.
Mulţimea tuturor fişierelor se divide în două categorii: fişiere textuale şi fişiere
binare.
Există o serie de particularităţi în ceea ce priveşte fişierele textuale. Unele
fragmente informaţionale pot să suporte anumite transformări în procesul citirii din
fişier sau a scrierii în fişier. Şi anume:
a) simbolul ‘\n’ (trecere în rând nou) se transformă la scriere în fişier în
perechea de simboluri ”\n\r”;
b) perechea de simboluri ”\n\r” se transformă la citire din fişier în simbolul
’\n’;
c) simbolul generat de combinaţia de taste Ctrl+z (’\32’) va insemna ieşire
din fişier.
Fiindcă există astfel de particularităţi, sunt două simboluri utilizate pentru a
face deosebire între fişiere textuale şi binare. Simbolul ‘t’ este utilizat pentru a
indica că este deschis un fişier textual. De exemplu, următorul mod de deschidere
”rt+”
arată că fişierul va fi deschis pentru citire şi scriere în regim textual. Simbolul ‘b’
va indica că fişierul este deschis în regim binar. De exemplu, un astfel de mod
”wb”
arată că fişierul va fi deschis pentru scriere în regim binar.
În afară de fluxurile pe care le generează programatorul, mai sunt 5 fluxuri
predefinite. Pentru ele nu trebuie aplicate operaţiile de deschidere sau închidere. În
cele ce urmează, sunt prezentate aceste fluxuri predefinite:
stdin – fluxul predefinit de intrare (de regulă, este fixat pe tastatură);
stdout – fluxul de ieşire (de regulă, este fixat pe ecran);
stderr – fluxul predefinit al erorilor (este fixat pe ecran);
stdaux – fluxul predefinit auxiliar (este fixat pe un port);
stdprn – fluxul predefinit al imprimantei (de regulă, este fixat pe imprimantă).
Pe lângă operaţia de deschidere, mai este importantă şi operaţia de închidere a
fluxurilor. Funcţia care permite închiderea unui flux are următorul prototip:
int fclose(FILE *var_fl);
unde parametrul var_fl este variabila asociată cu fluxul de date. Valoarea
returnată de această funcţie este 0, dacă fluxul este închis cu succes, sau este -1,
valoare exprimată prin constanta EOF, dacă este depistată vreo eroare. De exemplu:
fclose(cit);
va închide fluxul asociat cu variabila cit.
Pentru a închide toate fluxurile de date deschise, este utilizată următoarea
funcţie:
int fcloseall ();
care returnează ca valoare numărul fluxurilor de date închise, dacă este executată
cu succes sau valoarea EOF, în caz contrar, adică la întâlnirea unor erori. Fluxurile
stdin, stdout, stdaux, stderr, stdprn nu pot fi închise.
La închiderea unui flux de date, are loc golirea buferului care îi corespunde.
Bufer (memorie tampon) este un fragment de memorie care ocupă o poziţie
intermediară între operaţiile de citire/scriere şi fluxul de date, adică toate operaţiile
de citire/scriere în fluxul de date au loc prin intermediul buferului. Astfel la citire
din fişier buferul este umplut automat cu date, indiferent de mărimea porţiei de
date citite din fişier. Tot aşa, dacă sunt efectuate operaţii de scriere în fişier, toate
datele vor fi plasate în bufer până la umplerea lui. Când buferul se va umple el va
fi golit, înscriindu-se automat datele din bufer în fişier. Operaţia de golire a
buferului poate fi atât automată, cât şi forţată. Buferele legate cu fluxurile de date
se golesc automat în următoarele situaţii:
a) la închiderea fluxului;
b) la închiderea programului;
c) atunci când sunt pline.
Însă operaţia de golire a buferului poate fi şi forţată, utilizând funcţii proiectate
pentru astfel de acţiuni. Pentru golirea forţată a buferului unui flux, este utilizată
următoarea funcţie:
int fflush(FILE *var_f);
care goleşte buferul fluxului asociat cu variabila var_f. Funcţia returnează
valoarea 0, dacă golirea buferului are loc cu succes, sau returnează valoarea EOF,
dacă operaţia eşuează din careva motive. Pentru golirea buferelor tuturor
fluxurilor, este proiectată următoarea funcţie:
int flushall();
Această funcţie goleşte buferele fluxurilor atât de intrare, cât şi de ieşire,
returnând numărul de fluxuri deschise. Operaţiile de golire nu închid fluxurile de
date.
Este de menţionat faptul că buferul fluxului de date este alocat automat la
deschiderea fluxului de date. Acest bufer de sistem nu este accesibil direct, ci doar
prin operaţii fie de citire sau de scriere. Totodată, este fixată şi mărimea unui bufer
de sistem, ea fiind egală cu 512 octeţi. Uneori însă este necesar un control mai mare
asupra buferului fluxului şi în asemenea situaţii sunt permise operaţii de schimbare a
buferelor. O astfel de operaţie este oferită de următoarea funcţie:
void setbuf(FILE *var_fl, char *buf_nou);
unde buf_nou este adresa fragmentului de memorie care va juca rolul de bufer al
fluxului de date identificat de variabila var_fl. Această funcţie poate schimba
buferul, dar nu poate acţiona asupra dimensiunii buferului, care va fi tot de 512
octeţi. Iată un mic exemplu, utilizând această funcţie.
char domeniu[1000];
FILE *fc;
fc = fopen(”nume.txt”, ”r”);
setbuf(fc, domeniu); // buferul nou are marimea
// de 512 octeti
*(domeniu + 9) = ’A’;

Un control mai bun asupra buferului este oferit de funcţia


int setvbuf(FILE *var_fl, char *buf_nou,
int tip_de_acces, size_t dimensiune);
unde buf_nou este adresa fragmentului de memorie ce urmează să fie bufer al
fluxului de date asociat cu variabila var_fl, parametrul tip_de_acces descrie
tipul buferului, iar următorul parametru exprimă dimensiunea buferului.
Parametrul ce se referă la tipul buferului poate lua trei valori, exprimate respectiv
prin trei constante definite în fişierul antet stdio.h, sensul cărora este descris în
următorul tabel.
Tip de acces Semnificaţia tipului
_IOFBF Fluxul de date este complet buferizat,
ceea ce înseamnă că operaţiile de
citire au loc prin bufer după schema
obişnuită, iar în procesul operaţiilor
de scriere buferul se goleşte la
umplerea completă.

_IOLBF Fluxul de date este liniar buferizat,


ceea ce înseamnă că operaţiile de
citire au loc prin bufer după schema
obişnuită, iar în procesul operaţiilor
de scriere, buferul se goleşte la
întâlnirea simbolului trecere la linie
nouă.
_IONBF Fluxul de date este nebuferizat, ceea
ce înseamnă că atât operaţiile de
citire, cât şi cele de scriere au loc
direct ocolind buferul.

Parametrul buf_nou poate lua ca valoare şi valoarea NULL. În acest caz, are
loc mărirea buferului de sistem cu valoarea indicată de parametrul dimensiune.
Exemplele ce urmează descriu diferite laturi ale funcţiei setvbuf():
a) mărirea buferului de sistem;
setvbuf(fc, NULL, _IOFBF, 100); //cu 100 de octeti
//mai mare
b) definirea unui bufer nou, având mărimea 5000 de octeţi şi tipul
_IOLBF;
char domeniu[5000];
. . .
setvbuf(fc, domeniu, _IOLBF, 5000);
c) definirea unui bufer nou, având mărimea 1000 de octeţi şi tipul
_IONBF, ceea ce înseamnă că de fapt buferul nu va fi utilizat în procesul
operaţiilor de citire şi scriere.
char bufer[1000];
. . .
setvbuf(fc, bufer, _IONBF, 1000); // flux
// nebuferizat

O altă categorie de funcţii este alcătuită de funcţiile ce controlează poziţia curentă în


cadrul fluxului de date. Poziţia curentă este exprimată printr-o valoare cuprinsă între 0
pentru începutul fişierului şi lungimea fişierului minus 1 pentru sfârşitul fişierului. A
fost deja subliniat anterior că orice operaţie de citire sau scriere schimbă poziţia curentă
în flux, cu un număr de poziţii egal cu numărul de octeţi din care constă fragmentul de
date citit sau scris în fişier. Ca primă posibilitate oferită de această categorie de funcţii
este funcţia ce permite determinarea poziţiei curente în flux. Ea are următorul prototip
long ftell(FILE *var_fl);
unde var_fl este variabila asociată cu fluxul de date. Funcţia returnează poziţia
curentă în flux la o execuţie cu succes a ei, sau returnează valoarea -1, dacă
survine vreo eroare. Pe lângă această posibilitate, mai este necesară, în unele
cazuri, schimbarea poziţiei curente în flux. Una dintre funcţiile cu o aşa destinaţie
este următoarea:
int fseek(FILE *var_fl, long deplasament,
int originea);
unde deplasament indică cu cât va fi deplasată poziţia curentă a fluxului asociat
cu variabila var_fl, iar parametrul originea indică faţă de ce poziţie va fi
efectuată deplasarea. Parametrul originea poate lua trei valori exprimate prin
trei constante simbolice. Următorul tabel descrie semantica legată de fiecare
valoare:
Valoare Constantă Semantica
simbolică parametrului
0 SEEK_SET Deplasarea se
produce faţă de
începutul fluxului
(fişierului)
1 SEEK_CUR Deplasarea se
produce faţă de
poziţia curentă a
fluxului
(fişierului)
2 SEEK_END Deplasarea se
produce faţă de
sfârşitul fluxului
(fişierului)
Valoarea returnată de funcţie este egală cu 0, dacă funcţia are o execuţie cu
succes sau este diferită de 0 dacă survine vreo eroare.
Parametrul deplasament poate lua valori atât ≥0, cât şi ≤0, însă trebuie de
ţinut cont de faptul că dacă noua poziţie curentă devine o valoare mai mică decât 0,
atunci operaţiile de citire şi scriere nu vor mai putea fi efectuate. Dacă noua poziţie
curentă devine mai mare decât lungimea fişierului, atunci operaţiile de scriere sunt
posibile, poziţiile de la sfârşitul fişierului până la poziţia curentă fiind completate
cu 0. Iată câteva exemple, utilizând această funcţie:
a) fixarea poziţiei curente egală cu 10;
fseek(fc, 10, SEEK_SET);
b) fixarea poziţiei curente egală cu -20 (în ceea ce urmează, vor apărea
probleme de scriere şi citire);
fseek(fc, -20, SEEK_SET);
c) poziţia curentă va depăşi cu 25 valoarea lungimii fişierului.
fseek(fc, 25, SEEK_END);

Următoarele funcţii foarte asemănătoare ca prototip permit respectiv


determinarea şi fixarea poziţiei curente întrun flux de date.
int fgetpos(FILE *var_fl, fpos_t *pozitia);
int fsetpos(FILE *var_fl, fpos_t *pozitia);

În ambele funcţii este utilizat tipul fpos_t destinat descrierii variabilelor cu


valori de tip poziţie într-un flux de date. În cazul primei funcţii, parametrul
pozitia este adresa variabilei în care se va memora poziţia curentă, iar în cazul
celei de a doua funcţii este adresa variabilei de unde se va lua valoarea poziţiei
curente ce urmează a fi fixată. Ambele funcţii returnează valoarea 0 în cazul unei
execuţii cu succes şi o valoare diferită de 0 în caz de eroare.
O funcţie care, de asemenea, controlează poziţia curentă ar putea fi şi
următoarea:
void rewind(FILE *var_fl);
care reîntoarce poziţia curentă la începutul fluxului. Această funcţie are o
particularitate, care o deosebeşte de funcţia fseek(). Dacă se întâmplă vreo eroare,
atunci funcţia fseek() nu mai poate efectua cu succes operaţia de schimbare a
poziţiei curente, pe când funcţia rewind() şterge indicatorul erorii şi fixează poziţia
curentă la începutul fluxului.
O acţiune importantă atunci când se lucrează cu fluxurile de date este testarea
în flux a sfârşitului de fişier. Această operaţie este posibilă în baza următoarei
funcţii:
int feof(FILE *var_fl);
care returnează valoarea 0, dacă nu a fost atins sfârşitul de fişier, sau o valoare
diferită de 0, în caz contrar.
Operaţiile de intrare/ieşire reprezintă nişte acţiuni foarte importante atunci când
se lucrează cu dispozitive periferice sau fişiere. Există o mulţime bogată de funcţii
ce realizează operaţiile de citire/scriere în flux. Următorul tabel oferă o clasificare
compactă a funcţiilor date:
Operaţii de intrare/ieşire (funcţii)
Forma Citire Scriere
datelor Din Din Din În În flux În şir
prelucrate stdin flux şir de stdout general de
general carac. carac.
Secvenţă fread fwrite
de octeţi
Caracter getchar getc putchar putc
fgetchar fgetc fputchar fputc
Intreg getw putw
Şir gets fgets puts fputs
Date scanf fscanf sscanf printf fprintf sprintf
formatate

Caracterizarea funcţiilor va începe cu funcţiile ce permit prelucrarea unor date


neformatate, ceea ce corespunde unor secvenţe de octeţi. Funcţia cu următorul
prototip
size_t fread(void *domeniu_cit, size_t dim_elem,
size_t nr_elem, FILE *var_fl);
permite citirea din fluxul de date asociat cu parametrul var_fl a nr_elem de
dimensiunea dim_elem fiecare în locaţia de memorie ce ţine de parametrul
domeniu_cit de tip pointer. Funcţia returnează numărul de elemente mari citite
de facto din flux. Dacă este depistat sfârşit de fişier sau are loc vreo eroare, atunci
valoarea returnată va fi posibil mai mică decât valoarea parametrului nr_elem,
putând fi egală şi cu 0. Iată un fragment de program în care se testează dacă prima
citire este cu succes sau a generat anumite probleme
. . .
char dom_c[5000];
int n;
FILE *fc;
fc = fopen(”imagine.bmp”, ”rb”);
. . .
n = fread(dom_c, 4, 1000, fc); // citire 4000
// octeti
if(n<1000)
{
printf(”eroare sau sfarsit de fisier”);
if(feof(fc))
printf (”sfirsit de fisier”);
else
printf (”eroare”);
}

Pentru a efectua operaţii de scriere în flux, este utilizată o funcţie cu următorul


prototip asemănător cu al funcţiei precedente
size_t fwrite(void *domeniu_scr, size_t dim_elem,
size_t nr_elem, FILE *var_fl);
unde domeniu_scr identifică locaţia de memorie din care se vor scrie în fluxul
asociat cu parametrul var_fl nr_elem de dimensiunea dim_elem fiecare.
Funcţia returnează numărul de elemente mari scrise de facto în flux. Dacă în
procesul scrierii are loc vreo eroare, atunci valoarea returnată va fi mai mică decât
valoarea parametrului nr_elem, putând fi egală şi cu 0.

Citirea unui caracter este posibilă atât din fluxul predefinit stdin, cât şi din
fluxuri asociate cu fişiere şi dispozitive periferice. Astfel, pentru a citi un caracter
din fluxul stdin, pot fi utilizate două construcţii asemănătoare ca sens,
macroinstrucţiunea
int getchar();
şi funcţia
int fgetchar();
care returnează caracterul citit în caz de succes sau valoarea EOF în caz de eroare
sau sfârşit de fişier. Iată un exemplu de citire a unui caracter de la tastatură
char cifra;
cifra=fgetchar();

O situaţie similară este şi pentru cazul fluxurilor de date generale: există o


macroinstrucţiune
int getc(FILE *var_fl);
şi o funcţie
int fgetc(FILE *var_fl);
orientate la citirea unui caracter din flux. Ele returnează caracterul citit în caz de
succes sau valoarea EOF în caz de eroare sau sfârşit de fişier. Iată un fragment,
conţinând operaţia de citire a unui caracter dintr-un flux de date
char litera;
FILE *cit;
. . .
cit = fopen(”litere.txt”, ”r”);
. . .
litera = fgetc(cit);

În calitate de flux poate fi utilizat şi fluxul predefinit stdin, obţinând astfel


posibilitatea citirii unui caracter de la tastatură.
char ts;
ts = getc(stdin); //citire de la tastatură

Considerând situaţia referitoare la posibilităţile de scriere a unui caracter, vom


avea câte o macroinstrucţiune şi câte o funcţie pentru scriere, respectiv, în fluxul
standard stdout (adeseori afişare la ecran)
int putchar(int car);
int fpuchar(int car); //afisarea unui caracter
şi în fluxul general de date
int putc(int car, FILE *var_fl);
int fputc(int car, FILE *var_fl); // scrierea unui
// caracter

Fiecare dintre ele returnează caracterul scris în caz de succes sau EOF în caz de
eroare.
fc = fopen (”caract.txt”, ”a”);
fputc (c, fc);
Dacă sunt necesare operaţii de citire sau scriere efectuate asupra valorilor de tip
int, pot fi utilizate două funcţii proiectate pentru un astfel de context. Pentru
citirea unei valori de tip int, va fi folosită următoarea funcţie:
int getw(FILE *var_fl);
iar pentru scriere va fi aplicată funcţia:
int putw(int num, FILE *var_fl);
Una dintre cerinţe este că atunci, când sunt utilizate getw() şi putw(), fişierul
trebuie deschis în regim binar. Ambele funcţii returnează valori de tip int: în caz de
succes, valoarea citită din flux sau valoarea înscrisă în flux, iar la depistare de erori
sau şi sfârşit de fişier în cazul primei funcţii valoarea EOF.
Pentru citirea unui şir de caractere din fluxul standard stdin, este utilizată
funcţia cu următorul prototip:
char *gets(char *sir);

unde parametrul sir reprezintă adresa domeniului de memorie în care va fi


plasată informaţia citită. În calitate de informaţie sunt acceptate toate caracterele
generate de la tastatură, criteriul de sfârşit al mulţimii de caractere fiind depistarea
caracterului linie nouă (’\n’) obţinut la acţionarea tastei ’Enter’. Caracterul
linie nouă este înlocuit cu caracterul nul ’\0’, care corespunde sfârşitului de şir.
Funcţia returnează adresa de început al şirului din memorie, dacă totul a decurs
fară erori şi valoarea NULL în caz de eroare. Iată un exemplu de aplicare a acestei
funcţii, citind de la tastatură informaţia despre o persoană:
char numePrenume[50];
gets(numePrenume);

O funcţie asemănătoare, dar destinată pentru citirea din fluxuri de date


generale, este următoarea:
char *fgets(char *sir, int num_max, FILE *var_fl);
care realizează operaţia de citire din fluxul de date var_fl în fragmentul de
memorie cu adresa sir. Criteriul de terminare a operaţiei de citire este unul dintre
următoarele posibile:
1) depistarea caracterului linie nouă (’\n’);
2) citirea din flux a num_max – 1 caractere.
Dacă în procesul citirii este depistat caracterul linie nouă, el este citit, de
asemenea, în memorie. În ambele cazuri de terminare a operaţiei de citire, la
sfârşitul şirului de caractere mai este adăugat caracterul nul ’\0’, pentru o
terminare corectă a şirului. Funcţia returnează adresa de început al şirului din
memorie la executare fară erori şi valoarea NULL în caz de eroare. Citirea a nu mai
mult de 20 caractere dintr-o linie a fişierului “lab1.c” este exemplificată mai jos:
char linie[20];
FILE *cit;
cit=fopen(”lab1.c”,”rt”);
. . .
fgets(linie, sizeof(linie), cit);

Scrierea în fluxul standard stdout, ceea ce adeseori înseamnă afişarea pe


ecran, şi scrierea într-un flux de date general pot fi efectuate cu ajutorul funcţiei
int puts(char *sir);
şi, respectiv,
int fputs(char *sir, FILE *var_fl);
unde parametrul sir este adresa informaţiei scrise în fluxul stdout sau în fluxul
general asociat cu variabila var_fl. Funcţiile returnează o valoare nenegativă la o
executare corectă, sau valoarea EOF în caz de erori. Este de remarcat faptul că
aceste funcţii se deosebesc puţin prin acţiune. puts() scrie în flux şi caracterul
linie nouă (’\n’), pe când fputs() nu face acest lucru şi dacă acest fapt este
necesar, atunci scrierea caracterului linie nouă în flux se face separat. Iată un mic
exemplu în ilustrarea acestei idei:
char constanta[]=”#define Z 10”;
FILE *sc;
sc=fopen(”lab1.c”,”r+t”);
. . .
fputs(constanta, sc);
fputs(”\n”, sc);
Citirea formatată poate fi făcută din fluxul standard stdin, dintr-un flux
general şi dintr-un şir de caractere. Funcţiile care permit această operaţie sunt
respectiv
int scanf(char *sir_form, lista_adr_var);
int fscanf(FILE *var_fl, char *sir_form,
lista_adr_var);
int sscanf(char *sir_sr, char *sir_form,
lista_adr_var);

Modul de utilizare a funcţiei scanf() a fost deja descris amănunţit. Celelalte


două pot fi utilizate într-un mod similar cu funcţia scanf(), atât doar că au alte
surse de citire a datelor: fscanf() un flux de date, sscanf() un şir de
caractere. Toate trei funcţii returnează o valoarea care înseamnă numărul de
câmpuri prelucrate cu succes, atunci când are loc o executare măcar parţial reuşită
(prelucrarea cu succes a unor câmpuri). Executarea cu erori a oricărei dintre
funcţiile date duce la returnarea valorii EOF. Iată un exemplu de utilizare a funcţiei
de citire dintr-un şir de caractere, din care se vede asemănarea izbitoare cu funcţia
scanf().
char sir[] = ”1 790”;
int i, j;
sscanf(sir, ”%i %i”, &i, &j);
printf(“i=%i, j=%i\n”, i, j); // va afisa i=1,
// j=790

Scrierea formatată are ca model funcţia printf() de scriere în fluxul


standard stdout, existând şi funcţii pentru scriere într-un flux general şi într-un
şir de caractere. Iată prototipurile acestor funcţii:
int printf(char *sir_form, lista_var);
int fprintf(FILE *var_fl, char *sir_form,
lista_var);
int sprintf(char *sir_dest, char *sir_form,
lista_var);
Pentru a putea aplica aceste funcţii, trebuie recapitulat modul de utilizare a funcţiei
printf(), existând între ele o asemănare foarte mare la acest capitol. Atunci când
executarea acestor funcţii are loc cu succes, ele returnează o valoare care înseamnă
numărul de caractere scrise în flux. La o executare cu erori, funcţiile date returnează
valoarea EOF. Iată un exemplu de utilizare a funcţiei de scriere într-un şir de caractere.
char sir[200];
int i=234;
float f=-31.2;
sprintf(sir, ”%4i %5.2f”, i, f);
printf(”%s\n”, sir); //va afisa: 234 -31.20

În exemplul ce urmează vor fi utilizate o serie dintre funcţiile cercetate


anterior.
Exemplu. Sa se alcătuiască un program care afişează nu mai mult de ultimele
N caractere din fiecare linie a unui fişier (dacă linia este mai scurtă de N
caractere, este afişată întreaga linie).
#include<stdio.h>
#include<conio.h>
#include<string.h>

#define DIM 10
void Afisare(FILE *fc, int N)
{
char sir[DIM];
int lungimeLinie=0, ecran=0;
while (1)
{
fgets(sir, sizeof(sir), fc);
if(feof(fc))
break;
if(ecran==1)
printf("%s", sir);
lungimeLinie+=strlen(sir);
if(sir[strlen(sir)-1] != '\n')
continue;
if(ecran==0)
{
if(lungimeLinie>N+1)
lungimeLinie=N+1;
fseek(fc, -(lungimeLinie+1), SEEK_CUR);
}
ecran=(ecran+1)%2;
lungimeLinie=0;
}
}
//------------
void main(int argu, char *argc [])
{
FILE *fc;
int N=20;
fc = fopen(argc[1], "r");
if (fc != NULL)
{
Afisare(fc, N);
fclose (fc);
}
else
printf ("Eroare de deschidere (la citire).");
getch ();
}

S-ar putea să vă placă și