Sunteți pe pagina 1din 39

Lucrarea de laborator Nr. 2 la SDA pentru gr. TI 171-173, FCIM.

aLl_fisiere2013
Tema: Elaborarea programelor pentru prelucrarea funcţiilor cu diverse
structuri şi fişiere în limbajul C.
Sarcina şi obiectivele:
1. să se analizeze principiile organizării şi gestiunii fişierelor în sistemele de operare şi procesarea fişierelor în
limbajul C, apoi şi să se analizeze algoritmii şi programele (declarări, utilizări, parcurgeri, salvare şi ştergeri).
Pentru aprofundarea şi rularea programelor în limbajul C să se elaboreze scenariile succinte de soluţionare cu
calculele de verificare şi explicaţii.
2. de studiat şi însuşit materialul teoretic prin lansarea exerciţiilor de antrenament şi verificări ale cunoştinţelor
(din indicaţiile acestea) şi să se elaboreze algoritmii şi, totodată, să organizeze calculele de verificare cu
explicaţii pentru evidenţierea esenţialului prelucrării fişierelor cu structuri de date în elaborarea modelelor
soluţiei. Toate observaţiile se înregistrează în raport;
3. să se preia de la profesor varianta (6. Variante pentru lucrul individual) şi să se elaboreze algoritmii şi şi
programul unde să organizeze antetul functiilor şi transmiterea functiei apelate adresele variabilelor cu
calculele de verificare şi cu explicaţii la prelucrarea fişierelor.
4. să se analizeze listingurile din compartimentul 4,5 (4. Exemple de verificare a cunoştinţelor însuşite; 5.
Exemplu model pentru evidenţierea principiilor de elaborare şi prelucrarea grafului cu funcţii şi diverse SD.
De fragmentat și de ansamblat cu diverse posibilități.) corectitudinea și rezultatele obținute cu argumentări.)
5. în baza funcţiilor de timp şi dată din fişierul header time.h apreciaţi timpul definit de sistem şi timpul
execuţiei programului în secunde pentru ambele cazuri (tradiţional şi cu pointeri) şi să se descrie scenariile şi
principiile de algoritmizare si rezolvare ale problemei în baza diferitor modele de SD complexe,
implementând subprograme în C;
6. în raport să se reflecte toate exemplele efectuate cu analize a tehnicii programării eficiente cu argumentări şi
comentarii, incluzând fişierele cu teste de verificare şi vizualizări ale rezultatelor.
Consideraţii teoretice:
1. Organizarea şi gestiunea fişierelor în sistemele de operare (SO).
Tratarea informaţiilor cere prezenţa lor în memorie în timpul execuţiei programului dat. Dar în majoritatea
cazurilor trebuie neapărat ca aceste informaţii să fie conservate de o manieră durabilă .Ca exemplu elementar , se
poate de citat informaţiile relative ale clienţilor unor întreprinderi. De aceleaşi date (cod, client, numele clientului,
adresa ,cifra de afaceri ), sunt cele mai des exploatate pe o perioadă lungă de timp. Ele trebuie să fie rechemate la
moment şi în particular. În acest scop ele sunt scrise într-un fişier, care este stocat pe o memorie masivă (discul
magnetic) şi accesibil programului, manipulând informaţiile.
Un fişier nu este altceva decât o mulţime mai mult sau mai puţin importante de date, conservate pe un
oarecare suport.
Fişierele pot fi cu acces direct (stocate pe disc) sau cu acces secvenţial (stocate pe bandă). Numele fişierelor
are structura: numefişer.extensia.
SO UNIX suportă aşa-numitele fişiere conductă ("pipes") care pot fi deschise de două procese pentru a
stabili un canal de comunicaţie interproces.
Fişierele sunt împărţite în tipuri diferite în funcţie de utilizarea lor. Diferenţierea tipurilor se face prin
extensii diferite a numelui fişierului. De exemplu:
FILE.C; FILE.CPP: program - sursă în C/C++;
FILE.PAS: program - sursă în Pascal;
FILE.FTN: program - sursă în Fortran;
FILE.OBJ: fişier - obiect, rezultat în urma compilării;
FILE.BIN: program executabil (în mod binar);
FILE.DAT: fişier de date, etc.
Uneori extensia este o simplă convenţie, sistemul de operare neţinând cont de aceasta.
1.1. ORGANIZAREA SISTEMELOR DE FIŞIERE
Organizarea fişierelor este specifică fiecărui sistem de operare.
În sistemul de operare UNIX, fişierele sunt organizate în arborele unic al fişierelor, existând o singura rădăcină.
Acest sistem de operare tratează egal fişiere sau dispozitive.
În sistemul de operare MS-DOS există nume de dispozitive (ex.: A,B,C). Dispozitivele de disc permit organizări
arborescente.
Simplificarea accesului a dus la apariţia conceptului de directoare. Un director este un fişier de indicare a localizării
celorlalte fişiere. Un director e organizat pe înregistrări (articole), câte una pentru fiecare fişier; fiecare articol conţine
informaţii despre fişier ca: nume, tip, dimensiune, timp etc. La CP/M directorul conţinea şi numerele de ordine ale blocurilor
alocate. Fişierul este localizat prin cale (path), care precizează locul în arbore.
1.2 GESTIUNEA SPAŢIULUI PE DISC
Gestiunea spaţiului pe disc nu se face pe sectoare fizice; există unităţi de alocare, fiecare unitate conţinând un
multiplu de sectoare fizice, oferind flexibilitate la schimbarea dispozitivului. Contabilizarea sectoarelor ocupate se
realizează in doua moduri:
1. lista înlănţuită, care conţine unităţi de 16 biţi pe care se înregistrează numărul de blocuri ocupate succesiv;
2. bit-map, în care primul bit are semnificaţia de ocupat / neocupat.
Sistemul MS-DOS foloseşte listele înlănţuite (fiecare bloc conţine doi octeţi ce reprezintă un pointer către
următorul bloc din lanţ), ceea ce permite întreţinerea rapidă la eliberare/alocare spaţii pentru fişiere. La ştergere,
dispar înregistrările de 16 biţi corespunzătoare blocurilor fişierelor. La alocare, se ocupa în măsura găsirii spaţiilor
neînregistrate în FAT.
Sistemul UNIX înlatură dezavantajul fişierelor mari cu unităţi multe de alocare, care necesită un FAT mare in
sistemul MS-DOS astfel: se utilizează gestiunea spaţiului pe disc cu I-noduri (Index-nod). Fiecare fişier are un I-nod
(indiferent de dimensiunea fişierului respectiv).
1.3 ORGANIZAREA FIŞIERELOR ÎN UNIX
Spaţiul de pe un disc cu sistem de operare UNIX este împărţit astfel:
- Boot
- Superbloc:-volumul;
- nr. blocuri libere;
- tabelul blocurilor libere;
- index la primul bloc liber din tabela blocurilor libere;
- dimensiunea zonei de I-noduri;
- număr de I-noduri libere;
- index la primul I-nod liber;
- câmpuri cheie.
- I-noduri
- Date
- Swap.
Superblocul este prezent în memorie.
1.3.1 FIŞIERE PARTAJATE
Mai mulţi utilizatori care lucrează împreună la o aplicaţie au nevoie să exploateze în comun fişiere comune; este
convenabil ca un astfel de fişier să apară simultan în directoare de lucru diferite aparţinând unor utilizatori diferiţi.

Director rădăcină

A B C

A B B B C C

B C C

? C C C

Fişier partajat

Fig.1 Sistem de gestiune a fişierelor conţinând un fişier partajat


Legătura la fişierul partajat (pus în comun) este numita link. Sistemul de gestiune este acum un graf aciclic directat
(directed acyclic graph-DAG), mai curând decât un arbore.
Partajarea fişierelor este convenabilă, dar introduce unele probleme: dacă directoarele conţin adrese de disc, ca în
CP/M, atunci o copie a adreselor de disc trebuie să fie făcută în directorul lui B atunci când fişierul este linkat. Dacă B sau C
modifică succesiv fişierul, noile blocuri vor fi scrise numai în directorul utilizatorului care a făcut modificarea. Schimbările
nu sunt vizibile de celălalt utilizator, ceea ce reprezintă o inconvenienţă a partajării.
Această problemă poate fi rezolvata în două moduri. O primă metodă constă în faptul că blocurile nu sunt organizate
în directoare ci constituie structuri de date de dimensiune redusă asociate fişierului. Directoarele trebuie să adreseze apoi doar
aceste structuri de date. Aceasta este abordarea utilizată în sistemul UNIX deoarece structura de date este chiar I-nodul.
În a doua soluţie, B se leagă la unul din fişierele lui C prin crearea de către sistem a unui nou fişier, de tip Link, şi
introducând acest fişier în directorul lui B. Noul fişier conţine doar numele căii fişierului la care se face legarea. Când B
citeşte din fişierul partajat, sistemul de operare vede că fişierul care este citit este de tip LINK, drept care caută numele
fişierului partajat şi citeşte acest fişier. Aceasta abordare se numeşte symbolic linking.
Dacă C încearcă să şteargă fişierul, sistemul este confruntat cu o problemă. Dacă şterge fişierul şi şterge I-nodul, B
va avea o intrare în director ce adresează un I-nod invalid. Dacă I-nodul este apoi reasignat altui fişier, legătura lui B va
adresa un fişier greşit.
Utilizând legarea simbolică, această problemă nu mai apare, deoarece doar adevăratul proprietar are pointerul către
I-nodul respectiv, ceilalţi utilizatori având doar calea.
O altă problemă care apare este aceea că la stocare sau back-up se pot face multiple copii ale fişierului partajat.
1.4 ORGANIZAREA FIŞIERELOR ÎN MS-DOS
Pentru a gestiona fişierele, sistemul de fişiere prevede directoare, care în majoritatea sistemelor sunt ele însele
fişiere. Un director obişnuit conţine câte o intrare pentru fiecare fişier, ca în figura de mai Jos.:

numele fişierului
tipul fişierului
ENTRY lungimea
posesor
ENTRY
informaţie de protecţie
ENTRY data şi ora creerii
data şi ora ultimei modificări
ENTRY
lista de blocuri utilizate

Cel mai simplu sistem este constituit dintr-un singur director care conţine toate fişierele (intările lor) pentru toţi
userii. Dar dacă mai mulţi useri încearcă să acceseze în acelaşi timp un fişier va apărea un conflict. Această metodă este
folosită în sistemele mai vechi.
O altă metodă este să existe câte un director pentru fiecare user. Acest model elimină conflictele dar rămâne un
neajuns: utilizatorii nu îşi pot organiza fişierele în grupuri.
Un sistem flexibil este acela în care fiecare utilizator poate avea oricâte directoare are nevoie.
Root Root
directory directory

a b c a b c

a a a b c c
Pentru un astfel de sistem de fişiere organizat sub forma unui arbore, există două metode de a identifica fişierele:
1. Fiecare fişier primeşte un nume de cale absolută (absolute path name) care constă într-o cale din directorul radacină.
2. Alt mod este precizarea numelui căii relative (relativ path name).
Acest procedeu este folosit în conjuncţie cu conceptul de director de lucru (director curent). Un utilizator poate desemna
un director curent şi în acest caz numele căilor nu încep de la rădăcină, ci sunt relative la directorul de lucru.
1.5 STOCAREA FIŞIERELOR
Un fişier este memorat pe un anumit mediu într-o secvenţă de blocuri care trebuie gestionată de sistem. Stocarea
consecutivă a acestor blocuri nu este un lucru fezabil.
O metodă realizabilă este stocarea blocurilor într-o listă înlănţuită. Există două dezavantaje:
1. Nmărul octeţilor de date nu mai este o putere a lui 2;
2. Accesul aleator este scump de implementat.
Totuşi ideea de reprezentare a fişierelor ca o listă înlînăuită s-a păstrat, însă pointerii sunt stocaţi în memorie. Se asociază
fiecărui disc o tabelă de alocare de fişiere (FAT). FAT-ul are o intrare pentru fiecare bloc de pe disc. Intrarea directorului
pentru fiecare fişier primeşte numărul primului bloc de pe disc al fişierului. Mai departe slotul din FAT corespunzător fiecărui
bloc conţine numărul blocului următor.
Acest model a fost utilizat pe discuri floppy pentru discuri floppy de 360 k cu dimensiunea blocului de 1 k.
Numărul de identificare al blocului este de 12 biţi existând deci 480 de octeţi în FAT.
Principala problemă a FAT-ului este că pointerii tuturor fişierelor de pe întreg discul sunt mixate aleator în
această tabelă. Deci e nevoie de întreg FAT-ul chiar dacă un singur fişier este deschis. O metodă mai bună ar fi păstrarea mai
multor liste de blocuri pentru fişiere diferite în locuri diferite. Această metodă este folosită de UNIX, unde fiecare fişier are
asociată o mică tabelă (pe disc) numită I-node. Fiecare I-nod conţine pointeri către 10 blocuri de date de pe disc plus încă 3
pointeri indirecţi.

I-NOD spre blocuri


de date
atribute
10 pointeri spre blocuri
de date
la blocuri
point. simplu
spre blocuri
point. dublu de date
point. triplu

spre blocuri
de date
Pentru primele 10 blocuri din fişier adresele sunt trecute chiar în i-nod, fiind foarte uşor de accesat. Pentru fişiere mai
lungi de 10 blocuri se alocă un bloc de pointeri pe disc ce va fi accesat prin intermediul primului pointer indirect. Pointerul
dublu către blocuri de pointeri ce pointează la blocuri de pointeri către blocuri de date. Pointerul triplu acţionează după un
raţionament similar. Doar cu ajutorul pointerului dublu pot fi accesaţi 64 kblocuri.
Esenţial la acest sistem este faptul că blocurile de pointeri indirecţi sunt utilizate (încărcate în memorie) doar dacă este
necesar, făcându-se cel mult trei referinţe la disc oricât de lung ar fi fişierul.
1.6 STRUCTURA DIRECTOARELOR
Înainte ca un fişier să poată fi citit el trebuie deschis de către sistemul de operare care preia de la utilizator numele căii
pentru a putea identifica blocurile de pe disc alocate fişierului.
În sistemul CP/M exista doar un singur director. Pointerii către blocurile de date de pe disc sunt stocaţi chiar în intrarea
directorului.
16
1 8 3 1 2 1
File name ... ...

User code ext. extent block count

Câmpul “user code” specifică apartenenţa fişierului la un anumit utilizator; câmpul


“extend” indică dacă fişierul are mai mult de o singură intrare în director; câmpul “block count” precizează câte din cele
16 blocuri sunt ocupate; ultimele 16 câmpuri conţin adresele a 16 blocuri pe disc. Sistemul nu poate determina lungimea unui
fişier cu precizie mai bună de un bloc.
Un sistem cu arbore de directoare ierarhic este MS-DOS.

8 3 1 10 2 2 2 44
File name Reserved Time Date Size

Extension Attributes First block number


O intrare într-un director MS-DOS are lungimea de 32 de octeţi. Câmpul “first block number” este utilizat ca un index în
FAT pentru identificarea următorului bloc.
Structura de directoare utilizată în UNIX este mult mai simplă: fiecare intrare conţine doar un nume de fişier şi numărul i-
nodului său. Toată informaţia despre un fişier se află în
i-nod. Toate directoarele din UNIX sunt fişiere. File nume

i-nod number
Când se deschide un fişier sistemul de gestiune trebuie să găsească numele fişierului şi blocurile de pe disc. Ex.:
Fie calea /usr/ast/mbox. Mai întâi se localizează directorul rădăcină, apoi se identifică prima componentă a căii căutând i-
nodul fişierului /usr. Din acest i-nod sistemul de fişiere localizează directorul pentru /usr şi caută în el componenta următoare
ast. Din acest i-nod şi identifică similar mbox. I-nodul acestui fişier este încărcat în memorie şi reţinut până când fişierul se
închide.
1 . mod 6 . mod 26 .
1 .. m\rime 1 .. m\rime 6 ..
4 bin data 26 ast data 17 src
6 usr 132 51 jim 406 60 mbox
14 lib
8 tmp
Identificarea fişierelor prin precizarea numelui căii relative se face similar, dar procesul de căutare începe din directorul
de lucru.
1.7 VERIFICAREA CORECTITUDINII GESTIONăRII FIŞIERELOR
Multe sisteme de operare citesc blocuri, le modifică iar apoi le scriu; dacă sistemul cade înainte ca toate blocurile
modificate să fie scrise, sistemul de gestiune a fişierelor poate rămâne într-o stare nedefinită. Această problemă este cu atât
mai gravă cu cât blocurile care nu au fost scrise sunt I-noduri, blocuri de directoare sau blocuri conţinând liste libere.
Pentru a rezolva această problemă multe calculatoare dispun de un program utilitar care verifică soliditatea gestiunii
fişierelor: programul este rulat ori de câte ori se execută secvenţa de boot, mai ales după o cădere a sistemului respectiv.
Probleme ce pot apare: blocuri lipsă, caz în care programul de verificare doar le adaugă în lista blocurilor libere; blocuri
alocate dublu în lista de blocuri libere (această problemă apare doar dacă se lucrează cu lista; cu bit-map este imposibil), în
acest caz programul de verificare reconstruind lista blocurilor libere; sau acelaşi bloc de date este prezent în două sau mai
multe fişiere. Dacă oricare din aceste fişiere este şters, blocul respectiv va fi pus în lista blocurilor libere, ajungându-se la
situaţia în care un acelaşi bloc este simultan şi liber şi ocupat; dacă ambele fişiere sunt şterse, blocul va fi trecut de două ori
în lista blocurilor libere.Verificarea se poate face în două moduri: pe blocuri şi pe fişiere.
La verificarea pe bloc programul construieşte o tabelă cu doi contori per bloc, fiecare contor fiind iniţializat cu 0. Primul
contor urmăreşte de câte ori un bloc este prezent într-un fişier; al doilea înregistrează cât de adesea este prezent în lista
blocurilor libere (sau în bit-map-ul blocurilor libere). După aceasta, programul citeşte toate I-nodurile; pornind de la un
I-nod programul poate construi o listă cu toate numerele blocurilor utilizate ce corespund fişierului. Pe măsură ce fiecare
număr de bloc este citit, primul contor este incrementat; programul examinează apoi lista blocurilor libere sau bit-map-ul
pentru a găsi toate blocurile care nu sunt utilizate. Fiecare apariţie a blocului în lista blocurilor libere sau bit-map este
contorizată în cel de-al doilea contor.

