Uploaded by Ionn

Lucrare de an

advertisement
Ministerul Educaţiei Republicii Moldova
Universitatea Tehnică a Moldovei
Facultatea Calculatoare, Informatică şi Microelectronică.
Departamentul de Informatică şi Ingineria sistemelor
Lucrare de an
La disciplina: “Structuri de date şi algoritmi”.
Tema: “Realizarea unei Baze de Date cu ajutorul limbajului C”.
A efectuat :
st.gr.
A verificat :
Chişinău, 2018
Cuprins
1. Introducere.............................................................................3
2. Liste…………........................................................................5
3. Liste circulare simplu inlantuite............................................10
4. Tipuri de fisiere.....................................................................14
5. Lucrul cu fişierele.................................................................15
6. Citirea si scrierea fisierelor...................................................17
7. Stergerea, redenumirea si crearea fisierelor..........................21
8. Listingul programului...........................................................22
9. Rezultatul final……..............................................................32
10. Concluzii............................................................................34
11. Bibliografie .......................................................................35
1
1.Introducere
Scrierea unui program intr-un limbaj de programare este doar primul pas
dintr-un proces care mai cuprinde si alti pasi. Mai corect ar fi sa spunem
scrierea unei versiuni initiale a programului, pentru ca intotdeauna aceasta
forma initiala este corectata, modificata sau extinsa pentru eliminarea unor
erori, pentru satisfacerea unor noi cerinte sau pentru imbunatatirea performantelor
in executie.
Un program scris intr-un limbaj independent de masina (C, Pascal, s.a.)
trebuie mai intai tradus de catre un program translator sau compilator.
Compilatorul citeste si analizeaza un text sursa (de exemplu in limbajul C) si
produce un modul obiect (scris intr-un fisier), daca nu s-au gasit erori in textul
sursa. Pentru programele mari este uzual ca textul sursa sa fie format din mai
multe fisiere sursa, care sa poata fi scrise, compilate, verificate si modificate
separat de celelalte fisiere sursa.
Mai multe module obiect, rezultate din compilari separate sunt legate
impreuna si cu alte module extrase din biblioteci de functii standard intr-un
program executabil de catre un program numit editor de legaturi (“Linker” sau
“Builder”). Executia unui program poate pune in evidenta erori de logica sau
chiar erori de programare care au trecut de compilare (mai ales in limbajul C).
Cauzele erorilor la executie sau unor rezultate gresite nu sunt de obicei
evidente din cauza ca ele sunt efectul unui numar mare de operatii efectuate de
calculator. Pentru descoperirea cauzelor erorilor se poate folosi un program
depanator (“Debugger”) sau se pot insera intructiuni de afisare a unor rezultate
intermediare in programul sursa, pentru trasarea evolutiei programului.
Fazele de modificare (editare) a textului sursa, de compilare, linkeditare si
executie sunt repetate de cate ori este necesar pentru a obtine un program corect.
De fapt, testarea unui program cu diverse date initiale poate arata prezenta unor
erori si nu absenta erorilor, iar efectuarea tuturor testelor necesare nu este posibila
pentru programe mai complexe (pentru. un compilator sau un editor de texte, de
exemplu).
Programele compilator si linkeditor pot fi apelate in mod linie de comanda
sau prin selectarea unor optiuni din cadrul unui mediu integrat de dezvoltare a
programelor (IDE = Integrated Development Environment).
Alte programe utilizate in procesul de dezvoltare a unor aplicatii mari sunt:
- program bibliotecar pentru crearea si modificarea unor biblioteci de subprograme
pe baza unor module obiect rezultate din compilare.
- program pentru executia unor fisiere de comenzi necesare pentru compilarea
selectiva si re-crearea programului executabil, dupa modificarea unor fisiere
sursa sau obiect (“make”).
- program de control al versiunilor succesive de fisiere sursa.
Limbajul C s-a impus în principal datoritã existentei unui standard care
contine toate facilitãtile necesare unui limbaj pentru a putea fi folosit într-o mare
diversitate de aplicatii, fãrã a fi necesare abateri sau extinderi fatã de standard
2
(cazul limbajului Pascal). Un exemplu este recunoasterea posibilitãtii ca un
program sã fie format din mai multe fisiere sursã si a compilãrii lor separate,
inclusiv referiri dintr-un fisier în altul. In plus, existã un numãr relativ mare de
functii uzuale care fac parte din standardul limbajului si care contribuie la
portabilitatea programelor C.
Limbajul C permite un control total asupra operatiilor realizate de procesor
si asupra functiilor sistemului de operare gazdã, aproape la fel ca si limbajele de
asamblare. Astfel se explicã de ce majoritatea programelor de sistem si utilitare
sunt scrise de mai multi ani în limbajul C, pe lângã multe programe de aplicatii.
Limbajul C permite scrierea unor programe foarte compacte, ceea ce poate fi
un avantaj dar si un dezavantaj, atunci când programele devin criptice si greu de
înteles. Scurtarea programelor C s-a obtinut prin reducerea numãrului de cuvinte
cheie, prin existenta unui numãr mare de operatori exprimati prin unul sau prin
douã caractere speciale dar si prin posibilitatea de a combina mai multi operatori si
expresii într-o singurã instructiune (acolo unde alte limbaje folosesc mai multe
instructiuni pentru a obtine acelasi efect).
Din perspectiva timpului se poate spune cã instructiunile C sunt o reusitã a
limbajului (si au fost preluate fãrã modificari de multe alte limbaje : C++, Java
s.a.) dar functiile de intrare-iesire (printf,scanf) nu au fost un succes (si au fost
înlocuite în alte limbaje). Un alt neajuns s-a dovedit a fi necesitatea argumentelor
de tip pointer pentru functiile care trebuie sã modifice o parte din argumentele
primite si a fost corectat prin argumente de tip referintã. Utilizarea directã de
pointeri (adrese de memorie) de cãtre programatorii C corespunde lucrului cu
adrese de memorie din limbajele de asamblare si permite operatii imposibile în alte
limbaje, dar în timp s-a dovedit si o sursã importantã de erori la executie, greu de
depistat.
Au mai fost preluate în limbajele post-C si anumite conventii, cum ar fi
diferenta dintre litere mici si litere mari, diferenta dintre caractere individuale si
siruri de caractere (si terminarea sirurilor de caractere cu un octet zero), operatorii,
comentariile s.a.
3
2. Liste
Aspecte teoretice. Definiţie. Operaţii asupra listelor
O listă L e o secvenţă de zero sau mai multe elemente, numite noduri, toate
fiind de acelaşi tip de baza T. L=a1,a2,...,an (n>=0)
Dacă n>=1, a1 se spune că este primul nod al listei, iar an, ultimul nod. Daca
n=0, lista este vida.
O proprietate importantă a unei liste este aceea că nodurile sale pot fi ordonate
liniar funcţie de poziţia lor în cadrul listei. Se spune că ai precede pe ai+1
(i=1,2,...,n-1), iar ai succede pe ai-1 (i=2,3,...,n), ai aflându-se pe poziţia i.
Se postulează(presupune) existenta poziţiei următoare ultimului element al
listei şi se introduce funcţia FIN(L) ce va returna poziţia următoare poziţiei n din
lista L de n elemente.
Folosind notaţiile anterioare şi notând x(de tip T) un nod al listei, iar p fiind
de tip poziţie, se introduce următorul set reprezentativ de operatori aplicabili
obiectelor de tip lista:
INSEREAZA(L,x,p)- inserează în lista L nodul x, în poziţia p;
dacă L=a1,a2,...,an, în urma inserţiei:
p<FIN(L),L=a1,...,ap-1,x,a p+1,...,an
p=FIN(L),L=a1,...,an,x
p>FIN(L),rezultatul inserţiei este imprevizibil.
Implementarea listelor . Structuri recursive de tip listă
Cu ajutorul tipului pointer, se defineşte structura unui nod al listei liniare care
apare ca o structură recursivă, având o componentă de tip identic cu al structurii
complete.
type PointerNod=^Nod;
Nod=record
cheie:TipCheie;
urmator:PointerNod;
info:TipInfo
end;
var început:PointerNod;
Caracteristica unei astfel de structuri constă în prezenta unei singure
înlănţuiri. Câmpul cheie serveşte la identificarea nodului( acest câmp poate face
parte din informaţia utilă, el este utilizat în cazul căutărilor, sortării…), câmpul
următor e pointer de înlănţuire la nodul următor, iar cel info conţine informaţia
utilă.
Variabila început indica spre primul nod al listei; în unele situaţii în locul lui
început se utilizează un nod fictiv, adică o variabila de tip nod cu câmpurile cheie
şi info neprecizate, dar câmpul următor indicând spre primul nod al listei.
De asemenea uneori e util a se păstra pointerul spre ultimul nod al listei.
4
O varianta este a listelor circulare la care dispare noţiunea de prim, ultim
nod.
Tehnici de inserţie a nodurilor şi de creare a listelor înlănţuite
a)inserţia unui nod la începutul listei
Dacă început e variabila pointer ce indica spre primul nod al listei, iar q o
variabila auxiliara de tip pointer, secvenţa următoare realizează inserţia la
începutul listei şi actualizează pointerul început:
new(q); {creează spaţiu pentru un nou nod}
q^.urmator:=inceput;
{asignarea câmpurilor cheie şi info}
inceput:=q;
Secvenţa e corectă şi pentru inserţia într-o listă vidă, caz în care inceput=nil
(nil fiind pointerul vid, care nu se refera la nici o variabilă indicată).
b)inserţia unui nod la sfârşitul listei
Devine mai simplă dacă se păstrează o variabilă sfârşit indicând spre ultimul
nod al listei:
new(q); {creează spatiu pentru noul nod ultim al listei}
sfirsit^.urmator:=q;
q^.urmator:=nil;
{asignarea câmpurilor cheie şi info}
sfirsit:=q;
Pentru inserţia la sfârşitul listei e necesara existenta a cel puţin un nod, care se
creează prin procedura de la paragraful anterior.
c)inserţia unui nod după unul indicat (p)
E simplă pentru că se cunoaşte pointerul spre nodul anterior şi spre cel următor
celui ce se inserează (pointerul spre nodul următor e valoarea câmpului următor al
nodului indicat).
new(q);
q^.urmator:=p^.urmator; {legăm nodul de nodul anterior}
p^.urmator:=q; {legăm nodul anterior de q}
d)inserţia unui nod în fata unui nod indicat
Printr-un artificiu, se reduce acest caz la cel anterior: se inserează un nod după
cel indicat, cheia şi informaţia din nodul indicat fiind atribuite noului nod inserat
şi fiind înlocuite cu valorile nodului ce trebuia inserat.
Tehnici de suprimare
a) Suprimarea nodului următor celui indicat de o variabila pointer q se face
astfel:
p:=q^.urmator; {punem un indicator către nodul care urmează a fi şters}
5
q^.urmator:=q^.urmator^.urmator;{nodul anterior celui ce urmează a fi şters
pointează către nodul următor acestuia}
dispose(p);{ eliberăm memoria ocupată de nod}
Pentru a elibera memoria ocupată de nodul care va fi şters mai avem nevoie de un
pointer spre acest nod. După ce s-a făcut ruperea legăturilor se eliberează memoria
cu dispose.
b) Suprimarea nodului indicat de o variabilă pointer q se face astfel:
p:=q^.urmator;{se memorează legătura către nodul următor}
q^:=q^.urm^;{se copiază conţinutul nodului următor peste cel curent}
dispose(p);{se dezalocă memoria}
Această metodă nu poate fi utilizată pentru ultimul nod din listă.
Traversarea unei liste înlănţuite
Dacă nodul de început al listei e indicat de variabila început, o variabila
auxiliara q, care parcurge toate nodurile listei până când valoarea ei devine nil,
permite accesul la fiecare nod şi efectuarea operaţiei specifice traversării.
Aplicatii ale listelor înlănţuite
Liste ordonate şi reorganizarea listelor
a)Căutarea intr-o lista neordonată; tehnica fanionului.
Se considera o lista simplu înlănţuita, cu nodurile de tip Nod. Daca început
indica spre primul nod al listei, iar ordinea cheilor în lista este aleatoare,
căutarea unei chei implica traversarea listei. Funcţia booleana găsit returnează
valoarea true şi pointerul spre nodul cu cheia egala cu cea căutată, dacă un astfel
de nod există şi valoarea false în caz contrar:
function gasit(val:TipCheie;var poz:PointerNod):boolean;
var found:boolean;
begin
poz:=inceput;found:=false;
while (poz<>nil) and not found do
if poz^.cheie=val then found:=true
else poz:=poz^.urmator;
gasit:=found
end;
Căutarea se poate perfecţiona prin utilizarea metodei fanionului, lista
prelungindu-se cu un nod fictiv numit fanion, la creare lista conţinând acest unic
6
nod. În funcţia gasit, înainte de baleierea listei, informaţia căutată se introduce
în
cheia nodului fanion, astfel încât va exista cel puţin un nod cu cheia căutată:
var fanion:PointerNod;
...
function gasit(val:TipCheie;var poz:PointerNod):boolean;
begin
poz:=inceput;fanion^.cheie:=val;
while poz^.cheie<>val do poz:=poz^.urmator;
gasit:=poz<>fanion
end;
b)Crearea unei liste ordonate; tehnica celor doi pointeri
în continuare se prezintă o metodă foarte simpla pentru crearea unei liste
ordonate, tipurile PointerNod şi Nod fiind cele definite anterior. Lista se
iniţializează cu doua noduri fictive pointate de doua variabile pointer, inceput şi
fanion:
var inceput, fanion:PointerNod;
procedure init;
begin
new(inceput);
new(fanion);
inceput^.urmator:=fanion
end;
Pentru introducerea unei noi chei în listă, păstrând ordonarea, se va scrie o
funcţie gasit, care dacă găseşte cheia în listă returnează valoarea true şi pointerii
p1 spre nodul gasit şi p2 spre cel anterior, respectiv în cazul negasirii cheii,
valoarea false şi pointerii p1 şi p2 spre nodurile intre care trebuie făcută inserţia:
function gasit(val:TipCheie;var p1,p2:TipPointer):boolean;
begin
p2:=inceput;
p1:=p2^.urmator;
fanion^.cheie:=val;
while p1^.cheie<val do
begin
p2:=p1;
p1:=p2^.urmator
end;
gasit:=(p^.cheie=val) and (p1<>fanion)
end;
7
Fragmentul de program ce inserează o noua cheie este:
var p1,p2,p3:PointerNod;val:TipCheie;
...
if not gasit(val,p1,p2) then
begin
new(p3);
p2^.urmator:=p3;
with p3^ do
begin
cheie:=val;
{info}
urmator:=p1
end
end;
Pentru o tipărire a cheilor dintr-o listă ordonată astfel creată, pointerul ce
parcurge nodurile trebuie sa fie iniţializat cu valoarea pointerului spre primul
nod efectiv al listei, următor celui început, iar parcurgerea listei se face până la
întâlnirea nodului fanion:
var p:PointerNod;
...
p:=inceput^.urmator;
while p<>fanion do
begin
{prelucrare nod}
p:=p^.urmator
end;
c)tehnica de căutare în listă cu reordonare
În compilatoare, structurile de date de tip listă liniară sunt foarte avantajoase
în crearea şi exploatarea
listei identificatorilor. Conform principiului
localizării, apariţia unui identificator oarecare în textul sursa, poate fi urmata cu
mare probabilitate de una sau mai multe reapariţii.
Pornind de la acest principiu, s-a conceput metoda de căutare cu
reordonare, care consta în aceea ca ori de câte ori un identificator se caută şi se
găseşte în listă, el se aduce la începutul listei, astfel încât la proxima apariţie, deci
căutare, el se va găsi la începutul listei, iar dacă nu s-a găsit se inserează la
începutul listei.
8
3. Liste circulare simplu inlantuite
O lista circulara simplu inlantuita este o lista in care ultimul element contine
campul ce adreseaza elementul urmator, adresa primului element.
1.1. Definirea unei liste circulare simplu inlantuite
Type lista = ^nod;
nod = record
inf: integer;
adr: lista;
end;
var pr: lista;
inf1
adr2
inf2
adr3
inf3
adr1
Crearea unei liste circulare se realizeaza in mod asemanator cu o lista liniara
simplu inlantuita, cu deosebirea ca ultimul element adaugat in lista nu va mai avea
in campul de adresa valoarea NIL, ci adresa primului element adaugat.
1.2. Crearea unei liste circulare cu numar cunoscut de elemente
Vom crea mai intai primul element al listei. Folosind un ciclu for vor fi
adaugate la sfarsitul listei celelalte elemente. In final campul de adresa al ultimului
element adaugat va contine adresa primului element.
Vom utiliza pointerii : pr – contine adresa primului element adaugat in lista;
ul – contine adresa ultimului element adaugat in lista; p – contine adresa
elementului ce se adauga.
Procedure creare (var p:lista);
Var p, ul : lista;
i: integer;
begin
new(pr);
readln(pr^.inf);
ul:=pr;
for i := 1 to n-1 do begin
new(p); readln(p^.inf);
ul^.adr:=p;
ul:=p;
9
end;
ul^.adr:pr;
end;
1.3. Afisarea elementelor unei liste circulare
Parcurgem nodurile listei cu ajutorul unui pointer care plecand de la un
element al listei, va referi pe rand fiecare nod al listei, pana cand va adresa nodul
de pornire.
Parcurgerea folosind un ciclu while
Procedure parc1 (pr:lista);
var p:lista;
begin
p:=pr;
while (p^.adr<>pr) do begin
write (p^.inf,’ ’); p:= p^.adr;
end;
write (p^.inf);
end;
Parcurgerea folosind un ciclu repeat
Procedure parc2 (pr:lista);
var p:lista;
begin
p:=pr;
repeat
write (p^.inf,’ ’);
p:=p^.adr;
until p=pr;
end;
1.4. Adaugarea unui element intr-o lista circulara
Sa se scrie un subprogram ce realizeaza inserarea unui nod dupa elementul
de cheie k dintr-o lista circulara.
Observam ca intr-o lista circulara putem accesa toate elementele listei
pornind din orice nod al acesteia. Avand in vedere acest lucru, pentru a evita
tratarea cazului particular de inserare inainte primului element, vom parcurge lista
prin intermediul lui pr, salvand adresa primului element intr-o variabila p.
Procedure adaug (var pr:lista; k:integer);
var p: lista;
begin
10
p:=pr:
repeat
if pr^.inf=k then begin
new(q); readln(q^.inf);
q^adr:= pr^.adr;
pr:=p;
end;
else pr:=pr^.adr;
until (pr=p);
end;
1.5. Eliminarea elementelor dintr-o lista circulara
Sa se scrie un subprogram ce realizeaza eliminarea elementelor de cheie para
dintr-o lista circulara.
In situatia in care toate elementele sunt pare lista devine vida. Punem in
evidenta acest lucru prin pr:=nil. Parcurgem lista prin pr, pozitionandu-ne pe
elementul anterior care trebuie sters.
Procedure elimin (var pr:lista);
var p,q:lista;
begin
p:=pr;
while pr^.adr<>p do
if pr^.adr^.inf mod 2 = 0 then begin
{se elimina pr^.adr}
q:=pr^.adr;
pr^.adr:=q^.adr;
dispose(q);
end
else pr:=pr^.adr;
if p^.adr=pr then begin
{lista are un singur element}
if pr^.inf mod 2 = 0 the begin
dispose(pr);
pr:=nil;
end
end
else
{se verifica daca nodul de pornire este par, situatie in care se elimina}
pr^.inf mod 2 = 0 then begin
dispose(p);
end;
end;
11
1.6. Crearea unei liste circulare cu numar necunoscut de elemente
Se sa fisierul Numere.in. Sa se creeze o lista circulara simplu inlantuita ce
contine numerele pare din fisier.
type lista = ^nod;
nod = record
inf:integer;
adr:lista;
end;
var pr:lista; f:text;
procedure creare (var pr:lista);
var p,ul:lista; k:integer;
begin
assign(f,’numere.in’); reset(f);
pr:=nil;
while not seekof(f) do begin
read(f,k);
if k mod 2=0 then begin
new(p);
p^.inf:=k;
if pr=nil then begin
pr:=p;
ul:p;
end
else begin
ul^.adr:=p; ul:=p;
end;
end;
end;
ul^.adr:= pr; close(f);
end;
procedure parc (pr:lista);
var p:lista;
begin
p:=pr;
repeat
write (p^.inf, ’ ’);
p:=p^.adr;
until p=pr;
end;
begin {main}
creare (pr);
parc (pr);
end.
12
4.Tipuri de fisiere
Un fisier ("File") este o colectie de date memorate pe un suport extern si care este
identificatã printr-un nume. Fisierele se folosesc fie pentru date initiale si pentru
rezultate mai numeroase, fie pentru pãstrarea de duratã a unor date de interes
pentru anumite aplicatii.
Fisierele sunt entitãti ale sistemului de operare si ca atare ele au nume care
respectã conventiile sistemului, fãrã legãturã cu un limbaj de programare.
Operatiile cu fisiere sunt realizate de cãtre sistemul de operare, iar compilatorul
unui limbaj traduce functiile (instructiunile) de acces la fisiere în apeluri ale
functiilor sistem. Programatorul se referã la un fisier printr-o variabilã; tipul acestei
variabile
depinde de limbajul folosit si chiar de functiile utilizate (în C). Asocierea dintre
numele extern (un sir de caractere) si variabila din program se face la deschiderea
unui fisier, printr-o functie standard. De obicei prin "fisier" se subîntelege un fisier
disc (pe suport magnetic sau optic), dar notiunea de fisier este mai generalã si
include orice flux de date din exterior spre memorie sau dinspre memoria internã
spre exterior. Dispozitivele periferice uzuale au nume de fisiere predefinite; de
exemplu, în limbajul C sub MS-DOS si MS-Windows se pot folosi urmãtoarele
nume :
CON = consola sistem (tastaura la citire si monitor la scriere)
PRN (LPT) = imprimanta sistem
Pentru fisierele disc un nume de fisier poate include urmãtoarele:
- Numele unitãtii de disc sau partitiei disc ( ex: A:, C:, D:, E:)
- "Calea" spre fisier, care este o succesiune de nume de fisiere catalog
(director), separate printr-un caracter ('\' în MS-DOS si MS-Windows, sau '/' în
Unix si Linux)
- Numele propriu-zis al fisierului ( max 8 litere si cifre în MS-DOS)
- Extensia numelui, care indicã tipul fisierului (continutul sãu) si care poate
avea între 0 si 3 caractere în MS-DOS).
Exemple de nume de fisiere disc:
A:bc.rar , c:\borlandc\bin\bc.exe
c:\work\p1.cpp , c:\work\p1.obj
Sistemele MS-DOS si MS-Windows nu fac deosebire între litere mari si litere
mici, în cadrul numelor de fisiere, dar sistemele de tip Unix sau Linux fac
deosebire între litere mari si litere mici.
Consola si imprimanta sunt considerate fisiere text, adicã:
- între aceste fisiere si memorie se transferã caractere ASCII
- se recunoaste caracterul sfârsit de fisier (Ctrl-Z în MS-DOS si MSWindows,
Ctrl-D în Unix)
- se poate recunoaste la citire un caracter terminator de linie ('\n').
Un fisier text pe disc contine numai caractere ASCII, grupate în linii si este
terminat printr-un caracter terminator de fisier (Ctrl-Z), adãugat automat la
închiderea fisierului, dupã scriere în fisier. Functiile de citire sau de scriere numere
13
din/in fisiere text realizeazã conversia automatã din format extern (sir de caractere)
în format intern (binary virgulã fixã sau virgulã mobilã) la citire si conversia din
format intern în format extern, la scriere.
Fisierele disc pot contine si numere în reprezentare internã (binarã) sau alte date ce
nu reprezintã numere (de exemplu, fisiere cu imagini grafice, în diverse formate).
Aceste fisiere se numesc fisiere binare, iar citirea si scrierea se fac fãrã conversie
de format. Pentru fiecare tip de fisier binar este necesar un program care sã
cunoascã si sã interpreteze corect informatiile binare din fisier.
Fisierele disc trebuie deschise si închise, dar fisierele consolã si imprimanta nu
trebuie deschise si închise.
5. Lucrul cu fişierele
a)Deschiderea fisierelor – functia fopen ( )
FILE *fopen(char *nume_fisier, char *mod);
Functia primeste in nume_fisier un pointer spre numele fisierului si un pointer, mod,
spre un sir de caractere care defineste modul de acces si returneaza un pointer spre
fisier, daca operatia a decurs normal sau NULL, daca fisierul nu se poate deschide.
Acest pointer trebuie testat inainte de a trece la alte prelucrari pentru a ne asigura ca
deschiderea s-a facut corect. Valorile pentru mod sunt date in tabelul alaturat.
Valorile posibile care definesc modul de acces
Mod – Semnificatie
r - deschiderea unui fisier text pentru CITIRE (read)
w - deschiderea unui fisier text pentru SCRIERE (write)
a - deschiderea unui fisier text pentru ADAUGARE (append) dupa ultima
intregistrare.Un fisier inexistent poate fi creat in modurile w sau a
r# - citire si modificare (scriere) in mod text
w# - deschidere pentru modificare in mod text
a# - deschidere pentru modificare cu scriere la sfarsitul de fisier; mod text
rb - deschidere pentru citire in mod binar
wb - deschiderea unui fisier pentru modificare in mod binar
ab - adaugare in mod binar
r#b - deschidere fisier binar pentru citire/scriere
w#b – deschidere fisier binar pentru scriere
a#b – adaugare la un fisier binar
14
Exista constantele predefinite:

