Intrări / ieşiri

Intrări / ieşiri

Solus

Membru
Membru personal
Fondator BitArena
Moderator
Utilizator
Înscris
6 Iul 2018
Mesaje
459
Scor reacție
84
Puncte
26
Locație
Bucuresti
Site web
www.bitarena.eu

Reputation:

Întrucît limbajul C nu a fost dezvoltat pentru un sistem particular de operare şi datorită faptului că s-a dorit realizarea unei portabilităţi cît mai mari, atît a unui compilator C, cît şi a programelor scrise în acest limbaj, el nu posedă facilităţi de intrare / ieşire.
Există totuşi un sistem de intrare / ieşire (sistemul I/O) constituit dintr-un număr de subprograme care realizează funcţii de intrare / ieşire pentru programe scrise în C, dar care nu fac parte din limbajul C. Aceste subprograme se găsesc în biblioteca C.
Scopul acestui capitol este de a descrie cele mai utilizate subprograme de intrare / ieşire şi interfaţa lor cu programele scrise în limbajul C.

Intrări şi ieşiri standard; fişiere

Sistemul I/O oferă utilizatorului trei "fişiere" standard de lucru. Cuvîntul fişier a fost pus între ghilimele, deoarece limbajul nu defineşte acest tip de dată şi pentru că fişierele reprezintă mai degrabă nişte fluxuri de intrare / ieşire standard puse la dispoziţia utilizatorului. Aceste fişiere sînt:
– fişierul standard de intrare (stdin);
– fişierul standard de ieşire (stdout);
– fişierul standard de afişare a mesajelor (stderr).
Toate aceste trei fişiere sînt secvenţiale şi în momentul execuţiei unui program C sînt implicit definite şi deschise.
stdin şi stdout sînt asociate în mod normal terminalului de la care a fost lansat programul în execuţie. Sistemul I/O permite redirectarea acestor fişiere pe alte periferice sau închiderea lor după lansarea programului. Redirectarea fişierului stdin se specifică prin construcţia:
<specificator-fişier
în linia de comandă prin care a fost lansat programul.
Redirectarea fişierului stdout se specifică prin construcţia:
>specificator-fişier
în linia de comandă prin care a fost lansat programul.
Redirectarea fişierului stdout pe un alt periferic, în scopul efectuării unei operaţii de adăugare (append) se specifică prin construcţia :
>>specificator-fişier
stderr este întotdeauna asociat terminalului de la care a fost lansat programul în execuţie şi nu poate fi redirectat.
Pentru a se putea face o referire la aceste fişiere orice program C trebuie să conţină fişierul stdio.h, care se include printr-o linie de forma:
#include <stdio.h>
dacă acest fişier se află în biblioteca standard.
Pentru claritatea şi lizibilitatea programelor scrise în C, cît şi pentru crearea unei imagini sugestive asupra lucrului cu fişiere, în fişierul de definiţii standard stdio.h s-a definit un nou nume de tip de dată şi anume FILE care este o structură. Pentru a referi un fişier, este necesară o declaraţie de forma:
FILE *fp;
unde fp va fi numele de dată cu care se va referi fişierul în orice operaţie de intrare / ieşire asociată. Iată cîteva informaţii păstrate de structura FILE:
– un identificator de fişier pe care sistemul de operare îl asociază fluxului pe durata prelucrării; acesta poate fi aflat cu ajutorul funcţiei fileno;
– adresele zonelor tampon asociate; poziţia curentă în aceste zone;
– indicatorii de sfîrşit de fişier şi de eroare;
– alte informaţii.

Accesul la fişiere; deschidere şi închidere

Nume
fopen - deschide un flux

Declaraţie
FILE *fopen(const char *path,
const char *mode);

Descriere

Funcţia fopen deschide fişierul al cărui nume este un şir indicat de path şi îi asociază un flux.
Argumentul mode indică un şir care începe cu una din secvenţele următoare:
r deschide un fişier pentru citire;
r+ deschide pentru citire şi scriere;
w trunchiază fişierul la lungime zero sau creează un fişier pentru scriere;
w+ deschide pentru adăugare la sfîrşit, în citire şi scriere; fişierul este creat dacă nu există, altfel este trunchiat;
a deschide pentru adăugare la sfîrşit, în scriere; fişierul este creat dacă nu există;
a+ deschide pentru adăugare la sfîrşit, în citire şi scriere; fişierul este creat dacă nu există;