1.8 PERFORMANŢE ALE SISTEMULUI DE GESTIUNE A FIŞIERELOR


Accesul la disc este mult mai lent decât accesul la memorie, fapt pentru care multe sisteme de gestiune a fişierelor sunt
proiectate pentru a reduce numărul de accesuri la disc necesare.
Cea mai utilizata metodă pentru reducerea timpului de acces la disc este utilizarea unui bloc cache sau a unui buffer
cache. În acest context, cache-ul este o colecţie de blocuri care logic aparţin discului dar care, din motive de performanţă
sunt păstrate în memorie.
Pentru managementul cache-ului cea mai folosită metodă este de a verifica toate cererile de citire pentru a vedea dacă
blocul respectiv este în cache. Dacă este, cererea de citire este satisfăcută fără a mai accesa discul; în caz contrar, blocul este
mai întîi citit în cache şi apoi copiat oriunde este necesar.
Când un bloc urmează a fi încărcat într-un cache care este deja plin, unele blocuri trebuiesc şterse şi rescrise pe disc dacă
au fost modificate după ce au fost aduse în cache. Această situaţie seamănă foarte mult cu procesul de paginare astfel că toţi
algoritmii uzuali de paginare ca FIFO, a doua şansă (second chance) sau LRU sunt utilizabili. Diferenţa dintre paginare şi
cache este ca cache-ul face referiri relativ rare, astfel încât este posibil să se păstreze toate blocurile în ordinea strictă LRU cu
liste înlănţuite.
Problemele ce pot apare sunt asemănătoare cu cele ce apar la corectitudinea gestionarii fişierelor, prezentată în paragraful
precedent; dacă un bloc important (cum ar fi un I-nod) este scris în cache şi apoi modificat, dar nu este rescris pe disc, o
cădere a sistemului va părăsi sistemul de gestiune a fişierelor într-o stare nedefinită.
Dacă blocul este esenţial pentru corectitudinea gestionării fişierelor (de fapt, orice exceptând blocurile de date) şi a fost
modificat, acesta trebuie scris pe disc imediat, indiferent de sfârşitul listei LRU în care este pus.
Sistemul MS-DOS utilizează metoda de a scrie fiecare bloc modificat pe disc imediat ce a fost modificat: metoda este
numită write-through caches (implică, în schimb, mai multe operaţii de I/O cu discul).
La UNIX, toate modificările sunt stocate în cache şi sunt scrise pe disc la fiecare 30 de secunde sau ori de câte ori un bloc
este şters din cache.
1.9 SERVERE DE FIŞIERE
Sistemele de distribuţie dispun adesea de mecanisme prin care oferă servicii de fişiere altor mecanisme; ele sunt numite
servere de fişiere.
O metodă uzuală de a păstra un cost scăzut al sistemelor de distribuţie este de a permite existenţa unor utilizatori cu staţii
de lucru fără disc, permiţându-le accesul la fişiere prin trimiterea unor cereri READ şi WRITE prin intermediul unei reţele la
un server de fişiere comun.
Servere-le de fişiere pot prezenta o interfaţă către utilizator la oricare din următoarele trei nivele:
 disc la distanţă: în acest model, fiecare utilizator are alocat un disc virtual care este o porţiune privată din
discul serverului de fişiere. Utilizatorii pot folosi discul virtual în acelaşi mod ca şi un disc local; serverul de
fişiere furnizează comenzi READ BLOCK şi WRITE BLOCK exact ca şi un disc local. Ca urmare, reţeaua este
utilizată pentru a simula un controler de disc; toate codurile de gestiune a fişierelor în calculatoarele
utilizatorilor rulează exact ca în cazul unui disc local.
 sisteme de gestiune la distanţă fără servicii de directoare (serviciile de directoare se fac local): comenzile
sunt disponibile pentru a crea şi şterge fişiere, citire, scriere, căutare de fişiere şi alte operaţii specifice lucrului
cu fişiere. Când utilizatorul creează un fişier, serverul de fişiere returneaza, în general, un identificator care
poate fi utilizat pentru operaţiile viitoare cu fişierul respectiv. Identificatorul poate fi, spre exemplu, un număr
aleator de lungime mare pentru a împiedica aflarea lui de către utilizatori neautorizaţi (aceşti identificatori sunt
analogi cu numerele I-nodurilor stocate în directoarele UNIX). O problemă care apare în acest caz este: dacă un
utilizator creează un fişier pe un server de fişiere şi apoi sistemul cade înainte de înregistrarea identificatorului
într-un director, fişierul este ”pierdut”. Fişierul va continua să existe dar nu va putea să fie accesat niciodată,
deoarece identificatorul său nu este cunoscut; singura cale de a ieşi din această situaţie este de a avea
posibilitatea ca serverul de fişiere să furnizeze o comandă prin care utilizatorul poate cere o listă completă cu
toate fişierele sale.
 sisteme de gestiune completă la distanţă: în acest caz, comenzile disponibile permit nu numai manipularea
fişierelor, ci şi crearea şi ştergerea directoarelor, schimbarea directorului de lucru, realizarea şi distrugerea legaturilor la
fişierele existente şi alte operaţii similare. Sistemul apare ca fiind local.
1.10 BACKUP ATOMIC
Dacă se face actualizarea unei înregistrări fie că operaţia se execută complet (se verifică şi totul este corect), fie că nu (şi
în acest caz utilizatorului îi revine sarcina să reia operaţia de modificare), părăsirea sistemului are loc în starea sa originală.
În cazul serverelor care oferă toleranţă la erori, backup-ul atomic implementează, de obicei, un driver de disc logic ca drivere
fizice; când informaţia este scrisă în blocul logic n serverul mai întîi scrie informaţia la blocul fizic n de pe driverul 1. Apoi îl
citeşte pentru a verifică că ceea ce a scris este corect; dacă totul este corect serverul scrie apoi aceeaşi informaţie în blocul
fizic n de pe driverul 2 şi verifică de asemenea. Această tehnică se numeşte depozit stabil (stable storage). Dacă apare o
cădere în timpul scrierii la oricare din drivere, blocul în curs de scriere va da o eroare de sumă de control; atâta timp cât
aceasta poate fi detectată blocul bun poate fi utilizat pentru a suprascrie blocul defect. Dacă serverul cade în timp ce se scrie
pe driverul 1 sistemul va fi readus la starea lui originală; oricum sistemul nu rămâne într-o stare intermediară ambiguă.
O idee derivată din update-ul atomic este cea a fişirelor multiversiune (multiversion files); în acest caz un fişier nu este
niciodată modificat după ce a fost creat. Schimbările sunt înregistrate prin cererea unei copii temporare a fişierului,
modificarea copiei, iar schimbările devin permanente prin ”îngheţarea” copiei temporare printr-un update atomic (se verifică,
că noua versiune este corectă şi abia apoi se şterge vechea versiune).
1.11 SECURITATEA FIŞIERELOR
Fişierele conţin informaţii foarte importante pentru utilizatori. Implementarea mecanismelor de securitate a fişierelor este,
din această cauză, o cerinţă majoră a sistemelor de operare. Acestea conţin mecanisme de protecţie date de politica de
protecţie adoptată. Prin securitatea fişierelor se înţelege starea lor protejată la accesul utilizatorilor neautorizaţi precum şi la
orice pierdere de date.
Cele mai importante cauze ale pierderilor de date sunt:
- cazuri de forţă majoră (incendii, calamităţi, deteriorări ale aparaturii);
- erori hard/soft (dischete, erori CPU, erori de comunicaţii, greşeli de programare);
- erori umane (tastări greşite, rulări incorecte de programe).
Aceste pierderi pot fi prevenite în general prin păstrarea de copii în locuri protejate, chiar departe de locul datelor
originale.
Accesele neautorizate la date strict confidenţiale pot fi:
- întîmplătoare (utilizatori cărora nu li s-a interzis accesul la unele date);
- conştiente, fără intenţii rele (programatori buni care "sparg" sistemele);
- conştiente, cu intenţii rele (pentru bani, furt de informaţii, eludarea taxelor);
- spionaj militar, comercial, terorism (între state adverse, corporaţii concurente).
De asemenea trebuie asigurată confidenţialitatea, privită ca respectarea drepturilor individuale de acces la date,
împiedicînd folosirea datelor proprii de alte persoane fizice sau juridice, chiar şi de stat sau justiţie, inclusiv de proiectantul
sistemului.
2.Noţiuni, exemple şi importanţa implementării funcţiilor predefinite în procesarea
fişierelor în limbajul C
În ceea ce priveşte limbajul C , se poate de reprezentat un fişier ca un tablou gigantic permanent , în care un
program poate să scrie sau să citească datele. Un fişier trebuie să conţină elemente de aceeaşi natură , de un
conţinut omogen . Contrar altor limbaje, conţinutul unui fişier C nu este structurat la timp. Din contra aceste
donaţii sunt simplu aranjate sub forma unui şir de caractere(octeţi). Iată de ce un fişier este câteodată denumit flux
de donaţii. Fiecare caracter (octet conţinând caracterul ) luat individual poate fi localizat în fişier printr-un index.
Mai mult ca atât ca un fişier să fie considerat ca un şir nonstructurat de octeţi , îi încredinţează programatorului să
creeze o structură de fişiere aşa ca datele să fie administrate cum îl aud. Pentru aceasta dispune de o serie de
funcţii adaptate , care îi permit să manipuleze datele de toate dimensiunile şi toate tipurile.
În C se poate de lucrat pe două fişiere cu două niveluri : nivelul inferior; nivelul superior
La nivelul inferior se folosesc metode de acces elementar , fondat pe funcţiuni, care se bazează pe rutinele
corespondente ale sistemului de exploatare , relative . Funcţiile nivelului inferior depind direct de sistemul de
exploatare, şi nu fac parte din standardul ANSI. Accesele la fişierele nivelului superior se fac într-o manieră puţin
mai elementară şi mai facilă Ele sunt fondate pe funcţii predefinite relativ complexe , independente de sistem de
exploatare, si implementate pe funcţii de nivel înalt.
Operaţiile neelementare. Deoarece un program trebuie să citească sau să scrie datele într-un fişier , printr-o
metodă de acces de un nivel mai înalt, informaţiile trec pentru a ajunge la destinaţia lor printr-un bufer (tampon).
Acest bufer este o zonă de memorie RAM în care sunt temporar stocate, înainte de a fi transferate la destinaţie ,
informaţii citite sau scrise în fişier . Avantajul constă: că nu este necesar de a declanşa o operaţie de intrare / ieşire
specific pentru fiecare informaţie citită sau scrisă . Din contra o singură operaţie în program permite de a scrie un
bloc de informaţii în bufer.
Structurile FILE. Dislocarea memoriei din bufer de tip intare /ieşire de un oarecare fişier este furnizat de
variabile de tip FILE. Acesta e dotat cu valori când un program deschide un fişier pentru a-l manipula . Tipul
FILE este definit ca o structură, header <stdio.h>. Câmpurile sale conţin adresa tamponu-lui: un pointer spre
caracterul lui următor în bufer, numărul de carctere, starea fişierului (dreptul de acces, natura operaţiei efectuate
asupra fişierului ) şi descriptor . Descriptorul este un număr întreg care identifica fişierul dat .
După cum defineşte limbajul C noţiunea de fişier, el se poate referi la un fişier disc, ecran, tastatură, port, fişier
bandă, etc. Deşi fişierele diferă ca formă stream-urile sunt aceleaşi. În C un stream este o interfaţă logică între
computer şi unul din diferitele perifericele sale dar, în general între computer şi un fişier. Un stream este asociat
unui fişier cu ajutorul comenzii ‘open’ şi eliberat de el prin intermediul ‘close’. Există două tipuri de stream-uri:
binar şi text. Stream-ul text se utilizează pentru lucrul cu caractere ASCII. Trebuie de remarcat însă, că atunci
când lucrăm cu un stream text apare translatorul de caractere, astfel întâlnindu-se cu un caracter ‘newline’, de
exemplu, el este convertit într-un cod ‘caricatură’, de acea nu întotdeauna ceea ce vom tasta la monitor va fi salvat
în fişerul text. În cazul celor binare translatorul nu apare, în fişier înscriindu-se fiecare bit
Un fisier este o structura dinamica, situata in memoria secundara ( pe flopyy disk-uri sau harddisk-uri );
numarul de elemente ale unui fisier este variabil, chiar nul.. Limbajul C permite operarea cu fisiere:
 de tip text - un astfel de fisier contine o succesiune de linii, separate prin NL ('\n')
 de tip binar - un astfel de fisier contine o succesiune de octeti, fara nici o structura.