FILENAME_MAX, care precizeaza lungimea maxima a numelui unui fisier,
si

FOPEN_MAX care precizeaza numarul maxim de fisiere ce pot fi deschise
simultan.
b) Inchiderea fisierelor – functia fclose ( )
int fclose(FILE *f);
Functia primeste pointerul spre fisier f, obtinut cu functia fopen() si returneaza zero
daca se incheie cu succes sau –1 in caz de eroare.
Prin inchiderea fisierului se pierde conexiunea logica intre pointer si fisier si au loc
operatiile:
1. scrierea datelor nescrise din bufferul de iesire in fisier (tehnica se foloseste pentru
a mari eficienta accesului la fisiere deschise pentru scriere/actualizare, prin
inlocuirea scrierii in fisier inregistrare cu inregistrare, cu scrierea intr-un buffer a
mai multor inregistrari; la umplerea bufferului acesta fiind scris o singura data,
automat, pe disc. Operatia se numeste "flushing the buffer" si poate fi apelata
explicit cu functia:
int fflush(FILE *f);
in scopul de a elibera zona tampon a fisierului.
2. abandonarea datelor necitite din bufferul de intrare
3. eliberarea automata a bufferelor alocate fisierelor
c) Reasignarea din program a fisierelor
FILE *freopen(const char *nume_f,const char *mod, FILE *f);
Efectul functiei este inchiderea fisierului pointat de pointerul f si deschiderea unui
nou fisier cu numele precizat de nume_f in modul de acces dat de mod . Pointerul f
va deveni noul pointer spre fisier. Astfel, prin intermediul aceluiasi pointer f putem
avea acces la fisiere diferite, dar in momente de timp diferite
15
6. Citirea si scrierea fisierelor
a) intrari/iesiri la nivel de caracter
a1) int fgetc(FILE *f);
int getc (FILE *f);
Functia returnreaza codul ASCII al urmatorului caracter citit din fisierul f.
Caracterul este convertit la intreg sau EOF in caz de eroare sau detectie de sfarsit de
fisier.
a2) int fputc(int c, FILE *f);
int putc (int c, FILE *f);
Scrie in fisierul f caracterul c ca un unsigned char . Se returneaza caracterul c sau
EOF in caz de eroare.
a3) int getchar(void); - citeste un caracter de la tastatura
int getc(stdin); - citeste un caracter de la tastatura
int puchar(int c); - scrie un caracter pe ecran
int putc(int c, stdout); - scrie un caracter pe ecran
b) intrari/iesiri la nivel de sir de caractere
b1) char *fgets(char *s, int n, FILE *f);
Citeste n-1 caractere din fisierul f in tabloul s.Citirea se opreste la detectarea codului
'\n'.Caracterul '\n' se include in s ,apoi se adauga 'i0'. Se returneaza un pointer spre
sirul s sau NULL in caz de eroare sau sfarsit de fisier.
b2) char *gets(char *s);
Citeste o linie de la tastatura in sirul de caractere s . Caracterul '\n' nu se include in s,
dar la sfarsit se adauga 'i0'.
b3) int fputs(const char *s, FILE *f);
Se scrie sirul s in fisierul f. Se introduce EOF in caz de eroare sau o valoare pozitiva
sau egala cu zero in rest.
16
b4) int puts(const char *s); - scrie sirul de caractere s pe ecran
Exemplu:
Un program care deschide fisierul de pe unitatea de disc c:, c:text.txt in care se va
scrie un text citit de la tastatura. Fisierul se va inchide, apoi se va redeschide pentru
a-l citi si afisa pe ecran. In final fisierul se inchide .
#include<stdio.h>
#incude<stdlib.h>
void main(void)
{
FILE *f;
char mesaj[60], c, *psir;
printf("\n Intoduceti un mesaj de maxim
60 de caractere :ih");
gets (mesaj);
// deschidem fisierul pentru scriere
if ((f = fopen ("c:text.txt","w")) = = NULL){
printf ("\n Eroare la deschidere fisier");
exit (1);
}
// scriem in fisier
psir = mesaj;
while(*psir){
if(fputc(*psir++, f) == EOF){
printf ("\n Eroare la scriere in fisier");
exit (1);
}
}
// inchidem fisierul
fclose(f);
// redeschidem fisierul pentru citire
if ((f =fopen("c:text.txt", "r")) == NULL ) {
printf ("\n Eroare deschidere fisier");
exit (1);
}
// citim fisierul si scriem pe ecran
while((c = fgetc(f) != EOF) putchar(c);
// inchidem fisierul
fclose(f);
}
Se cere sa se rescrie programul folosind functiile fputs ( ) si fgets ( ) .
17
c) intrari/iesiri cu conversie de format
c1) int fprintf( FILE *f, const char *format, .. ..);
Scrie in fisierul f , conform cu formatul dat, un anumit numar de argumente.
Numarul descriptorilor din format trebuie sa coincida cu numarul de argumente.
Exemplu:
int I=6;
float r=6.0;
fprintf(fis1, "%dit%f, i, r); /* scrie in fisierul pointat de fis1 un
intreg, apoi un tab si apoi un real */
c2) int fscanf(FILE *f, const char *format,.. ...);
Citeste date din fisierul f sub controlul specificatorului de format si atribuie valorile
argumentelor. Argumentele trebuie sa fie obligatoriu pointeri. Citirea se termina la
epuizarea sirului care precizeaza specificatorul de format .
Exemplu:
fscanf(fis2, "%f%d", &v, &i);
citeste din fis2 doua variabile: prima reala (%f), a doua intreaga (%d).
d) intrari/iesiri pentru date binare
Desi functiile fprintf( ) si fscanf sunt foarte utile pentru ca permit scrierea/citirea
datelor sub controlul unui format, ele au dezavantajul ca la transfer realizeaza
conversia din format intern in format ASCII si invers. Aceasta conversie duce la
cresterea timpului de acces la informatiile din fisiere scazand viteza de prelucrare.
Fisierele create cu aceste functii vor fi mai mari decat cele create cu functii in care
datele sunt scrise in format intern .
Functiile fread( ) si fwrite( ) permit citirea si scrierea fara nici o conversie si fara a
face vreo interpretare a datelor. Astfel, fisierul va fi exact imaginea datelor din
memorie. Se utilizeaza notiunea de articol pentru a referi o variabila simpla sau
compusa de lungime fixa.
d1) unsigned fread(void *p,unsigned dim,
unsigned nr_artic, FILE *f) ;
Citeste un numar de nr_artic articole, fiecare de lungime dim octeti, din fisierul f
intr-o zona de memorie pointata de pointerul p. Functia returneaza numarul de
articole citite corect sau –1 in caz de eroare .
18
Observatii:
- pointerul p trebuie sa pointeze spre un tip de variabila in concordanta cu tipul
articolului sau catre o zona de memorie alocata cu malloc( );
- pentru a prelucra fisiere binare ele se vor deschide in modul b (modul binar):
wb – creare
rb – citire
r#b – citire/scriere
w#b – scriere , modificare
a#b – adaugare
Exemplu:
fread(&i, 2, 1, fis); /* citeste din fisierul fis 1 articol de 2 octeti si-i
depune in variabila i (intreg) */
p = malloc(4);
fread(p, 4, 1, fis); /* citeste din fisierul fis 1 articol de 4 octeti si-i depune la adresa
data de p (real) */
d2) unsigned fwrite(void *p, unsigned dim,
unsigned nr_artic, FILE *f);
Scriem in fisierul f un numar de nr_artic articole, fiecare de lungime dim octeti,
articole preluate din zona de memorie pointata de p .
19
7. Stergerea , redenumirea si crearea fisierelor
a) int remove(const char *nume_fis);
int unlink(const char *nume_fis);
Se sterge fisierul cu numele nume_fis si se returneaza 0 la realizarea cu succes a
functiei sau diferit de zero 0 in caz de eroare.
Exemplu:
char nume_fis[12]
printf("\nIntroduceti numele fis de sters:");
gets(nume_fis);
remove(nume_fis);
b) int rename(const char *nume_nou,
const char *nume_vechi);
Redenumeste fisierul specificat de nume_vechi cu un alt nume, nume_nou.
c) FILE *tempfile(void);
Se creeaza un fisier temporar in modul "wb#", care se va sterge automat la
inchiderea sau terminarea normala a programului. Functia intoarce un pointer la
fisier sau NULL in caz de eroare. Apeluri succesive vor deschide fisiere distincte.
Functia este utilizata in special atunci cand se manevreaza un volum mare de date
care nu incape in memorie si pentru care este necesara crearea unor fisiere de
manevra pe disc. Aceste fisiere sunt transparente pentru utilizator, ele fiind doar
zone de memorare temporara a datelor.
Pentru lucrul cu mai multe fisiere care se gasesc in acelasi director exista functiile:
findfirst – (se apeleaza o singura data) pozitioneaza pointerul de fisiere pe
primul fisier care indeplineste anumite conditii legate de nume generic ( *.exe, *.*)
20
8. Listingul programului
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
//elementele listei--------------------------------------------------------typedef struct angajat_
{ char nume_angajat[20];
int salariu;
long telefon;
long nr_legitimatiei;
int an_nastere;
} angajat;
//structura ce contine lista------------------------------------------------typedef struct List_
{ angajat data;
struct List_ *Next, *Back;
} List;
List *First=NULL, *Last=NULL;
const char *file="angajat.txt";
int iConstr;
int operatie;
FILE *f;
int alocare(angajat *item);
angajat inc(angajat Constr);
int adaugare_angajat(angajat Constr, int i);
int creare(void);
int afisare(void);
int adaugare(void);
int salvare(List *pFirst);
int open(void);
int sortare(void);
int cautare(List *intrep);
int modificare(void);
int sterge(void);
void meniu(void);
void contin(List *Constr);
//functiile-----------------------------------------------------------------int main()
{
textcolor(GREEN);
while(1)
{
meniu();
fflush(stdin);
switch(operatie)
{
case 1: clrscr();
puts("\n\n\tBAZA DE DATE A ANGAJATILOR UNEI
INTREPRINDERI\n\n");
creare(); break;
case 2: clrscr();
afisare(); break;
case 3: open(); break;
case 4: clrscr();
adaugare();clrscr();
afisare();
break;
case 5: clrscr();
sortare();
clrscr();
afisare();
break;
21
case 6: clrscr();
cautare(First); break;
case 7: clrscr();
modificare();
clrscr();
afisare();
break;
case 8: clrscr();
sterge(); break;
case 9: salvare(First); break;
case 0:
int k;
clrscr();
printf("\n\tSalvati modificarile inainte
de iesire?\n");
default:
printf("\n\t1- Da
2- Nu\n");
scanf("%d",&k);
if(k==1)
{ salvare(First);
exit(0);
}
if(k==2) exit(0);
printf("\n\n\tEroare!!!"
"\n\t\tTastati o tasta pentru
reintoarcere...");
getch(); break;
}
}
return 0;
}
//alocare de memorie--------------------------------------------------------int alocare(angajat *item)
{
List *New_item;
New_item = (List *)malloc(sizeof(List));
if(!New_item)
{
printf("\n\tEroare!!!"
"\n\tMai incercati o data!!!");
getch(); return 0;
}
New_item->data = *item;
if (First)
First->Back = New_item;
(*New_item).Back = NULL;
(*New_item).Next = First;
First = New_item;
return 1;
}
//introducerea datelor despre angajat---------------------------------------angajat inc(angajat Constr)
{
fflush(stdin);
printf("\n\tNumele angajatului: ");
scanf("%15s", &Constr.nume_angajat);
fflush(stdin);
printf("\tSalariul %s: ", Constr.nume_angajat);
scanf("%d", &Constr.salariu);
fflush(stdin);
printf("\tTelefonul %s: ",Constr.nume_angajat);
scanf("%ld", &Constr.telefon);
fflush(stdin);
printf("\tNr_legitimatie %s: ",Constr.nume_angajat);
scanf("%ld", &Constr.nr_legitimatiei);
fflush(stdin);
printf("\tAnul_nasterii %s: ",Constr.nume_angajat);
scanf("%d", &Constr.an_nastere);
fflush(stdin);
22
return Constr;
}
//adaugare angajati-------------------------------------------------------int adaugare_angajat(angajat Constr, int i)
{
int v;
do
{
i++;
alocare(&(inc(Constr)));
puts("\n\tMai aveti nevoie de audaugat angajati?"
" 1 - Da, 0 - Iesire\n");
scanf("%d",&v);
}
while (v);
printf("\n\tLista cu angajati este creata si completatata!!!\n\tTastati
o tasta pentru continuare...\n"); getch();
}
//crearea listei de angajati-----------------------------------------------int creare()
{
angajat Constr;
int i=0,k;
if (First != NULL)
{
printf("\n\tExista deja o lista,daca continuati "
"o pierdeti!!! \n\t1 - Continuare
0-Anulare\n");
scanf("%d",&k);
if (k!=1)return 0;
else First=NULL;
}
else
{
alocare(&(inc(Constr)));
}
adaugare_angajat(Constr, i);
return i;
}
//--------------------------------------------------------------------------int adaugare()
{
angajat Constr; int i=0;
adaugare_angajat(Constr, i);
return i;
}
//salvarea listei de angajati-----------------------------------------------int salvare(List *First)
{
angajat Constr; List *intrep;
int i=1;
int r;
intrep=First;
if (f=fopen(file, "rb"))
{
printf("\n\tExista deja fisier,"
"veti pierde informatia. \n");
printf("\n\n\tPentru rvenire tastati-1 \n\tPentru continuare
tastati-0\n");
scanf("%d",&r);
if (r) return 0;
}
f=fopen(file, "wb");
while(intrep)
{
fwrite(&intrep->data, sizeof(angajat),1,f);
intrep= intrep->Next;
++i;
}
fclose(f);
printf("\n\tLista cu angajati este salvata cu succes"
"in fisier <%s>!!!", file); getch();
return 0;
23
}
//deschiderea fisierului pt actiune-----------------------------------------int open()
{ angajat constr;
int i=0;
int c;
if (First != NULL)
{
printf("\n\tLista exista, daca continuati "
"o pierdeti!!! \n\t1 - Continuare
0-Anulare\n");
scanf("%d",&c);
if (!c)
return 0; else First=NULL;
}
if(!(f=fopen(file, "rb")))
{
puts("\n\t\tCreati mai intii fisierul!!!");
getch();
return 0;
}
fread(&constr,sizeof(angajat), 1, f);
while(! feof(f))
{
alocare(&constr);
fread(&constr, sizeof(angajat), 1, f);
}
return (afisare());
}
//continutul listei de angajati---------------------------------------------void contin(List *intrep)
{
int i=1;
while(intrep)
{
printf(" | %2d |", i);
printf(" %16s|",intrep->data.nume_angajat);
printf(" %8d|",intrep->data.salariu);
printf(" %8ld|",intrep->data.telefon);
printf("
%13ld |",intrep->data.nr_legitimatiei);
printf("
%6d|",intrep->data.an_nastere);
printf("
_____________________________________________________________________________
__\n");
intrep = intrep->Next;
++i;
}
}
//afisare listei de angajati------------------------------------------------int afisare()
{
int j=1;
puts("\n\t\t\tINFORMATIA DESPRE Angajati:\n");
printf("
_____________________________________________________________________________
\n");
printf(" | Nr. |
Nume angajat | salariu | telefon |
nr_legitimatiei |an_naster|\n");
printf("
|____________________________________________________________________________
_|\n");
contin(First);
printf("\n\t\tTastati o tasta pentru continuare...");
getch();
return (j-1);
}
//sortare listei de angajati------------------------------------------------int sortare()
{ List *temp1, *temp2, *min, *prev, *Sort=NULL;
int i, j, iConstr=0,ales;
24
iConstr=afisare()-1;
puts("");
printf("\n\t Sortati lista dupa:\n");
puts("\t 1 - Numele angajatului");
puts("\t 2 - Nr_legitimatiei");
puts("\t 3 - Anul nasterii");
puts("\t 0 - Inapoi\n");
scanf("%d",&ales);
switch(ales)
{
case 1:
{
while(First != NULL)
{
prev = NULL;
min = temp1 = First;
temp2 = First -> Next;
while ( temp2 != NULL )
{
if(strcmpi(min -> data.nume_angajat, temp2 ->
data.nume_angajat) > 0)
{ min = temp2; prev = temp1;
}
temp1 = temp2;
temp2 = temp2 -> Next;
}
if(prev == NULL)
First = min -> Next;
else
prev -> Next = min -> Next;
min -> Next = NULL;
if( Sort == NULL )
Sort = min;
else
{
temp1 = Sort;
while( temp1 -> Next != NULL)
temp1 = temp1 -> Next;
temp1 -> Next = min;
}
}
break;
}
case 2:
{
while(First != NULL)
{ prev = NULL;
min = temp1 = First;
temp2 = First -> Next;
while ( temp2 != NULL )
{
if(min -> data.nr_legitimatiei > temp2 ->
data.nr_legitimatiei)
{
min = temp2; prev = temp1;
}
temp1 = temp2;
temp2 = temp2 -> Next;
}
if(prev == NULL)
First = min -> Next;
else
prev -> Next = min -> Next;
min -> Next = NULL;
if( Sort == NULL )
Sort = min;
else
{ temp1 = Sort;
while( temp1 -> Next != NULL)
temp1 = temp1 -> Next;
temp1 -> Next = min;
}
}
break;
25
}
case 3:
{
while(First != NULL)
{ prev = NULL;
min = temp1 = First;
temp2 = First -> Next;
while ( temp2 != NULL )
{
if(min -> data.an_nastere > temp2 -> data.an_nastere)
{
min = temp2; prev = temp1;
}
temp1 = temp2;
temp2 = temp2 -> Next;
}
if(prev == NULL)
First = min -> Next;
else
prev -> Next = min -> Next;
min -> Next = NULL;
if( Sort == NULL )
Sort = min;
else
{ temp1 = Sort;
while( temp1 -> Next != NULL)
temp1 = temp1 -> Next;
temp1 -> Next = min;
}
break;
}
}
case 0: break;
default:
{
printf("\n\t\tNu ati ales varianta potrivita!!!
\n\t");
getch(); break; exit(0);
}
}
First=Sort;
printf("\n\t\tTastati o tasta pentru continuare... "); getch();
return 0;
}
//cautarea in lista de angajati---------------------------------------------int cautare(List *intrep)
{
int j=1; char eticheta[20]; List *Start;
Start=intrep;
if (First == NULL)
{ printf("\n\t\tLista este vida!!!");
getch();
return 0;
}
printf("\n\t\tIntroduceti numele angajatului cautat:\n ");
gets(eticheta);
puts("\n\t\t\tINFORMATIA DESPRE ANGAJATI:\n");
printf("
__________________________________________________________________________
\n");
printf(" | Nr. | Nume angajat
| salariu | telefon |
nr_legitimatiei |an_nas|\n");
printf("
|__________________________________________________________________________|\
n");
while(Start)
{
if(strcmpi(Start->data.nume_angajat, eticheta) == 0)
{
printf(" | %2d |", j);
26
printf(" %-15s|",Start->data.nume_angajat);
printf(" %-8d |",Start->data.salariu);
printf(" %-8ld |",Start->data.telefon);
printf(" %13ld |",Start->data.nr_legitimatiei);
printf(" %6d |\n",Start->data.an_nastere);
printf("
__________________________________________________________________________\n"
);
++j;
}
Start = Start->Next;
}
printf("\n\t\tTastati o tasta pentru continuare...");
getch();
return (j-1);
}
//modificarea listei de angajati--------------------------------------------int modificare()
{
int i,k,ales;
List *Curent; angajat Constr;
Curent = First;
afisare();
printf("\n\tIntroduceti numarul elementului pe care doriti sa-l
monificati: ");
scanf("%d", &ales);
fflush(stdin);
if (ales < 0) return 0;
for (i=1; i<ales; ++i)
{
Curent = Curent->Next;
if (!Curent)
{
printf("\n\t\tEroare!!! Elementul nu este gasit!Tastati o
tasta pentru continuare...");
getch();
return 0;
}
}
printf("\n\tCare cimp doriti sa modificati?"
"\n\t1- Numele angajatului"
"\n\t2- Salariul"
"\n\t3- Telefonul"
"\n\t4- Nr_legitimatiei"
"\n\t5- Anul nasterii\n");
scanf("%d",&k);
switch(k)
{
case 1:
printf("\n\tIntroduceti date noi despre ");
printf("\n\tnumele angajatului: ");
scanf("%s",&Curent->data.nume_angajat);
fflush(stdin);
break;
case 2:
printf("\n\tIntroduceti date noi despre ");
printf("\n\tsalariuarii: ");
scanf("%d",&Curent->data.salariu);
fflush(stdin);
break;
case 3:
printf("\n\tIntroduceti date noi despre ");
27
printf("\n\ttelefonarii: ");
scanf("%ld", &Curent->data.telefon);
fflush(stdin);
break;
case 4:
printf("\n\tIntroduceti date noi despre ");
printf("\n\tnr. politei de asigurare: ");
scanf("%ld", &Curent->data.nr_legitimatiei);
fflush(stdin);
break;
case 5:
printf("\n\tIntroduceti date noi despre ");
printf("\n\tanul nasterii: ");
scanf("%d", &Curent->data.an_nastere);
fflush(stdin);
break;
default: printf("\n\tNu ati ales nici o varianta potrivita!!! \n\t");
getch(); return 0;
}
return 1;
}
//stergere-------------------------------------------------------------------------int sterge()
{
int k;
List *del;
if (!First)
{
printf("\n\t\tNu exista nici o lista de sters!!!");
getch();
return 0;
}
printf("\n\tAceasta operatie va sterge lista de angajati\n\t"
"din memorie!!!"
"\n\tDoriti sa stergeti lista???"
"\n\t1 - Da, 0- Nu\n", file);
scanf("%d",&k);
if (k)
{
while(First)
{
del = First;
First = First->Next;
free(del);
}
printf("\n\tLista este stearsa cu succes!!!");
getch();
}
return 1;
}
//meniul--------------------------------------------------------------------void meniu()
{
clrscr();
puts("\n\n\n\n\n\n\n");
puts("\t====================MENIU=======================");
puts("\t||
||");
puts("\t||
||");
puts("\t||
1:--==CREARE==-||");
puts("\t||
2:--==AFISARE==-||");
puts("\t||
3:--==DESCHIDERE==-||");
puts("\t||
4:--==ADAUGARE==-||");
28
puts("\t||
5:--==SORTARE==-||");
puts("\t||
6:--==CAUTARE==-||");
puts("\t||
7:--==MODIFICARE==||");
puts("\t||
8:--==ELIMINARE==-||");
puts("\t||
9:--==SALVARE==-||");
puts("\t||
0:--==IESIRE==-||");
puts("\t||
||");
puts("\t||
||");
puts("\t================================================");
puts("\n\tINTRODUCETI COMANDA:\n");
scanf("%d",&operatie);
}
29
9. Rezultatul final:
30
31
10. Concluzii:
Lucrarea data reprezinta un model de prelucrare a informatiei unei baze de date ce
contine date despre angajatii unei intreprinderi. Informatia despre angajati se
introduce cu ajutorul unei liste, lista la rindul sau este salvata in sructura si pastrata
in fisier, informatia este prelucrata prin intermediul tablourelor unidimensionale.
Informatia se pastreaza in fisierul: „angajati.txt” si este manipulata cu ajutorul
meniului.
32
11. Bibliografie
1. Colectia Informanica nr. 8 – Culegere de probleme – Varianta Pascal
Editura Else. D. Botofei; R. Tamplaru; L. Schiopu.
2. L.Negrescu.Iniţiere în limbajul C,C++.-Cluj,1999.
3. Internet:
www.referat.ro,
www.pcmagazine.ro,
www.elth.srv.ro,
www.proeducation.md/infpro.
4. Limbajul Pascal structuri dinamice de date, grafuri si programare orientata pe
obiecte. Editura Else . E. Popescu; S. Vitelaru; M. Codres.
5. Sergiu G.Istrati.Programarea în limbajele C,C++.UTM Chişinău 2004.
6. G.D.Mateescu.C++limbaj de programare.-Bucureşti:ed.Petrion 1998.
7.D.M.Popovici,I.M.Popovici,I.Tănase.C++.Tehnologia orientată pe
obiecte.Aplicaţii.-Bucureşti:ed.Teora,1996
33
Download