După deschidere, în primele patru cazuri indicatorul poziţiei în flux este la începutul fişierului, în ultimele două la sfîrşitul acestuia.
Şirul mode include de asemenea litera b (deschide un fişier binar) sau t (deschide un fişier text) fie pe ultima poziţie fie pe cea din mijloc.
Operaţiile de citire şi scriere pot alterna în cazul fluxurilor read / write în orice ordine. Să reţinem că standardul ANSI C cere să existe o funcţie de poziţionare între o operaţie de intrare şi una de ieşire, sau între o operaţie de ieşire şi una de intrare, cu excepţia cazului cînd o operaţie de citire detectează sfîrşitul de fişier. Această operaţie poate fi inefectivă - cum ar fi fseek(flux, 0L, SEEK_CUR) apelată cu scop de sincronizare.

Valori returnate
În caz de succes se returnează un pointer de tip FILE. În caz de eroare se returnează NULL şi variabila globală errno indică codul erorii.

Nume
fclose - închide un flux

Declaraţie
int fclose( FILE *flux);

Descriere
Funcţia fclose închide fişierul asociat fluxului flux. Dacă flux a fost deschis pentru ieşire, orice date aflate în zone tampon sînt scrise în fişier în prealabil cu un apel fflush.

Valori returnate
În caz de succes se returnează 0. În caz de eroare se returnează EOF şi variabila globală errno indică codul erorii.

Nume
tmpfile - creează un fişier temporar

Declaraţie
FILE *tmpfile();

Descriere
Funcţia tmpfile generează un nume unic de fişier temporar. Acesta este deschis în mod binar pentru scriere / citire ("wb+"). Fişierul va fi şters automat la închidere sau la terminarea programului.

Valoare returnată
Funcţia returnează un descriptor de flux în caz de succes, sau NULL dacă nu poate fi generat un nume unic de fişier sau dacă fişierul nu poate fi deschis. În caz de eroare variabila globală errno indică codul erorii.

Nume
fflush - forţează scrierea în flux

Declaraţie
int fflush(FILE *flux);

Descriere
Funcţia fflush forţează o scriere a tuturor datelor aflate în zone tampon ale fluxului flux. Fluxul rămîne deschis.

Valori returnate
În caz de succes se returnează 0. În caz de eroare se returnează EOF şi variabila globală errno indică codul erorii.

Nume
fseek, ftell, rewind - repoziţionează un flux

Declaraţie
int fseek(FILE *flux, long offset,
int reper);
long ftell(FILE *flux);
void rewind(FILE *flux);

Descriere
Funcţia fseek setează indicatorul de poziţie pentru fişierul asociat fluxului flux. Noua poziţie, dată în octeţi, se obţine adunînd offset octeţi la poziţia specificată de reper. Dacă reper este SEEK_SET, SEEK_CUR, sau SEEK_END, offset este relativ la începutul fişierului, poziţia curentă a indicatorului, respectiv sfîrşitul fişierului. Funcţia fseek şterge indicatorul de sfîrşit de fişier.
Funcţia ftell obţine valoarea curentă a indicatorului de poziţie pentru fişierul asociat fluxului flux.
Funcţia rewind poziţionează indicatorul de poziţie pentru fişierul asociat fluxului flux la începutul fişierului. Este echivalentă cu:
(void)fseek(flux, 0L, SEEK_SET)
cu completarea că funcţia rewind şterge şi indicatorul de eroare al fluxului.

Valori returnate
Funcţia rewind nu returnează nici o valoare. În caz de succes, fseek returnează 0, şi ftell returnează offset-ul curent. În caz de eroare se returnează EOF şi variabila globală errno indică codul erorii.

Citire şi scriere fără format

Nume
fgets - citeşte un şir de caractere dintr-un flux text

Declaraţie
char *fgets(char *s, int size, FILE *flux);

Descriere
Funcţia fgets cel mult size-1 caractere din flux şi le memorează în zona indicată de s. Citirea se opreşte la detectarea sfîrşitului de fişier sau new-line. Dacă se citeşte caracterul new-line acesta este memorat în s. După ultimul caracter se memorează null.
Apeluri ale acestei funcţii pot fi combinate cu orice apeluri ale altor funcţii de intrare din bibliotecă (fscanf, de exemplu) pentru un acelaşi flux de intrare.

Valori returnate
Funcţia returnează adresa s în caz de succes, sau NULL în caz de eroare sau la întîlnirea sfîrşitului de fişier dacă nu s-a citit nici un caracter.


Nume
fputs - scrie un şir de caractere într-un flux text

