Intrucit limbajul C nu a fost dezvoltat pentru un sistem particular
de operare si datorita faptului ca s-a dorit realizarea unei portabilitati cit
mai mari, atit a unui compilator C, cit si a programelor scrise
in acest limbaj, el nu poseda facilitati de intrare / iesire. n2s8sg
Exista totusi un sistem de intrare / iesire (sistemul I/O) constituit dintr-un
numar de subprograme care realizeaza functii de intrare / iesire pentru programe
scrise in C, dar care nu fac parte din limbajul C. Aceste subprograme
se gasesc in biblioteca C.
Scopul acestui capitol este de a descrie cele mai utilizate subprograme de intrare
/ iesire si interfata lor cu programele scrise in limbajul C.
11.1. Intrari si iesiri standard; fisiere
Sistemul I/O ofera utilizatorului trei "fisiere" standard de lucru.
Cuvintul fisier a fost pus intre ghilimele, deoarece limbajul nu
defineste acest tip de data si pentru ca fisierele reprezinta mai degraba niste
fluxuri de intrare / iesire standard puse la dispozitia utilizatorului. Aceste
fisiere sint:
-; fisierul standard de intrare (stdin);
-; fisierul standard de iesire (stdout);
-; fisierul standard de afisare a mesajelor (stderr).
Toate aceste trei fisiere sint secventiale si in momentul executiei
unui program C sint implicit definite si deschise. stdin si stdout sint asociate in mod normal terminalului de la care
a fost lansat programul in executie. Sistemul I/O permite redirectarea
acestor fisiere pe alte periferice sau inchiderea lor dupa lansarea programului.
Redirectarea fisierului stdin se specifica prin constructia:
<specificator-fisier
in linia de comanda prin care a fost lansat programul.
Redirectarea fisierului stdout se specifica prin constructia:
>specificator-fisier
in linia de comanda prin care a fost lansat programul.
Redirectarea fisierului stdout pe un alt periferic, in scopul efectuarii
unei operatii de adaugare (append) se specifica prin constructia :
>>specificator-fisier stderr este intotdeauna asociat terminalului de la care a fost lansat
programul in executie si nu poate fi redirectat.
Pentru a se putea face o referire la aceste fisiere orice program C trebuie
sa contina fisierul stdio.h, care se include printr-o linie de forma:
#include <stdio.h> daca acest fisier se afla in biblioteca standard.
Pentru claritatea si lizibilitatea programelor scrise in C, cit
si pentru crearea unei imagini sugestive asupra lucrului cu fisiere, in
fisierul de definitii standard stdio.h s-a definit un nou nume de tip de data
si anume FILE care este o structura. Pentru a referi un fisier, este necesara
o declaratie de forma:
FILE *fp; unde fp va fi numele de data cu care se va referi fisierul in orice operatie
de intrare / iesire asociata. Iata citeva informatii pastrate de structura
FILE:
-; un identificator de fisier pe care sistemul de operare il asociaza
fluxului pe durata prelucrarii; acesta poate fi aflat cu ajutorul functiei fileno;
-; adresele zonelor tampon asociate; pozitia curenta in aceste zone;
-; indicatorii de sfirsit de fisier si de eroare;
-; alte informatii.
11.2. Accesul la fisiere; deschidere si inchidere
Nume fopen - deschide un flux
Declaratie
FILE *fopen(const char *path, const char *mode);
Descriere
Functia fopen deschide fisierul al carui nume este un sir indicat de path
si ii asociaza un flux.
Argumentul mode indica un sir care incepe cu una din secventele urmatoare: r deschide un fisier pentru citire; r+ deschide pentru citire si scriere;
w trunchiaza fisierul la lungime zero sau creeaza un fisier pentru scriere;
w+ deschide pentru adaugare la sfirsit, in citire si scriere; fisierul
este creat daca nu exista, altfel este trunchiat; a deschide pentru adaugare la sfirsit, in scriere; fisierul este
creat daca nu exista; a+ deschide pentru adaugare la sfirsit, in citire si scriere; fisierul
este creat daca nu exista;
Dupa deschidere, in primele patru cazuri indicatorul pozitiei in
flux este la inceputul fisierului, in ultimele doua la sfirsitul
acestuia.
Sirul mode include de asemenea litera b (deschide un fisier binar) sau t (deschide
un fisier text) fie pe ultima pozitie fie pe cea din mijloc.
Operatiile de citire si scriere pot alterna in cazul fluxurilor read /
write in orice ordine. Sa retinem ca standardul ANSI C cere sa existe
o functie de pozitionare intre o operatie de intrare si una de iesire,
sau intre o operatie de iesire si una de intrare, cu exceptia cazului
cind o operatie de citire detecteaza sfirsitul de fisier. Aceasta
operatie poate fi inefectiva - cum ar fi fseek(flux, 0L, SEEK_CUR) apelata cu
scop de sincronizare.
Valori returnate
In caz de succes se returneaza un pointer de tip FILE. In caz de
eroare se returneaza NULL si variabila globala errno indica codul erorii.
Nume fclose - inchide un flux
Declaratie int fclose( FILE *flux);
Descriere
Functia fclose inchide fisierul asociat fluxului flux. Daca flux a fost
deschis pentru iesire, orice date aflate in zone tampon sint scrise
in fisier in prealabil cu un apel fflush.
Valori returnate
In caz de succes se returneaza 0. In caz de eroare se returneaza
EOF si variabila globala errno indica codul erorii.
Nume tmpfile - creeaza un fisier temporar
Declaratie
FILE *tmpfile();
Descriere
Functia tmpfile genereaza un nume unic de fisier temporar. Acesta este deschis
in mod binar pentru scriere / citire ("wb+"). Fisierul va fi
sters automat la inchidere sau la terminarea programului.
Valoare returnata
Functia returneaza un descriptor de flux in caz de succes, sau NULL daca
nu poate fi generat un nume unic de fisier sau daca fisierul nu poate fi deschis.
In caz de eroare variabila globala errno indica codul erorii.
Nume fflush - forteaza scrierea in flux
Declaratie int fflush(FILE *flux);
Descriere
Functia fflush forteaza o scriere a tuturor datelor aflate in zone tampon
ale fluxului flux. Fluxul ramine deschis.
Valori returnate
In caz de succes se returneaza 0. In caz de eroare se returneaza
EOF si variabila globala errno indica codul erorii.
Nume fseek, ftell, rewind - repozitioneaza un flux
Declaratie int fseek(FILE *flux, long offset, int reper); long ftell(FILE *flux); void rewind(FILE *flux);
Descriere
Functia fseek seteaza indicatorul de pozitie pentru fisierul asociat fluxului
flux. Noua pozitie, data in octeti, se obtine adunind offset octeti
la pozitia specificata de reper. Daca reper este SEEK_SET, SEEK_CUR, sau SEEK_END,
offset este relativ la inceputul fisierului, pozitia curenta a indicatorului,
respectiv sfirsitul fisierului. Functia fseek sterge indicatorul de sfirsit
de fisier.
Functia ftell obtine valoarea curenta a indicatorului de pozitie pentru fisierul
asociat fluxului flux.
Functia rewind pozitioneaza indicatorul de pozitie pentru fisierul asociat fluxului
flux la inceputul fisierului. Este echivalenta cu:
(void)fseek(flux, 0L, SEEK_SET) cu completarea ca functia rewind sterge si indicatorul de eroare al fluxului.
Valori returnate
Functia rewind nu returneaza nici o valoare. In caz de succes, fseek returneaza
0, si ftell returneaza offset-ul curent. In caz de eroare se returneaza
EOF si variabila globala errno indica codul erorii.
11.3. Citire si scriere fara format
Nume fgets - citeste un sir de caractere dintr-un flux text
Declaratie char *fgets(char *s, int size, FILE *flux);
Descriere
Functia fgets cel mult size-1 caractere din flux si le memoreaza in zona
indicata de s. Citirea se opreste la detectarea sfirsitului de fisier
sau new-line. Daca se citeste caracterul new-line acesta este memorat in
s. Dupa ultimul caracter se memoreaza null.
Apeluri ale acestei functii pot fi combinate cu orice apeluri ale altor functii
de intrare din biblioteca (fscanf, de exemplu) pentru un acelasi flux de intrare.
Valori returnate
Functia returneaza adresa s in caz de succes, sau NULL in caz de
eroare sau la intilnirea sfirsitului de fisier daca nu s-a
citit nici un caracter.
Nume fputs - scrie un sir de caractere intr-un flux text
Declaratie int fputs(const char *s, FILE *flux);
Descriere
Functia fputs scrie sirul s in flux fara caracterul terminator null.
Apeluri ale acestei functii pot fi combinate cu orice apeluri ale altor functii
de iesire din biblioteca (fprintf, de exemplu) pentru un acelasi flux de iesire.
Valori returnate
Functia returneaza o valoare non-negativa in caz de succes, sau EOF in
caz de eroare.
Nume fread, fwrite - intrari / iesiri pentru fluxuri binare
Declaratie unsigned fread(void *ptr, unsigned size, unsigned nel, FILE *flux); unsigned fwrite(const void *ptr, unsigned size, unsigned nel, FILE *flux);
Descriere
Functia fread citeste nel elemente, fiecare avind marimea size octeti,
din fluxul indicat de flux, si le memoreaza in zona indicata de ptr.
Functia fwrite scrie nel elemente, fiecare avind marimea size octeti,
din fluxul indicat de flux, pe care le ia din zona indicata de ptr.
Valori returnate
Functiile returneaza numarul de elemente citite sau scrise cu succes (si nu
numarul de caractere). Daca apare o eroare sau se intilneste sfirsitul
de fisier, valoarea returnata este mai mica decit nel (posibil zero).
11.4. Citire cu format
Nume scanf, fscanf, sscanf - citire cu format
Declaratie int scanf(const char *format, ...); int fscanf(FILE *flux, const char *format,
...); int sscanf(const char *str, const char
*format, ...);
Descriere
Familia de functii scanf scaneaza intrarea in concordanta cu sirul de
caractere format dupa cum se descrie mai jos. Acest format poate contine specificatori
de conversie; rezultatele unor astfel de conversii (daca se efectueaza) se memoreaza
prin intermediul argumentelor pointer. Functia scanf citeste sirul de intrare
din fluxul standard stdin, fscanf din flux, si sscanf din sirul indicat de str.
Fiecare argument pointer trebuie sa corespunda in ordine ca tip cu fiecare
specificator de conversie (dar a se vedea suprimarea mai jos). Daca argumentele
nu sint suficiente comportamentul programului este imprevizibil. Toate
conversiile sint introduse de caracterul %. Sirul format poate contine
si alte caractere. Spatii albe (blanc, tab, sau new-line) din sirul format se
potrivesc cu orice spatiu alb in orice numar (inclusiv nici unul) din
sirul de intrare. Orice alte caractere trebuie sa se potriveasca exact. Scanarea
se opreste atunci cind un caracter din sirul de intrare nu se potriveste
cu cel din format. Scanarea se opreste de asemenea atunci cind o conversie
nu se mai poate efectua (a se vedea mai jos).
Conversii
Dupa caracterul % care introduce o conversie poate urma un numar de caractere
indicatori, dupa cum urmeaza:
* Suprima atribuirea. Conversia care urmeaza se face in mod obisnuit,
dar nu se foloseste nici un argument pointer; rezultatul conversiei este pur
si simplu abandonat.
h Conversia este de tip dioux sau n si argumentul asociat este un pointer la
short (in loc de int).
l Conversia este de tip dioux sau n si argumentul asociat este un pointer la
long (in loc de int), sau conversia este de tip efg si argumentul asociat
este un pointer la double (in loc de float).
L Conversia este de tip efg si argumentul asociat este un pointer la long double.
In completare la acesti indicatori poate exista o marime w maxima optionala
pentru cimp, exprimata ca un intreg zecimal, intre caracterul
% si cel de conversie, si inaintea indicatorului. Daca nu este data o
marime maxima se foloseste marimea implicita infinit (cu o exceptie la conversia
de tip c); in caz contrar se scaneaza cel mult un numar de w caractere
in timpul conversiei. Inainte de a incepe o conversie, majoritatea
conversiilor ignora spatiile albe; acestea nu sint contorizate in
marimea cimpului.
Sint disponibile urmatoarele conversii:
% Potrivire cu un caracter %. Cu alte cuvinte, %% in sirul format trebuie
sa se potriveasca cu un caracter %. Nu se efectueaza nici o conversie si nici
o atribuire.
d Potrivire cu un intreg zecimal (eventual cu semn); argumentul asociat
trebuie sa fie un pointer la int.
i Potrivire cu un intreg (eventual cu semn); argumentul asociat trebuie
sa fie un pointer la int. Valoarea intreaga este citita in baza
16 daca incepe cu 0x sau 0X, in baza 8 daca incepe cu 0, si
in baza 10 in caz contrar. Sint folosite numai caracterele
care corespund bazei respective.
o Potrivire cu un intreg octal fara semn; argumentul asociat trebuie
sa fie un pointer la unsigned.
u Potrivire cu un intreg zecimal fara semn; argumentul asociat trebuie
sa fie un pointer la unsigned.
x Potrivire cu un intreg hexazecimal fara semn; argumentul asociat trebuie
sa fie un pointer la unsigned.
f Potrivire cu un numar in virgula mobila (eventual cu semn); argumentul
asociat trebuie sa fie un pointer la float.
e,g Echivalent cu f.
s Potrivire cu o secventa de caractere diferite de spatiu alb; argumentul asociat
trebuie sa fie un pointer la char, si zona trebuie sa fie suficient de mare
pentru a putea primi toata secventa si caracterul terminator null. Sirul de
intrare se termina la un spatiu alb sau la atingerea marimii maxime a cimpului
(prima conditie intilnita).
c Potrivire cu o secventa de caractere de marime w (daca aceasta este specificata;
prin lipsa se ia w?1); argumentul asociat trebuie sa fie un pointer la char,
si zona trebuie sa fie suficient de mare pentru a putea primi toata secventa
(nu se adauga terminator null). Nu se ignora ca de obicei spatiile albe din
fata. Pentru a ignora mai intii spatiile albe se indica un spatiu
explicit in format.
a Potrivire cu o secventa nevida de caractere din setul specificat de caractere
acceptate; argumentul asociat trebuie sa fie un pointer la char, si zona trebuie
sa fie suficient de mare pentru a putea primi toata secventa si caracterul terminator
null. Nu se ignora ca de obicei spatiile albe din fata. Sirul de intrare va
fi format din caractere aflate in (sau care nu se afla in) setul
specificat in format; setul este definit de caracterele aflate intre
a si i. Setul exclude acele caractere daca primul caracter dupa a este ^. Pentru
a include caracterul i in set, acesta trebuie sa fie primul caracter dupa
a sau ^; caracterul i aflat in orice alta pozitie inchide setul.
Caracterul - are si el un rol special: plasat intre doua alte caractere
adauga toate celelalte caractere aflate in intervalul respectiv la set.
Pentru a include caracterul - acesta trebuie sa fie ultimul caracter inainte
de i. De exemplu, "%a^i0-9-i" semnifica setul orice caracter cu exceptia
i, 0 pina la 9, si -. Sirul se termina la aparitia unui caracter care
nu se afla (sau, daca se precizeaza ^, care se afla) in set sau daca se
atinge marimea maxima specificata.
p Potrivire cu o valoare pointer (asa cum se afiseaza cu %p in printf);
argumentul asociat trebuie sa fie un pointer la pointer.
n Nu se prelucreaza nimic din sirul de intrare; in schimb, numarul de
caractere consumate pina la acest punct din sirul de intrare este memorat
la argumentul asociat, care trebuie sa fie un pointer la int.
Valori returnate
Functiile returneaza numarul de valori atribuite, care poate fi mai mic decit
numarul de argumente pointer, sau chiar zero, in cazul in care apar
nepotriviri intre format si sirul de intrare. Zero indica faptul ca, chiar
daca avem un sir de intrare disponibil, nu s-a efectuat nici o conversie (si
atribuire); aceasta situatie apare atunci cind un caracter din sirul de
intrare este invalid, cum ar fi un caracter alfabetic pentru o conversie %d.
Valoarea EOF este returnata daca apare un eroare inainte de prima conversie,
cum ar fi detectarea sfirsitului de fisier. Daca o eroare sau un sfirsit
de fisier apare dupa ce o conversie a inceput, se returneaza numarul de
conversii efectuate cu succes.
11.5. Scriere cu format
Nume printf, fprintf, sprintf - scriere cu format
Declaratie int printf(const char *format, ...); int fprintf(FILE *flux, const char
*format, ...); int sprintf(char *str, const char *format,
...);
Descriere
Functiile din familia printf genereaza o iesire in concordanta cu format
dupa cum se descrie mai jos. Functia printf afiseaza iesirea la fluxul standard
stdout; fprintf scrie iesirea la flux; sprintf scrie iesirea in sirul
de caractere str.
Aceste functii genereaza iesirea sub controlul sirului format care specifica
cum se convertesc argumentele pentru iesire.
Sirul de formatare
Sirul format este un sir de caractere, printre care se pot afla zero sau mai
multe directive: caractere obisnuite (diferite de %) care sint copiate
asa cum sint in fluxul de iesire, si specificatii de conversie,
fiecare dintre ele rezultind din incarcarea a zero sau mai multe
argumente. Fiecare specificatie de conversie este introdusa de caracterul %
si se termina cu un specificator de conversie. Intre acestea pot fi (in
aceasta ordine) zero sau mai multi indicatori, o marime minima a cimpului
optionala, o precizie optionala si un modificator optional de lungime.
Argumentele trebuie sa corespunda in ordine cu specificatorii de conversie.
Acestea sint folosite in ordinea data, unde fiecare caracter * si
fiecare specificator de conversie solicita urmatorul argument. Daca argumentele
nu sint suficiente comportamentul programului este imprevizibil.
Caractere indicatori
Caracterul % este urmat de zero, unul sau mai multi indicatori:
# Valoarea numerica se converteste in format alternativ. Pentru conversii
de tip o, primul caracter al sirului de iesire este zero (prin prefixare cu
0 daca valoarea nu este zero). Pentru conversii de tip x si X, o valoare nenula
este prefixata cu 0x (sau 0X pentru conversii de tip X). Pentru conversii de
tip e, E, f, F, g si G, rezultatul va contine intotdeauna punctul zecimal,
chiar daca nu apare partea fractionara (in mod normal punctul zecimal
apare in aceste conversii numai daca exista si partea fractionara). Pentru
conversii de tip g si G zerourile finale nu sint eliminate asa cum se
procedeaza in mod normal. Pentru alte conversii rezultatul este nedefinit.
0 Valoarea numerica este convertita cu zerouri la stinga. Pentru conversii
de tip d, i, o, u, x, X, e, E, f, F, g si G, valoarea convertita este completata
cu zerouri la stinga in loc de blanc. Daca apar indicatorii 0 si
- impreuna, indicatorul 0 este ignorat. Daca pentru o conversie numerica
(d, i, o, u, x, X) este data o precizie, indicatorul 0 este ignorat. Pentru
alte conversii rezultatul este nedefinit.
- Valoarea convertita este aliniata la stinga (implicit alinierea se
face la dreapta). Cu exceptia conversiilor de tip n, valoarea convertita este
completata la dreapta cu blanc, in loc sa fie completata la stinga
cu blanc sau zero. Daca apar indicatorii 0 si - impreuna, indicatorul
0 este ignorat.
Sp (spatiu) In cazul unui rezultat al unei conversii cu semn, inaintea
unui numar pozitiv sau sir vid se pune un blanc.
+ Semnul (+ sau -) este plasat inaintea numarului generat de o conversie
cu semn. Implicit semnul este folosit numai pentru numere negative. Daca apar
indicatorii + si Sp impreuna, indicatorul Sp este ignorat.
Latimea cimpului
Un sir de cifre zecimale (cu prima cifra nenula) specifica o latime minima pentru
cimp. Daca valoarea convertita are mai putine caractere decit latimea
specificata, va fi completata cu spatii la stinga (sau dreapta, daca s-a
specificat aliniere la stinga). In locul unui numar zecimal se poate
folosi * pentru a specifica faptul ca latimea cimpului este data de argumentul
urmator, care trebuie sa fie de tip int. O valoare negativa pentru latime este
considerata un indicator - urmat de o valoare pozitiva pentru latime. In
nici un caz nu se va trunchia cimpul; daca rezultatul conversiei este
mai mare decit latimea cimpului, cimpul este expandat pentru
a contine rezultatul conversiei.
Precizia
Precizia (optionala) este data de caracterul . urmat de un sir de cifre zecimale.
In locul sirului de cifre zecimale se poate scrie * pentru a specifica
faptul ca precizia este data de argumentul urmator, care trebuie sa fie de tip
int. Daca precizia este data doar de ., sau daca precizia este negativa, atunci
aceasta se considera zero. Precizia da numarul minim de cifre care apar pentru
conversii de tip d, i, o, u, x, X, numarul de cifre care apar dupa punctul zecimal
pentru conversii de tip e, E, f, F, numarul maxim de cifre semnificative pentru
conversii de tip g si G, sau numarul maxim de caractere generate pentru conversii
de tip s.
Modificator de lungime
In acest caz prin conversie intreaga intelegem conversie de
tip d, i, o, u, x, X.
h Conversia intreaga care urmeaza corespunde unui argument short sau
unsigned short, sau urmatoarea conversie de tip n corespunde unui argument de
tip pointer la short.
l Conversia intreaga care urmeaza corespunde unui argument long sau unsigned
long, sau urmatoarea conversie de tip n corespunde unui argument de tip pointer
la long.
L Urmatoarea conversie de tip e, E, f, g sau G corespunde unui argument long
double.
Specificator de conversie
Un caracter care specifica tipul conversiei care se va face. Specificatorii
de conversie si semnificatia lor sint:
d,i
Argumentul de tip int este convertit la notatia zecimala cu semn. Precizia,
daca este data, da numarul minim de cifre care trebuie sa apara; daca valoarea
convertita necesita mai putine cifre, aceasta este completata la stinga
cu zerouri. Precizia implicita este 1. Daca valoarea 0 este afisata cu precizie
explicita 0, iesirea este vida.
o,u,x,X
Argumentul de tip unsigned este convertit la notatie octala fara semn (o), zecimala
fara semn (u), sau hexazecimala fara semn (x si X). Literele abcdef se folosesc
pentru conversii de tip x; literele ABCDEF pentru conversii de tip X. Precizia,
daca este data, da numarul minim de cifre care trebuie sa apara; daca valoarea
convertita necesita mai putine cifre, aceasta este completata la stinga
cu zerouri. Precizia implicita este 1. Daca valoarea 0 este afisata cu precizie
explicita 0, iesirea este vida.
e,E
Argumentul de tip flotant este rotunjit si convertit in stil a-id.ddde±dd
unde avem o cifra inainte de punctul zecimal si numarul de cifre dupa
acesta este egal cu precizia; daca aceasta lipseste se considera 6; daca precizia
este zero, punctul zecimal nu apare. O conversie de tip E foloseste litera E
(in loc de e) pentru a introduce exponentul. Exponentul are intotdeauna
cel putin doua cifre; daca valoarea este zero, exponentul este 00.
f,F
Argumentul de tip flotant este rotunjit si convertit in notatie zecimala
in stil a-iddd.ddd, unde numarul de cifre dupa punctul zecimal este egal
cu precizia specificata. Daca precizia lipseste se considera 6; daca precizia
este explicit zero, punctul zecimal nu apare. Daca punctul zecimal apare, cel
putin o cifra apare inaintea acestuia.
g,G
Argumentul de tip flotant este convertit in stil f sau e (sau E pentru
conversii de tip G). Precizia specifica numarul de cifre semnificative. Daca
precizia lipseste se considera 6; daca precizia este zero se considera 1. Stilul
e este folosit daca exponentul rezultat in urma conversiei este mai mic
decit ?4 ori mai mare sau egal cu precizia. Zerourile finale sint
eliminate din partea fractionara a rezultatului; punctul zecimal apare numai
daca este urmat de cel putin o cifra.
c Argumentul de tip int este convertit la unsigned char si se scrie caracterul
rezultat.
s Argumentul de tip const char * este un pointer la un sir de caractere. Caracterele
din sir sint scrise pina la (fara a include) caracterul terminator
null; daca precizia este specificata, nu se scrie un numar mai mare decit
cel specificat. Daca precizia este data, nu e nevoie de caracterul null; daca
precizia nu este specificata, sau daca este mai mare decit marimea sirului,
sirul trebuie sa contina un caracter terminator null.
p Argumentul de tip pointer este scris in hexazecimal; formatul este
specific sistemului de calcul.
n Numarul de caractere scrise pina in acest moment este memorat
la argumentul de tip int *. Nu se face nici o conversie.
% Se scrie un caracter %. Nu se face nici o conversie. Specificatia completa
este %%.
Valoare returnata
Functiile returneaza numarul de caractere generate (nu se include caracterul
terminator null pentru sprintf).
11.6. Tratarea erorilor
Nume perror - afiseaza un mesaj de eroare sistem
Declaratie void perror(const char *s);
#include <errno.h> const char *sys_errlistai; int sys_nerr;
Descriere
Rutina perror afiseaza un mesaj la iesirea standard de eroare, care descrie
ultima eroare intilnita la ultimul apel sistem sau functie de biblioteca.
Mai intii se afiseaza argumentul s, apoi virgula si blanc, si in
final mesajul de eroare si new-line. Se recomanda (mai ales pentru depanare)
ca argumentul s sa includa numele functiei in care a aparut eroarea. Codul
erorii se ia din variabila externa errno.
Lista globala de erori sys_errlistai indexata cu errno poate fi folosita pentru
a obtine mesajul de eroare fara new-line. Ultimul indice de mesaj din lista
este sys_nerr-1. Se recomanda o atentie deosebita in cazul accesului direct
la lista deoarece unele coduri noi de eroare pot lipsi din sys_errlistai.
Daca un apel sistem esueaza variabila errno indica codul erorii. Aceste valori
pot fi gasite in <errno.h>. Functia perror serveste la afisarea
acestui cod de eroare intr-o forma lizibila. Daca un apel terminat cu
eroare nu este imediat urmat de un apel perror, valoarea variabilei errno se
poate pierde daca nu e salvata.
Nume clearerr, feof, ferror - verifica si reseteaza starea fluxului
Declaratie void clearerr(FILE *flux); int feof(FILE *flux); int ferror(FILE *flux); int fileno( FILE *flux);
Descriere
Functia clearerr sterge indicatorii de sfirsit de fisier si eroare ai
fluxului.
Functia feof testeaza indicatorul de sfirsit de fisier al fluxului, si
returneaza non-zero daca este setat. Acesta este setat daca o operatie de citire
a detectat sfirsitul de fisier.
Functia ferror testeaza indicatorul de eroare al fluxului, si returneaza non-zero
daca este setat. Acesta este setat daca o operatie de citire sau scriere a detectat
o eroare (datorata de exemplu hardware-ului).
Functiile de citire (cu sau fara format) nu fac distinctie intre sfirsit
de fisier si eroare, astfel ca trebuie apelate functiile feof si ferror pentru
a determina cauza.
Functia fileno examineaza argumentul flux si returneaza descriptorul asociat
de sistemul de operare acestui flux.
Atentie! Este foarte frecventa folosirea incorecta a functiei feof pentru
a testa daca s-a ajuns la sfirsitul fisierului. Nu se recomanda in
nici un caz acest stil de programare:
#define LSIR 80 char linaLSIRi;
FILE *fi,*fo; fi=fopen(nume-fisier-intrare,"rt"); fo=fopen(nume-fisier-iesire,"wt");
while (!feof(fi)) A /* gresit! */ fgets(lin,LSIR,fi); fputs(lin,fo);
S fclose(fi); fclose(fo);
In aceasta secventa, daca si ultima linie a fisierului text de intrare
este terminata cu new-line, aceasta va fi scrisa de doua ori in fisierul
de iesire. De ce? Dupa ce se citeste ultima linie inca nu este pozitionat
indicatorul de sfirsit de fisier, deci functia fgets returneaza succes.
La reluarea ciclului se incearca un nou fgets si abia acum se depisteaza
sfirsitul de fisier, fapt marcat in zona rezervata fluxului fi.
Astfel continutul tabloului lin ramine nemodificat si este scris a doua
oara in fisierul de iesire. Abia la o noua reluare a ciclului functia
feof ne spune ca s-a depistat sfirsitul de fisier.
In acest manual sint prezentate mai multe programe care efectueaza
diferite prelucrari asupra unor fisiere text. Pentru simplitate toate programele
presupun ca nu apar erori la citire sau la scriere.
11.7. Operatii cu directoare
Functiile de parcurgere a cataloagelor de fisiere descrise in aceasta
sectiune (opendir, readdir, closedir) sint definite de mai multe medii
de programare C (Borland, Watcom, Visual C, GNU Linux), precum si de standardul
POSIX. Aceste functii sint descrise in <dirent.h>.
Functiile de redenumire si stergere a unor fisiere sint descrise in
<stdio.h>.
Nume opendir - deschide un director
Declaratie
DIR *opendir(const char *nume);
Descriere
Functia opendir deschide un flux pentru directorul cu numele nume, si returneaza
un pointer la fluxul deschis. Fluxul este pozitionat pe prima intrare din director.
Valoare returnata
Functia returneaza un pointer la flux in caz de succes, sau NULL in
caz de eroare si variabila globala errno indica codul erorii.
Citeva erori posibile
EACCES Acces interzis
ENOTDIR nume nu este un director
Nume readdir - citeste un director
Declaratie struct dirent *readdir(DIR *dir);
Descriere
Functia readdir returneaza un pointer la o structura de tip dirent care reprezinta
urmatoarea intrare din directorul indicat de fluxul dir. Returneaza NULL daca
s-a depistat sfirsitul de director sau daca a aparut o eroare.
Structura de tip dirent contine un cimp char d_nameai. Utilizarea altor
cimpuri din structura reduce portabilitatea programelor.
Valoare returnata
Functia returneaza un pointer la o structura de tip dirent, sau NULL daca s-a
depistat sfirsitul de director sau daca a aparut o eroare.
Nume closedir - inchide un director
Declaratie int closedir(DIR *dir);
Descriere
Functia closedir inchide fluxul dir.
Valoare returnata
Functia returneaza 0 in caz de succes sau EOF in caz de eroare.
Nume rename - redenumeste un fisier remove - sterge un fisier
Declaratie int rename(const char *old, const char
*new); int remove(const char *name);
Descriere
Functia rename schimba numele unui fisier din old in new. Daca a fost
precizat un periferic in new, acesta trebuie sa coincida cu cel din old.
Directoarele din old si new pot sa fie diferite, astfel ca rename poate fi folosita
pentru a muta un fisier dintr-un director in altul. Nu se permit specificatori
generici (wildcards).
Functia remove sterge fisierul specificat prin name.
Valoare returnata
In caz de succes se returneaza 0. In caz de eroare se returneaza
EOF si variabila globala errno indica codul erorii.
11.8. Programe demonstrative
Primele trei programe primesc ca parametri in linia de comanda numele
fisierelor pe care le vor prelucra. Ultimul program primeste ca parametru in
linia de comanda numele directorului al carui continut va fi afisat.
1) Determinarea marimii unui fisier
#include <stdio.h>
FILE *f; int main(int ac, char **av) A if (ac!=2) A fputs("Un argument!\n",stderr); return 1;
S f = fopen(ava1i,"rb"); if (!f) A perror("Eroare la deschidere"); return 1;
S fseek(f,0,SEEK_END); fprintf(stderr,"File %s, size %ld\n", ftell(f)); fclose(f); return 0;
S
2) Copierea unui fisier
Functiile fgets si fputs se folosesc pentru fluxuri deschise in mod
text. Cum se utilizeaza pentru copierea unui fisier text?
#include <stdio.h>
#define LSIR 80 char linaLSIRi;
FILE *fi, *fo; int main(int ac, char **av) A if (ac!=3) A fputs("Doua argumente!\n",stderr);
S fi=fopen(ava1i,"rt"); fo=fopen(ava2i,"wt"); if (!fi || !fo) A perror("Eroare la deschidere"); return 1;
S
while (fgets(lin,LSIR,fi)) fputs(lin,fo); fclose(fi); fclose(fo); return 0;
S
Functiile fread si fwrite se folosesc pentru fluxuri deschise in mod
binar. Cum se utilizeaza pentru copierea unui fisier binar?
#include <stdio.h>
#define LZON 80 char zonaLZONi;
FILE *fi, *fo; int k; int main(int ac, char **av) A if (ac!=3) A fputs("Doua argumente!\n",stderr); return 1;
S fi=fopen(ava1i,"rb"); fo=fopen(ava2i,"wb"); if (!fi || !fo) A perror("Eroare la deschidere"); return 1;
S
while (k=fread(zon,1,LZON,fi)) fwrite(zon,1,k,fo); fclose(fi); fclose(fo); return 0;
S
3) Prelucrarea unui fisier text
Programul prezentat in continuare citeste un fisier text care contine
pe fiecare linie un sir de caractere (fara spatii) si trei valori intregi,
si afiseaza pe terminal numele pe 12 pozitii aliniat la stinga si media
aritmetica a celor trei valori intregi.
#include <stdio.h>
FILE *fi; char numa10i; int a,b,c; double m; int main(int ac, char **av) A if (ac!=2) A fputs("Un argument!\n",stderr); return 1;
S fi=fopen(ava1i,"rt"); if (!fi) A perror("Eroare la deschidere"); return 1;
S
while (fscanf(fi,"%s %d %d %d", num,&a,&b,&c)!=EOF) A m=(a+b+c)/3.0; printf("%-12s%6.2lf\n",num,m);
S fclose(fi); return 0;
S
4) Afisarea continutului unui director
#include <dirent.h>
#include <stdio.h>
DIR *dir; struct dirent *ent; int main(int ac, char **av) A if (ac!=2) A printf("Un parametru\n"); return 1;
S dir = opendir(ava1i); if (!dir) A perror("Eroare open dir"); return 1;
S
while (ent=readdir(dir)) printf("%s\n",ent->d_name); return 0;
S