Definiţia structurii FILE în < stdio.h> poate să varieze de la un sistem la altul , în ceea ce priveşte numărul
tipul, şi numărul câmpurilor . Ea conţine întotdeauna informaţii precedent descrise .
typedef struct { char buffer; /* pointerul spre adresa tamponului */
char */ pointerrul spre caracterul următor în tampon */
int cnt; /* numărul de caractere în tampon */
int flags ; /* biţi dând starea fişierului */
int fd ; /* descriptorul */ } FILE;
Fişierul <stdio.h> conţine declaraţia unui tablou de oarecare structuri FILE. Fiecare element din acest tablou
este o variabilă structurată, care poate să stocheze informaţii relative la un fişier, sub forma precedent descrisă.
Pentru a acceda concret la un fişier în programul dat, trebuie de utilizat un pointer spre o variabilă de tip FILE.
Trebuie de definit pointerul: FILE * fp ; /* pointer spre variabila structurată FILE
Definiţia precedentă crează un pointer fp de tip pointer spre FILE, capabil de a memoriza adresa unei
variabile structurate FILE. Deoarece un fişier este deschis pentru a fi manipulat, funcţia competentă caută o
structură FILE disponibilă în tabloul precedent evocat. Adresa acestei variabile structurate este afectată la un
pointer ad.hoc, aşa ca fp. Toate accesele ulterioare se vor face prin intermediul acestui pointer.
Imaginea următoare ilustrează conexiunea între un program şi un fişier la care accedează programul:
Structurile
FILE
Pointer spre tampon

Poiter spre caracterul


următor în tampon
Numărul de acractere
în tampon
Descriptor

Scierea
Pointer
FILE Citirea

Program tampon

2.1 Deschiderea fişierelor


Înainte ca un program să poată manipula un fişier , el trebuie să înceapă prin a-l deschide. Deschiderea unui
fişier pentru programul dat constă prin a deschide un acces cu ajutorul sistemului de exploatare :în caz de reuşită
el va acţiona aranjând într-o structură FILE în vederea operaţiilor ulterioare asupra fişierului . Toate aceste acţiuni
sunt efectuate prin funcţia predefinită fopen.
Iată prototipul funcţiei : FILE *fopen (char *  nume_fişier ,char* mod_ acces )
Fopen returnează efectiv pointerul spre tipul FILE .Acest pointer o întoarce spre structură în care funcţia
aranjează informaţiile conţinute în fişierul deschis. Parametrul nume_fişier este un pointer spre şirul de
caractere ce conţine numele fişierului conţinut. Parametrul mod_acces este un pointer spre şirul de caractere ,
care indică natura operaţiilor pe care programul va trebui să-l execute după deschiderea fişierului. Să presupunem
că se doreşte să se deschidă un fişier .
Trebuie de început prin definirea pointerului FILE: FILE */ defineşte un pointer FILE */
Pentru a efectua operaţia propriu-zisă:
Fp=fopen (xyz,dat, r): /* deschide fişierul */
Dacă ea reuşeşte , adresa structurii FILE conţinând informaţiile relative fişierului este afectat de pointerul Fp
Dacî fişierul nu-l va găsi în repertoriul indicat , funcţia fopen se fondează pe modelul r . El returnează atunci
valoarea NULL .
/* open xyz încearcă fişierul xzy.dat */
#include <stdio.h > /* pentru FILE , open , printf */
main () {
FILE fp ; / defineşte pointerul fişierului */
if (( fp=fopen (xyz.dat, a))==NULL /* încearcă să deschidă fişierul */
printf ( eroare : imposibil de deschis fişierul /XYZ:dat /./n);
printf ( fişier / xyz.dat / deschide .n);
În acest exemplu de program funcţia fopen nu reîntoarce pointerul nul dacă fişierul nu există. Din contra,
fişierul este creat în acest caz în repertoriul curent. Funcţia fopen returnează NULL dacă fişierul nu poate fi
deschis printr-o altă cale.
2.2 Fişierele texte şi fişierele binare
Conceptul de fişier-text corespunde la reprezentarea unui fişier sub forma unui şir de linii ; fiecare din ele
fiind compuse dintr-un oarecare număr (0 la n) de caractere şi terminînd printr-un caracter special. Din contra un
fişier binar corespunde la un simplu şir de octeţi .
Un mare număr de sisteme de exploatare (aşa ca DOS) disting fişierele texte de cele binare nu doar la nivel
logic , dar şi la nivel fizic. Aceste reprezentaţii diferite de caracterul de la sfârşitul liniei în tampon şi în fişier au
poziţia X. Aceasta se traduce cam complicat , dacă fişierul text nu este manipulat , dar contrariu tratatelor de
acces direct . În efect în acest caz conversia caracterelor de la sfârşitul liniei nu a avut loc. Conţinutul fişierului de
tip text , se disting fizic, deoarece este interpretat ca fişier binar.
Caracterul de la sfârşitul liniei utilizat de fişiere texte poate pune probleme asupra numerelor sistemelor.
Pentru a deschide un fişier în mod binar trebuie de adăugat litera b la şirul de caractere care specifică modul său
de acces . rb va semnifica că fişierul este deschis în mod binar şi în lectură . Dacă stringul care dă modul de acces
conţine un caracter +, atunci b poate să fie plasat înainte sau după semnul+.
Într-un fişier text, toate datele sunt memorate ca şiruri de caractere, organizate pe linii, separate între ele prin
marcajul sfârşit de linie ‘\n’ .
Într-un fişier text spaţiul de memorare pe disc nu este folosit în mod eficient pentru datele numerice (astfel
întregul 12345 ocupă 5 octeţi).
Într-un fişier binar, datele sunt păstrate în formatul lor intern (2 octeţi pentru int, 4 octeţi pentru float, etc).
La fişierele text marcajul de sfârşit de fişier (caracterul 0X1A) există fizic în fişier. La întâlnirea acestui
caracter funcţia fgetc() întoarce EOF (-1). Marcajul de sfârşit de fişier se generează de la tastatură prin Ctrl-Z.
În cazul fişierelor binare, marcajul de sfârşit de fişier nu există fizic în fişier, ci este generat de funcţia fgetc().
În MS-DOS (şi în Unix), la nivelul liniei de comandă intrările şi ieşirile standard pot fi redirectate în fişiere
disc, fără a opera nici o modificare la nivelul programului. Astfel:
< redirectează intrarea standard către fişierul specificat
> redirectează ieşirea standard către fişierul specificat
Fişierul standard de eroare nu poate fi redirectat. Fişierul specificat poate fi:
con – pentru consola sistem (tastatura, respectiv ecranul)
prn – pentru imprimanta paralelă
com1 – pentru interfaţa serială de date
nume_fişier – pentru un fişier disc
NUL – pentru perifericul nul.
Exemple:
> test.exe > prn redirectează ieşirea programului la imprimantă
> test.exe < f1.dat > f2.dat redirectează atât intrarea cât şi ieşirea programului
int fseek(FILE *fp, long offset, int whence);- repozitioneaza pointerul asociat unui fisier . Offset - numarul de
octeti intre pozitia data de whence si noua pozitie. Whence - are una din cele trei valori posibile:
SEEK_SET = 0 - Cautarea se face de la inceputul fisierului
SEEK_CUR = 1 - Cautare din pozitia curenta
SEEK_END = 2 - Cautare de la sfirsitul fisierului
int feof(FILE *fis);- returneaza 0 daca nu s-a detectat sfarsit de fisier la ultima operatie de citire, respectiv o
valoare nenula ( adevarata ) pentru sfarsit de fisier.

Argumentele liniei de comanda


La lansarea in executie a unui fisier executabil, in linia de comanda, pe langa numele fisierului s epot
specifica argumente, care se transmit ca parametrii functiei main. Antetul functiei main va fi atunci:
int main( int argc, char ** argv )
argc - reprezinta numarul de argumente
argv -este un pointer la un tablou de siruri, reprezentand argumentele.
Argumentele liniei de comanda vor fi sirurile:
argv[0] - numele fisierului executabil
argv[1]
...
argv[argc-1]
Programul urmator tipareste argumentele liniei de comanda:
// fisier listare.c
#include<stdio.h>
int main( int argc, char** argv){
int i;
puts("Argumente:");
for(i=0;i<argc;i++)
puts(argv[i]);
return 0;
}
O linie de comanda de forma:
listare iata patru argumente
va lansa in executie listare.exe, care va tipari pe ecran:
listare.exe
iata
patru
argumente:

2.2.1 Închiderea fişierelor


Când un fişier nu mai serveşte , el se poate închide. Legătura sa cu pointerul FILE corespunzător este
întrerupt. Funcţia nivelului înalt competent pentru a închide un fişier este fclose .Teoretic s-ar putea de renunţat să
apeleze explicit fclose în program . Fclose este chemat automatic la sfârşitul programului , pentru a închide toate
fişierele încă deschise.
Funcţia predefinită fclose admite prototipul:
int fclose (FILE * pointer_fişier );
Ea posedă ca parametru un pointer spre tipul FILE . Fclose returnează valoarea 0 dacă a putut să deschidă
fişierul ataşat la pointer_fiţier .
Următorul exemplu de program încearcă să deschidă un fişier a cărui nume e trecut pe linia de
comandă .Dacă va reuşi , fişierul este reînchis cu ajutorul funcţiei fclose
/* openclose arată cum se deschide şi se închide un fişier a cărui nume a dat pe linia de comandă. */
#include stdio.h  /* printf , fopen , close */
#include stdlib.h /* exit */
#define READ “r”
main(int argc, char *argv ) 
FI LE *fp;
if (argc! =2) /* un singur parametru admis */
 printf(?*=(“nsintaxa: opnclose fişier .exit/n”); exit(0); 
if ((fp=fopen (argv1, READ ))==NULL) /*deschiderea fişierului în citire */
printf(“EROARE:imposibil de deschis fişierul %s./n”, argv 1 );
else  fclose (fp); /* deschiderea fişierului */
printf (“fişierul %s a fost închis. /n”, argv 1 );  
2.3. Operaţiile de citire şi de scriere
Pentru a citi sau a scrie datele unui fişier , se dispun de funcţii analogice a celor care servesc la prinderea
datelor la clavir şi la afişarea lor la ecran . Poziţia la care se citeşte sau se scrie într-un fişier este dat de un pointer
specific (seek pointer ), utilizat pentru operaţiile de lectură şi scriere. Acest pointer este condus de un sistem de
exploatare : el semnalează poziţia de tratare a mişcării într-un fişier. După fiecare lectură şi scriere acest pointer
este deplasat. Acest deplasament este efectuat prin sistem. Să presupunem că se citesc trei caractere (pe imaginea
următoare : A ,B, C) de un fişier X
SEEK pointer(citirea /scrierea )

A B C D E F G H

2.3.1 citirea şi scrierea cu caractere


Funcţiile fputc şi fgetc permit de a scrie sau de a citi caracterele izolate în fişier.
Iată prototipul funcţiei fputc : int fputc (intcaracter , FILE pointer _fişier).
Ea transferă un caracter dat ca prim parametru , în fişierul reprezentat prin pointer_fişier. Tipul caracterului
este convertit de int cu unsigned char. Valoarea fputc nu este altceva decât caracterul scris sau mai bine EOF în
caz de eroare .Să presupunem că este un pointer ataşat la un oarecare fişier , pointerul conţinând adresa structurii
FILE aferente. Deci instrucţia :
fputc(“A”, fp); /* scrierea unui caracter în fişier */
scrie caracterul A în fişierul ataşat la fp , la poziţia tratamentului curente.
Citirea cu caractere cu ajutorul funcţiei fgetc Omologul funcţiei fputc este funcţia fgetc care citeşte un
singur caracter în fişier.

int fgetc (FILE * pointer_fişier);  /* prototipul lui fgetc */
Funcţia fgetc returnează caracterul citit sub forma unei valori int. Dacă valoarea trimisă este EOF , sfârşitul
fişierului a fost atins sau are o eroare. Valoarea EOF explică de ce caracterul citit este returnat sub forma valorii
int şi nu valorii char.
Programul următor arată o aplicare elementară cu fgetc şi fputc. El scrie în fişier un text introdus de la
tastatură. Numele fişierului este introdus de utilizator .
/* scrie în fişier un text în lungime introdus de la tastatură, apoi afişează la cerere. Operaţiile */
/* de I/E în fişier utilizează funcţiile fgetc şi fputc. */
# include stdio.h /* fgetc, fputc, getchar , printf */
# include conio.h /* getche , getch */
# include ctype.h /* toupper */
# include stdlib.h /* exit */
#define END 64 /* caractere @ */
main () 
FILE *fp; /* pointer spre structura FILE */
char fillename 81; /* numele fişierului */
int I , repl, rep 2; /* variabile de control */
int c ; /* caracterul tampon */
printf (“Înregistrarea textului. Numele fişierului */n” );
do  printf (“ /n Fişier :”); gets (file name);
if (( fp=fopen (filename, “r” )) !=NULL)
 printf (“Fişierul existent. Să-l înlocuiască  (0/n)”);
repl=getche(); repl=toupper (repl); if (repl !=”0”) fclose (fp); 
else /* fişierul nu mai există */
break; /*sfârşitul buclei */
 while ( repl==”0”);
if (fp !=NULL) /* fişier înlocuit ,deci : */
fclose (fp); /* se închide şi se redeschide în scriere */
if ((fp=fopen (filename , “w”))==NULL
 printf(“n imposibil de scris în fişier . /n” ); exit(1); 
printf(“/n introduceţi textul”);
while ((c=getchar ()) !=END) /*scie textul în fişier */
fputf (c, fp); fclose (fp);
/*** afişarea conţinutului fişierului **********/
printf (De afişat fişierul (0/n”);
rep2=getche(); rep2=toupper (rep2);
if (rep2==”o”)  if ((fp=fopen (file name, “r” )) ==NULL)
 printf(“/n Eroarea deschiderii fişierului. /n”); exit(2);
printf(“/n Conţinutul fişierului %s :/n “, filename);
I=0;
while ((c= fgetc(fp)) !=EOF /*citirea caracterului în fişier */
 putchar(c); /* afişarea caracterului */
if (c==”/n”) /* numărul liniilor */
I++; If (I==20) /* nouă pagină pe toate 20 linii */
 printf (“/n Intrare pentru pagina următoare.” ); getch(); I=0; 
 /* fin while */
fclose (fp);  /* fin if rep2==”0” */ 
Comentarii: Programul dat verifică dacă fişierul în care trebuie de scris există deja. Pentru aceasta el încearcă
să-l deschidă. Dacă fişierul există funcţia fopen întoarce un pointer spre structura FILE. Dacă nu , el trimite
NULL. Şi dacă nu vrea să zdrobească un fişier existent , îl închide şi se poate atunci de ales o altă denumire a
fişierului. Deci programul deschide fişierul în scriere şi utilizează funcţia fputc pentru a scrie textul ales la
tastatură. Apoi fişierul este din nou închis . Dacă se doreşte să se afişeze conţinutul său fişierul este redeschis, dar
de această dată pentru a-l citi. Fiecare deschidere a fişierului în mod r sau w , plasează pointerul de pe poziţia lui
(seek pointer) la începutul fişierului. Acesta din urmă este întotdeauna citit, chiar de la început. În caz de
deschidere , pointerul va fi plasat la sfârşitul fişierului. Pentru a citi datele la tastatură , programul dat ,înlocuieşte
cu funcţia getchar. Este un fişier periferic în care se pot scrie datele , nu doar cu ajutorul funcţiei fputc sau putc.
2.4. Fişierele periferice standarde şi pointerii FILE predefiniţi
De obicei , în pornirea unui program în limbajul C sunt automatic deschişi 5 fişiere periferice aşa ca:
1. intrarea standard
2. ieşirea standard
3. ieşirea standard pentru erori
4. fişierul special de intrare/ieşire auxiliar
5. imprimanta standard
În principiu , intrarea standard este claviatura , iar ieşirea standard este ecranul . Ieşirea erorilor standard este
constituit din ecran . Un fişier special suplimentar este prevăzut pentru operare de I/E efectuate printr-un periferic
conectat în serie .Se poate de modificat afecţiunea fişierelor speciale standard la perifericile , pe care noi vrem să
le evocăm.
Rezumatul care urmează arată relaţia între pointerii FILE predefiniţişi fişierele periferice:
Imprimanta standard permite de a dirija datele spre o imprimantă .
Pentru aceste 5 fişiere speciale este definit în stdio.h un pointer FILE care o întoarce spre o structură FILE
adecvată şi care este ataşat fişierului periferic concernat. Denumirile acestor pointeri FILE sunt: stdin, stdout ,
stdrn , stdaux şi stdrn . Ultimii nu sunt pointeri variabili , ci pointeri constante de tip FILE . Ca şi toate
constantele , pointerii constante FILE nu sunt lvalue.
În limbajul C sunt utilizate două tipuri de fluxuri: fluxuri text şi ] fluxuri binare. Fluxul text este un şir de caractere
ASCII şi este utilizat pentru fişierele uzuale DOS. Aceste fluxuri sunt formate din linii, despărţite de caracterul LF (line
feed). La înscrierea pe disc, de exemplu, a fişierului fiecare caracter LF este înlocuit cu două caractere: CR/LF (carriage-
return şi linefeed). La citirea fişierului text, fiecare pereche de caractere care separă liniile sunt înlocuite printr-un caracter
LF. Prin urmare, în aşa operaţii de intrare/ieşire nu există o relaţie univocă între simbolurile din flux şi cele din fişier.
Fluxul binar este un şir de octeţi care se află într-o corespondenţă biunivocă cu informaţia din fişierul respectiv. Deci,
informaţia transmisă în fluxul binar sau citită dintr-un flux de acest tip nu cere o prelucrare suplimentară. Aşa cum unui
fişier i se poate asocia orice tip de flux, el poate fi accesat în orice mod.
Într-un program Turbo C, în afară de fluxurile definite de programator, pot fi utilizate încă cinci fluxuri predefinite
(standard), care sunt deschise automat o dată cu lansarea programului. Acestea sunt:
• stdin - flux de tip text pentru operaţia de intrare, asociat consolei (tastaturii);
• stdout - flux de tip text pentru operaţia de ieşire, asociat consolei (ecranului);
• stderr - flux de tip text pentru operaţia de ieşire, asociat ecranului (eroare standard);
• stdaux - flux de tip binar pentru operaţia de intrare/ieşire auxiliară;
• stdprn - flux de tip binar pentru operaţia de ieşire, asociat imprimantei.
Primele trei fluxuri sunt compatibile cu standardul ANSI şi, cu toate că ele sunt asociate implicit consolei, fluxurile
stdin şi stdout permit redirectarea de către sistemul de operare spre alte dispozitive. Numele fluxurilor predefinite sunt
constante pointer către tipul FILE şi ele, deci, nu pot fi nici deschise cu ajutorul funcţiei fopen() şi nici închise.
Pointerul la fişier va fi asociat unui anumit flux în momentul deschiderii acestuia prin utilizarea funcţiei fopen(),
al cărei prototip este: FILE* fopen (char *fnume, char * mod_ acces );
Parametrul fnume al funcţiei este un pointer către structura FILE şi care constituie un şir de caractere valid pentru
sistemul dat de operare. În particular, acest nume poate să specifice calea spre fişier care urmează a fi deschis. Parametrul
mod_ acces este un pointer către un şir de caractere care indică modul în care va fi deschis fişierul respectiv. Valorile posibile
ale acestui parametru sunt prezentate în tabelul următor.
Mod Acţiune
"r" Deschide un fişier text pentru citire.
"w" Creează un fişier text pentru scriere. Dacă fişierul există, conţinutul este distrus.
"a" Deschide un fişier text pentru scriere la sfвrşit (adăugare). Dacă fişierul nu există, se creează.
"rb" Deschide un fişier binar pentru citire.
"wb" Deschide un fişier binar pentru scriere.
"ab" Deschide fişierul binar pentru scriere la sfвrşit (adăugare).
"r+" Deschide un fişier text pentru citire/scriere.
"w+" Creează un fişier text pentru citire/scriere. Dacă fişierul există, conţinutul este distrus.
"a+" Deschide un fişier text pentru adăugare sau creează pentru citire/scriere un fişier gol.
"r+b" Deschide un fişier binar care există pentru citire/scriere.
"w+b" Creează un fişier binar gol pentru citire/scriere.
"a+b" Deschide un fişier binar pentru adăugare sau creează un fişier pentru citire/scriere.
"rt" Deschide un fişier text pentru citire.
"wt" Deschide un fişier text pentru scriere.
"at" Deschide un fişier text pentru adăugare.
"r+t" Deschide un fişier text pentru citire/scriere.
"w+t" Deschide un fişier text pentru citire/scriere.
"a+t" Deschide un fişier text pentru adăugare sau îl creează pentru citire/scriere.
Dacă operaţia de deschidere a fişierului s-a terminat cu succes, funcţia fopen() returnează un pointer către structura
FILE asociată cu fişierul. In cazul în care operaţia de deschidere se termină cu eşec, funcţii fopen() returnează valoarea
NULL (pointerul null). Acest pointer este
definit în fişierul stdio.h.
Dacă funcţia de deschidere a fişierului fopen() leagă fluxul cu un fişier, atunci funcţia fclose() distruge această
legătură, adică închide fluxul deschis şi goleşte zona tampon. Prototipul funcţiei este: int fclose(FILE*fp);
Aici fp este pointerul returnat de funcţia fopen(). Apariţia în program a funcţiei fclose() conduce la memorarea
automată a datelor din zona tampon pe disc, indiferent de faptul dacă este sau nu plin tamponul, şi la eliberarea memoriei
alocate tamponului şi structurii FILE. Funcţia returnează în cazul operaţiei reuşite de închidere a fişierului valoarea 0, iar în
caz de eroare - valoarea -l (EOF).
Alte funcţii de prelucrare a fişierelor şi definite în stdio.h sunt:
Funcţia Acţiunea funcţiei
putc() Scrie un caracterl în fişier.
getc() Citeşte un caracter din fişier.
fputs() Scrie un şir de caractere în fişier.
fgets() Citeşte un şir de caractere în fişier.
fseek() Schimbă poziţia pointerului în fişier la o nouă locaţie.
fprintf() Înscrierea cu format în fişier.
fscanf() Citeşte cu format din fişier.
feof() Întoarce o valoare diferită de 0, dacă s-a ajuns la sfвrşitul fişierului.
fread() Citeşte un articol din flux.
fwrite() Înscrie în flux un articol.
rewind() Repoziţionează pointerul fişierului asociat fluxului la început de fişier.
remove() Şterge fişierul.
Exemple pentru functiile ce opereaza cu fisiere specificate de utilizator:
 pentru un caracter:
int getc(FILE *fis);- returneaza un caracter din fisierul precizat convertit la un intreg fara semn, iar la
eroare returneaza EOF
int ungetc(int c, FILE *fis);- inapoiaza caracterul c in fisierul deschis pentru citire
int putc(int c, FILE * fis); - trimite caracterul in fisierul deschis pentru scriere, la eroare returneaza EOF
 pentru un sir de caractere:
char *fgets(char *s, int n, FILE *fis);- citeste maxim n-1 caractere sau pina la '\n' inclusiv, si le depune in s,
adauga la sfirsit '\0' si returneaza adresa sirului. La eroare intoarce valoarea NULL
int fputs(const char *s, FILE *fis); - scrie sirul in fisier, fara caracterul '\0'. La eroare intoarce EOF.
 pentru scriere si citire cu format:
int fscanf (FILE *fis, const char *format [, adresa, ...]); - numarul de adrese trebuie sa corespunda cu
numarul de specificatori de format. Formatul contine - caractere spatii - se sare peste spatii pina la primul
caracter nespatiu - caractere obisnuite - caractere ASCII, mai putin '%', se trece peste un caracter corespunzator in
intrare
specificatorul de format: % [*] [width] type
- se sare peste urmatoarea data
- width - nr. de maxim de caractere ce se citesc
- type - tipul informatiei citite:
 - octal , u - fara semn, x,X - hexa
- d - zecimal, l - long, f - float, lf - double,
- e,E- format stiintific, c - char, s - sir
int fprintf (FILE *fis, const char *format [, argum...]); - preia un sir de argumente si le aplica formatul
corespunzator, dupa care le scrie in fisierul dat. Formatul contine - caractere obisnuite, care apar la fel la iesire
specificatori de format (egal sau mai mic decit numarul de argumente): % [fanion] [width][.prec] type
 fanion - alinierea la dreapta sau stinga, prezenta semnului, etc.
 width - numarul minim de caractere ce se afiseaza
 prec - precizia
  conio.h - functii de intrare, iesire pentru consola
void window(int left, int top, int right, int bottom);- defineste o fereastra text precizata prin colturile stinga sus,
dreapta jos
void clreol( void );- sterge intr-o fereastra text de la cursor pina la sfirsirul liniei
void clrscr( void );- sterge fereastra text activa si muta cursorul in pozitia 1,1
void gotoxy( int x, int y );- muta cursorul la coordonatele date
int wherex( void );- returneaza coordonata curenta x
int wherey( void );- returneaza coordonata curenta y
int getch( void ); - citeste un caracter fara a-l afisa la consola
int getche( void ); - citeste si afiseaza caracterul
int kbhit( void ); - verifica daca a fost apasata o tasta
int putch( int c );- pune un caracter in fereastra text curenta.
  stdlib.h - contine tipuri, variabile si functii uzuale
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define min(a,b) (((a) < (b)) ? (a) : (b))
pentru conversia unui sir:
double atof(const char *s);- returneaza valoarea reala obtinuta prin conversia sirului, iar la eroare
valoarea 0
int atoi(const char *s); - converteste sirul la un intreg
long atol(const char *s); - converteste sirul la un long
pentru terminarea programului:
void exit(int status); - termina programul si inchide toate fisierele. Parametrul status indica terminare
normala (valoarea 0) sau anormala.
void abort(void);- termina anormal programul
pentru alocare dinamica:
void free(void *bloc);- elibereaza memorie alocata dinamic anterior
void *malloc(dim_t nr);- aloca nr locatii de memorie de cite sizeof(dim_t) octeti. La succes returneaza
adresa de inceput a zonei alocate, la eroare returneaza NULL
cautare binara:
void * bsearch(const void *key, const void *base, size_t nelem, size_t width, int (*fcmp)(const void *,
const void *));- returneaza adresa primei intrari din tablou care coincide cu parametrul cautat si zero daca acesta
nu exista in tablou. ( key- adresa cheii cautate, base- inceputul tabloului, nelem- nr.elemente din tablou, width-
dim. unui elem. de tablou, fcmp- functia de comparare definita de utilizator si care primeste doi parametrii )
sortare cu algorimul Quicksort:
void qsort(void *base, size_t nelem, size_t width, int (*fcmp)(const void *, const void *));- sorteaza
tabloul dat.
Funcţii de citire/scriere fără conversie Funcţiile efectuează transferuri de secvenţe de octeţi între memoria internă şi un
fişier de pe disc, fără a interveni asupra conţinutului sau ordinii octeţilor respectivi.
Citirea dintr-un fişier binar se realizează prin apelul funcţiei fread, care are următorul prototip:
size_t fread(void* ptr,size_t dim,size_t n,FILE* f);
Funcţia citeşte din fişierul f, de la poziţia curentă, un număr de n entităţi, fiecare de dimensiune dim, şi le depune, în
ordinea citirii, la adresa ptr. fread returnează numărul de entităţi citite. În total se citesc, în caz de succes, n*dim octeţi. În caz
de eroare sau cînd se întîlneşte sfîrşitul de fişier, funcţia returnează o valoare negativă sau 0; s ize_t este definit în mai multe
header-e (între care stdio.h) şi este un tip dedată folosit pentru a exprima dimensiunea obiectelor din memorie. Este
compatibil cu tipul unsigned.
Exemplu:
struct complex {int x,y} articol;
FILE * f_complex;
if(f_complex=fopen("NR_COMPL.DAT", "rb") fread(&articol,sizeof(articol),1,f_complex);
else printf("Fisierul nu poate fi deschis");
În exemplul anterior se deschide un fişier binar din care se citeşte un articol de tip struct complex care se depune în
variabila articol.
Scrierea într-un fişier binar se poate realiza prin apelul funcţiei fwrite, care are următorul prototip:
size_t fwrite(const void* ptr,size_t dim,size_t n,FILE* f);
Funcţia scrie în fişierul f, începînd cu poziţia curentă, un număr de n entităţi contigue, fiecare de dimensiune dim, aflate în
memorie la adresa ptr; fwrite returnează numărul entităţilor scrise cu succes. În caz de eroare se returnează o valoare
negativă.
Exemplu:
struct complex {int x,y} articol;
FILE *pf;
pf=fopen("NR_COMPL.DAT","wb"); fwrite(& articol,sizeof (articol),1,pf);
Exemplul anterior creează un fişier binar nou în care scrie o secvenţă de octeţi conţinînd reprezentarea binară a unei date
de tip struct complex.
Exemplu: Să se scrie funcţia care calculează numărul de articole dintr-un fişier binar, cunoscînd lungimea în octeţi a unui
articol. Funcţia are ca parametri fişierul şi lungimea în octeţi a unui articol. Prin numele funcţiei se întoarce numărul de
articole din fişier.
int nrart(FILE *f, int l) {long p; int n; p=ftell(f); fseek(f,0,2); n=ftell(f)/l; fseek(f,0,p); return n;}
Funcţii de citire/scriere cu conversie Funcţiile efectuează transferuri de secvenţe de octeţi între memoria internă şi un
fişier de pe disc, convertind secvenţa de la reprezentarea internă (binară) la reprezentarea externă (ASCII) şi invers.
Transferul de caractere se efectuează prin următoarele funcţii:
int fgetc(FILE* f);
int fputc(int c, FILE *f);
int getc(FILE* f);
int putc(int c, FILE *stream);
Funcţia fgetc şi macrodefiniţia getc returnează următorul caracter din fişierul f (după ce îl converteşte la reprezentarea de
tip întreg fără semn). Dacă s-a ajuns la sfîrşitul fişierului, funcţia va întoarce EOF (valoarea -1). Tot EOF va întoarce şi dacă
sînt probleme la citirea din fişier.
Funcţia fputc şi macrodefiniţia putc scriu caracterul c în fişierul f. În caz de eroare se returnează valoarea c, altfel se
returnează EOF.
Funcţia ungetc pune caracterul c în bufferul de citire asociat fişierului f. La următoarea citire cu fread sau getc acesta va
fi primul octet/caracter citit. Un al doilea apel al funcţiei ungetc, fără să fie citit primul caracter pus în flux, îl va înlocui pe
acesta. Apelarea funcţiilor fflush, fseek, fsetpos sau rewind şterge aceste caractere din flux. În caz de succes, ungetc
returnează caracterul c, iar în caz de eroare returnează EOF.
Transferul de şiruri de caractere se efectuează prin funcţiile:
char* fgets(char* s,int n,FILE* f);
int fputs(const char* s,FILE* f);
Funcţia fgets citeşte un şir de caractere din fişierul f şi îl depune la adresa s. Transferul se încheie atunci cînd s-au citit n-
1 caractere sau s-a întîlnit caracterul newline. La terminarea transferului, se adaugă la sfîrşitul şirului din memorie caracterul
nul ‘\0’. Dacă citirea s-a terminat prin întîlnirea caracterului newline, acesta va fi transferat în memorie, caracterul nul fiind
adăugat după el (spre deosebire de gets, care nu îl reţine). La întîlnirea sîrşitului de fişier (fără a fi transferat vreun caracter)
sau în caz de eroare fgets returnează NULL. În caz de succes returnează adresa şirului citit (aceeaşi cu cea primită în
parametrul s).
Funcţia fputs scrie în fişierul f caracterele şirului aflat la adresa s.
Terminatorul de şir (‘\0’) nu este scris şi nici nu se adaugă caracterul newline (spre deosebire de puts). În caz de succes
fputs returnează ultimul caracter scris. În caz de eroare returnează EOF.
Transferul de date cu format controlat este realizat prin funcţiile:
int fprintf(FILE* f,const char* format[,…]);
int fscanf(FILR* f,const char* format[,…]);
Cele două funcţii lucrează identic cu printf şi scanf. Singura diferenţă constă în fişierul în/din care se transferă datele.
Dacă printf şi scanf lucrează cu fişierele standard stdin şi stdoud, pentru fprintf şi fscanf este necesară precizarea explicită a
fişierului cu care se lucrează, prin parametrul f.
Deşi nu lucrează cu fişiere în mod direct, se pot folosi şi funcţiile
int sprintf(char *s,const char *format[,...]);
int sscanf(const char *s,const char *format[,...]);
Aceste funcţii lucrează identic cu printf şi scanf, diferenţa constînd în entitatea din/în care se transferă datele. În locul
fişierelor standard, acest funcţii folosesc o zonă de memorie de tip şir de caractere, a cărei adresă este furnizată în parametrul
s. Şirul de la adresa s poate fi obţinut prin transfer fără format dintr-un fişier text (pentru sscanf) sau poate urma să fie scris
într-un fişier text prin funcţia fputs.
Pentru tratarea erorilor se folosesc următoarele funcţii: void clearerr (FILE* f);
Funcţia resetează indicatorii de eroare şi indicatorul de sfîrşit de fişier pentru fişierul f (se înscrie valoarea 0). O dată ce
indicatorii de eroare au fost setaţi la o valoare diferită de 0, operaţiile de intrare/ieşire vor semnala eroare pînă la apelul lui
clearerr sau rewind.
int ferror (FILE* nume_intern);
Este o macrodefiniţie care returnează codul de eroare al ultimei operaţii de intrare/ieşire asupra fişierului nume_intern (0
dacă nu s-a produs eroare).
Exemplu:
#include <stdio.h>
int main(void) { FILE *f; /* deschide fisierul pentru scriere:*/
f=fopen("test.ttt","w"); /* se produce eroare la incercarea de citire */ getc(f);
if(ferror(f)) /* s-a produs eroare de I/E? { /* afiseaza mesaj de eroare */
printf("Eroare al citirea din test.ttt\n"); //reseteazaindicatorii de eroare si sfirsit de fisier
clearerr(f);} fclose(f); return 0;}
Exemplu: Să se scrie un program care calculează şi afişează valoarea unei funcţii introduse de la tastatură într-un punct
dat. Funcţia se introduce ca şir de caractere şi poate conţine apeluri de funcţii standard C.
Programul creează un fişier sursă C (în care este scrisă forma funcţiei, ca subprogram C), apoi compilează şi execută un
alt program, care va include subprogramul creat. Descrierea funcţiei introduse de la tastatură trebuie să conţină maxim 200 de
caractere.
a) Fişierul 51_iii_a.cpp conţine programul care realizează citirea formei funcţiei, compilarea şi execuţia programului
care calculează valoarea funcţiei.
#include<stdlib.h>
#include<stdio.h>
#include<conio.h>
#include<string.h>
#include<process.h>
void main() { char s1[213]="return(";
char s2[]="double f(double x)\r\n\{\r\n";
FILE *f; int n,i,j;
f=fopen("functie.cpp","w");
fputs(s2,f);
printf("functia f(x)="); gets(&s1[7]);
strncat(s1,");\r\n}",6);
fputs(s1,f);
fclose(f);
system("bcc -Id;\borlandc\include -Ld:\borlandc\lib 51_iii_b.cpp>>tmp.txt");
execl("51_iii_b ",NULL);}
b) Fişierul 51_iii_b conţine programul care citeşte punctul x, calculează valoarea funcţiei în acest punct şi o afişează.
#include<stdio.h>
#include<conio.h>
#include<math.h>
#include"functie.cpp"
void main() {double x;
printf("x=");scanf("%lf",&x);
printf("f(%7.2lf)=%7.2lf",x,f(x));
getch();}
2.4.1 Un canal special pentru analiza erorilor
Ieşirea erorilor standard ne prezintă un fişier special de ieşire , destinat pentru recuperarea mesajelor de
eroare .În general ieşirea erorilor standard este ataşată la ecran , de ieşire care afişează datele pe monitor spre un
alt canal , ieşirea standard.
Se dau exemplele următoare de variabile:
File * fp;
int I=0;
char eroare în mesaj [ ] =”eroare la deschiderea fişierului .”;
S-ar putea deci de înlocuit formularea deschiderii fişierului xyz.dat:
if ((fp=fopen (“xyz.dat”, “r”))==NULL)
Prin noua scriere :
if ((Fp =fopen (“xyz.dat”, “R”))==NULL)
while (eroare mesaj [ i])
fputc(eroare mesaj [I++], stderr);
În acest caz , afişarea masajului eroare nu se face spre funcţia stdout, dar stderrr
Afişarea caracterului de caracterul mesaj de eroare prin funcţia fput c poate fi puţin complicat.
2.4.2 Direcţiile de intrare şi de ieşire
Se întreabă dacă canalul de ieşire rezervat mesajelor erori este într-adevăr indispensabil. El este în cazul unde
intrările-ieşirile unui program sunt redirijate. I/E standard nu mai sunt reprezentate de tastatură /ecran , dar de un
fişier ordinar. Să considerăm ,deci, următorul exemplu de program:
/* finout recopie intrarea standard la ieşirea standard */
#include <stdio.h> /* fgetc, fputc, feof */
main ()
{ char mesaj [] = “/n eroare în citire ./n”; int I=0; int c;
while ((c=fgetc (stdin)) !=EOF) fputc(C, stdout );
if (!feof (stdin)) /* eroare în citire */
while (mesaj [i] ) fputc (mesaj [I++], stdout);
2.4.2 Citirea şi scrierea în lanţ
Se cunosc funcţiile gets şi puts care citesc/ scriu un şir de caractere la I/E standard . Funcţia fgets citeşte un şir
de caractere într-un fişier .
Iată prototipul fgets: char fgets (char pinter_tampon int număr , FILE pointer_fişier ).
Aici pointer _ bufer  trimite buferul utilizat pentru stocarea şirului de caractere citit .pointer_fişier indică
pointerul FILE ataşat la fişier , pe care trebuie să-l citească . Funcţia fgets returnează un pointer la începutul
buferului conţinând şirul de caractere citit. În ceea ce priveşte valorii returnate NUL fgets se comporta ca fgets cu
EOF: se poate deci de utilizat feof pentru a verifica dacă valoarea returnată semnalează o eroare .
Funcţia fget citeşte în fişier un oarecare număr de caractere şi le aranjează în locul memoriei prin
pointer_tampon, până ce se produce una din evenimentele următoare.
Fgets întâlneşte caracterul noii linii, funcţia se termină. Iată de ce fgets se pregăteşte bine la citirea liniei într-
un fişier .
2.4.3. Duplicarea fişierelor cu ajutorul funcţiei fgets şi fputs
Programul care urmează utilizează funcţii fgets şi fputs pentru duplicarea fişierelor texte. Numele fişierului
copiat este trecut ca parametru pe linia de comandă. Un apel de tcopy:
/’ tcopy copie un fişier text cu ajutorul funcţiilor fgets şi fputs. */
/* tcopy este lansat ca la sintaxă : tcopy sursa principală. */
/* Programul nu verifică, în această versiune ci o copie */
/* fişier ezistent.
# include <stdio.h> /* fopen, fclose all, fgets, fputs */
#include <stdlib,h> /’ exit, toupper */
#include <string.h> /* strcmp */
#define SYNTAX “sintaxa : tcopy sursa principală /n”/
“ Tcopy CON principal /n”
“ tcopy sursa CON”
#define NOREAD “imposibil de deschis fişierul principal .”
#define NOWRITE “imposibil de deschis fişierul principal”
#define NOCOPY “ imposibil de duplicat un fişier pe el însăşi.”
void upstr (char s ); / conversia unui lanţ în majuscule */
main (int argc, char *argv [])
{ file * infile =stdin; /’ pointerul spre fişierul sursă : iniţialiyat la “stdin” pentru cayul unde lectura se face
la tastatură. */
file / out file = stdout ; / pointer spre fişierul principal:iniţialiyat la “stdout” pentru cazul scrierea se face la
ecran .*/
char sbuf [512]; /* tampon de citire / scriere */
int I;
if (argc !=3) /* trebuie de dat o sursă ! */
{ fputs (SYNTAX, stderr); exit (1); }
for (I=1; I<3) /* convertirea parametrilor pe linia de comandă */
upstr (argv[1]):
if (! Strcmp (argv [1], argv [2]) /’ sursa =cible */
{ fputs (NOCOPY,stderr); exit (2); }
if (strcmp (argv [1], “con”) /* sursa !=claviatura */
{ if (infile = fopen (argv [1], “R”))==NULL) { fputs (NOREAD, stderr); exit (3); } }
if (strcmp (argv [2, “CON”)
if (! Strcmp (argv [2]) /’ sursa =cible */
{ fputs (NOCOPY,stderr); exit (2); }
if (strcmp (argv [1], “con”) /* sursa !=claviatura */
{ if (infile = fopen (argv [1], “R”))==NULL)
{ fputs (NOREAD, stderr); exit (4); } }
/* duplicare *7
WHILE (fgets (sbuf, 512, infile) !=NULL)
fputs (sbuf, outfile );
fcloseall(); /* se închid fişierele /*
}
void upstr (char s) / converteşte stringul ăn majuscule */
{ int I=0;
while (S[i]) { S [i]=toper (S[i]); I++; } }
2.4.4 Citirea şi scrierea formatelor
Funcţiile fprintf şi fscanf permit de a efectua scrierea sau citirea formatelor de date în fişier . Cele două funcţii
lucrează practic ca funcţii de terminal printf ţi scanf .În particular ele folosesc formatări . Singura diferenţă este că
printf şi scanf reclamă un pointer FILE în mai mult de un lanţ de format şi alţi parametri efectivi.
printf este o funcţie care acceptă un număr variabil de parametri , returnează ca rezultat numărul de caractere
scrise.
fscanf este o funcţie care citeşte datele în fişier , formatându-le.
2.4.4.1 Citirea formatelor într-un fişier cu ajutoril funcţiei :fscanf
Funcţia fscanf citeşte dateşe din fişier formatându-le. Ea admite prototipul:
Int fscanf (FILE * <pointer fişier >, char *< lanţ format >,…);
Funcţia fscanf dă ca rezultat numărul de date corect citite . Valoarea de retur EOF signalează la sfârşitul
fişierului o eroare.
Dacă a definit prototipul variabilelor:
long no ; /* cod client */
char nom [31]; /* numele clientului */
long cp ; /* cod poştal */
char oraş [31 ]; cifrele de afaceri */
Atunci instrucţia :
if ((fp=fopen (“ clienţi.dat”,”R”)) ==NULL) fputs (“ imposibil de a deschide fişierul.”, stderr);
else while (fscanf (fp, “%1d%30s %1d %30s %f”, /no , nume, /cp, oraş, /ca)==%5)
printf (“% 1d %s %. 2f / n /!,no, nume,cp, oraş ,ca);
citeşte şi afişează înregistrările din fişier dat, până ce survine o eroare , sau la sfârşitul fişierului să fie atent
2.5. Citirea şi scrierea în bloc
Funcţiile de intrare /ieşire sunt adaptate tratamentelor de entităţi de diferite tipuri , care citeşte sau scrie într-
un fişier de caractere , şiruri sau valori numerice. Dar cu funcţiile fread şi fwrite , se dispun de 2 funcţii care
permit de a transfera spre un fişier , nu numai de entităţi complete , dar şi din contra , un număr oarecare de
octeţi.
Scrierea blocurilor în fişier cu funcţia f write:
Funcţia fwrite admite prototipul:
size t fwrite (void * pointer tampon, size_t taille
size_t număr, FILE */pointer_fişier);
Ea scrie un bloc de taille * număr octeţi aranjaţi în locul memoriei referenţiate prin pointer_tampon în
fişierul ataşat la pointer_fişier. Blocul se compune din număr de obiecte, fiecare din ele fiind de dimensiuni
taille. Valoarea returnată de fwrite este egală cu numărul de date complet recopiate în fişier . În caz de eroare ,
fwrite trimite o valoare inferioară la număr. Tipul size t este definit în stdio.h ca total neănsemnat şi şi
câtevai headere. Pointerul pointer_tampon este de tip void *, şi poate conţine adresa blocului de date de tip
oarecare.
2.6 Particularităţi ale algoritmilor de prelucrare cu fişier conducător Caracteristica generală a algoritmilor de
prelucrare cu fişier conducător este parcurgerea secvenţială a fişierului conducător şi efectuarea unor prelucrări în funcţie de
fiecare articol citit din acesta. Problema care se pune este detectarea sfîrşitului de fişier. Modul în care se realizează acest
lucru în Pascal diferă radical de cel din C. În Pascal, funcţia eof realiza prima etapă a citirii (transferul datelor din fişier în
buffer) şi de aceea trebuia apelată înainte de citirea efectivă. În C, macrodefiniţia feof nu face decît să furnizeze valoarea
indicatorului de sfîrşit de fişier, care este setat de operaţia de citire; în program, citirea trebuie să apară înaintea verificării
sfârşitului de fişier. Forma generală a algoritmului în cele două limbaje este:
Pascal:
while not eof(f) do
begin <citire articol> <prelucrare articol citit>end;
C:
<citire articol>
while(!feof(f)) { <prelucrare articol citit><citire articol>}
Exemplu: Crearea şi consultarea unui fişier text care memorează elemente întregi, folosind funcţia feof pentru
gestionarea sfîrşitului de fişier. La crearea fişierului, fişier conducător este fişierul standard de intrare. La afişare, conducător
este fişierul f.
#include<stdio.h>
#include<conio.h>
void main() { FILE *f; int x; long dim; clrscr(); f=fopen("numere.dat","w+"); scanf("%d",&x);
while(!feof(stdin)) {fprintf(f,"%d\n",x); scanf("%d",&x);}
fseek(f,0,SEEK_SET); fscanf(f,"%d",&x);
while(!feof(f)) {printf("%d\t",x); fscanf(f,"%d",&x);} fclose(f); getch();}
Acelaşi exemplu, folosind fişier binar:
#include<stdio.h>
#include<conio.h>
void main() { FILE *f; int x,g; long dim; clrscr(); f=fopen("numere.dat","wb+"); scanf("%d",&x);
while(!feof(stdin)) {fwrite(&x,sizeof(x),1,f); scanf("%d",&x);}
fseek(f,0,SEEK_SET); fread(&x,sizeof(x),1,f);
while(!feof(f)) {printf("%d\t",x); fread(&x,sizeof(x),1,f); } fclose(f); c=getch();}
3.1 Exemple de antrenament
1. Program care realizează copierea unui fişier. Numele celor doua fişiere (sursă şi destinaţie) sunt citite de la
terminal.
#include <stdio.h>
/* copierea unui fisier */
void copiere1(FILE *, FILE *);
void main(void){
char numes[12], numed[12];
gets(numes);
gets(numed);
FILE* s = fopen(numes,”r”);
FILE* d = fopen(numed,”w”);
copiere1(d, s);
fclose(s);
fclose(d);
}
void copiere1(FILE *d, FILE *s) {
int c;
while ((c=fgetc(s)) != EOF)
fputc(c, d);
}
2. Alt program care copiaza continutul unui fisier in altul, numele sursei si destinatiei fiind transmise in linia
de comanda
// fisier copiere.c
# include <stdio.h>
int main(int argc, char** argv){
FILE *fisi, *fise; char c;
if(!(fisi=fopen(argv[1],"r")|| !(fise=fopen(argv[2],"w")){ puts("Fisierele nu pot fi deschise"); return 1;
} //eroare daca fisierele nu pot fi deschise
while((c=fgetc(fisi))!=EOF) //copiere caracter cu caracter
fputc(fise); fclose(fisi); fclose(fise); return 0; }
Lansarea in executie a programului se va face cu o linie de comanda de forma:
copiere fisier_sursa.dat fisier_dest.dat
Folosind redirectarea fisierelor standard, printr-o linie de comanda de forma:
copiere1 <fisier_sursa.dat >fisier_dest.dat
3. Intr-un fisier de tip text sunt pastrate valorile reale ale unei masuratori sub forma: nr_masuratori '\n' val1 '\n' val2 '\n'
val3 ... Se scrie programul care afiseaza numarul de masuratori si valorile respective, dupa care adauga la fisier noi
masuratori pina la introducerea valorii 0. Valorile citite se afiseaza in format stiintific.
# include <math.h>
# include <stdio.h>
# include <stdlib.h>
# define MAX 100
FILE *fp;
double masur[MAX], mas_noua;
char nume_fis[12],s[20]; int nr_mas;
double convf(char *s){ double val=0.0,putere; int i=0,semn;
while(isspace(s[i])) i++; semn=(s[i]=='-')?-1:1; if(s[i]=='+'||s[i]=='-') i++;
for(val=0.0;isdigit(s[i]);i++) val=10*val+s[i]-'0'; if(s[i]=='.'){ i++;
for(putere=1.0;isdigit(s[i]);i++){ val=10*val+s[i]-'0'; putere*=10; } val/=putere; } /*sfirsit parte zecimala*/
val*=semn; if(s[i]=='e' || s[i]=='E'){ i++; semn=(s[i]=='-')?-1:1; if(s[i]=='+'||s[i]=='-') i++;
for(putere=0.0;isdigit(s[i]);i++) putere=10*putere+s[i]-'0'; val*=pow10(semn*putere); } /*sfirsit parte exponentiala*/
return val; }
void loadmat (FILE *fp,int *nrm,double *mas){ int i=0; fscanf(fp,"%d",nrm);
if (*nrm>MAX) *nrm=MAX;
for(;i<*nrm;i++) fscanf(fp,"%lf",&mas[i]); }
void afiseaza(double *mas,int nrm){ int i;
for(i=0;i<nrm;i++) printf("masuratoarea %d = %6.2e\n",i+1,mas[i]); }
void main(){ printf("nume fisier:"); gets(nume_fis);
if((fp=fopen(nume_fis,"r+"))==0){ printf("nu exista fisierul\n"); exit(1); }
loadmat(fp,&nr_mas,masur); afiseaza(masur,nr_mas); fseek(fp,0L,SEEK_END);
printf("\nmasuratoarea %d =",++nr_mas);
while((mas_noua=convf(gets(s))) && nr_mas<MAX-1){ printf("\nmasuratoarea %d =",++nr_mas);
fprintf(fp,"%lf\n",mas_noua); } fseek(fp,0L,SEEK_SET); fprintf(fp,"%3d",--nr_mas); fclose(fp); }

4. /* Problema 1 set 4 : Program pentru crearea unui fisier binar, avand articole structuri cu urmatoarele campuri:
-nume depunator (sir de maxim 30 de caractere)
-data depunerii (o structura avand campurile intregi: zi,luna,an)
-suma depusa (o valoare reala).
Articolele sunt grupate pe zile in ordine cronologica.
Datele se introduc de la consola, fiecare pe 3 linii. */
#include<stdio.h>
#include<conio.h>
#include<dos.h>
#include<stdlib.h>
#define MAX 3
typedef struct { int zi; int luna; int an; } DATA;
typedef struct { unsigned char nume[30]; DATA dat; int sum; } CLIENT;
void main()
{ CLIENT bd[MAX]; int i; FILE *baza; printf("\n Introduceti datele persoanelor ");
for(i=0;i<MAX;i++) { printf("\n====================================");
printf("\n Nume : "); scanf("%s",&bd[i].nume);
printf("\n Data : "); scanf("%d-%d-%d",&bd[i].dat.zi,&bd[i].dat.luna,&bd[i].dat.an);
printf("\n Suma : "); scanf("%d",&bd[i].sum); };
baza=fopen("date.dat","w"); fwrite( bd, sizeof( CLIENT ), MAX, baza ); fclose( baza ); }
5. /* Program care, folosind fisierul creat in problema 1, calculeaza si afiseaza:
- -suma maxima depusa, impreuna cu data si numele depunatorului
- -numarul depunerilor din fiecare zi, si suma totala depusa in fiecare zi, tinand cont ca tranzactiile dintr-o zi sunt contigue
in fisier. */
#include<stdio.h>
#include<conio.h>
#include<dos.h>
#include<stdlib.h>
#define MAX 3
typedef struct { int zi; int luna; int an; } DATA;
typedef struct { unsigned char nume[30]; DATA dat; int sum; } CLIENT;
void main() { CLIENT bd[MAX]; int j,sm,i,smax,ni; FILE *baza;
baza=fopen("date.dat","r"); fread( bd, sizeof( CLIENT ), MAX, baza ); fclose( baza ); smax=0;
for(i=0;i<MAX;i++) { if (smax<bd[i].sum) { smax=bd[i].sum; ni=i; } }
printf("\n %s , %d-%d-%d , %d \n",bd[ni].nume, bd[ni].dat.zi, bd[ni].dat.luna, bd[ni].dat.an, bd[ni].sum);
j=1; sm=bd[0].sum;
for (i=1;i<MAX;i++) {
if (bd[i].dat.zi==bd[i-1].dat.zi && bd[i].dat.luna==bd[i-1].dat.luna && bd[i].dat.an==bd[i-1].dat.an)
{ j=j+1; sm=sm+bd[i].sum; } else {
printf(" \n Nr. depuneri din data %d-%d-%d = %d ; Suma depusa = %d ",bd[i-1].dat.zi,bd[i-1].dat.luna,bd[i-1].dat.an,j,sm);
j=1; sm=bd[i].sum; } }
printf(" \n Nr. depuneri din data %d-%d-%d = %d ; Suma depusa = %d ",bd[i-1].dat.zi,bd[i-1].dat.luna,bd[i-1].dat.an,j,sm);
printf("\n \n"); }
6. / Program, care folosind fisierul creat in problema 5, actualizeaza acest fisier prin adaugarea dobanzii, la data curenta. Se
precizeaza urmatoarele date: -data curenta la care se calculeaza dobanda (an,luna,zi) -dobanda anuala. Se va folosi o functie
care determina numarul de zile dintre data depunerii si data curenta, pentru a calcula dobanda cuvenita.*/
#include<stdio.h>
#include<conio.h>
#include<dos.h>
#include<stdlib.h>
#define MAX 3
typedef struct { int zi; int luna; int an; } DATA;
typedef struct { unsigned char nume[30]; DATA dat; int sum; } CLIENT;
int nrzile(int a1,int a2,int a3) { int y,nr; nr=0;
for(y=1;y<a3;y++) if (y % 4==0) nr=nr+365; else nr=nr+364;
for(y=1;y<a2;y++); if (y%2==0) if (y!=2) nr=nr+30;
else nr=nr+28; else nr=nr+31; nr=nr+a1; return(nr); }
void main() { CLIENT bd[MAX]; int i,n1,n2,n3,dobanda; FILE *baza;
baza=fopen("date.dat","r"); fread( bd, sizeof( CLIENT ), MAX, baza ); fclose( baza );
printf(" Introduceti data curenta : "); scanf("%d-%d-%d",&n1,&n2,&n3);
printf("\n Introduceti dobanda : "); scanf("%d",&dobanda);
for (i=0;i<MAX;i++) { bd[i].sum=bd[i].sum+(nrzile(n1,n2,n3)-nrzile(bd[i].dat.zi,bd[i].dat.luna,bd[i].dat.an))*dobanda; }
baza=fopen("date.dat","w"); fwrite( bd, sizeof( CLIENT ), MAX, baza ); fclose( baza );}
4. Exemple de verificare a cunoştinţelor însuşite: în listingul programelor de mai jos verificaţi
corectitudinea, scopul şi rezultatele:
1. Listingul programului:
#include<conio.h>
#include<stdio.h>
#include<string.h>
void main() {clrscr(); int i,n;
FILE *f;
f=fopen("d:\\input.txt","r");
char *s,**s1,*aux;
fgets(s,1000,f);
for(i=0,n=0;i<strlen(s);i++) if((s[i]=='.')||(s[i]=='!')) n++;
s1[0]=strtok(s,".!");
for(i=1;i<n;i++) s1[i]=strtok(NULL,".!");
aux=s1[0]; s1[0]=s1[2]; s1[2]=aux;
for(i=0;i<n;i++)printf("%s. ",s1[i]);
fclose(f);
getch();
}
2. Listingul programului:
#include<stdio.h>
#include<conio.h>
void main() {clrscr();
FILE *f;
int i,x;
f=fopen("e:\\numbers.txt","a");
printf("\n Introduceti 5 numere:\n");
for(i=0;i<5;i++)
{scanf("%d",&x);
fprintf(f,"%d\n",x);
}
fclose(f);
getch();
}
3. Listingul programului:
#include<conio.h>
#include<stdio.h>
void main() {clrscr();
FILE *f;
int i,x,S=0;
f=fopen("file.txt","w+");
printf("\n introduceti zece numere intregi \n");
for(i=0;i<10;i++) { scanf("%d",&x); fprintf(f,"%d ",x); } rewind(f);
while(!feof(f)) {
fscanf(f,"%d",&x);
if(!feof(f))
S+=x; }
printf("S=%i",S); getch(); fclose(f); }
4. Listingul programului:
#include<iostream.h>
#include<stdio.h>
#include<conio.h>
#include<dos.h>
void main() {clrscr();
struct dosdate_t d;
struct dostime_t t; printf(" \n De la inceputul erei noastre au trecut: \n "); _dos_getdate(&d);
printf("\n %d veacuri %d ani %d luni %d zile ",d.year/100,d.year,d.month,d.day); _dos_gettime(&t);
printf(" %2d:%02d:%02d.%02d\n", t.hour, t.minute,t.second, t.hsecond); getch(); }
5. Listingul programului:
#include <string.h>
#include <stdio.h>
int main(void){ FILE *fp;
char buf[11] = "0123456789"; /* create a file containing 10 bytes */
fp = fopen("DUMMY.FIL", "w"); fwrite(&buf, strlen(buf), 1, fp);
/* close the file */ fclose(fp); getchar(); return 0; }
6. Listingul programului:
#include <stdio.h>
#include <ctype.h>
#include <mem.h>
char q[250]; int g[26]; int k[26]; int len=0;
int main()
{ FILE *f; int ch,i; long kol; f=fopen("input.txt","r");
while((ch=fgetc(f))!='\n') { if(isalpha(ch)) { g[ch-'A']++; len++; } }
i=0; kol=0; if(len>0)
while((ch=fgetc(f))!=EOF) { if(isalpha(ch))
{ if(q[i]) k[q[i]-'A']--; q[i]=ch; k[ch-'A']++; i=(i+1)%len; if(memcmp(g,k,sizeof(g))==0) kol++; } }
fclose(f); f=fopen("output.txt","w"); fprintf(f,"%ld\n",kol); fclose(f); return 0; }
7. Listingul programului:
#include<stdio.h>
#include<conio.h>
main()
{ int acc; char nume[10]; float balanta;
FILE *cfPtr; clrscr();
if ((cfPtr= fopen("clientii.txt","w"))==NULL) printf("Failul nu poate fi deschis\n");
else {printf("introdu banii,numele,si balanta\n"); printf("introdu sf. daca m.\n"); printf("?");
scanf("%d%s%f",&acc,nume,&balanta);
while(!feof(stdin)){ fprintf(cfPtr,"%d%s%.2f\n", acc,nume,balanta); printf("?");
scanf("%d%s%f",&acc,nume,&balanta); } fclose(cfPtr); } return 0;
}
8. Listingul programului:
#include <conio.h>
#include <stdio.h>
#include <string.h>
struct regest{ char name[20]; int ani; }; regest cat[2]; FILE *f1,*f2;
void init_f()
{int num=sizeof(cat)/sizeof(cat[0]); f1 = fopen("f1","w"); f2 = fopen("f2","w"); clrscr();
printf(" Introduceti %d de inregistrari.\n",num+1);
for(int i=0;i<=num;i++) { printf("Inregistr. nr.%d \n",i); scanf("%s %d", &cat[i].name, &cat[i].ani);
fprintf(f1,"%s ",cat[i].name); fprintf(f2,"%d ",cat[i].ani); };
// fflush(f1); fflush(f2);
fclose(f1); fclose(f2); }
void init(){ int i=0;
while (!feof(f1)) { fscanf(f1,"%s ",&cat[i].name); fscanf(f2,"%d ",&cat[i].ani); i++; } }
void afish(){ int num=sizeof(cat)/sizeof(cat[0]); printf("Afisarea continutului catalogului\n");
for (int i=0;i<=num;i++) printf("%s %d\n",cat[i].name,cat[i].ani); }
int num_lit(){ int num=sizeof(cat)/sizeof(cat[0]); int len,min=strlen(cat[0].name);
for (int i=1; i<=num; i++) { len=strlen(cat[i].name); if (len<min) min=len; } return (min); }
void afish_min(int l)
{ int num=sizeof(cat)/sizeof(cat[0]);
for (int i=0;i<=num;i++) { if (strlen(cat[i].name)==l) printf("%s %d \n",cat[i].name,cat[i].ani); } }
void main(){ int lungimea; clrscr(); f1 = fopen("f1","r"); f2 = fopen("f2","r");
if (f1==NULL) {init_f();} else{init();}; lungimea = num_lit(); afish(); afish_min(lungimea);
fclose(f1); fclose(f2); getch(); }
9. Listingul programului:
#include <iostream.h>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
void main(){ clrscr(); FILE *fin; int x,w,d,y,max=0,min=0; int k,p,s; fin=fopen("ts.txt","r"); int a[20]; int i=0;
if (fin==NULL) { printf(" Eroare"); exit(1); }
while(!feof(fin)) { fscanf(fin,"%d",&y); a[++i]=y; printf("%d ",y); } fclose(fin); max=a[1];
{ for (k=1;k<=i;k++) if (max<a[k]) { max=a[k]; w=k;} } min=a[1];
{ for ( k=1;k<=i;k++) if (min>a[k]) { min=a[k]; s=k;} }
printf("\n Numarul maxim %d si num minim %d \n",max,min);
printf("\n Locul num maxim %d si num minim %d\n ",w,s);
for (k=w;k>=s; k--) printf("%d ",a[k]); getch(); }
10. Listingul programului:
#include <stdio.h>
#include <conio.h>
#define MIN_DISCOUNT .97
#define MAX_DISCOUNT .95
void main()
{ float frPrice, fbPrice; FILE *fin, *fout; fin = fopen("customer.dat", "r"); fout = fopen("billing.dat", "w");
if (fin == NULL) { printf("Fisierul CUSTOMER.DAT nu exista!"); getch(); return; }
while (fscanf(fin, "%f", &frPrice) != EOF) { if (frPrice < 100) fbPrice = frPrice * MIN_DISCOUNT;
else fbPrice = frPrice * MAX_DISCOUNT;
fprintf(fout, "Suma $%8.2f ", frPrice); printf("Suma $%8.2f ",frPrice); fprintf(fout, "cu rabat e $%8.2f\n", fbPrice);
printf("cu rabat e $%8.2f\n", fbPrice); } printf("\nDatele de mai sus au fost salvate");
printf(" in fisierul BILLING.DAT!"); getch(); }
11. Listingul programului:
#include<stdio.h>
#include<conio.h>
#include<alloc.h>
typedef struct articol{ int camp1; char camp2[80]; unsigned char camp3; float camp4; };
int *p_int; int **p_mat; articol *p_art; int mat[3][3]={{1,2,3},{4,5,6},{7,8,9}};
articol art[1]={{100,"sir1",’a’,12.3},};
void main(){ clrscr(); p_int=(int *)malloc(sizeof(int)); *p_int=10; p_mat=(int**)malloc(3*sizeof(int*));
for(int i=0;i<3;i++) p_mat[i]=(int*)malloc(sizeof(int));
for(i=0;i<3;i++) for(int j=0;j<3;j++) p_mat[i][j]=mat[i][j]; p_art=(articol *)malloc(sizeof(articol));
p_art=art; printf("\nintregul este:...%d", *p_int); printf("\nmat[1][1] este:...%d",p_mat[1][1]);
printf("\ncamp 3 este:...%c",p_art->camp3); getch(); }
5. Exemplu model pentru evidenţierea principiilor de elaborare şi prelucrarea grafului cu funcţii şi
diverse SD. De fragmentat și de ansamblat cu diverse posibilități.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <alloc.h>
#include <ctype.h>
#include <string.h>
#include <graphics.h>
#include <math.h>
#define MAXARC 20
#define MINARC 2
#define MAXVIRF 20
#define MINVIRF 2
#define WINDX 40
#define WINDY 10
#define WINDCOLBK 9
#define WINDCOLFR 15
#define WINDCOLBKSEL 2
#define WINDCOLFRSEL 11
#define WINDCOLTITLE 14
#define WINDCOLFRAME 7
#define FEXTENSION ".grf"
#define MAXRADIUS 220
#define RADPERVIRF 20
#define VIRFRADIUS 10
#define PI M_PI
#define ORIGX 320
#define ORIGY 240
const char *MAIN_MENU[] =
{"$Meniu:","1 Graf nou ","2 Afisare ","3 Transformare ",
"6 Prelucrare ","4 Citire ","5 Salvare ","0 Iesire ",
"9 Despre program ",""};
const char *MENU_NEW[] =
{"$Graf nou:","1 Matrice de incedenta ","2 Matrice de adiacenta ",
"3 Lista de adiacenta ","0 Meniu precedent",""};
const char *MENU_SHOW1[] =
{"$Modul de afisare:","1 Mod text ","2 Mod grafic ",
"0 Meniu precedent ",""};
const char *MENU_SHOW2[] =
{"$Afisare:","1 Matrice de incedenta ","2 Matrice de adiacenta ",
"3 Lista de adiacenta ","0 Meniu precedent ",""};
const char *MENU_TRANS1[] =
{"$Indicati sursa:","1 Matrice de incedenta ",
"2 Matrice de adiacenta ","3 Lista de adiacenta ",
"0 Meniu precedent ",""};
const char *MENU_TRANS2[] =
{"$Indicati destinatia:","1 Matrice de incedenta ",
"2 Matrice de adiacenta ","3 Lista de adiacenta ",
"0 Meniu precedent ",""};
const char *MENU_SAVE[] =
{"$Salvare:","1 Matrice de incedenta ","2 Matrice de adiacenta ",
"3 Lista de adiacenta ","0 Meniu precedent ",""};
const char *MENU_EXIT[] =
{"$Doriti sa iesiti din program ?","1 DA ","0 NU ",""};
typedef struct LISTA {
int val;
LISTA *next;
};
LISTA **lista=NULL;
char **matr_inc=NULL,
**matr_adi=NULL,
tip_inc=-1, tip_adi=-1, tip_lista=-1, screen=1;
int virf=0, arce=0, radius; float alfa;
char graf_nou(void);
char afisare(char);
char afisare_sursa(void);
void afisare_text(char);
void afisare_matr_inc(void);
void afisare_matr_adi(void);
void afisare_lista(void);
char afisare_graf(char);
void afisare_graf_matr_inc(void);
void afisare_graf_matr_adi(void);
void afisare_graf_lista(void);
void transformare(void);
void citire(void);
char cit_matr_inc(FILE *, int, int, char);
char cit_matr_adi(FILE *, int, char);
char cit_lista(FILE *, int, char);
void salvare(void);
void sal_matr_inc(FILE *f);
void sal_matr_adi(FILE *f);
void sal_lista(FILE *f);
void iesire(void);
void trans_adi_inc(void);
void trans_inc_adi(void);
void trans_inc_lista(void);
void trans_lista_inc(void);
void trans_adi_lista(void);
void trans_lista_adi(void);
void prelucrare(void);
char control_graf(void);
void read_matr_adi(void);
void read_matr_inc(void);
void read_lista(void);
char **getmatr(int, int);
void freematr(char **, int);
LISTA **getlista(int);
LISTA *getlista_el(void);
void freelista(LISTA **,int);
void freelista_el(LISTA *);
int show_menu(const char **);
void draw_frame(char, char);
void about(void);
void Graph_Init(void);
void getcoord(int *,int *, int);
void drawvirf(int ,int ,int);
void joinvirf(int ,int ,char );
void main(void)
{start:
while (1) { if (screen) { window(1,1,80,25); textbackground(0); textcolor(WINDCOLFRAME); clrscr();
screen=0; draw_frame(WINDX,WINDY); }
switch (show_menu(MAIN_MENU)) {
case '1': graf_nou();break;
case '2': afisare_sursa();break;
case '3': transformare();break;
case '6': prelucrare();break;
case '4': citire();break;
case '5': salvare();break;
case '0': iesire();break;
case '9': about();break; }
} }
char graf_nou(void)
{ switch (show_menu(MENU_NEW)) {
case '1': read_matr_inc();break;
case '2': read_matr_adi();break;
case '3': read_lista();break;
case '0': return -1;
} return 0; }
char afisare(char tip)
{char ch;
do {
switch (ch=show_menu(MENU_SHOW1)) {
case '1': afisare_text(tip);break;
case '2': afisare_graf(tip);break;
case '0': return -1;
} } while (ch==-1); return 0; }
char afisare_sursa(void)
{ char ch;if (control_graf()==1) return 0;
do {
switch (ch=show_menu(MENU_SHOW2)) {
case '1': if (tip_inc==-1) ch=-1;break;
case '2': if (tip_adi==-1) ch=-1;break;
case '3': if (tip_lista==-1) ch=-1;break;
case '0': return -1;
}
if (ch==-1) {
cprintf("Nu este introdusa.");
getch();
}
else ch=afisare(ch);
} while (ch==-1); return 0; }
void afisare_text(char tip)
{switch (tip) {
case '1': afisare_matr_inc();break;
case '2': afisare_matr_adi();break;
case '3': afisare_lista();break;
} getch(); }
void afisare_matr_inc(void)
{int i,j; window(1,1,80,25); textbackground(0); clrscr(); textcolor(YELLOW);
cprintf("Matricea de incidenta."); draw_frame(virf*3+1,arce+2); textcolor(YELLOW);
for (i=0;i<arce;i++) {
for (j=0;j<virf;j++)
if (matr_inc[i][j]==1) cprintf(" 1 ");
else if (matr_inc[i][j]==0) cprintf(" 0 ");
else cprintf("-1 "); } screen=1; }
void afisare_matr_adi(void)
{int i,j;
window(1,1,80,25);
textbackground(0);
clrscr();
textcolor(YELLOW);
cprintf("Matricea de adiacenta.");
draw_frame(virf*3+1,virf+2);
textcolor(YELLOW);
for (i=0;i<virf;i++) {
for (j=0;j<virf;j++)
if (matr_adi[i][j]==1) cprintf(" 1 ");
else if (matr_adi[i][j]==0) cprintf(" 0 "); } screen=1; }
void afisare_lista(void)
{ int i;
LISTA *l;
window(1,1,80,25);
textbackground(0);
clrscr();
textcolor(YELLOW);
cprintf("Lista de adiacenta.");
draw_frame(virf*3+7,virf+2);
textcolor(YELLOW);
for (i=0;i<virf;i++) {
l=lista[i];
cprintf(" %02d -",i);
while (l!=NULL) {
cprintf("%3d",l->val);
l=l->next;
}
cprintf("\n\r");
}
screen=1;
}
char afisare_graf(char tip)
{
int i,j,x,y;
radius=RADPERVIRF*virf;
if (radius>MAXRADIUS) radius=MAXRADIUS;
alfa=2*PI/virf;
Graph_Init();
setcolor(WINDCOLTITLE);
outtextxy(10,15,"Afisarea grafica.");
settextjustify(CENTER_TEXT, CENTER_TEXT);
setcolor(WINDCOLBKSEL);
switch (tip) {
case '1': afisare_graf_matr_inc();break;
case '2': afisare_graf_matr_adi();break;
case '3': afisare_graf_lista();break;
}
setfillstyle(1,BLACK);
for (i=0;i<virf;i++) {
getcoord(&x,&y,i);
drawvirf(x,y,i);
}
settextjustify(RIGHT_TEXT, CENTER_TEXT); outtextxy(10,465,"Apasati ori ce tasta."); getch(); closegraph();
screen=1; return 0; }
void afisare_graf_matr_inc(void)
{int i,j,k;
for (i=0;i<arce;i++)
for (j=0;j<virf;j++)
if (tip_inc==0 && matr_inc[i][j]==1) {
for (k=0;k<virf;k++)
if (matr_inc[i][k]==1 && k!=j) joinvirf(j,k,tip_inc);
}
else if (tip_inc==1 && matr_inc[i][j]==-1)
for (k=0;k<virf;k++)
if (matr_inc[i][k]==1) joinvirf(j,k,tip_inc); }
void afisare_graf_matr_adi(void)
{ int i,j;
for (i=0;i<virf;i++)
for (j=0;j<virf;j++)
if (matr_adi[i][j]==1) joinvirf(i,j,tip_adi); }
void afisare_graf_lista(void)
{ LISTA *l;
int i;
for (i=0;i<virf;i++) {
l=lista[i];
while (l!=NULL) {
joinvirf(i,l->val,tip_lista);
l=l->next;
}
}
}

void citire(void)
{
FILE *f;
int i,arce,virf;
char fname[12],str,tip,ch;
wrongname:
clrscr();
cprintf("Citirea grafului:\n\r");
cprintf("Introduceti numele fisierului.\n\r");
cprintf("Nume: ");
scanf("%8s",fname);
for (i=0;i<strlen(fname);i++)
if (!isalnum(fname[i])) {
gotoxy(1,WINDY-1);
cprintf("Nume incorect!");
getch();
goto wrongname;
}
strcat(fname,FEXTENSION);
if ((f=fopen(fname,"r"))==NULL) {
gotoxy(1,WINDY-1);
cprintf("Nu pot sa deschid fisierul de intrare.");
getch();
return;
}
fscanf(f,"%c:%c %d,%d",&str,&tip,&arce,&virf);
if (arce>MAXARC || virf>MAXVIRF || arce<MINARC || virf<MINVIRF) {
gotoxy(1,WINDY-1);
cprintf("Numarul arcelor sau virfurilor in afara limitei.");
getch();
return;
}
tip-=48;
switch (str) {
case '1': ch=cit_matr_inc(f,arce,virf,tip);break;
case '2': ch=cit_matr_adi(f,virf,tip);break;
case '3': ch=cit_lista(f,virf,tip);break;
default: {
gotoxy(1,WINDY-1);
cprintf("Fisier de format nedeterminat.");
getch();
return;
}
}
gotoxy(1,WINDY-1);
if (ch==0) cprintf("\nGraful a fost citit cu succes.");
else cprintf("\nGraful nu a fost citit. Erroare.");
getch();
}
char cit_matr_inc(FILE *f, int arc_new, int virf_new, char tip)
{int i,j,k,val;
char ch,cp,cm;
freematr(matr_adi,virf);matr_adi=NULL;
freelista(lista,virf);lista=NULL;
freematr(matr_inc,arce);
arce=arc_new;
virf=virf_new;
tip_inc=tip;
clrscr();
cprintf("Citirea matricei de incedenta.");
cprintf("\n\rNumarul arcelor: %d",arce);
cprintf("\n\rNumarul virfurilor: %d",virf);
cprintf("\n\rOrientarea grafului: %s",tip_inc?"ORIENTAT\0":"NEORIENTAT\0");
getch();
matr_inc=getmatr(arce,virf);
tip_lista=tip_adi=-1;
for (i=0;i<arce;i++) {
cp=0;cm=0;
for (j=0;j<virf;j++) {
fscanf(f,"%d",&val);
cprintf("\n\rU[%d],X[%d]: %d",i,j,val);
if (val==-1) cm++;
else if (val==1) cp++;
if (val!=0 && val!=1 && val!=-1) {
cprintf(" - ERROARE");
tip_inc=-1;
return -1;
}
matr_inc[i][j]=val;
}
if (tip_inc==0) {
if (cp!=2) {
cprintf("\n\rLinia %d contine erroare.",i);
tip_inc=-1;
return -1;
}
}
else if (cp>1 || (cm>1 && tip_inc==1)) {
cprintf("\n\rLinia %d contine erroare.",i);
tip_inc=-1;
return -1;
}
}
for (i=0;i<arce-1;i++)
for (j=i+1;j<arce;j++)
for (k=0;k<virf;k++)
if (matr_inc[i][k]==matr_inc[j][k]) {
if (k==virf-1) {
cprintf("\n\rMatricea contine arce ce se repeta.");
tip_inc=-1;
return -1;
}
}
else break;
return 0;
}
char cit_matr_adi(FILE *f, int virf_new, char tip)
{ int i,j,val;
char ch;
freematr(matr_inc,arce);matr_inc=NULL;
freelista(lista,virf);lista=NULL;
freematr(matr_adi,virf);
virf=virf_new;
tip_adi=tip;
clrscr();
cprintf("Citirea matricei de adiacenta.");
cprintf("\n\rNumarul virfurilor: %d",virf);
cprintf("\n\rOrientarea grafului: %s",tip_adi?"ORIENTAT\0":"NEORIENTAT\0");
getch();
matr_adi=getmatr(virf,virf);
tip_lista=tip_inc=-1;
for (i=0;i<virf;i++) {
for (j=0;j<virf;j++) {
fscanf(f,"%d",&val);
cprintf("\n\rX[%d][%d]: %d",i,j,val);
if (val!=0 && val!=1) {
cprintf(" - ERROARE");
tip_adi=-1;
return -1;
}
matr_adi[i][j]=val;
}
}
if (tip_adi==0)
for (i=0;i<virf-1;i++)
for (j=i;j<virf-1;j++)
if (matr_adi[j+1][i]!=matr_adi[i][j+1]) {
cprintf("\n\rLinia sau coloana %d contine erroare.",i);
tip_adi=-1;
return -1;
}
return 0;
}
char cit_lista(FILE *f, int virf_new, char tip)
{
int i,j,val;
char ch;
LISTA *l,*lc;
freematr(matr_inc,arce);matr_inc=NULL;
freematr(matr_adi,virf);matr_adi=NULL;
freelista(lista,virf);
virf=virf_new;
tip_lista=tip;
clrscr();
cprintf("Citirea listei de adiacenta.");
cprintf("\n\rNumarul virfurilor: %d",virf);
cprintf("\n\rOrientarea grafului: %s",tip_lista?"ORIENTAT\0":"NEORIENTAT\0");
getch();
lista=getlista(virf);
tip_inc=tip_adi=-1;
for (i=0;i<virf;i++) {
j=0;
do {
fscanf(f,"%d",&val);
cprintf("\n\rX[%d][%d]: %d",i,j,val);
lc=lista[i];
while (lc!=NULL) {
if (lc->val==val) {
cprintf(" - ERROARE");
tip_lista=-1;
return -1;
}
lc=lc->next;
}
if (val<0) {
cprintf(" - ERROARE");
tip_lista=-1;
return -1;
}
else if (val<virf) {
if (j++==0) lista[i]=l=getlista_el();
else {
l->next=getlista_el();
l=l->next;
}
l->val=val;
}
} while (val<virf && j<virf);
}
return 0;
}
void salvare(void)
{
FILE *f;
int i;
char fname[12],str,tip;
if (control_graf()==1) return;
wrongchoose:
str=show_menu(MENU_SAVE);
if (str=='0') return;
switch (str) {
case '1': tip=tip_inc;break;
case '2': tip=tip_adi;break;
case '3': tip=tip_lista;break;
}
if (tip==-1) {
cprintf("Nu este introdusa.");
getch();
goto wrongchoose;
}
tip+=48;
wrongname:
clrscr();
cprintf("Salvarea grafului:\n\r");
cprintf("Introduceti numele fisierului.\n\r");
cprintf("Nume: ");
scanf("%8s",fname);
for (i=0;i<strlen(fname);i++)
if (!isalnum(fname[i])) {
gotoxy(1,WINDY-1);
cprintf("Nume incorect!");
getch();
goto wrongname;
}
strcat(fname,FEXTENSION);
if ((f=fopen(fname,"w"))==NULL) {
gotoxy(1,WINDY-1);
cprintf("Nu pot sa creez fisierul de iesire.");
getch();
return;
}
fprintf(f,"%c:%c %d,%d\n",str,tip,arce,virf);
switch (str) {
case '1': sal_matr_inc(f);break;
case '2': sal_matr_adi(f);break;
case '3': sal_lista(f);break;
}
fclose(f);
gotoxy(1,WINDY-1);
cprintf("Graful este salvat: %s",fname);
getch();
}
void sal_matr_inc(FILE *f)
{
int i,j;
for (i=0;i<arce;i++) {
for (j=0;j<virf;j++) fprintf(f," %2d",matr_inc[i][j]);
fprintf(f,"\n");
}
}
void sal_matr_adi(FILE *f)
{
int i,j;
for (i=0;i<virf;i++) {
for (j=0;j<virf;j++) fprintf(f," %2d",matr_adi[i][j]);
fprintf(f,"\n");
}
}
void sal_lista(FILE *f)
{
int i;
LISTA *l;
for (i=0;i<virf;i++) {
l=lista[i];
while (l!=NULL) {
fprintf(f," %2d",l->val);
l=l->next;
}
fprintf(f," %2d\n",virf);
}
}
void iesire(void)
{switch (show_menu(MENU_EXIT)) {
case '1': exit(0);
case '0': break;
}
}
void transformare(void)
{
char tip1,tip2;
if (control_graf()==1) return;
do {
switch (tip1=show_menu(MENU_TRANS1)) {
case '1': if (tip_inc==-1) tip1=-1;break;
case '2': if (tip_adi==-1) tip1=-1;break;
case '3': if (tip_lista==-1) tip1=-1;break;
case '0': return;
}
if (tip1==-1) {
cprintf("Nu este introdusa.");
getch();
}
} while (tip1==-1);
do {
switch (tip2=show_menu(MENU_TRANS2)) {
case '1': if (tip1==tip2) tip2=-1;break;
case '2': if (tip1==tip2) tip2=-1;break;
case '3': if (tip1==tip2) tip2=-1;break;
case '0': return;
}
if (tip2==-1) {
cprintf("Selectati tip diferit.");
getch();
}
} while (tip2==-1);
tip1-=49;
tip2-=49;tip2*=3;
tip1+=tip2;
switch (tip1) {
case 1: trans_adi_inc();break;
case 2: trans_lista_inc();break;
case 3: trans_inc_adi();break;
case 5: trans_lista_adi();break;
case 6: trans_inc_lista();break;
case 7: trans_adi_lista();break;
}
cprintf("Transformarea s-a petrecut cu succes.");
getch();
}
void trans_adi_inc(void)
{
int i,j,k=0;
for (i=0;i<virf;i++)
for (j=0;j<virf;j++) if (matr_adi[i][j]==1 && i!=j) k++;
freematr(matr_inc,arce);
arce=k;
matr_inc=getmatr(arce,virf);
for (i=0;i<arce;i++)
for (j=0;j<virf;j++) matr_inc[i][j]=0;
k=0;
if (tip_adi==1) {
for (i=0;i<virf;i++)
for (j=0;j<virf;j++)
if (matr_adi[i][j]==1 && i!=j) {
matr_inc[k][i]=-1;
matr_inc[k++][j]=1;
}
}
else {
arce/=2;
for (i=0;i<virf-1;i++)
for (j=i+1;j<virf;j++)
if (matr_adi[i][j]==1 && i!=j) {
matr_inc[k][i]=1;
matr_inc[k++][j]=1;
}
}
tip_inc=tip_adi;
}
void trans_inc_adi(void)
{
int i,j,k;
freematr(matr_adi,virf);
matr_adi=getmatr(virf,virf);
for (i=0;i<virf;i++)
for (j=0;j<virf;j++) matr_adi[i][j]=0;
for (j=0;j<virf;j++)
for (i=0;i<virf;i++)
if ((tip_inc==1 && matr_inc[i][j]==-1) || (tip_inc==0 && matr_inc[i][j]==1)) {
for (k=0;k<virf;k++)
if (matr_inc[i][k]==1 && k!=j) {
matr_adi[j][k]=1;
break;
}
}
tip_adi=tip_inc;
}
void trans_inc_lista(void)
{int i,j,k,m;
LISTA *l;
freelista(lista,virf);
lista=getlista(virf);
for (j=0;j<virf;j++) {
m=0;
for (i=0;i<virf;i++)
if ((tip_inc==1 && matr_inc[i][j]==-1) || (tip_inc==0 && matr_inc[i][j]==1))
for (k=0;k<virf;k++)
if (matr_inc[i][k]==1 && k!=j) {
if (m++==0) lista[j]=l=getlista_el();
else {
l->next=getlista_el();
l=l->next;
}
l->val=k;
break;
}
}
tip_lista=tip_inc;
}
void trans_lista_inc(void)
{int i,j,k;
LISTA *l;
freematr(matr_inc,arce);
k=0;
for (i=0;i<virf;i++) {
l=lista[i];
while (l!=NULL) {
k++;
l=l->next;
}
}
//if (tip_lista==0) arce=k/2;
arce=k; // ?????????????????????????//
matr_inc=getmatr(arce,virf);
for (i=0;i<arce;i++)
for (j=0;j<virf;j++) matr_inc[i][j]=0;
k=0;
for (i=0;i<virf;i++) {
l=lista[i];
while (l!=NULL) {
if (tip_lista==1) matr_inc[k][i]=-1;
else matr_inc[k][i]=1;
matr_inc[k][l->val]=1;
k++;
l=l->next;
}
}
tip_inc=tip_lista;
}
void trans_adi_lista(void)
{int i,j,m;
LISTA *l;
freelista(lista,virf);
lista=getlista(virf);
for (i=0;i<virf;i++) {
m=0;
for (j=0;j<virf;j++)
if (matr_adi[i][j]==1) {
if (m++==0) lista[i]=l=getlista_el();
else {
l->next=getlista_el();
l=l->next;
}
l->val=j;
}
}
tip_lista=tip_adi;
}
void trans_lista_adi(void)
{int i,j;
LISTA *l;
freematr(matr_adi,virf);
matr_adi=getmatr(virf,virf);
for (i=0;i<virf;i++)
for (j=0;j<virf;j++) matr_adi[i][j]=0;
for (i=0;i<virf;i++) {
l=lista[i];
while (l!=NULL) {
matr_adi[i][l->val]=1;
l=l->next;
}
}
tip_adi=tip_lista;
}
void prelucrare(void) {if (control_graf()==1) return;}
char control_graf(void) {
if (tip_inc==-1 && tip_adi==-1 && tip_lista==-1) { // window(1,1,80,25);
draw_frame(26,3);
textcolor(WINDCOLBKSEL);
cprintf("Nu este posibil.\n\r");
cprintf("Graful nu este introdus.");
screen=1;
getch();
return 1;
}
return 0;
}
void read_matr_adi(void)
{
int i,j;
char ch;
freematr(matr_inc,arce);matr_inc=NULL;
freelista(lista,virf);lista=NULL;
freematr(matr_adi,virf);
clrscr();
cprintf("Introduceti numarul virfurilor: ");
do scanf("%d",&virf); while (virf<MINVIRF || virf>MAXVIRF);
cprintf("\rGraful este orientat ? (D/N): ");
do {
ch=toupper(getch());
if (ch=='D') tip_adi=1;
else if (ch=='N') tip_adi=0;
} while (ch!='D' && ch!='N');
cprintf("%c",ch);
cprintf("\n\rIntroduceti matricea:");
matr_adi=getmatr(virf,virf);
tip_lista=tip_inc=-1;
for (i=0;i<virf;i++) {
for (j=0;j<virf;j++) {
cprintf("\n\rX[%d][%d]: ",i,j);
do {
ch=getch();
if (ch=='1') matr_adi[i][j]=1;
else if (ch=='0') matr_adi[i][j]=0;
} while (ch!='1' && ch!='0');
cprintf("%c",ch);
}
}
if (tip_adi==0)
for (i=0;i<virf-1;i++)
for (j=i;j<virf-1;j++)
if (matr_adi[j+1][i]!=matr_adi[i][j+1]) {
cprintf("\n\rLinia sau coloana %d contine erroare.",i);
tip_adi=-1;
getch();
}
/*else for (i=1;i<virf;i++)
for (j=0;j<i;j++)
if (matr_adi[i][j]!=0) {
printf("\n\rLinia sau coloana %d contine erroare.",i);
tip_adi=-1;
}*/
}
void read_matr_inc(void)
{int i,j,k;
char ch,cp,cm;
freematr(matr_adi,virf);matr_adi=NULL;
freelista(lista,virf);lista=NULL;
freematr(matr_inc,arce);
clrscr();
cprintf("Introduceti numarul virfurilor: ");
do scanf("%d",&virf); while (virf<MINVIRF || virf>MAXVIRF);
cprintf("\rIntroduceti numarul arcelor: ");
do scanf("%d",&arce); while (arce<MINARC || arce>MAXARC);
cprintf("\rGraful este orientat ? (D/N): ");
do {
ch=toupper(getch());
if (ch=='D') tip_inc=1;
else if (ch=='N') tip_inc=0;
} while (ch!='D' && ch!='N');
cprintf("%c",ch);
cprintf("\n\rIntroduceti matricea:");
matr_inc=getmatr(arce,virf);
tip_lista=tip_adi=-1;
for (i=0;i<arce;i++) {
lineerror:
cp=0;cm=0;
for (j=0;j<virf;j++) {
cprintf("\n\rX[%d][%d]: ",i,j);
do {
ch=getch();
if (ch=='1') {matr_inc[i][j]=1;cp++;}
else if (ch=='0') matr_inc[i][j]=0;
else if (ch=='-' && tip_inc==1) {matr_inc[i][j]=-1;cm++;}
} while (ch!='1' && ch!='0' || (ch=='-' && tip_inc==0));
if (isdigit(ch)) cprintf("%c",ch);
else cprintf("-1");
}
if (tip_inc==0) {
if (cp!=2) {
cprintf("\n\rLinia %d contine erroare.\n\rIntroduceti-o din nou.",i);
goto lineerror;
}
}
else if (cp>1 || (cm>1 && tip_inc==1)) {
cprintf("\n\rLinia %d contine erroare.\n\rIntroduceti-o din nou.",i);
goto lineerror;
}
}
for (i=0;i<arce-1;i++)
for (j=i+1;j<arce;j++)
for (k=0;k<virf;k++)
if (matr_inc[i][k]==matr_inc[j][k]) {
if (k==virf-1) {
cprintf("\n\rMatricea contine arce ce se repeta.");
tip_inc=-1;
getch();
return;
}
}
else break;
}
void read_lista(void)
{int i,j,val;
char ch;
LISTA *l,*lc;
freematr(matr_inc,arce);matr_inc=NULL;
freematr(matr_adi,virf);matr_adi=NULL;
freelista(lista,virf);
clrscr();
cprintf("Introduceti numarul virfurilor: ");
do scanf("%d",&virf); while (virf<MINVIRF || virf>MAXVIRF);
cprintf("\rGraful este orientat ? (D/N): ");
do {
ch=toupper(getch());
if (ch=='D') tip_lista=1;
else if (ch=='N') tip_lista=0;
} while (ch!='D' && ch!='N');
cprintf("%c",ch);
cprintf("\n\rIntroduceti lista:\n\r");
lista=getlista(virf);
tip_inc=tip_adi=-1;
for (i=0;i<virf;i++) {
j=0;
do {
cprintf("\rX[%d][%d]: ",i,j);
scanf("%d",&val);
lc=lista[i];
if (val==virf) val++;
while (lc!=NULL) {
if (lc->val==val) {
cprintf("\rVirful a fost introdus deja!");
val=virf;
break;
}
lc=lc->next;
}
if (val<0) cprintf("\rNu exista asa virf!");
else if (val<virf) {
if (j++==0) lista[i]=l=getlista_el();
else {
l->next=getlista_el();
l=l->next;
}
l->val=val;
}
} while (val<=virf && j<virf);
}
/*if (tip_adi==0) {
for (i=0;i<virf-1;i++)
for (j=i;j<virf-1;j++)
if (matr_adi[j+1][i]!=matr_adi[i][j+1]) {
cprintf("\n\rLinia sau coloana %d contine erroare.",i);
tip_adi=-1;
}
}
/*else for (i=1;i<virf;i++)
for (j=0;j<i;j++)
if (matr_adi[i][j]!=0) {
printf("\n\rLinia sau coloana %d contine erroare.",i);
tip_adi=-1;
}*/
}
char **getmatr(int n, int m)
{int i,j;
char **matr;
if ((matr=(char **)calloc(n,sizeof(char *)))==NULL) {
printf("\nNu ajunge memorie pentru pastrarea matricei.");
getch();
exit(1);
}
for (i=0;i<n;i++)
if ((matr[i]=(char *)calloc(m,sizeof(char)))==NULL) {
printf("\nNu ajunge memorie pentru pastrarea matricei.");
getch();
exit(1);
}
return matr;
}
void freematr(char **matr, int n)
{
int i;
if (matr==NULL) return;
for (i=0;i<n;i++) free(matr[i]);
free(matr);
}

LISTA **getlista(int n)
{
LISTA **l;
if ((l=(LISTA **)calloc(n,sizeof(LISTA *)))==NULL) {
printf("\nNu ajunge memorie pentru pastrarea listei.");
getch();
exit(1);
}
return l;
}
LISTA *getlista_el(void)
{LISTA *l;
if ((l=(LISTA *)malloc(sizeof(LISTA)))==NULL) {
printf("\nNu ajunge memorie pentru pastrarea listei.");
getch();
exit(1);
}
l->val=32768;
l->next=NULL;
return l;
}
void freelista(LISTA **l, int n)
{int i;
if (l==NULL) return;
for (i=0;i<n;i++) freelista_el(l[i]);
free(l);
}
void freelista_el(LISTA *l)
{
if (l==NULL) return;
else freelista_el(l->next);
free(l);
}
int show_menu(const char **menu)
{char m=0,m_max=0,m_min=-1,ch=0;
textbackground(WINDCOLBK);
clrscr();
_setcursortype(_NOCURSOR);
for (m=0;menu[m][0]!='\0';m++)
if (isdigit(menu[m][0])) {
textcolor(WINDCOLFR);
cprintf("\n\r%s",menu[m]+1);
if (m_min==-1) m_min=m;
m_max++;
}
else {
textcolor(WINDCOLTITLE);
cprintf("%s",menu[m]+1);
}
m=m_min;
do {
textbackground(WINDCOLBK);
textcolor(WINDCOLFR);
gotoxy(1,m+1);cprintf("%s",menu[m]+1);
switch (ch) {
case 72: if (m>m_min) m--;break;
case 80: if (m<m_max) m++;break;
case 75: m=m_min;break;
case 77: m=m_max;break;
}
textbackground(WINDCOLBKSEL);
textcolor(WINDCOLFRSEL);
gotoxy(1,m+1);cprintf("%s",menu[m]+1);
} while ((ch=getch())!=13);
_setcursortype(_NORMALCURSOR);
textbackground(WINDCOLBK);
textcolor(WINDCOLFR);
gotoxy(1,WINDY-1);
return menu[m][0];
}
void draw_frame(char dx, char dy)
{int i,x1,y1,x2,y2;
window(1,1,80,25);
textbackground(WINDCOLBK);
textcolor(WINDCOLFRAME);
x1=(80-dx)/2;
y1=(25-dy)/2+1;
x2=x1+dx;
y2=y1+dy;
gotoxy(x1,y1);cprintf("г");
for (i=1;i<dx;i++) cprintf("=");
cprintf("¬");
for (i=y1+1;i<y2;i++) {gotoxy(x2,i);cprintf("¦");}
gotoxy(x1,y2);cprintf("L");
for (i=1;i<dx;i++) cprintf("=");
cprintf("-");
gotoxy(x1,y1+1);
for (i=y1+1;i<y2;i++) {gotoxy(x1,i);cprintf("¦");}
window(x1+1,y1+1,x2-1,y2-1);
clrscr();
}
void about(void)
{ //window(1,1,80,25);
draw_frame(60,7); //clrscr();
textcolor(WINDCOLFR);
cprintf("Universitate Tehnica a Moldovei\n\r");
cprintf("Facultatea Calculatoare, Informatica, Microelectronica\n\r");
cprintf("Disciplina: Matematica Discreta\n\r");
cprintf("Lucrare de laborator Nr. 1\n\r");
cprintf("Tema: Pastrarea grafurilor in memoria calculatorului\n\r");
cprintf("A efectuat: Lazari Alexei, studentul grupei TI-001");
screen=1;
getch();
}
void Graph_Init(void)
{int graphdriver=DETECT, graphmode, errorcode;
errorcode=graphresult();
if (errorcode < 0) {
printf("\n\rGraphics System Error: %s\n",grapherrormsg(errorcode));
exit(9);
}
initgraph(&graphdriver, &graphmode, "");
errorcode=graphresult();
if (errorcode != grOk) {
printf("\n\rGraphics System Error: %s\n",grapherrormsg(errorcode));
exit(9);
}
}
void getcoord(int *x, int *y, int v)
{*x=ORIGX+radius*cos(alfa*v); *y=ORIGY-radius*sin(alfa*v); }
void drawvirf(int x, int y, int v)
{char num[3]; itoa(v+1,num,10); fillellipse(x,y,VIRFRADIUS,VIRFRADIUS);
setcolor(WINDCOLFRAME); circle(x,y,VIRFRADIUS); circle(x,y,VIRFRADIUS+1); setcolor(WINDCOLFR);
outtextxy(x,y,num); }
void joinvirf(int v1, int v2, char tip)
{int x1,y1,x2,y2; getcoord(&x1,&y1,v1); getcoord(&x2,&y2,v2); line(x1,y1,x2,y2); tip++; }
setbkcolor – functia data are prototipul in biblioteca graphics.h . Cu ajutorul ei se poate seta culoarea background-ului.
setcolor - functia data are prototipul in biblioteca graphics.h . Cu ajutorul ei se seteaza culoarea textului la afisare.
outtextxy – functia data are prototipul in biblioteca graphics.h . Cu ajutorul ei se poate aduce un text. Functia mai are ca
parametri coordonatele x,y unde si se afiseaza textul.
delay - functia data are prototipul in biblioteca dos.h . Ia are menirea de a face o pauza. Durata se indica in milisecunde.
putpixel - functia data are prototipul in biblioteca graphics.h . Pune un pixel cu coordonatele ce se indica.
closegraph - functia data are prototipul in biblioteca graphics.h . Functia de inchidere a regimului grafic.
strcat – concatineaza doua siruri de caractere.
remove – functia de stergere a unui fisier.
6. Variante pentru lucrul individual. Sarcini:
1.Program care citeste din fisier 3 propozitii si le afiseaza in ordinea inversa, apoi le salvează în alt fişier.
2.Sa se scrie un program care creaza un fisier numbers.txt pe discul D, in care inscrie 5 numere intregi, introduse
de la tastatura. Fiecare se scrie pe linie separata, apoi se afişează la ecran.
3. Intr-un fisier "cod.dat" este memorata o tabela de codificare, sub forma: car_de_codif ' ' car_codif '\n'. Sa
se preia un text din fisierul "dat1.dat", sa se codifice conform codului, iar textul obtinut sa se scrie in fisierul
"dat2.txt".
4.Sa se calculeze cat timp a trecut de la inceputul erei noastre.Structurile de baza sunt:
deceniu={veac,era}
timp={ora,minutul,secunda}
data={zi,luna,an}; apoi le salvează în alt fişier
5. Sa se scrie un program care creaza un fisier cu 10 elemente de tip intreg. Citeste din fisier si calculeaza
suma acestor elemente, apoi se afişează la ecran şi le salvează în alt fişier.
6. Sa se interclaseze continutul a doua fisiere intr-un al treilea fisier. Informatiile dintr-un fisier sunt:
numarul_de_valori '\n' val1 '\n' val2 '\n'... Valorile intregi val1, val2, etc. sunt strict crescatoare. Valorile comune
se trec o singura data in fisierul rezultant.
7. Dintr-un fisier se citesc 15 caractere distincte, care codifica cifrele zecimale 0,1,2...9 si operatorii +,-,*,/ si
=. Tot din fisier se citeste un sir de maxim 80 de caractere, terminat prin caracterul '='si care reprezinta o expresie
aritmetica cu operanzi intregi fara semn. Se considera expresie corecta cea care satisface urmatoarele conditii:
- contine numai caractere ale carei coduri au fost citite initial
- nu contine doi operatori succesivi
- nu contine impartiri la zero.
Daca expresia este incorecta se afiseaza un mesaj de eroare corespunzator primei erori intilnite. Daca expresia
este corecta se va evalua, efectuind operatiile de la stinga la dreapta in ordinea in care apar si se va afisa valoarea
calculata codificata conform listei de coduri date.
8. Dintr-un fisier de intrare se citeste o propozitie terminata printr-un punct. Propozitia este formata din
cuvinte ce contin doar litere mari. Cuvintele sunt separate prin unul sau mai multi separatori din multimea
blanc,'\t','\n'. Stiind ca propozitia are cel mult 30 de cuvinte, sa se afiseze grupurile de cuvinte in care fiecare
membru reprezinta anagrama altui membru din grup. Un grup va contine numarul maxim de membrii, iar
membrii sunt distincti.
9.Un fisier contine 7 linii, pe fiecare scriind o zi a saptamanii urmata dupa un spatiu de suma cheltuita in ziua
respectiva, apoi se afişează la ecran.
10. Sa se scrie un program C ce prelucreaza fisierul de mai sus (9) si afiseaza suma totala cheltuita, ziua cu
suma maxima si suma medie. Daca sunt mai multe zile cu aceeasi suma maxima, puteti tipari doar prima zi in
care s-a cheltuit suma sau toate.
11) Se cere programul C care sa afiseze dimensiunea in octeti a fisierului de tip text AUTOEXEC.BAT aflat pe
discul D: .
12) Scrieti un program care sa citeasca de la tastatura numele a n studenti pe care sa le memoreze intr-un fisier cu
numele STUDENTI.TXT de tip text, numele fiind separate intre ele prin <Enter>. Afisati pe ecran ceea ce se scrie
in fisier. Vrificati daca fisierul s-a creat corect folosind comenzi DOS.
13) Pentru fisierul creat anterior sa se scrie programul care il actualizeaza prin adaugarea a inca m studenti la
sfarsitul fisierului. Dupa adaugare se cere generarea unui alt fisier cu numele studentilor in ordine alfabetica.
Folositi functiile qsort si strcmp, precum si pointeri spre siruri de caractere pentru ordonare.
14) Se cere programul pentru a copia continutul unui fisier in alt fisier. Numele celor doua fisiere se vor da in
linia de comanda.
15) Se considera un fisier text anterior creat printr-o metoda oarecare. Scrieti programul care sa determine
numarul de aparitii a fiecarei cifre de la 0 la 9. Pe ecran se va afisa: "Cifra … apare de …ori".
16) Programul urmator trebuie sa realizeze transformarea unui fisier text in alt fisier text, care sa contina doar
litere mari (inlocuirea literelor mici cu litere mari). Numele fisierelor se vor da in linia de comanda. Se cere sa se
completeze programul cu secventele potrivite (inlocuind semnele .. .. cu instructiuni sau functii corespunzatoare).
17) Pentru un concurs de admitere se genereaza un fisier cu numele "concurs.not" care contine numele
candidatilor impreuna cu notele la matematica, la fizica si media. Se cere programul pentru generarea acestui
fisier de la tastatura.
18) Pentru fisierul creat anterior se cere programul de consultare, care sa afiseze pe ecran o inregistrare a unui
candidat identificata prin numarul ei de ordine in fisier.
19) Se cere programul care concateneaza doua fisiere, cu generarea unui al treilea fisier. Numele fisierelor se
preiau din linia de comanda.
20) Se considera un fisier text si doua tablouri de siruri de caractere, care contin cuvinte. Se cere programul C
care pe baza fisierului dat genereaza un alt fisier, inlocuind cuvintele pe care le gaseste in primul tablou cu
cuvintele corespunzatoare din al doilea tablou.
21. Fisierul ELEVI.TXT contine urmatoarele informatii despre elevii unei scoli: numele si prenumele, data
nasterii, clasa, media (numarul de caractere pentru fiecare cimp se deduce din consultarea fisierului).
a). Se cere un tabel pe ecran si intr-un fisier text cu numarul si numele elevilor cu media 10.
22. Sa se creeze un fisier care contine numele tuturor fisierelor text dintr-un director dat ca parametru si din
subdirectoarele acestuia care au cuvinte mai lungi de 15 caractere. Fisierul va fi ordonat alfabetic.
23. Se da un fisier care contine pe fiecare rand un nume (un cuvint) urmat de 5 note. Se cere sa se construiasca un
al doilea fisier care contine numele urmat de medie, ordonat descrescator dupa medie. Daca un nume apare pe
mai multe linii in fisierul original, liniile respective vor fi scrise intr-un fisier cu numele 'eronat', si pentru acestea
nu se va calcula media.
24. Sa se scrie un fisier de comenzi care are ca parametri doua cuvinte si o lista de fisiere. Sa se construiasca un
fisier prin concatenarea fisierelor din lista dupa ce se aplica urmatoarele modificari: pentru fisierele de rang impar
din lista se vor inlocui toate aparitiile primului cuvant cu al doilea, iar pentru fisierele de rang par, se va inlocui
ultima aparitie din fiecare linie a celui de-al doilea cuvant cu primul.
25. Pentru fiecare fisier din linia de comanda se vor afisa toate liniile care sunt mai lungi de 10 caractere. De
asemenea, se vor inlocui toate cifrele cu caracterul 'x'. Liniile unui fisier vor fi precedate de numele fisierului. Se
va face o situatie finala cu numarul liniilor afisate din fiecare fisier, in ordine descrescatoare in functie de numarul
liniilor.
26. Să se scrie în fişier un text în lungime N introdus de la tastatură, apoi afişează la cerere. Operaţiile de I/E în
fişier utilizează funcţiile respective.
27. Să se scrie programul care creează un fişier text în care se memorează două matrice, astfel: pe prima linie numărul
de linii şi numărul de coloane ale primei matrice, separate printr-un spaţiu; pe fiecare din liniile următoare, în ordine,
elementele unei linii din matrice, separate prin cîte un spaţiu; în continuare a doua matrice, în aceeaşi formă.. Apoi de
afişat.
28. Să se scrie programul care înmulţeşte matricele aflate în fişierul creat la problema anterioară. Rezultatul se va
memora în alt fişier, în aceeaşi formă. Dacă înmulţirea nu e posibilă, se va scrie ca rezultat un mesaj de eroare.
Matricele sînt suficient de mici pentru a putea fi încărcate în memorie (n,m =5).
29. Să se scrie programul care numără frecvenţa de apariţie a fiecărei valori dintr-un vector memorat într-un fişier
binar. Rezultatul va fi memorat într-un fişier text astfel: pe fiecare linie, separate printr-un spaţiu, se vor scrie valoarea,
numărul de apariţii şi frecvenţa relativă de apariţie.
30. Matrice memorate în fişiere binare. Pentru lucrul cu matrice memorate în fişiere binare s-a adoptat
următorulmod de organizare: primul articol conţine numărul de linii ale matricei, iar următoarele articole conţin, în
ordine, cîte un element al matricei, în ordine lexicografică. Se va lucra cu matrice cu elemente reale. Numărul de linii
este întreg (primul articol are altă dimensiune). Să se scrie programul care memorează într-un fişier binar o matrice
introdusă de la tastatură.
31. Se dă un fișier care conține un şir alfanumeric(80). De determinat elementele şirului care corespund
respectivului sistem numeric (zecimal, octal, hexazecimal sau binar) şi de grupat pe categorii, aflîndu-le valorile în
sistemul zecimal, totodată, aranjîndu-le în creştere.
32. Într-un fișier este dat un şir S de numere întregi. Elementele şirului fiind alcătuite aleatoriu din mai multe cifre
de 1,2 şi 3, formînd subşiruri de trei cifre, şi orice două elemente ale subşirului pot fi iinterschimbate. Se cere de
efectuat minimul de iinterschimbări , astfel încît din şirul dat S să obţineţi altfel de subşiruri în care pe primele K
poziţii se află unităţi, urmatoarele L poziţii conţin numărul 2, iar restul sunt pozitii cu numarul 3. Argumentaţi motivul
metodei alese din punct de vedere de eficienţă.
33. Sa se caute in directorul specificat toate programele sursa de tip *.CPP si sa se salveze în alt fișier și să se
afiseze pe ecran, caracter cu caracter, aceste programe determinadu-se si afisandu-se pentru fiecare numarul de
linii sursa.
34. Sa se creeze, in directorul curent, mai multe fisiere text, caracter cu caracter, precizandu-se pentru fiecare,
prin dialog, numele si extensia.
35. Sa se includa, printr-o functie adecvata de includere include(), intr-un fisier text, dupa o linie al carei
numar de secventa este precizat, un alt fisier text anterior creat.
Bibliografie:
1. ."Limbajul de programare C". Brian W.Kernighan. Dennis M.Ritchie.
2. Liviu Negrescu. ”Limbajul de programare C şi C++” V.1-4. Buc. 1999
3. Bacivarov, A.; Nastac, I. - "Limbajul C. Indrumar de laborator", Tipografia UPB, Bucuresti, 1997.
4. BibliogrШилдт, Герберт. Полный справочник по С, 4-е издание. : Пер. с англ. - М,: Издательский дом "Вильямс",
2002. - 704 с. : ил. - Парал.т ит. англ.
5. Павловская Т.А. С/C++. Программирование на языке высокого уровня. / Т.А. Павловская. - СПб.: Питер, 2002. -
464 с.: ил.
6. Культин Н.Б. C/C++ в задачах и примерах. - СПб.:БХВ-Петербург, 2001. - 288 с.: ил.
7. Першиков В.И., Савинков В.М. Толковый словарь по информатике.-М.: Финансы и статистика, 1991. - 543 с.

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