Declaraţie
int fputs(const char *s, FILE *flux);

Descriere
Funcţia fputs scrie şirul s în flux fără caracterul terminator null.
Apeluri ale acestei funcţii pot fi combinate cu orice apeluri ale altor funcţii de ieşire din bibliotecă (fprintf, de exemplu) pentru un acelaşi flux de ieşire.

Valori returnate
Funcţia returnează o valoare non-negativă în caz de succes, sau EOF în caz de eroare.

Nume
fread, fwrite - intrări / ieşiri pentru fluxuri binare

Declaraţie
unsigned fread(void *ptr, unsigned size,
unsigned nel, FILE *flux);
unsigned fwrite(const void *ptr, unsigned
size, unsigned nel, FILE *flux);

Descriere
Funcţia fread citeşte nel elemente, fiecare avînd mărimea size octeţi, din fluxul indicat de flux, şi le memorează în zona indicată de ptr.
Funcţia fwrite scrie nel elemente, fiecare avînd mărimea size octeţi, din fluxul indicat de flux, pe care le ia din zona indicată de ptr.

Valori returnate
Funcţiile returnează numărul de elemente citite sau scrise cu succes (şi nu numărul de caractere). Dacă apare o eroare sau se întîlneşte sfîrşitul de fişier, valoarea returnată este mai mică decît nel (posibil zero).

Citire cu format

Nume
scanf, fscanf, sscanf - citire cu format

Declaraţie
int scanf(const char *format, ...);
int fscanf(FILE *flux, const char *format,
...);
int sscanf(const char *str, const char
*format, ...);

Descriere
Familia de funcţii scanf scanează intrarea în concordanţă cu şirul de caractere format după cum se descrie mai jos. Acest format poate conţine specificatori de conversie; rezultatele unor astfel de conversii (dacă se efectuează) se memorează prin intermediul argumentelor pointer. Funcţia scanf citeşte şirul de intrare din fluxul standard stdin, fscanf din flux, şi sscanf din şirul indicat de str.
Fiecare argument pointer trebuie să corespundă în ordine ca tip cu fiecare specificator de conversie (dar a se vedea suprimarea mai jos). Dacă argumentele nu sînt suficiente comportamentul programului este imprevizibil. Toate conversiile sînt introduse de caracterul %. Şirul format poate conţine şi alte caractere. Spaţii albe (blanc, tab, sau new-line) din şirul format se potrivesc cu orice spaţiu alb în orice număr (inclusiv nici unul) din şirul de intrare. Orice alte caractere trebuie să se potrivească exact. Scanarea se opreşte atunci cînd un caracter din şirul de intrare nu se potriveşte cu cel din format. Scanarea se opreşte de asemenea atunci cînd o conversie nu se mai poate efectua (a se vedea mai jos).


Conversii

După caracterul % care introduce o conversie poate urma un număr de caractere indicatori, după cum urmează:

* Suprimă atribuirea. Conversia care urmează se face în mod obişnuit, dar nu se foloseşte nici un argument pointer; rezultatul conversiei este pur şi simplu abandonat.

h Conversia este de tip dioux sau n şi argumentul asociat este un pointer la short (în loc de int).

l Conversia este de tip dioux sau n şi argumentul asociat este un pointer la long (în loc de int), sau conversia este de tip efg şi argumentul asociat este un pointer la double (în loc de float).

L Conversia este de tip efg şi argumentul asociat este un pointer la long double.

În completare la aceşti indicatori poate exista o mărime w maximă opţională pentru cîmp, exprimată ca un întreg zecimal, între caracterul % şi cel de conversie, şi înaintea indicatorului. Dacă nu este dată o mărime maximă se foloseşte mărimea implicită infinit (cu o excepţie la conversia de tip c); în caz contrar se scanează cel mult un număr de w caractere în timpul conversiei. Înainte de a începe o conversie, majoritatea conversiilor ignoră spaţiile albe; acestea nu sînt contorizate în mărimea cîmpului.

Sînt disponibile următoarele conversii:

% Potrivire cu un caracter %. Cu alte cuvinte, %% în şirul format trebuie să se potrivească cu un caracter %. Nu se efectuează nici o conversie şi nici o atribuire.

d Potrivire cu un întreg zecimal (eventual cu semn); argumentul asociat trebuie să fie un pointer la int.

i Potrivire cu un întreg (eventual cu semn); argumentul asociat trebuie să fie un pointer la int. Valoarea întreagă este citită în baza 16 dacă începe cu 0x sau 0X, în baza 8 dacă începe cu 0, şi în baza 10 în caz contrar. Sînt folosite numai caracterele care corespund bazei respective.

o Potrivire cu un întreg octal fără semn; argumentul asociat trebuie să fie un pointer la unsigned.

u Potrivire cu un întreg zecimal fără semn; argumentul asociat trebuie să fie un pointer la unsigned.

x Potrivire cu un întreg hexazecimal fără semn; argumentul asociat trebuie să fie un pointer la unsigned.

f Potrivire cu un număr în virgulă mobilă (eventual cu semn); argumentul asociat trebuie să fie un pointer la float.

e,g Echivalent cu f.

s Potrivire cu o secvenţă de caractere diferite de spaţiu alb; argumentul asociat trebuie să fie un pointer la char, şi zona trebuie să fie suficient de mare pentru a putea primi toată secvenţa şi caracterul terminator null. Şirul de intrare se termină la un spaţiu alb sau la atingerea mărimii maxime a cîmpului (prima condiţie întîlnită).

c Potrivire cu o secvenţă de caractere de mărime w (dacă aceasta este specificată; prin lipsă se ia w=1); argumentul asociat trebuie să fie un pointer la char, şi zona trebuie să fie suficient de mare pentru a putea primi toată secvenţa (nu se adaugă terminator null). Nu se ignoră ca de obicei spaţiile albe din faţă. Pentru a ignora mai întîi spaţiile albe se indică un spaţiu explicit în format.

[ Potrivire cu o secvenţă nevidă de caractere din setul specificat de caractere acceptate; argumentul asociat trebuie să fie un pointer la char, şi zona trebuie să fie suficient de mare pentru a putea primi toată secvenţa şi caracterul terminator null. Nu se ignoră ca de obicei spaţiile albe din faţă. Şirul de intrare va fi format din caractere aflate în (sau care nu se află în) setul specificat în format; setul este definit de caracterele aflate între [ şi ]. Setul exclude acele caractere dacă primul caracter după [ este ^. Pentru a include caracterul ] în set, acesta trebuie să fie primul caracter după [ sau ^; caracterul ] aflat în orice altă poziţie închide setul. Caracterul - are şi el un rol special: plasat între două alte caractere adaugă toate celelalte caractere aflate în intervalul respectiv la set. Pentru a include caracterul - acesta trebuie să fie ultimul caracter înainte de ]. De exemplu, "%[^]0-9-]" semnifică setul orice caracter cu excepţia ], 0 pînă la 9, şi -. Şirul se termină la apariţia unui caracter care nu se află (sau, dacă se precizează ^, care se află) în set sau dacă se atinge mărimea maximă specificată.

p Potrivire cu o valoare pointer (aşa cum se afişează cu %p în printf); argumentul asociat trebuie să fie un pointer la pointer.

n Nu se prelucrează nimic din şirul de intrare; în schimb, numărul de caractere consumate pînă la acest punct din şirul de intrare este memorat la argumentul asociat, care trebuie să fie un pointer la int.

Valori returnate
Funcţiile returnează numărul de valori atribuite, care poate fi mai mic decît numărul de argumente pointer, sau chiar zero, în cazul în care apar nepotriviri între format şi şirul de intrare. Zero indică faptul că, chiar dacă avem un şir de intrare disponibil, nu s-a efectuat nici o conversie (şi atribuire); această situaţie apare atunci cînd un caracter din şirul de intrare este invalid, cum ar fi un caracter alfabetic pentru o conversie %d. Valoarea EOF este returnată dacă apare un eroare înainte de prima conversie, cum ar fi detectarea sfîrşitului de fişier. Dacă o eroare sau un sfîrşit de fişier apare după ce o conversie a început, se returnează numărul de conversii efectuate cu succes.



Scriere cu format

Nume
printf, fprintf, sprintf - scriere cu format

Declaraţie
int printf(const char *format, ...);
int fprintf(FILE *flux, const char
*format, ...);
int sprintf(char *str, const char *format,
...);

Descriere
Funcţiile din familia printf generează o ieşire în concordanţă cu format după cum se descrie mai jos. Funcţia printf afişează ieşirea la fluxul standard stdout; fprintf scrie ieşirea la flux; sprintf scrie ieşirea în şirul de caractere str.
Aceste funcţii generează ieşirea sub controlul şirului format care specifică cum se convertesc argumentele pentru ieşire.

Şirul de formatare
Şirul format este un şir de caractere, printre care se pot afla zero sau mai multe directive: caractere obişnuite (diferite de %) care sînt copiate aşa cum sînt în fluxul de ieşire, şi specificaţii de conversie, fiecare dintre ele rezultînd din încărcarea a zero sau mai multe argumente. Fiecare specificaţie de conversie este introdusă de caracterul % şi se termină cu un specificator de conversie. Între acestea pot fi (în această ordine) zero sau mai mulţi indicatori, o mărime minimă a cîmpului opţională, o precizie opţională şi un modificator opţional de lungime.
Argumentele trebuie să corespundă în ordine cu specificatorii de conversie. Acestea sînt folosite în ordinea dată, unde fiecare caracter * şi fiecare specificator de conversie solicită următorul argument. Dacă argumentele nu sînt suficiente comportamentul programului este imprevizibil.


Caractere indicatori
Caracterul % este urmat de zero, unul sau mai mulţi indicatori:

# Valoarea numerică se converteşte în format alternativ. Pentru conversii de tip o, primul caracter al şirului de ieşire este zero (prin prefixare cu 0 dacă valoarea nu este zero). Pentru conversii de tip x şi X, o valoare nenulă este prefixată cu 0x (sau 0X pentru conversii de tip X). Pentru conversii de tip e, E, f, F, g şi G, rezultatul va conţine întotdeauna punctul zecimal, chiar dacă nu apare partea fracţionară (în mod normal punctul zecimal apare în aceste conversii numai dacă există şi partea fracţionară). Pentru conversii de tip g şi G zerourile finale nu sînt eliminate aşa cum se procedează în mod normal. Pentru alte conversii rezultatul este nedefinit.

0 Valoarea numerică este convertită cu zerouri la stînga. Pentru conversii de tip d, i, o, u, x, X, e, E, f, F, g şi G, valoarea convertită este completată cu zerouri la stînga în loc de blanc. Dacă apar indicatorii 0 şi -împreună, indicatorul 0 este ignorat. Dacă pentru o conversie numerică (d, i, o, u, x, X) este dată o precizie, indicatorul 0 este ignorat. Pentru alte conversii rezultatul este nedefinit.

- Valoarea convertită este aliniată la stînga (implicit alinierea se face la dreapta). Cu excepţia conversiilor de tip n, valoarea convertită este completată la dreapta cu blanc, în loc să fie completată la stînga cu blanc sau zero. Dacă apar indicatorii 0 şi - împreună, indicatorul 0 este ignorat.

Sp (spaţiu) În cazul unui rezultat al unei conversii cu semn, înaintea unui număr pozitiv sau şir vid se pune un blanc.

+ Semnul (+ sau -) este plasat înaintea numărului generat de o conversie cu semn. Implicit semnul este folosit numai pentru numere negative. Dacă apar indicatorii + şi Sp împreună, indicatorul Sp este ignorat.


Lăţimea cîmpului
Un şir de cifre zecimale (cu prima cifră nenulă) specifică o lăţime minimă pentru cîmp. Dacă valoarea convertită are mai puţine caractere decît lăţimea specificată, va fi completată cu spaţii la stînga (sau dreapta, dacă s-a specificat aliniere la stînga). În locul unui număr zecimal se poate folosi * pentru a specifica faptul că lăţimea cîmpului este dată de argumentul următor, care trebuie să fie de tip int. O valoare negativă pentru lăţime este considerată un indicator - urmat de o valoare pozitivă pentru lăţime. În nici un caz nu se va trunchia cîmpul; dacă rezultatul conversiei este mai mare decît lăţimea cîmpului, cîmpul este expandat pentru a conţine rezultatul conversiei.

Precizia
Precizia (opţională) este dată de caracterul . urmat de un şir de cifre zecimale. În locul şirului de cifre zecimale se poate scrie * pentru a specifica faptul că precizia este dată de argumentul următor, care trebuie să fie de tip int. Dacă precizia este dată doar de ., sau dacă precizia este negativă, atunci aceasta se consideră zero. Precizia dă numărul minim de cifre care apar pentru conversii de tip d, i, o, u, x, X, numărul de cifre care apar după punctul zecimal pentru conversii de tip e, E, f, F, numărul maxim de cifre semnificative pentru conversii de tip g şi G, sau numărul maxim de caractere generate pentru conversii de tip s.

Modificator de lungime
În acest caz prin conversie întreagă înţelegem conversie de tip d, i, o, u, x, X.

h Conversia întreagă care urmează corespunde unui argument short sau unsigned short, sau următoarea conversie de tip n corespunde unui argument de tip pointer la short.

l Conversia întreagă care urmează corespunde unui argument long sau unsigned long, sau următoarea conversie de tip n corespunde unui argument de tip pointer la long.

L Următoarea conversie de tip e, E, f, g sau G corespunde unui argument long double.

Specificator de conversie
Un caracter care specifică tipul conversiei care se va face. Specificatorii de conversie şi semnificaţia lor sînt:

d,i
Argumentul de tip int este convertit la notaţia zecimală cu semn. Precizia, dacă este dată, dă numărul minim de cifre care trebuie să apară; dacă valoarea convertită necesită mai puţine cifre, aceasta este completată la stînga cu zerouri. Precizia implicită este 1. Dacă valoarea 0 este afişată cu precizie explicită 0, ieşirea este vidă.

o,u,x,X
Argumentul de tip unsigned este convertit la notaţie octală fără semn (o), zecimală fără semn (u), sau hexazecimală fără semn (x şi X). Literele abcdef se folosesc pentru conversii de tip x; literele ABCDEFpentru conversii de tip X. Precizia, dacă este dată, dă numărul minim de cifre care trebuie să apară; dacă valoarea convertită necesită mai puţine cifre, aceasta este completată la stînga cu zerouri. Precizia implicită este 1. Dacă valoarea 0 este afişată cu precizie explicită 0, ieşirea este vidă.

e,E
Argumentul de tip flotant este rotunjit şi convertit în stil [-]d.ddddd unde avem o cifră înainte de punctul zecimal şi numărul de cifre după acesta este egal cu precizia; dacă aceasta lipseşte se consideră 6; dacă precizia este zero, punctul zecimal nu apare. O conversie de tip E foloseşte litera E (în loc de e) pentru a introduce exponentul. Exponentul are întotdeauna cel puţin două cifre; dacă valoarea este zero, exponentul este 00.

f,F
Argumentul de tip flotant este rotunjit şi convertit în notaţie zecimală în stil [-]ddd.ddd, unde numărul de cifre după punctul zecimal este egal cu precizia specificată. Dacă precizia lipseşte se consideră 6; dacă precizia este explicit zero, punctul zecimal nu apare. Dacă punctul zecimal apare, cel puţin o cifră apare înaintea acestuia.

g,G
Argumentul de tip flotant este convertit în stil f sau e (sau E pentru conversii de tip G). Precizia specifică numărul de cifre semnificative. Dacă precizia lipseşte se consideră 6; dacă precizia este zero se consideră 1. Stilul e este folosit dacă exponentul rezultat în urma conversiei este mai mic decît -4 ori mai mare sau egal cu precizia. Zerourile finale sînt eliminate din partea fracţionară a rezultatului; punctul zecimal apare numai dacă este urmat de cel puţin o cifră.

c Argumentul de tip int este convertit la unsigned char şi se scrie caracterul rezultat.

s Argumentul de tip const char * este un pointer la un şir de caractere. Caracterele din şir sînt scrise pînă la (fără a include) caracterul terminator null; dacă precizia este specificată, nu se scrie un număr mai mare decît cel specificat. Dacă precizia este dată, nu e nevoie de caracterul null; dacă precizia nu este specificată, sau dacă este mai mare decît mărimea şirului, şirul trebuie să conţină un caracter terminator null.

p Argumentul de tip pointer este scris în hexazecimal; formatul este specific sistemului de calcul.

n Numărul de caractere scrise pînă în 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. Specificaţia completă este %%.

Valoare returnată
Funcţiile returnează numărul de caractere generate (nu se include caracterul terminator null pentru sprintf).

Tratarea erorilor


Nume
perror - afişează un mesaj de eroare sistem

Declaraţie
void perror(const char *s);

#include <errno.h>
const char *sys_errlist[];
int sys_nerr;

Descriere
Rutina perror afişează un mesaj la ieşirea standard de eroare, care descrie ultima eroare întîlnită la ultimul apel sistem sau funcţie de bibliotecă. Mai întîi se afişează argumentul s, apoi virgula şi blanc, şi în final mesajul de eroare şi new-line. Se recomandă (mai ales pentru depanare) ca argumentul s să includă numele funcţiei în care a apărut eroarea. Codul erorii se ia din variabila externă errno.
Lista globală de erori sys_errlist[] indexată cu errno poate fi folosită pentru a obţine mesajul de eroare fără new-line. Ultimul indice de mesaj din listă este sys_nerr-1. Se recomandă o atenţie deosebită în cazul accesului direct la listă deoarece unele coduri noi de eroare pot lipsi din sys_errlist[].
Dacă un apel sistem eşuează variabila errno indică codul erorii. Aceste valori pot fi găsite în <errno.h>. Funcţia perror serveşte la afişarea acestui cod de eroare într-o formă lizibilă. Dacă un apel terminat cu eroare nu este imediat urmat de un apel perror, valoarea variabilei errno se poate pierde dacă nu e salvată.

Nume
clearerr, feof, ferror - verifică şi resetează starea
fluxului

Declaraţie
void clearerr(FILE *flux);
int feof(FILE *flux);
int ferror(FILE *flux);
int fileno( FILE *flux);

Descriere
Funcţia clearerr şterge indicatorii de sfîrşit de fişier şi eroare ai fluxului.
Funcţia feof testează indicatorul de sfîrşit de fişier al fluxului, şi returnează non-zero dacă este setat. Acesta este setat dacă o operaţie de citire a detectat sfîrşitul de fişier.
Funcţia ferror testează indicatorul de eroare al fluxului, şi returnează non-zero dacă este setat. Acesta este setat dacă o operaţie de citire sau scriere a detectat o eroare (datorată de exemplu hardware-ului).
Funcţiile de citire (cu sau fără format) nu fac distincţie între sfîrşit de fişier şi eroare, astfel că trebuie apelate funcţiile feof şi ferror pentru a determina cauza.
Funcţia fileno examinează argumentul flux şi returnează descriptorul asociat de sistemul de operare acestui flux.

Atenţie! Este foarte frecventă folosirea incorectă a funcţiei feof pentru a testa dacă s-a ajuns la sfîrşitul fişierului. Nu se recomandă în nici un caz acest stil de programare:

#define LSIR 80
char lin[LSIR];
FILE *fi,*fo;
fi=fopen(nume-fişier-intrare,"rt");
fo=fopen(nume-fişier-ieşire,"wt");
while (!feof(fi)) { /* greşit! */
fgets(lin,LSIR,fi);
fputs(lin,fo);
}
fclose(fi); fclose(fo);

În această secvenţă, dacă şi ultima linie a fişierului text de intrare este terminată cu new-line, aceasta va fi scrisă de două ori în fişierul de ieşire. De ce? După ce se citeşte ultima linie încă nu este poziţionat indicatorul de sfîrşit de fişier, deci funcţia fgets returnează succes. La reluarea ciclului se încearcă un nou fgets şi abia acum se depistează sfîrşitul de fişier, fapt marcat în zona rezervată fluxului fi. Astfel conţinutul tabloului lin rămîne nemodificat şi este scris a doua oară în fişierul de ieşire. Abia la o nouă reluare a ciclului funcţia feof ne spune că s-a depistat sfîrşitul de fişier.
În acest manual sînt prezentate mai multe programe care efectuează diferite prelucrări asupra unor fişiere text. Pentru simplitate toate programele presupun că nu apar erori la citire sau la scriere.

Operaţii cu directoare

Funcţiile de parcurgere a cataloagelor de fişiere descrise în această secţiune (opendir, readdir, closedir) sînt definite de mai multe medii de programare C (Borland, Watcom, Visual C, GNU Linux), precum şi de standardul POSIX. Aceste funcţii sînt descrise în <dirent.h>.
Funcţiile de redenumire şi ştergere a unor fişiere sînt descrise în <stdio.h>.

Nume
opendir - deschide un director

Declaraţie
DIR *opendir(const char *nume);

Descriere
Funcţia opendir deschide un flux pentru directorul cu numele nume, şi returnează un pointer la fluxul deschis. Fluxul este poziţionat pe prima intrare din director.

Valoare returnată
Funcţia returnează un pointer la flux în caz de succes, sau NULL în caz de eroare şi variabila globală errno indică codul erorii.

Cîteva erori posibile
EACCES Acces interzis
ENOTDIR nume nu este un director

Nume
readdir - citeşte un director

Declaraţie
struct dirent *readdir(DIR *dir);

Descriere
Funcţia readdir returnează un pointer la o structură de tip dirent care reprezintă următoarea intrare din directorul indicat de fluxul dir. Returnează NULL dacă s-a depistat sfîrşitul de director sau dacă a apărut o eroare.
Structura de tip dirent conţine un cîmp char d_name[]. Utilizarea altor cîmpuri din structură reduce portabilitatea programelor.

Valoare returnată
Funcţia returnează un pointer la o structură de tip dirent, sau NULL dacă s-a depistat sfîrşitul de director sau dacă a apărut o eroare.

Nume
closedir - închide un director

Declaraţie
int closedir(DIR *dir);

Descriere
Funcţia closedir închide fluxul dir.

Valoare returnată
Funcţia returnează 0 în caz de succes sau EOF în caz de eroare.


Nume
rename - redenumeşte un fişier
remove - şterge un fişier

Declaraţie
int rename(const char *old, const char
*new);
int remove(const char *name);

Descriere
Funcţia rename schimbă numele unui fişier din old în new. Dacă a fost precizat un periferic în new, acesta trebuie să coincidă cu cel din old. Directoarele din old şi new pot să fie diferite, astfel că renamepoate fi folosită pentru a muta un fişier dintr-un director în altul. Nu se permit specificatori generici (wildcards).
Funcţia remove şterge fişierul specificat prin name.

Valoare returnată
În caz de succes se returnează 0. În caz de eroare se returnează EOF şi variabila globală errno indică codul erorii.

Programe demonstrative

Primele trei programe primesc ca parametri în linia de comandă numele fişierelor pe care le vor prelucra. Ultimul program primeşte ca parametru în linia de comandă numele directorului al cărui conţinut va fi afişat.

1) Determinarea mărimii unui fişier

#include <stdio.h>
FILE *f;
int main(int ac, char **av) {
if (ac!=2) {
fputs("Un argument!\n",stderr);
return 1;
}
f = fopen(av[1],"rb");
if (!f) {
perror("Eroare la deschidere");
return 1;
}
fseek(f,0,SEEK_END);
fprintf(stderr,"File %s, size %ld\n",
ftell(f));
fclose(f);
return 0;
}
2) Copierea unui fişier

Funcţiile fgets şi fputs se folosesc pentru fluxuri deschise în mod text. Cum se utilizează pentru copierea unui fişier text?

#include <stdio.h>
#define LSIR 80
char lin[LSIR];
FILE *fi, *fo;
int main(int ac, char **av) {
if (ac!=3) {
fputs("Doua argumente!\n",stderr);
}
fi=fopen(av[1],"rt"); fo=fopen(av[2],"wt");
if (!fi || !fo) {
perror("Eroare la deschidere");
return 1;
}
while (fgets(lin,LSIR,fi))
fputs(lin,fo);
fclose(fi); fclose(fo);
return 0;
}

Funcţiile fread şi fwrite se folosesc pentru fluxuri deschise în mod binar. Cum se utilizează pentru copierea unui fişier binar?

#include <stdio.h>
#define LZON 80
char zon[LZON];
FILE *fi, *fo;
int k;
int main(int ac, char **av) {
if (ac!=3) {
fputs("Doua argumente!\n",stderr);
return 1;
}
fi=fopen(av[1],"rb"); fo=fopen(av[2],"wb");
if (!fi || !fo) {
perror("Eroare la deschidere");
return 1;
}
while (k=fread(zon,1,LZON,fi))
fwrite(zon,1,k,fo);
fclose(fi); fclose(fo);
return 0;
}

3) Prelucrarea unui fişier text

Programul prezentat în continuare citeşte un fişier text care conţine pe fiecare linie un şir de caractere (fără spaţii) şi trei valori întregi, şi afişează pe terminal numele pe 12 poziţii aliniat la stînga şi media aritmetică a celor trei valori întregi.

#include <stdio.h>
FILE *fi;
char num[10];
int a,b,c;
double m;
int main(int ac, char **av) {
if (ac!=2) {
fputs("Un argument!\n",stderr);
return 1;
}
fi=fopen(av[1],"rt");
if (!fi) {
perror("Eroare la deschidere");
return 1;
}
while (fscanf(fi,"%s %d %d %d",
num,&a,&b,&c)!=EOF) {
m=(a+b+c)/3.0;
printf("%-12s%6.2lf\n",num,m);
}
fclose(fi);
return 0;
}

4) Afişarea conţinutului unui director

#include <dirent.h>
#include <stdio.h>
DIR *dir;
struct dirent *ent;
int main(int ac, char **av) {
if (ac!=2) {
printf("Un parametru\n");
return 1;
}
dir = opendir(av[1]);
if (!dir) {
perror("Eroare open dir");
return 1;
}
while (ent=readdir(dir))
printf("%s\n",ent->d_name);
return 0;
}
 
Sus Jos