Descărcați ca pdf sau txt
Descărcați ca pdf sau txt
Sunteți pe pagina 1din 98

Academia de Studii Economice din Bucureti

Facultatea de Cibernetic, Statistic i Informatic Economic


Catedra de Informatic Economic







Algoritmi
n programarea
calculatoarelor
* material didactic pentru ID *



Cristian Uscatu Ctlina Cocianu

Ctlin Silvestru



Acest material are la baz lucrarea
Programarea calculatoarelor. Algoritmi n programare
autori I. Gh. Roca, B. Ghilic-Micu, C. Cocianu, M. Stoica, C. Uscatu, M. Mircea
publicat la Editura ASE Bucureti, 2007






Bucureti, 2010
Algoritmi n programare 2



Titlul cursului: Algoritmi n programare

Introducere: Cursul Algoritmi n programare se adreseaz studenilor facultii de
Cibernetic, Statistic i Informatic Economic din cadrul Academiei de Studii Economice
din Bucureti. Conform planului de nvmnt, cursul se desfoar n semestrul 1 al anului 2
de studiu.

Cursul Algoritmi n programare este destinat iniierii studenilor n cteva aspec-
te ale programrii calculatoarelor. Limbajul utilizat pentru demonstrarea concep-
telor i aplicaiile practice este C standard (ANSI C). Obiectivele principale ale
cursului vizeaz nsuirea de ctre studeni a cunotinelor teoretice i a abilitilor practice de lu-
cru referitoare la urmtoarelor elemente din cadrul programrii calculatoarelor:
tipurile dinamice de date i modul de lucru cu date alocate dinamic (masive de date);
analiza, proiectarea, implementarea i utilizarea a subprogramelor;
structurile de date externe (fiiere) i abiliti de lucru cu acestea.

Cursul Algoritmi n programare este structurat n patru uniti de nvare, corespun-
ztoare elementelor principale studiate (date dinamice i subprograme cte o unitate de nv-
are, fiiere de date 2 uniti de nvare).

n cadrul procesului de instruire pot fi utilizate ca resurse suplimentare materia-
lele puse la dispoziie de biblioteca facultii, att n cadrul slii de lectur ct i
prin serviciul de mprumut.

De asemenea, laboratoarele Catedrei de Informatic Economic pot fi utilizate
pentru studiu individual pe toat durata programului de lucru, atunci cnd nu se
desfoar ore (programarea orelor n laboratoare poate fi consultat la secretari-
atul Catedrei). Calculatoarele din laboratoare ofer medii de programare adecvate pentru dez-
voltarea abilitilor de lucru n limbajul C i posibilitatea de accesare a bibliotecii virtuale a
instituiei.

Evaluarea cunotinelor se va realiza prin intermediul lucrrilor susinute pe par-
cursul semestrului astfel:
o prob practic, constnd n rezolvarea a dou probleme de programare
din cadrul tematicii cursului;
o lucrare scris.
Ambele teste se susin n timpul orelor aferente temelor de control din calendarul
disciplinei.

Cele dou teste contribuie la formarea notei finale astfel:
proba practic constituie 40% din nota final;
lucrarea scris constituie 50% din nota final;
din oficiu se acord 10%.


* material didactic pentru ID * 3



Cuprins



1. Tipuri dinamice de date ....................................................................................................... 5
Obiectivele unitii de nvare ........................................................................................... 5
1.1. Tipuri de date dinamice ........................................................................................... 5
1.2. Declararea i iniializarea pointerilor..................................................................... 6
1.3. Utilizarea pointerilor................................................................................................ 7
1.3.1. Operaii cu pointeri ................................................................................................ 7
1.3.2. Legtura ntre pointeri i masive .......................................................................... 9
1.4. Alocarea dinamic a memoriei.............................................................................. 11
1.5. Modificatorul const................................................................................................. 12
1.6. Tratarea parametrilor din linia de comand....................................................... 13
Rspunsuri i comentarii la testele de autoevaluare ....................................................... 13
Rezumat............................................................................................................................... 14
Bibliografia unitii de nvare........................................................................................ 14

2. Subprograme....................................................................................................................... 15
Obiectivele unitii de nvare ......................................................................................... 15
2.1. Construirea i apelul subprogramelor.................................................................. 15
2.2. Transferul datelor ntre apelator i apelat ........................................................... 18
2.2.1. Transferul prin parametri ................................................................................... 18
2.2.2. Simularea transmiterii parametrilor prin adres ............................................. 20
2.2.3. Comunicaia prin variabile globale .................................................................... 21
2.3. Pointeri spre funcii ................................................................................................ 22
2.4. Funcii cu numr variabil de parametri............................................................... 26
2.5. Calcul recursiv........................................................................................................ 29
2.6. Exemple de aplicaii cu subprograme recursive.................................................. 31
Rspunsuri i comentarii la testele de autoevaluare ....................................................... 36
Rezumat............................................................................................................................... 38
Bibliografia unitii de nvare........................................................................................ 38

Algoritmi n programare 4
3. Articolul i fiierul .............................................................................................................. 39
Obiectivele unitii de nvare ......................................................................................... 39
3.1. Articol: caracteristici generale i mod de declarare ........................................... 39
3.2. Referirea articolului i a elementelor componente.............................................. 41
3.3. Articole cu structuri complexe.............................................................................. 44
3.4. Constante de tip articol.......................................................................................... 45
3.5. Fiierul i articolul.................................................................................................. 46
3.6. Metode de organizare a fiierelor i tipuri de acces............................................ 47
3.7. Structura sistemului de fiiere sub MS-DOS/Windows...................................... 49
3.8. Operaii de prelucrare a fiierelor........................................................................ 51
3.8.1. Nivelul inferior de prelucrare a fiierelor.................................................... 52
3.8.2. Nivelul superior de prelucrare a fiierelor................................................... 55
Rspunsuri i comentarii la testele de autoevaluare....................................................... 62
Rezumat............................................................................................................................... 62
Bibliografia unitii de nvare........................................................................................ 62

4. Algoritmi de prelucrare a fiierelor de date .................................................................... 63
Obiectivele unitii de nvare ......................................................................................... 63
4.1. Caracteristici generale ale algoritmilor de prelucrare a fiierelor.................... 63
4.2. Algoritmi de prelucrare a fiierelor binare care nu necesit actualizare............ 68
4.3. Algoritmi de prelucrare a fiierelor binare care necesit actualizare ................. 76
4.3.1. Codificarea extern prin numere relative..................................................... 76
4.3.2. Codificarea intern prin numere relative ..................................................... 78
4.3.3. Corespondena intern dintre chei i numere relative ................................. 79
4.4. Sortarea fiierelor binare memorate dens............................................................. 89
4.5. Interclasarea fiierelor binare memorate dens ..................................................... 93
4.6. Prelucrarea masivelor memorate n fiiere binare ............................................... 94
4.6.1. Prelucrarea vectorilor..................................................................................... 94
4.6.2. Prelucrarea matricelor ................................................................................... 95
Rspunsuri i comentarii la testele de autoevaluare....................................................... 96
Bibliografia unitii de nvare........................................................................................ 97
Bibliografie.............................................................................................................................. 98
* material didactic pentru ID * 5



1. Tipuri dinamice de date



Cuprins

Obiectivele unitii de nvare ........................................................................................... 5
1.1. Tipuri de date dinamice ........................................................................................... 5
1.2. Declararea i iniializarea pointerilor..................................................................... 6
1.3. Utilizarea pointerilor................................................................................................ 7
1.3.1. Operaii cu pointeri ................................................................................................ 7
1.3.2. Legtura ntre pointeri i masive .......................................................................... 9
1.4. Alocarea dinamic a memoriei.............................................................................. 11
1.5. Modificatorul const................................................................................................. 12
1.6. Tratarea parametrilor din linia de comand....................................................... 13
Rspunsuri i comentarii la testele de autoevaluare ....................................................... 13
Rezumat............................................................................................................................... 14
Bibliografia unitii de nvare........................................................................................ 14


Obiectivele unitii de nvare

Dup studierea acestei uniti de nvare, studenii vor avea cunotine teoretice i
abiliti practice despre tipurile dinamice de date utilizate n programarea calculatoa-
relor i vor putea utiliza aceste tipuri de date i structurile de tip masiv de date pen-
tru rezolvarea problemelor de programare. Concret, se vor asimila cunotine i abiliti de lu-
cru privind:
tipurile de date pointer;
operaii cu datele de tip pointer i aritmetica pointerilor;
legtura dintre pointeri i masivele de date, n limbajul C;
alocarea dinamic a datelor;
tratarea parametrilor primii n linia de comand.


1.1. Tipuri de date dinamice

Pointerul este un tip de dat predefinit, care are ca valoare adresa unei zone de memo-
rie (figura 1.1).


Pointer
Zona de memorie indicat de pointer
Memoria intern
Segmen:offset

Fig. 1.1. Un pointer este adresa unei alte zone de memorie

Folosirea pointerilor prezint urmtoarele avantaje:
Algoritmi n programare 6
nlocuirea expresiilor cu indici nmulirile din formula de calcul al rangului se transform
n adunri i deplasri;
posibilitatea alocrii dinamice a memoriei;
folosirea tipurilor procedurale de date;
calculul adreselor.

n operaiile cu pointeri se folosesc urmtorii operatori specifici:
Operatori Simbol Utilizare
Operator de refereniere
* tip*
Operator de refereniere
& &nume
Operator de derefereniere
* *nume
* definete un nou tip de dat (pointer la tip);
& extrage adresa unei variabile (creeaz o referin);
* acceseaz coninutul zonei de memorie indicate de pointer.

Cei doi operatori au efect invers: *&nume nume.

Exemplu
1. *&nume reprezint valoarea de la adresa variabilei nume (valoarea variabilei nume).


1.2. Declararea i iniializarea pointerilor

Fie TIP un tip de dat oarecare n limbajul C (inclusiv void). Declararea TIP* nume;
este o declaraie de pointer. TIP* este un nou tip de dat denumit pointer spre TIP, iar nume
este o variabil de tipul pointer spre TIP.

Exemple
2. int* n; n este o variabil de tip pointer spre ntreg;
3. struct complex {a,b:real;}* x; x este o variabil de tip pointer spre o structur de ti-
pul complex;
4. void* p; p este o variabil de tip pointer spre void; p poate primi ca valoare adresa
unei zone de memorie de orice tip.

Dac TIP este un tip oarecare (mai puin void) atunci tipul TIP* este adresa unei zone
de memorie de un tip cunoscut. Operaiile care se pot efectua asupra zonei respective de me-
morie snt definite de tipul acesteia. Dac TIP este void, atunci TIP* este adresa unei zone de
memorie de tip necunoscut. Deoarece nu se cunoate tipul zonei de memorie, nu snt definite
operaiile care se pot efectua asupra ei.
Pentru pointerii din exemplele anterioare se rezerv n memoria principal (n segmen-
tul de date) cte o zon de 4B n care se va memora o adres.
Cnd variabila nume nu este iniializat prin declarare, ea primete implicit valoarea
NULL. La execuie, poate primi ca valoare adresa unei variabile numai de tipul TIP. Dac TIP
este void, atunci nume poate primi adresa oricrei variabile, de orice tip.

Exemple
4. int* nume; int a; float b;
nume = &a; este o atribuire corect; nume are ca valoare adresa variabilei a.
nume = &b; este o atribuire incorect; nume poate primi ca valoare doar adresa
* material didactic pentru ID * 7
unei variabile ntregi.
5. void* nume; pointer fr tip
int a; float b; variabile de tip ntreg, respectiv real
nume = &a; atribuire corect
nume = &b; atribuire corect; nume poate primi ca valoare adresa oricrei
variabile, de orice tip.

Iniializarea pointerilor se poate realiza ca n exemplul precedent sau, ca i pentru ce-
lelalte variabile, la declarare, astfel:

int a; int* nume=&a;

Se observ folosirea operatorului de refereniere & pentru a crea o referin ctre vari-
abila a. La alocarea dinamic a memoriei se folosete o alt metod pentru iniializarea unui
pointer. Operatorul de derefereniere se utilizeaz att pentru definirea tipului pointer, ct i
pentru referirea datelor de la adresa indicat de pointer.

Exemplu
6.
int a,b,c; int* nume;
void* nume2;
b=5;
nume=&a;
*nume=b;
c=*nume+b;
nume2=&b;
*(int*)nume2=10;
c=*(int*)nume2;

Se observ folosirea conversiei de tip (typecasting), atunci cnd se lucreaz cu pointeri
spre tipul void (fr tip). Chiar dac un pointer spre tipul void poate primi ca valoare adresa
unei variabile de orice tip, pentru a putea lucra cu ea este necesar gestionarea corect a tipu-
lui operanzilor.

Teste de autoevaluare
1. Care snt operatorii specifici lucrului cu pointeri n limbajul C? Dai exemple de
utilizare a lor.
2. Care snt cele dou tipuri de pointeri? Care snt diferenele dintre ele?


1.3. Utilizarea pointerilor

1.3.1. Operaii cu pointeri
Asupra pointerilor se pot efectua operaii aritmetice. Fie secvena:
int *nume,*nume2, c, a, b; nume=&a; nume2=&a;
Incrementare/decrementare
Dac nume este pointer spre un tip TIP, prin incrementare/decrementare, valoarea lui
nume se incrementeaz/decrementeaz cu numrul de octei necesari pentru a memora o dat
de tip TIP, adic cu sizeof(TIP).
nume++ nume are ca valoare o adres care este incrementat i primete valoarea
nume+sizeof(int) (care este adresa lui b);
nume2-- nume are ca valoare o adres care este decrementat i primete valoa-
rea nume-sizeof(int) (care este adresa lui c);
Algoritmi n programare 8

Situaia iniial este urmtoarea:
nume nume2 c a b
4B 4B 2B 2B 2B
Dup cele dou operaii:
nume nume2 c a b
4B 4B 2B 2B 2B

Analog se execut operaiile ++nume i --nume.

Exemplu
7.
float v[20];
float* p;
int i;
p=&v[i]; unde i poate avea valori ntre 0 i 19

n urma atribuirii ++p sau p++, p va avea ca valoare adresa lui v[i] plus 4 octei, adic adresa
lui v[i+1].

Adunarea/scderea unui ntreg
n general, dac p este un pointer spre un tip TIP, atunci cnd se adun un ntreg n la
pointerul p, rezultatul va fi tot un pointer spre TIP, care are ca valoare adresa memorat n p,
la care se adun de n ori numrul de octei necesari pentru a memora o dat de tip TIP, adic
n*sizeof(TIP). Asemntor se execut scderea unui ntreg dintr-un pointer.
nume+n nume primete valoarea nume+n*sizeof(int)
nume-n nume primete valoarea nume-n*sizeof(int)

Exemplu
8. Fie p i q pointeri spre tipul float (float* p, *q). Presupunnd c p a fost iniializat
cu valoarea 0x0fff:0x3450, n urma operaiei q=p+3, q primete valoarea 0xfff:0x345c (se adu-
n 3*4 octei). n urma operaiei q=p-2, q primete valoarea 0xffff:0x344a (se scad 2*4 octei).

Operaiile descrise anterior se folosesc frecvent n lucrul cu masive.

Compararea a doi pointeri
Limbajul C permite compararea a doi pointeri ntr-o expresie, folosind oricare din ope-
ratorii relaionali (==, !=, <, >, <=, >=).
Rezultatul expresiei nume op nume2 (unde op este unul din operatorii precizai anteri-
or) este adevrat (nenul) sau fals (zero) dup cum nume este egal, mai mare sau mai mic dect
nume2. Doi pointeri snt egali dac adresele care constituie valorile lor snt egale. Privind
memoria intern liniar, ncepnd de la adresa 0 (zero), un pointer p este mai mare dect altul q,
dac adresa pe care o conine p este mai ndeprtat de nceputul memoriei dect adresa coni-
nut de q.
Este permis i compararea unui pointer cu o valoare constant. Uzual se folosete
comparaia cu valoarea NULL pentru a verifica dac pointerul a fost iniializat (un pointer ne-
iniializat are valoarea NULL), folosind unul din operatorii == sau !=. Valoarea NULL este
definit n stdio.h astfel: #define NULL 0
De multe ori se prefer comparaia direct cu zero (nume==0 sau nume!=0). n loc de nu-
me==0 se poate folosi expresia nume. Aceasta se interpreteaz astfel: dac nume nu a fost iniia-
lizat, atunci are valoarea NULL (adic 0), deci expresia este fals. n caz contrar valoarea ex-
presiei este nenul, deci adevrat. Asemntor se folosete expresia !nume.
* material didactic pentru ID * 9

Exemplu
9.
float* p,q,r,t;
float a,b;
p=&a; q=&b; r=&a;
a=5; b=7;
if(t) printf("Pointer initializat!\n");
else printf("Pointer neinitializat!\n");
if(p==r) printf("Pointeri egali\n");
else printf("Pointeri diferiti\n");
if(p>q) printf("%d\n",a);
else printf("%d\n",b);

Pe ecran se va afia:
Pointer neinitializat!
Pointeri egali
7
deoarece t are valoarea NULL, variabilele p i r au ca valoare adresa lui a, iar q conine adresa
lui b, care este mai mare dect a lui a (datorit faptului c a a fost alocat primul).

Diferena dintre doi pointeri
Fie secvena:
int m[50],* a, * b;
a=&m[i]; b=&m[j];
unde i i j snt ntregi n intervalul [0..49]. Expresia a-b are valoarea i-j, interpretat ca dis-
tan ntre adresele a i b, exprimat n zone de memorie de lungime sizeof(int).
Valoarea unei expresii diferen se calculeaz astfel: se face diferena ntre cele dou
adrese (n octei), apoi se mparte la dimensiunea tipului de dat referit de cei doi pointeri
(tipul int n exemplul de mai sus vezi figura 1.2). Cei doi pointeri trebuie s refere acelai
tip de dat, altfel rezultatul nu are semnificaie (trebuie s aib tipuri identice). Operaia este
util n lucrul cu masive.

m

a

b

i

j


Fig.1.2. Reprezentarea semnificaiei variabilelor din exemplul anterior

Atenie: vorbim despre diferena dintre doi pointeri (nelegnd distana dintre cele
dou adrese), nu despre scderea a doi pointeri.


1.3.2. Legtura ntre pointeri i masive
n limbajul C numele unui masiv este un pointer ctre tipul de dat al elementele ma-
sivului.

Pentru masivele unidimensionale:
int m[50]; m are tipul int*
int* p; p are tipul int*
Diferena const n faptul c zona de memorie ctre care puncteaz m este rezervat la
compilare (ceea ce nu se ntmpl n cazul pointerilor declarai ca atare). De aceea m nici nu
poate primi valori n timpul execuiei programului (nu se poate schimba adresa memorat n
m). El memoreaz adresa primului element din masiv. Referirea unui element m[i] este echi-
Algoritmi n programare 10
valent cu *(m+i) coninutul de la adresa m+i. Limbajul C nu face nici un fel de verificri n
privina depirii limitelor indicilor masivului, de aceea expresiile m[500] sau m[-7] vor fi
considerate corecte de compilator, existnd riscul unor erori logice. Este sarcina programato-
rului s se asigure c indicii nu vor depi limitele.

Pentru masivele bidimensionale:
int m[50][50]; m are semnificaia urmtoare: m[i][j] *(*(m+i)+j), re-
prezint coninutul de la adresa j plus coninutul de la adresa memorat n m plus i. Aceasta
poate fi interpretat astfel: m este un pointer spre un vector de pointeri, fiecare element al vec-
torului fiind la rndul lui un pointer spre o linie a matricei (un vector de elemente de tip float).
Figura 1.3. poate fi utilizat pentru a nelege mai bine cum se acceseaz elementele
unui masiv bidimensional.

Atenie: aceast figur NU reprezint modul de alocare n memorie a unei matrice sta-
tice! Doar pentru matricele alocate dinamic zonele de memorie snt alocate n acest
fel.

m
m[0]
m[1]
m[2]
m[3]
m[4]

m[49]
m[0,0] m[0,1] m[0,49]

m[0,0] m[0,1]

m[0,49]
m[2,0] m[2,1]

m[2,49]
m[3,0] m[3,1] m[3,49]
m[4,0] m[4,1]

m[4,49]
m[49,0] m[49,1]

m[49,49

Fig.1.3. Reprezentarea modului de alocare dinamic a spaiului necesar pentru memorarea
unei matrice 50x50

Analog pot fi interpretate masivele cu mai multe dimensiuni.
Exemplu
10. Un masiv cu trei dimensiuni float m[10][10][10] poate fi interpretat ca un pointer
spre un vector de pointeri spre matrice;
Un masiv cu n dimensiuni este tratat ca un pointer spre un vector de pointeri ctre masive cu
n-1 dimensiuni.

Pentru a lucra cu elementele unui masiv static se poate folosi adresarea indexat (m[i]
pentru vectori sau m[i][j] pentru matrice) sau adresarea elementelor prin pointeri (*(m+i)
pentru vectori sau *(*(m+i)+j) pentru matrice etc).
Mai mult, pentru vectori se poate declara un pointer iniializat cu adresa de nceput a
masivului, iar elementele masivului s fie referite prin intermediul acestui pointer.

Exemplu
11. float* v[10]; float* p; p=v;
Dup atribuire, pointerul p conine adresa de nceput a masivului i poate fi folosit pentru re-
ferirea elementelor masivului. De exemplu, v[3] i p[3] refer aceeai zon de memorie.

Test de autoevaluare
3. S se scrie secvena de program care citete de la tastatur elementele unei matrice,
folosind expresii cu pointeri pentru adresarea elementelor matricei.

* material didactic pentru ID * 11

1.4. Alocarea dinamic a memoriei

Pentru a memora o dat de un anumit tip n heap este necesar s se declare un pointer
ctre acel tip de dat, apoi s se rezerve memoria necesar. Pentru a rezerva spaiu n heap se
folosete funcia standard:

void* malloc(unsigned n);

Funcia rezerv o zon de n octei n heap i returneaz adresa acesteia. Deoarece funcia re-
turneaz pointer spre void este necesar conversia rezultatului spre tipul dorit, astfel:
int* nume;
nume=(int *) malloc(sizeof(int)); rezerv n heap spaiu pentru o valoare de tip ntreg.

Eliberarea unei zone de memorie rezervate anterior se face prin funcia standard:

void free(void* p);

Funcia primete ca parametru un pointer (indiferent de tip) spre zona de memorie pe care tre-
buie s o elibereze.

Limbajul C ofer posibilitatea de a aloca contiguu zone de memorie pentru mai multe
date de acelai tip, prin funcia standard:

void* calloc(unsigned nr_elem, unsigned dim_elem);

Funcia calloc rezerv o zon contigu de memorie pentru mai multe elemente de acelai tip,
ntorcnd un pointer spre zona respectiv.

Exist i o variant a lui malloc care returneaz n mod explicit un pointer ndeprtat
(far):
void* farmalloc(unsigned long n);

Pentru eliberarea unei zone de memorie rezervate prin farmalloc se folosete funcia
standard:
void farfree(void* p);

Exemple
12. int* masiv; masiv=(int*)calloc(50,sizeof(int)); rezerv spaiu de
memorie pentru un vector cu 50 de elemente ntregi.

13. Alocarea de spaiu n heap pentru o matrice se face conform figurii 1.3 pentru a putea ac-
cesa elementele la fel ca n cazul unei matrice statice, prin dubl indexare;

int** m;
int n,p;
/* se aloc spaiu pentru vectorul cu adresele celor n linii ale matricei */
m=(int**)malloc(m*sizeof(int*));
for(int i=0;i<m;i++)
/*se aloc spaiu pentru fiecare linie a matricei, cte p elemente*/
m[i]=(int*)malloc(n*sizeof(int));

14. S se scrie o funcie care s citeasc cel mult n numere ntregi i le pstreze n zona de
memorie a crei adres de nceput este dat printr-un pointer. Funcia returneaz numrul va-
Algoritmi n programare 12
lorilor citite.
int cit_nr(int n, int* p)
{ int nr, i;
int* q=p+n; // q este adresa unde se termina zona
// rezervata pentru cele n numere
i=0;
while(p<q) // cit timp nu s-au citit n numere
{ printf("Numarul %d= ", i);
if(scanf("%d", &nr)!=1) break; // in caz de eroare la citire
// se termina ciclul
*p=nr;
p++; i++;
}
return(i); }

Teste de autoevaluare
4. S se scrie o secven de program pentru alocarea dinamic spaiului necesar pentru
un vector i citirea de la tastatur a dimensiunii i elementelor sale.


1.5. Modificatorul const

n limbajul C constantele simbolice se declar prin directiva de preprocesare #define. O
alt posibilitate de lucru cu constante este iniializarea unei variabile cu o valoare i interzice-
rea modificrii valorii acesteia. n acest scop se folosete modificatorul const. Snt permise
urmtoarele forme de utilizare:

a) tip const nume = valoare; sau
const tip nume = valoare;

Declaraia este echivalent cu tip nume=valoare dar, n plus, nu permite modificarea valorii
lui nume printr-o expresie de atribuire nume = valoare_noua;
Fa de o constant simbolic, n acest caz se rezerv spaiu de memorie n care se nscrie va-
loarea constantei (constant obiect).

b) tip const* nume = valoare; sau
const tip* nume = valoare;

Prin aceast declarare se definete un pointer spre o zon cu valoare constant. Nu este permi-
s atribuirea de genul *nume=valoare_noua, dar se poate ca variabilei nume s i se atribuie o
adres (de exemplu, nume = p, unde p este un pointer spre tip). Pentru a modifica valoarea n-
scris n memorie la adresa memorat de pointerul nume se poate folosi totui un alt pointer:

tip *t;
t=nume;
*t=valoare_noua;

c) const tip* nume;

Construcia de mai sus se folosete la declararea parametrilor formali, pentru a mpiedica mo-
dificarea lor n corpul subprogramelor, n cazul n care apelatorul are nevoie de valorile iniia-
le.



* material didactic pentru ID * 13

1.6. Tratarea parametrilor din linia de comand

n linia de comand a unui program pot s apar parametri (sau argumente). Acetia
snt iruri de caractere desprite prin spaii. Programul poate accesa argumentele prin inter-
mediul parametrilor predefinii ai funciei main:

void main(int argc, char* argv[])

unde argc conine numrul de parametri ai programului, incrementat cu 1.

Exemplu
15. Dac programul nu are nici un parametru, argc are valoarea 1, dac programul are
doi parametri, argc are valoarea 3 etc.

Variabila argv este un vector de pointeri care conine adresele de memorie unde s-au
stocat irurile de caractere care constituie parametrii programului. Primul ir (cu adresa
argv[0]) conine identificatorul fiierului (inclusiv calea complet) care memoreaz progra-
mul executabil. Urmtoarele iruri conin parametrii n ordinea n care au aprut n linia de
comand (parametrii n linia de comand snt iruri de caractere separate prin spaii). Interpre-
tarea acestor parametri cade n sarcina programului.

Exemplu
16. S se scrie un program care afieaz parametrii din linia de comand.

#include<stdio.h>
main(int argc, char *argv[]);
{ int i;
printf("Fisierul executabil: %s\n", argv[0]);
for(i=1;i<argc;i++)
printf("Parametrul nr. %d: %s\n",i, argv[i]);
}

Teste de autoevaluare
5. S se scrie o un program care preia din linia de comand doua valori ntregi, le adu-
n i afieaz cele dou valori i suma lor. Dac n linia de comand nu se primesc doi
parametri ntregi, se va afia un mesaj de eroare..


Rspunsuri i comentarii la testele de autoevaluare
3.
int m,n;
float a[10][10];
printf("Nr. linii:\n"; scanf("%d", &m);
printf("Nr. coloane:\n"); scanf("%d", &n);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
{ printf("a(%d,%d)= ",i,j);
scanf("%f", *(a+i)+j );
}
Observaie: *(a+i)+j este un pointer, care conine adresa elementului a[i][j]; n
funcia scanf trebuie transmise ca parametri adresele unde se depun valorile citite; n
exemplul anterior se putea scrie &*(*(a+i)+j), i, reducnd, rezult *(a+i)+j.


Algoritmi n programare 14

4.
int i;
printf("Nr. elemente: ");
scanf("%d ", &n);
*v=(float*)malloc(*n*sizeof(float));
for(i=0;i<n;i++)
{ printf("v(%d)= ",i);
scanf("%f",&(*v)[i]); // sau scanf("%f", v+i);
}


Rezumat
n cadrul acestei uniti de nvare au fost studiate urmtoarele aspecte ale program-
rii calculatoarelor cu privire la tipurile dinamice de date:
definiia tipurilor de date pointer;
definirea tipurilor de date pointer n C, declararea i iniializarea variabilelor de tip
pointer;
utilizarea pointerilor, operaii aritmetice cu pointeri;
alocarea dinamic a datelor:
alocarea dinamic a masivelor de date i accesarea elementelor componente;
protejarea variabilelor statice i dinamice mpotriva modificrii, prin intermediul mo-
dificatorului const;
preluarea i prelucrarea parametrilor din linia de comand prin intermediul pointerilor
argc i argv.
Dup ncheierea studierii acestei uniti de nvare, studenii snt au cunotinele i
abilitile necesare lucrului cu pointeri i date alocate dinamic, abiliti necesare n continuare,
pentru abordarea aspectelor mai complexe ale programrii calculatoarelor.



Bibliografia unitii de nvare

1. I. Gh. Roca, B. Ghilic-Micu, C. Cocianu, M. Stoica, C. Uscatu, M. Mircea - Programarea
calculatoarelor. Algoritmi n programare, Ed. ASE Bucureti, 2007
2. I. Gh. Roca, B. Ghilic-Micu, C. Cocianu, M. Stoica, C. Uscatu - Programarea calculatoa-
relor. tiina nvrii unui limbaj de programare. Teorie i aplicaii, Ed. ASE Bucureti,
2003
3. Liviu Negrescu - Limbajele C i C++ pentru nceptori, vol. I, II, Ed. Microinformatica,
Cluj-Napoca, 1994
* material didactic pentru ID * 15



2. Subprograme



Cuprins

Obiectivele unitii de nvare ......................................................................................... 15
2.1. Construirea i apelul subprogramelor.................................................................. 15
2.2. Transferul datelor ntre apelator i apelat ........................................................... 18
2.2.1. Transferul prin parametri ................................................................................... 18
2.2.2. Simularea transmiterii parametrilor prin adres ............................................. 20
2.2.3. Comunicaia prin variabile globale .................................................................... 21
2.3. Pointeri spre funcii ................................................................................................ 22
2.4. Funcii cu numr variabil de parametri............................................................... 26
2.5. Calcul recursiv........................................................................................................ 29
2.6. Exemple de aplicaii cu subprograme recursive.................................................. 31
Rspunsuri i comentarii la testele de autoevaluare ....................................................... 36
Rezumat............................................................................................................................... 38
Bibliografia unitii de nvare........................................................................................ 38


Obiectivele unitii de nvare

Dup studierea acestei uniti de nvare, studenii vor avea cunotine teoretice i
abiliti practice necesare pentru lucrul cu subprograme. Ei vor putea analiza pro-
blemele i construi subprogramele care le rezolv corect. Concret, se vor asimila cu-
notine i abiliti de lucru privind:
tipurile de subprograme;
structura i apelul subprogramelor:
transferul parametrilor ntre apelator i apelat;
lucrul cu parametri de tip simplu, masiv, subprogram;
lucrul cu liste de parametri cu lungime variabil;
lucrul cu subprograme recursive.


2.1. Construirea i apelul subprogramelor

Conform teoriei programrii, subprogramele snt clasificate n funcii, care returneaz
un singur rezultat prin numele funciei i oricte prin parametri de ieire i proceduri, care
returneaz oricte rezultate, toate prin intermediul parametrilor de ieire.
Un program C este un ansamblu de funcii care realizeaz activiti bine definite. Exis-
t o funcie, numit main(), care este apelat la lansarea n execuie a programului. Subpro-
gramele C snt, n mod nativ, funcii. Pot fi construite subprograme care nu returneaz nici un
rezultat prin numele lor, comportndu-se ca o procedur (conform definiiei din teorie).
Sistemele C au colecii de biblioteci care conin funcii standard. Textul surs al unui
program C poate fi partiionat n mai multe fiiere. Fiecare fiier const dintr-un set de funcii
i declaraii globale. Fiierele care constituie partiia pot fi compilate i, eventual, testate sepa-
Algoritmi n programare 16
rat, dar numai unul va conine funcia main().

Funciile C snt formate din antet i un corp. Antetul are forma:

tip nume([lista-parametri-formali])
unde:
tip poate fi un tip simplu de dat. Dac lipsete, este considerat tipul implicit (int pen-
tru unele compilatoare, void pentru altele);
nume este un identificator care reprezint numele funciei;
lista-parametrilor-formali conine parametrii formali sub forma:

[tip1 identificator1[,tip2 identificator[,tip3 identificator ]]]

Parametrii snt separai prin virgul. La limit, lista poate fi vid. Pentru fiecare para-
metru trebuie specificat tipul, chiar dac mai muli parametri snt de acelai tip (nu este posi-
bil definirea de liste de parametri cu acelai tip).
Pentru funciile care nu ntorc o valoare prin numele lor, tipul funciei va fi void sau va
fi omis.

Corpul este o instruciune compus: conine declaraiile locale i instruciunile execu-
tabile care implementeaz algoritmul. Corpul funciei se execut pn la executarea ultimei in-
struciuni sau pn la executarea instruciunii return. Forma ei general este:

return(expresie); sau
return expresie; sau
return;

Prima i a doua form snt folosite n cazul funciilor care returneaz o valoarea prin
numele lor. Prin executarea acestei instruciuni se evalueaz expresia, valoarea sa este atribui-
t funciei i se ncheie execuia funciei. A treia form este folosit n cazul funciilor care nu
returneaz nici o valoare prin numele lor (poate chiar s lipseasc). Dac este prezent, efectul
ei este ncheierea execuiei funciei.
Tipul expresiei din instruciunea return trebuie s coincid cu tipul funciei.

Atenie: corect este tipul rezultatului ntors de funcie prin numele su. Vom vedea
mai trziu c sintagma tipul funciei are un alt neles, mai complex.

n limbajul C nu este admis imbricarea, adic definirea unui subprogram n cadrul al-
tui subprogram i nu snt permise salturi cu instruciunea goto (instruciune de salt necondii-
onat) n afara subprogramului curent.

Declararea unui subprogram apare, n cadrul fiierului surs, naintea primului apel.
Exist cazuri particulare n care, fie funciile se apeleaz unele pe altele (de exemplu, cazul
recursivitii mutuale), fie definiia nu se afl n fiierul surs. Pentru a oferi compilatorului
posibilitatea s efectueze verificarea validitii apelurilor, snt prevzute declaraii ale subpro-
gramelor fr definirea corpului lor (declaraii anticipate). Aceste declaraii se numesc proto-
tipuri i apar n afara oricrui corp de funcie. Sintaxa general este:

tip nume ([lista-parametri-formali]);

Prototipul este de fapt un antet de funcie dup care se scrie caracterul ; (punct i vir-
gul). Numele parametrilor pot lipsi, fiind suficient specificarea tipurilor lor. Prototipul tre-
* material didactic pentru ID * 17
buie inserat n program naintea primului apel al funciei. Domeniul de valabilitate a declara-
iei unui subprogram este limitat la partea care urmeaz declaraiei din fiierul surs.
Prototipurile funciilor standard se afl n fiiere header (cu extensia .h). Utilizarea
unei funcii din bibliotec impune includerea fiierului asociat, cu directiva #include.

Fiind funcii, subprogramele C se apeleaz ca operanzi n expresii, prin numele funci-
ei urmate de lista parametrilor reali. Expresia care conine apelul poate la limit s conin un
singur operand i chiar s fie o instruciune de tip expresie. n aceste cazuri valoarea returnat
de funcie se pierde, nefiind folosit n nici un fel.

Exemple
1. S se scrie o funcie care calculeaz cel mai mare divizor comun dintre dou nume-
re ntregi nenule, utiliznd algoritmul lui Euclid i un apelator pentru testare.

#include <stdio.h>

int cmmdc(int a, int b) /*definirea functiei cmmdc*/
{ int r,d=a,i=b;
do {r=d%i;
d=i; i=r;}
while(r<>0);
return i;
}

void main()
{ int n1,n2;
printf("Numerele pentru care se va calcula cmmdc:");
scanf("%d%d",&n1,&n2);
if(n1&&n2) printf("\ncmmdc=%d",cmmdc(n1,n2));
else printf("Numerele nu snt nenule!");
}

2. Acelai exemplu folosind un prototip pentru funcia cmmdc:

#include <stdio.h>

int cmmdc(int, int); /* prototipul functiei cmmdc*/

void main()
{ int n1,n2;
printf("Numerele pentru care se va calcula cmmdc:");
scanf("%d%d",&n1,&n2);
if(n1&&n2) printf("\ncmmdc=%d",cmmdc(n1,n2));
else printf("Numerele nu snt nenule! ");
}

int cmmdc(int a, int b) /*definirea functiei cmmdc*/
{ int r,d=a,i=b;
do {r=d%i;
d=i; i=r;}
while(r<>0);
return i;
}

Teste de autoevaluare
1. Care este diferena teoretic dintre un subprogram de tip funcie i un subprogram
de tip procedur?
2. Ce tipuri de subprograme pot fi scrise n limbajul C?
3. Ce este un prototip?

Algoritmi n programare 18
2.2. Transferul datelor ntre apelator i apelat

n practica programrii, s-au conturat dou posibiliti de transfer al datelor ntre ape-
lator i apelat: prin parametri i prin variabile globale. Prin utilizarea variabilelor globale nu
se face un transfer propriu-zis, ci se folosesc n comun anumite zone de memorie. Aceast
practic este nerecomandat.

2.2.1. Transferul prin parametri
Principial, transferul parametrilor se poate face prin valoare sau prin adres. n limba-
jul C este implementat numai transferul prin valoare (valoarea parametrului real este copiat
n stiv iar subprogramul lucreaz numai cu aceast copie). Operaiile efectuate asupra unui
parametru formal scalar (care nu este masiv) nu modific, la ieirea din subprogram, parame-
trul real corespunztor. Dezvoltrile ulterioare (C++) au implementat i transferul prin adres.
Transferul valorii este nsoit de eventuale conversii de tip realizate pe baza informai-
ilor de care dispune compilatorul despre subprogram (tipurile parametrilor). Dac prototipul
precede apelul subprogramului i nu exist o sublist variabil de parametri, conversiile se fac
similar atribuirilor.

Exemplu
3. tip_returnat nume(tip_parametru p); p este transferat prin valoare

Folosind transferul prin valoare se pot transmite numai parametri de intrare n subpro-
gram. Pentru a putea folosi parametri de ieire trebuie simulat transferul prin adres. n acest
scop, se vor efectua explicit operaiile care se fac automat la transferul prin adres din alte
limbaje: se transmite ca parametru adresa parametrului real iar n subprogram se lucreaz cu
indirectare (pentru a accesa valoarea parametrului, se derefereniaz adresa primit).

Exemplu
4. tip_returnat nume(tip_parametru *p); p este transferat prin valoare, fiind
adresa parametrului real.

Pentru parametrii de tip masiv, simularea transferului prin adres se face n mod im-
plicit, datorit modului de construire a masivelor n C: numele masivului este un pointer. La
apel, n stiv se va transfera adresa masivului iar referirea elementelor se face automat prin
calcul de adrese (vezi capitolul Tipuri dinamice de date).

Urmtoarele prototipuri snt echivalente:
tip_returnat nume1(float v[], int n);
tip_returnat nume2(float *v, int n);

Exemple
5. S se calculeze produsul scalar dintre doi vectori. Rezultatul se ntoarce prin nume-
le funciei:
float ps(float x[], float y[], int n)
{ int i,prod=0;
for(i=0;i<n;prod+=x[i]*y[i++]);
return prod;
}

Apelul se realizeaz astfel:
float a[30], b[30];
int dimensiune;

* material didactic pentru ID * 19
printf("Produsul scalar al vectorilor a si b este:%f", ps(a,b,dimensiune));

n a doua variant de rezolvare, rezultatul se ntoarce prin parametru, simulnd transferul prin
adres:

void ps(float x[], float y[], int n, float *prod)
{ int i;
*prod=0;
for(i=0;i<n;(*prod)+=x[i]*y[i++]);
}

Apelul se realizeaz astfel:
float a[30],b[30],produs_scalar;
int dimensiune;
ps(a,b,dimensiune,&produs_scalar);
printf("Produsul scalar al vectorilor a si b este:%f", produs_scalar);

6. S se calculeze elementul maxim dintr-un vector i poziiile tuturor apariiilor acestuia (v, n
snt parametri de intrare; max, nr_ap, poz snt parametri de ieire).

void maxim(float v[],int n,float *max,int *nr_ap,int poz[])
{ int i;
for(*max=v[0],i=1;i<n;i++)
if(*max<v[i])
{*nr_ap=1;poz[0]=i; max=v[i];}
else if(*max==v[i])poz[*nr_ap++]=i;
}

Apelul se realizeaz astfel:
float a[30],el_max;
int dimensiune,nr_aparitii,pozitii[30];
maxim(a,dimensiune,&max,&nr_aparitii,pozitii);

Antetul subprogramului este echivalent cu construcia

void maxim(float *v, int n, float *max, int *nr_ap, int *poz)

pentru care corpul subprogramului este acelai.

7. S se calculeze produsul a dou matrice statice.

void produs(float a[][10],float b[][20], float c[][20],int m, int n,int p)
{ int i,j,k;
for(i=0;i<m;i++)
for(j=0;j<p;j++)
for(c[i][j]=0,k=0;k<n;k++)c[i][j]+=a[i][k]*b[k][j];
}

Observaie: Dei un tablou (masiv) nu poate fi returnat ca tip masiv prin numele unei
funcii, se pot scrie funcii care returneaz prin nume un tablou ca pointer deoarece
numele tabloului este echivalent n C cu adresa sa (pointer la nceputul masivului).
Unui astfel de masiv i se aloc memorie n funcia care l calculeaz. Rezultatul ntors prin
numele funciei este adresa spaiului de memorie alocat pentru masiv.

Exemple
8. S se calculeze produsul dintre o matrice i un vector.
#include<malloc.h>

Algoritmi n programare 20
float * prod(float a[][30], float v[],int m, int n)
{ float *p;int i,j;
p=(float *)malloc(sizeof(float)*m);
for(i=0;i<m;i++)
for(p[i]=0,j=0;j<n;j++) p[i]+=a[i][j]*v[j];
return p;
}

Apelul se realizeaz astfel:
a) float a[20][30], b[30], *c;
int m,n;

c=prod(a,b,m,n);
Cu vectorul c se lucreaz n modul obinuit: elementele se refer prin indexare (c[i], i=0..m ).

b) float a[20][30], b[30];
int m,n;

Se lucreaz cu vectorul prod(a,b,m,n) elementele sale se refer ca prod(a,b,m,n)[i],
i=0..m.

Observaie: la fiecare referire de element se apeleaz i se execut funcia, ceea ce
duce la consum mare i inutil de resurse. Este preferabil prima variant.


Teste de autoevaluare
4. S se realizeze un program C pentru ridicarea unei matrice la o putere. Pentru
aceasta se folosesc dou funcii care returneaz, prin pointeri, produsul a dou matrice
(nmulire), respectiv ridicarea unei matrice la o putere (putere).

2.2.2. Simularea transmiterii parametrilor prin adres
Limbajul C permite transmiterea parametrilor numai prin valoare (la apelul subpro-
gramelor se copiaz n stiv valoarea parametrului real i subprogramul lucreaz cu aceast
copie). Subprogramul nu poate modifica valoarea parametrului din apelator.
Dac parametrul formal este un masiv, el este de fapt un pointer (adresa de nceput a
masivului). Folosind aceast proprietate, se pot modifica valorile elementelor masivului, iar
modificrile se vor propaga n blocul apelator, deoarece valoarea care se copiaz n stiv este
adresa de nceput a masivului. Masivul rmne n memoria principal i poate fi modificat
prin intermediul adresei sale de nceput. Astfel se poate simula transmiterea parametrilor prin
adres folosind pointerii. Subprogramul poate modifica valori care s se propage n apelator.
n acest scop se transmite ca parametru un pointer spre variabila cu care trebuie s lu-
creze subprogramul apelat. Subprogramul va folosi explicit acest pointer. Un exemplu n acest
sens este funcia de citire a datelor de la tastatur. Parametrii acestei funcii snt adresele vari-
abilelor ale cror valori trebuie citite (altfel spus: adresele zonelor de memorie unde trebuie
depuse valorile citite de la tastatur).

Exemple
9. Fie un subprogram care calculeaz suma elementelor unui vector v de lungime n.

void suma(float s, float v[], int n)
{ int i;
for(s=0,i=0;i<n;i++)
s+=v[i];
}

* material didactic pentru ID * 21
Subprogramul suma calculeaz suma elementelor vectorului dar aceasta nu poate fi fo-
losit de apelator, deoarece valoarea sumei este cunoscut numai n interiorul funciei (para-
metrul a fost transmis prin valoare). n apelator valoarea variabilei corespunztoare parame-
trului formal s nu va fi modificat. Pentru ca subprogramul s fie utilizabil, trebuie ca parame-
trul s s fie un pointer spre variabila n care se va memora suma elementelor vectorului:

void suma(float* s, float v[], int n)
{ int i;
for(s=0,i=0;i<n;i++) *s+=v[i];
}

La apelul funciei, primul parametru actual este adresa variabilei n care se memoreaz suma:

void main()
{ float x, m[20]; int n;
//
suma(&x, m, n);
//
}

10. S se realizeze un subprogram care citete de la tastatur o valoare ntreag care aparine
unui interval dat.

void citire(int a, int b, int* x)
{ do
printf("Introduceti numarul: ");
scanf("%d", x);
while((*x<=a)||(*x>=b));
}

2.2.3. Comunicaia prin variabile globale
Variabilele globale se declar n afara funciilor. Ele pot fi referite din orice alte func-
ii. De aceea, comunicarea valorilor ntre apelator i apelat se poate realiza prin intermediul
lor. Variabilele declarate ntr-o funcie se numesc locale (din clasa automatic) i pot fi referite
numai din funcia respectiv. Domeniul de valabilitate a unei variabile locale este blocul
(funcia sau instruciunea compus) n care a fost definit.

Exemplu
11.
#include <stdio.h>

int a;

float z(char b)
{ int b;

}

main()
{ int c;

{ /* instructiunea compusa r */
int d;

}
}
Domeniile de valabilitate a referirilor variabilelor declarate snt urmtoarele:
b poate fi referit doar n funcia z;
c poate fi referit doar n funcia main;
d poate fi referit doar n instruciunea compus r;
a este global i poate fi referit de oriunde.

Atenie: este impropriu spus transfer prin variabile globale, deoarece nu se realizeaz
un transfer propriu-zis. De fapt o zon de memorie este accesat de mai multe entiti
(subprograme), toate avnd posibilitatea utilizrii i modificrii valorii din acea zon.
Algoritmi n programare 22
Datorit lipsei controlului asupra modificrilor, acest mod de transmitere a datelor nu este re-
comandat. Se prefera utilizarea acestei metode doar atunci cnd este vorba de valori comune,
general valabile ntr-o aplicaie i care se modific relativ rar (de exemplu calea ctre fiierul
de date cu care se lucreaz).

Teste de autoevaluare
5. Cum se realizeaz fizic transferul unui parametru prin valoare, respectiv prin adre-
s? Care este efectul asupra proiectrii subprogramelor?


2.3. Pointeri spre funcii

n limbajul C, numele unei funcii este un pointer care indic adresa de memorie unde
ncepe codul executabil al funciei. Aceasta permite transmiterea funciilor ca parametri n
subprograme precum i lucrul cu tabele de funcii. n acest scop trebuie parcurse urmtoarele
etape:

a. Declararea unei variabile de tip procedural (pointer spre funcie):

tip_rezultat (*nume_var)(lista_parametri_formali);

unde nume_var este o variabil de tip procedural i are tipul pointer spre funcie cu parame-
trii lista_parametri_formali i care returneaz o valoare de tipul tip_rezultat. Lui nume_var i
se poate atribui ca valoare doar numele unei funcii de prototip corespunztor acestui tip:

tip_rezultat nume_f(lista_parametrilor_formali);

b. Descrierea funciei care utilizeaz parametrul procedural:

void f(, tip_rezultat (*nume)(lista_parametrilor_formali), )
{ tip_rezultat x;

x=(*nume)(lista_parametrilor_actuali);

}

unde nume este parametrul formal de tip procedural.

c. Apelul funciei cu parametri procedurali:

tip_rezultat nume_functie(lista_parametrilor_formali)
{ }

void main()
{
f(, nume_functie, );
}

Exemplu
12. Fie o funcie care efectueaz o prelucrare asupra unui vector. Nu se cunoate apri-
ori tipul prelucrrii, aceasta fiind descris de o alt funcie, primit ca parametru. Pot exista
mai multe funcii care descriu prelucrri diferite asupra unui vector i oricare din ele poate fi
transmis ca parametru.

* material didactic pentru ID * 23
float suma(float *v, int n)
{ for(int i=0, float s=0; i<n; i++)
s+=v[i];
return(s);
}

float media(float *v, int n)
{ for(int i=0, float m=0; i<n; i++)
m+=v[i];
m/=n;
return(m);
}

float functie( float vec[],int dim,float(* prelucrare)(float*, int))
{
return (*prelucrare)(vec,dim));
}

Apelul se realizeaz prin transmiterea ca parametru real a funciei potrivite prelucrrii dorite.

void main()
{ float tab[10]; int m,i;
printf("Numarul de elemente(<10): ");
scanf("%d ", &m);
for(i=0,i<m;i++)
{printf("a(%d)=",i);
scanf("%f",&tab[i]);
}
printf("Se calculeaza suma elementelor\n");
printf("Rezultatul prelucrarii este: %5.2f\n", functie(tab, m, suma));
printf("Se calculeaza media elementelor\n");
printf("Rezultatul prelucrarii este: %5.2f\n", functie(tab, m, suma));
return;
}

Limbajul C permite lucrul cu variabile de tip pointer, care conin adresa de nceput a
unei funcii (a codului su executabil). Aceste variabile permit transferul adresei funciei aso-
ciate ca parametru, precum i apelul funciei prin intermediul pointerului su.
Urmtoarea declaraie definete pointer_f ca pointer spre funcia cu rezultatul
tip_returnat i parametrii parametri.

tip_returnat (*pointer_f)([parametri])

Observaie: Nu trebuie s se confunde un pointer la o funcie cu o funcie care are ca
rezultat un pointer, cu sintaxa de forma
tip_returnat *pointer_f([parametri])

Adresa unei funcii se obine prin simpla specificare a identificatorului acesteia (fr
specificarea parametrilor sau parantezelor) i poate fi atribuit unui pointer spre funcie cu re-
zultat i parametri compatibili. Pointerul poate fi folosit ulterior pentru apelul funciei sau
transmis ca parametru real n apelul unui subprogram care conine, n lista parametrilor for-
mali, un pointer la un prototip de funcie compatibil.

Exemplu
13. S se aproximeze soluia unei ecuaii de forma f(x)=0 prin metoda biseciei.

#include<stdio.h>
#include<conio.h>
#include<math.h>

Algoritmi n programare 24
/*prototipul functiei bisectie*/
void bisectie(float,float,float(*f)(float),float,long,int *,float *);

/*prototipul functiei pentru care se aplica metoda bisectiei*/
float fct(float);

/* functia principala*/
void main()
{ float a,b,eps,x;
int cod;
long n;
float (*functie)(float);
clrscr();
printf("Introduceti capetele intervalului:");
scanf("%f%f",&a,&b);
printf("\nEroarea admisa:");
scanf("%f",&eps);
printf("\nNumarul maxim de iteratii:");
scanf("%li",&n);
functie=fct;
bisectie(a,b,functie,eps,n,&cod,&x);
if(!cod)
printf("\nNu se poate calcula solutia aproximativa");
else
printf("\n Solutia aproximativa este: %f",x);
}

/*descrierea functiei pentru care se aplica metoda bisectiei*/
float fct(float x)
{ return x*x*x-3*x+14;
}

/*functia ce implementeaza metoda bisectiei*/
void bisectie(float a,float b,float (*f)(float),float eps,long n,
int *cod,float *x)
{ int gata=0;
long c;
for(c=0;(c<n)&&!gata;c++)
{ *x=(a+b)/2;
gata=fabs(*x-a)<eps;
if ((*f)(*x)*(*f)(a)<0)
b=*x;
else a=*x;
}
*cod=gata;
}

Exemplu
14. S se sorteze un ir cu elemente de un tip neprecizat, dar pe care se poate defini o
relaie de ordine (de exemplu numeric, ir de caractere, caracter).
Metoda aleas spre exemplificare este sortarea prin selecie direct. Un subprogram de
sortare care s nu depind de tipul elementelor i de criteriul de sortare considerat trebuie s
aib ca parametri formali:
vectorul de sortat, ca pointer la tipul void, asigurndu-se astfel posibilitatea realizrii
operaiei de schimbare a tipului (cast) n funcie de necesitile ulterioare (la mo-
mentul apelului se poate realiza modificarea tipului void* n tip_element*, unde
tip_element reprezint tipul elementelor vectorului de sortat);
dimensiunea vectorului de sortat i numrul de octei din reprezentarea tipului elemen-
telor vectorului;
pointerul la o funcie de comparare, cu argumente de tip void *, care s permit la
apel att schimbarea de tip, ct i descrierea efectiv a relaiei de ordine.

* material didactic pentru ID * 25
Deoarece tipul elementelor vectorului nu este cunoscut la momentul descrierii proce-
durii de sortare, operaia de atribuire nu poate fi folosit, ea fiind nlocuit de o funcie de co-
piere a unui numr prestabilit de octei, de la o adres surs la una destinaie. O astfel de func-
ie exist n biblioteca mem.h, sintaxa ei fiind:
void *memmove(void *destinaie, const void *surs, unsigned n)

Pentru accesarea adresei elementului de rang i din vector se folosete formula
(char *)v+i*nr_octeti.

Fiierul surs care conine funcia de sortare descris anterior este urmtorul:

//fisier exp_tip.cpp
#include <mem.h>
include<alloc.h>

void sort(void *v, int n, int dim,
int (*compara)(const void * ,const void * ))
{ int i,j;
void *aux;
aux=malloc(dim);
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if((*compara)((char*)v+dim*i,(char*)v+dim*j))
{ memmove(aux,(char*)v+dim*i,dim);
memmove((char*)v+dim*i,(char*)v+dim*j,dim);
memmove((char*)v+dim*j,aux,dim);
}
free(aux);
}

Exemplu de apel pentru un vector de numere reale:

#include <stdio.h>
#include<conio.h>
#include "exp_tip.cpp"
int compara(const void *a, const void *b)
{ if(*(float *)a>*(float *)b)return 1;
else return 0;
}
void main()
{ float vect[20]; int n,i;
clrscr();
printf("Dimensiunea vectorului:");
scanf("%d",&n);
printf("\nElementele:");
for(i=0;i<n;i++)
scanf("%f",&vect[i]);
sort(vect,n,sizeof(float),compara);
printf("\nElementele sortate:");
for(i=0;i<n;i++)
printf("\n%f",vect[i]);
getch();
}

Exemplu de apel pentru un vector de cuvinte (iruri de caractere):

#include <stdio.h>
#include <string.h>
#include<conio.h>
#include "exp_tip.cpp"
int compara(const void *a, const void *b)
{ if(strcmp((char *)a, (char *)b)>0)return 1;
else return 0; }
Algoritmi n programare 26
void main()
{ typedef char cuvant[10];
cuvant vect[20];
int n;
clrscr();
printf("Dimensiunea vectorului de cuvinte:");
scanf("%d",&n);
printf("\nCuvintele:");
for(int i=0;i<n;i++)
scanf("%s",&vect[i]);
sort(vect,n,10,compara);
printf("\nCuvintele sortate:");
for(i=0;i<n;i++)
printf("\n%s",vect[i]);
getch();
}

Teste de autoevaluare
6. S se modifice exemplul de mai sus privind rezolvarea unei ecuaii prin metoda bi-
seciei astfel nct s se detecteze i situaia gsirii soluiei exacte a ecuaiei.
7. Folosind exemplul implementrii metodei biseciei, scriei un subprogram care implemen-
teaz metoda tangentei pentru rezolvarea unei ecuaii. Scriei i un program apelator, n care
s testai subprogramul.


2.4. Funcii cu numr variabil de parametri

Bibliotecile limbajului C conin subprograme standard cu numr variabil de para-
metri. Limbajul C permite definirea funciilor utilizator cu numr variabil de parametri, prin
utilizarea unui set de macrodefiniii, declarate n biblioteca stdarg.h, care permit accesul la
lista de parametri.
Fiierul stdarg.h declar tipul va_list i funciile va_start, va_arg i va_end, n care:

va_list este un pointer ctre lista de parametri. n funcia utilizator corespunztoare trebuie
declarat o variabil (numit n continuare ptlist) de acest tip, care va permite adresarea para-
metrilor.

va_start iniializeaz variabila ptlist cu adresa primului parametru din sublista variabil.
Prototipul acestei funcii este:

void va_start(va_list ptlist, ultim);
unde ultim reprezint numele ultimului parametru din sublista variabil. n unele situaii (vezi
exemplele) se transfer n acest parametru numrul de variabile trimise.

va_arg ntoarce valoarea parametrului urmtor din sublista variabil. Prototipul acestei
funcii este:

tip_element va_arg(va_list ptlist, tip_element);
unde tip_element este tipul elementului transferat din list. Dup fiecare apel al funciei
va_arg, variabila ptlist este modificat astfel nct s indice urmtorul parametru.

va_end ncheie operaia de extragere a valorilor parametrilor i trebuie apelat nainte de
revenirea din funcie. Prototipul funciei este:

void va_end(va_list ptlist);
* material didactic pentru ID * 27

Problema numrului de parametri i tipurilor lor este tratat de programator.

Exemplu
15. S se calculeze cel mai mare divizor comun al unui numr oarecare de numere n-
tregi.
#include<stdio.h>
#include<conio.h>
#include<stdarg.h>

int cmmdc_var(int,...); // functie cu numar variabil de parametri
int cmmdc(int, int);

void main()
{ int x,y,z,w;
clrscr();
scanf("%d%d%d%d",&x,&y,&z,&w);
printf("\nCmmdc al primelor 3 numere:%d\n",cmmdc_var(3,x,y,z));
printf("\nCmmdc al tuturor numerelor:%d\n",cmmdc_var(4,x,y,z,w));
}

int cmmdc(int x,int y) //cel mai mare divizor comun a doua numere
{ int d=x,i=y,r;
do{ r=d%i;
d=i;i=r;
}
while(r);
return d;
}

int cmmdc_var(int nr,...) //cel mai mare divizor comun a nr numere
{ va_list ptlist;

/*initializarea lui ptlist cu adresa de inceput a listei de parametri*/
va_start(ptlist,nr);

//extragerea primului parametru, de tip int
x=va_arg(ptlist,int);

for(int i=1;i<nr;i++)
{ //extragerea urmatorului element din lista de parametri
y=va_arg(ptlist,int);
z=cmmdc(x,y);x=z;
}
va_end(ptlist);
return x;
}

Exemplu
16. S se interclaseze un numr oarecare de vectori.
Spre deosebire de exemplul anterior, n care n lista de parametri a funciei cu numr
oarecare de parametri figurau elemente de acelai tip (int), acest exemplu ilustreaz modul de
transfer i acces la elemente de tipuri diferite. Funciei inter_var i se transmit la apel vectorul
rezultat, iar pentru fiecare vector de interclasat, adresa de nceput (pointer la tipul double) i
numrul de elemente (int). Numrul parametrilor din lista variabil este, n acest, caz 2 x nu-
mrul de vectori de interclasat.

#include<stdarg.h>
#include<stdio.h>
#include<conio.h>

void inter(double *,int,double *,int,double *);
void inter_var(double *,int nr,...);
Algoritmi n programare 28

void main()
{ int n1,n2,n3,n4;
double x1[10],x2[10],x3[10],x4[10],z[50];
clrscr();
scanf("%d%d%d%d",&n1,&n2,&n3,&n4);
for(int i=0;i<n1;i++)
scanf("%lf",&x1[i]);
for(i=0;i<n2;i++)
scanf("%lf",&x2[i]);
for(i=0;i<n3;i++)
scanf("%lf",&x3[i]);
for(i=0;i<n4;i++)
scanf("%lf",&x4[i]);
inter_var(z,4,x1,n1,x2,n2);
printf("\nRezultatul interclasarii primilor 2 vectori\n");
for(i=0;i<n1+n2;i++)
printf("%lf ",z[i]);
inter_var(z,8,x1,n1,x2,n2,x3,n3,x4,n4);
printf("\nRezultatul interclasarii celor 4 vectori\n");
for(i=0;i<n1+n2+n3+n4;i++)
printf("%lf ",z[i]);
}

void inter(double *x, int n1, double *y, int n2, double *z)
{ int i,j,k;
for(i=0,j=0,k=0;(i<n1)&&(j<n2);k++)
if(x[i]<y[j])
z[k]=x[i++];
else z[k]=y[j++];
if(i<n1)
for(;i<n1;z[k++]=x[i++]);
else for(;j<n2;z[k++]=y[j++]);
}

void inter_var(double *z,int nr,...)
{ va_list ptlist;
double *x,*y,x1[100];
int n1,n2;

/*initializarea lui ptlist cu adresa de inceput a listei de parametri*/
va_start(ptlist,nr);
//extragerea primului vector
x=va_arg(ptlist,double *);
//extragerea dimensiunii lui
n1=va_arg(ptlist,int);

for(int j=0;j<n1;j++) x1[j]=x[j];
for(int i=1;i<(int)(nr/2);i++)
{ //extragerea urmatorului vector
y=va_arg(ptlist,double *);
//extragerea numarului sau de elemente
n2=va_arg(ptlist,int);

inter(x1,n1,y,n2,z);
for(j=0;j<n1+n2;j++)
x1[j]=z[j];n1+=n2;
}
va_end(ptlist);
}

Teste de autoevaluare
8. S se scrie o funcie cu numr variabil de parametri care calculeaz produsul unui
ir de maxim n matrice. Funcia trebuie s aloce spaiu de memorie pentru masivul re-
zultat i s trimit ctre apelator adresa acestui spaiu, mpreun cu dimensiunile masivului
rezultat i un cod de eroare (nu orice ir de matrice se pot nmuli). Funcia primete ca para-
* material didactic pentru ID * 29
metri numrul de matrice care particip la operaie, adresele i dimensiunile lor, in ordinea:
adres matrice, nr. linii, nr. coloane, adres matrice, nr. linii, nr. coloane .


2.5. Calcul recursiv

Recursivitatea este tehnica de programare n care un subprogram se autoapeleaz.
Limbajul C face parte din clasa limbajelor de programare care admit scrierea de funcii recur-
sive.
n continuare snt prezentate cteva exemple simple de subprograme C prin intermedi-
ul crora snt calculate recursiv valorile f g f , C , ! n
k
n
o o , unde k , n N i f, g funcii, : g , f
R R. De asemenea, este ilustrat maniera n care snt efectuate apelurile recursive i trata-
rea condiiilor de terminare.

Exemplu
17. Calculul valorii n! pentru n dat poate fi efectuat pe baza formulei recursive
( )

>
=
=
0 n , ! 1 n n
0 n , 1
! n .
Fie fact(n) funcia C care calculeaz n!. Dac n1, evaluarea lui fact(n) rezult prin
multiplicarea cu n a valorii calculate de apelul fact(n-1), cu fact(0)=1. Cu alte cuvinte, apelul
funciei fact(n) realizeaz calculul imediat dac n=0, altfel presupune un nou apel al acele-
iai funcii pentru valoarea argumentului decrementat. Cazurile n care este posibil evalua-
rea imediat se numesc condiii de terminare.
n limbajul C, funcia fact este

long fact(unsigned n)
{ if (!n) return 1;
return n*fact(n-1);
}

Exemplu
18. Utilizarea formulei
( )! k n ! k
! n
C
k
n

= pentru calculul combinrilor ( k , n N date)


este ineficient i uneori imposibil deoarece n!, pentru n13 nu poate fi reprezentat n calcu-
lator ca dat de un tip ntreg, chiar dac numrul
k
n
C este relativ mic i poate fi reprezentat
prin intermediul unui tip ntreg. Pe baza relaiei de recuren
1 k
1 n
k
1 n
k
n
C C C


+ = , valoarea
k
n
C
poate fi calculat astfel. Fie comb(n,k) funcia care calculeaz
k
n
C . Conform relaiei de recu-
ren, dac nk 1, atunci evaluarea corespunztoare apelului comb(n,k) revine la nsumarea
rezultatelor obinute prin apelurile comb(n-1,k) i comb(n-1, k-1), unde comb(n,0)=1, n0.
Dac evalurile comb(n-1,k) i comb(n-1, k-1) snt realizate n acelai mod, rezult c apelul
comb(n,k) va determina o secven de apeluri ale aceleiai funcii pentru valori ale argumente-
lor din ce n ce mai mici, pn cnd este ndeplinit una din condiiile terminale comb(n,0)=1,
comb(k,k)=1.
Soluia recursiv a evalurii
k
n
C este:
long comb(unsigned n, unsigned k)
{ if (k>n) return 0;
if ((k==0)||(k=n)) return1;
return comb(n-1,k)+comb(n-1,k-1);
}

Algoritmi n programare 30
Funciile C recursive pentru calculul
k
n
C , ! n , unde k , n N realizeaz apeluri recursi-
ve directe. Schema unui apel recursiv poate fi descris astfel: se verific dac este ndeplinit
cel puin una din condiiile terminale; dac este ndeplinit o condiie terminal, atunci calcu-
lul este ncheiat i controlul este returnat unitii apelante, n caz contrar este iniiat calculul
pentru noile valori ale parametrilor, calcul care presupune unul sau mai multe apeluri recursi-
ve.

Mecanismul prin care este efectuat apelul unui subprogram se bazeaz pe utilizarea
stivei memoriei calculatorului. Fiecare apel determin introducerea n stiv a valorilor para-
metrilor reali, a adresei de revenire i a variabilelor locale. La momentul execuiei, aceste in-
formaii snt extrase cu eliminare din stiv, eliberndu-se spaiul ocupat.
n cazul subprogramelor recursive, mecanismul funcioneaz astfel: este generat un
numr de apeluri succesive cu ocuparea spaiului din stiv necesar efecturii apelurilor pn la
ndeplinirea unei condiii de terminare; apelurile snt executate n ordinea invers celei n care
au fost generate, iar operaia de inserare n stiv poate produce depirea spaiul de memorie
rezervat.

De exemplu, n cazul apelului fact(3), secvena de apeluri recursive este: fact(2),
fact(1), fact(0). n continuare execuia determin fact(0)=1, fact(1)=1*fact(0)=1,
fact(2)=2*fact(1)=2, fact(3)=3*fact(2)=6.
Evoluia determinat de apelul fact(3) n stiv este ilustrat n figurile 2.1.a i 2.1.b,
unde () reprezint adresa de revenire n punctul de unde a fost efectuat apelul fact(3).


3

Fact=3*Fact(2)


2


Fact=2*Fact(1)

3


Fact=3*Fact(2)

(o)
(o)
2


Fact=2*Fact(1)

3


Fact=3*Fact(2)

1


Fact=1*Fact(0)

2


Fact=2*Fact(1)

3


Fact=3*Fact(2)

1


Fact=1*Fact(0)

0


Fact=1

(o)
(o)

Fig. 2.1.a Evoluia n stiv pn la verificarea
condiiei de terminare n=0





2


Fact=2*Fact(1)

3


Fact=3*Fact(2)

1


Fact=1

2


Fact=2

3


Fact=3*Fact(2)

3


Fact=6

(o)
(o)
Fig. 2.1.b Eliberarea stivei dup execuia de-
terminat de condiia de terminare



* material didactic pentru ID * 31
Apelurile recursive ale unui subprogram S1 pot fi i indirecte, n sensul c este efectu-
at un apel al unui alt subprogram S2 i S2 iniiaz un apel al lui S1 (recursivitate mutual).

Exemplu
19. De exemplu, s se calculeze valorie funciei h=fgf , unde f,g:RR snt funcii
date. Pentru funciile f, g definite prin
( ) ( )

> +
+
=

>
< +
< +
=
1 x , 5 x x
1 x , 2 x 3 x 5
x g ,
8 x , 3
8 x 5 , 2 x
5 x , 1 x 2
x f
3
2
4
3

funciile C pentru calculul h=fgf pot fi descrise astfel:
float f(float x)
{ if (x<5) return 2*pow(x,3)+1;
if (x<8) return pow(x,4)+2;
return 3;
}

float g(float x)
{ if (x<=1) return 5*x*x-3*x+2;
return pow(x,3)-x+5;
}

float h(float x)
{ return f(g(f(x)));
}


2.6. Exemple de aplicaii cu subprograme recursive

Exemplu
20. S se scrie o funcie C care citete o secven oarecare de cuvinte a
1
, a
2
, .., a
n

terminat cu simbolul # i afieaz a
n
a
n-1
a
1
. Pentru rezolvarea problemei se utilizeaz func-
ia recursiv Scrie.

void Scrie()
{ char cuvant[100];
scanf(%s,&cuvant);
if (strcmp(cuvant,#))
{ Scrie;
printf( %s\n,cuvant);
}
}

Exemplu
21. Calculul valorii funciei Ackermann.

Funcia Ackermann este definit pentru argumentele m,n numere naturale prin
( ) ( )
( ) ( )


=
= +
=
altfel , 1 n , m a , 1 m a
0 n , 1 , 1 m a
0 m , 1 n
n , m a
Funcia C Ackermann calculeaz valoarea funciei a pentru m, n parametri naturali dai.
long Ackermann(unsigned m, unsigned n)
{ if (!m) return n+1;
if (!n) return Ackermann(m-1,1);
return Ackermann(m-1,Ackermann(m,n-1));
}
Algoritmi n programare 32

Exemplu
22. Problema calculului celui mai mare divizor comun dintre dou numere naturale a
i b poate fi rezolvat recursiv, conform definiiei urmtoare,
( )

>
>
=
=
a b ), a b , a (
b a ), b , b a (
b a , a
b , a
Funcia C cmmdc(a,b) este
long cmmdc(long a, long b)
{ if (a==b) return a;
if (a>b) return cmmdc(a-b,b);
return cmmdc(a,b-a);
}

Exemplu
23. Problema turnurilor din Hanoi ilustreaz foarte bine avantajele recursivitii. Pro-
blema poate fi enunat astfel: fie trei tije a, b, c; pe tija a snt plasate n discuri de di-
ametre diferite, n ordinea descresctoare a acestora (de jos n sus). Se cere ca cele n discuri
de pe tija a s fie deplasate pe tija c astfel nct s fie ndeplinite condiiile:
- la fiecare mutare este deplasat unul dintre discurile aflate pe poziia superioar pe una din
tije;
- oricare din discuri poate fi aezat numai pe un disc de diametru mai mare;
- tija b poate fi folosit pentru deplasri intermediare.

Notnd cu P(n,a,c) problema transferului celor n discuri de pe tija a pe tija c, pentru
rezolvarea ei putem raiona n modul urmtor. Dac s-a rezolvat problema P(n-1,a,b), atunci
discul de diametru maxim care se afl nc pe tija a este deplasat pe tija c i n continuare se
rezolv problema P(n-1,b,c). Soluia recursiv este prezentat n funcia Hanoi.

Exemplu presupunnd c discurile snt numerotate n ordinea cresctoare a diametrelor cu
etichetele 1, 2, 3, o soluie a problemei pentru n=3 poate fi descris astfel.

Tija a Tija b Tija c Mutarea efectuat
1
2
3
a c
2
3
1 a b
3 2 1 c b
3 1
2
a c
1
2
3 ba
1 2 3 bc
1 2
3
a c
1
2
3

#include <stdio.h>
#include <conio.h>

void Hanoi(unsigned n,unsigned a, unsigned b,unsigned c)
{
if(n>0)
* material didactic pentru ID * 33
{ Hanoi(n-1,a,c,b);
printf("Transfer disc de pe tija %u pe tija %u\n",a,b);
Hanoi(n-1,c,b,a); }
}

void main()
{ unsigned n,a,b,c;
clrscr();
printf("n=");scanf("%u",&n);
Hanoi(n,1,2,3);getch();
}

Exemplu
24. Sortarea cresctoare prin inserare
Pentru sortarea cresctoare a unei secvene de numere reale se poate raiona astfel: dac P(n)
este problema sortrii cresctoare a secvenei a
1
, a
2
, , a
n
i P(n-1) este problema sortrii
primelor n-1 componente, atunci soluia problemei P(n) rezult din soluia problemei P(n-1)
prin inserarea lui a
n
n soluia problemei P(n-1). Fiecare problem intermediar P(k),
n ,..., 2 k = este rezolvat aplicnd aceeai metod P(1) este o problem gata rezolvat (con-
diie terminal).
Funcia insera realizeaz inserarea valorii x n vectorul v n poziia corect. Funcia
recursiv inssort realizeaz sortarea vectorului cu n componente prin inserie.

void insera(float *v,int *n,float x)
{ for(int i=0;(i<*n)&&(x>v[i]);i++);
for(int j=*n;j>=i+1;j--)v[j]=v[j-1];
v[i]=x;(*n)++;
}

void inssort(float *v,int n)
{ if(n)
{ inssort(v,n-1);int m=n-1;
insera(v,&m,v[n-1]);
}
}

Exemplu
25. Pot fi realizate desene prin compunerea ntr-o manier recursiv a unor figuri ge-
ometrice primitiv (de baz). Compunerea const n repetarea primitivelor considerate i a re-
zultatelor obinute prin rotirea lor ntr-un sens sau cellalt. Astfel, dac mulimea de primitive
H
0
const dintr-un punct i pentru compunere este considerat un segment de lungime h,
atunci: H
1
rezult din patru exemple (copii, realizri, instane, clone) de primitive din H
0
unite
prin segmente de lungime h; H
2
rezult din 16 exemple din H
0
unite prin 15 segmente de lun-
gime h/2 .a.m.d. De asemenea, H
2
se poate obine prin interconectarea a patru copii ale lui H
1

rotite cu unghiuri drepte i prin interconectarea punctelor izolate prin segmente de aceeai
lungime. Generaliznd, o curb H
n
rezult din patru copii ale unei curbe H
n-1
, punctele izolate
fiind unite prin segmente de lungime h
n
=h/2
n
. Curbele rezultate se numesc curbele Hilbert
H
i
, i 0.


H1 H2 H3

Algoritmi n programare 34
Dac cele patru pri ale unei curbe Hilbert H
k
snt notate A, B, C, D i se reprezint
prin sgei rutinele care deseneaz segmentele care le interconecteaz, atunci rezult urmtoa-
rele scheme recursive.
B A A D : A

B A A D : A
A B B C : B

D C C B : C

C D D A : D

Prin executarea urmtoarei surse C snt obinute curbele Hilbert H
4
(exemplul a fost
scris n mediul Borland C 3.11).
#include <stdio.h>
#include <graphics.h>
#include <stdlib.h>
#include <conio.h>

const n=5;
const h0=480;
int i=0;
int h;
int x,y,x0,y0,gm;
int gd=DETECT;

void A(int);
void B(int);
void D(int);
void C(int);

void main()
{ clrscr();
initgraph(&gd,&gm,"D:\BC\BGI");
setbkcolor(0);
setcolor(4);
h=h0;y0=x0=h/2;
do{ i++;h/=2;
x0+=h/2;y0+=h/2;
x=x0;y=y0;moveto(x,y);
A(i); }
while(i<n);
getch();
closegraph();
}

void A(int i)
{ if (i>0)
{ D(i-1);x-=h;lineto(x,y);
A(i-1);y-=h;lineto(x,y);
A(i-1);x+=h;lineto(x,y);
B(i-1);
}
}

void B(int i)
{ if (i>0)
{ C(i-1);y+=h;lineto(x,y);
B(i-1);x+=h;lineto(x,y);
B(i-1);y-=h;lineto(x,y);
A(i-1);
}
}

void C(int i)
{ if (i>0)
{ B(i-1);x+=h;lineto(x,y);
C(i-1);y+=h;lineto(x,y);
C(i-1);x-=h;lineto(x,y);
D(i-1);
}
}

void D(int i)
{ if (i>0)
{ A(i-1);y-=h;lineto(x,y);
D(i-1);x-=h;lineto(x,y);
D(i-1);y+=h;lineto(x,y);
C(i-1);
}
}

Curba Hilbert obinut este


Exemplu
26. n cazul curbelor Hilbert, toate unghiurile determinate de segmentele care unesc
punctele snt de msur 90
0
. Dac se consider ca valori pentru msurile unghiurilor determi-
nate de aceste segmente 45
0
, 90
0
, 135
0
, rezult curbele Sierpinski S
n
, n1.
Curba lui Sierpinski pentru n=2 este urmtoarea:
* material didactic pentru ID * 35


Recursia pentru obinerea curbelor Sierpinski
poate fi descris astfel.
S: A B C D
A: A B D A
B: B C

A B
C: C D B C
D: D A

C D

unde sgeile duble indic segmente de lun-
gime 2h.
Urmtorul program deseneaz curbele Sierpinski S
4
(exemplul a fost scris n mediul
Borland C 3.11)

#include <stdio.h>
#include <graphics.h>
#include <stdlib.h>
#include <conio.h>

const n=4;
const h0=412;
int i=0;
int h;
int x,y,x0,y0,gm;
int gd=DETECT;

void A(int);
void B(int);
void D(int);
void C(int);

void main()
{ clrscr();
initgraph(&gd,&gm,"d:\bc\bgi");
setbkcolor(15);
setcolor(8);
h=h0/4;
x0=2*h;
y0=3*h;
do{ i++;
x0-=h;h/=2;y0+=h;
x=x0;y=y0; moveto(x,y);
A(i);x+=h;y-=h;lineto(x,y);
B(i);x-=h;y-=h;lineto(x,y);
C(i);x-=h;y+=h;lineto(x,y);
D(i);x+=h;y+=h;lineto(x,y);}
while(i!=n);
getch();
closegraph();
}

void A(int i)
{ if (i>0)
{ A(i-1);x+=h;y-=h;
lineto(x,y);
B(i-1);x+=2*h;
lineto(x,y);
D(i-1);x+=h;y+=h;
lineto(x,y);
A(i-1);
}
}

void B(int i)
{ if (i>0)
{ B(i-1);x-=h;y-=h;
lineto(x,y);C(i-1);
y-=2*h;
lineto(x,y);
A(i-1);x+=h;y-=h;
lineto(x,y);
B(i-1);
}
}

void C(int i)
{ if (i>0)
{ C(i-1);x-=h;y+=h;
lineto(x,y);
D(i-1);x-=2*h;
lineto(x,y);
B(i-1);x-=h;y-=h;
lineto(x,y);
C(i-1);
}
}
void D(int i)
{ if (i>0)
{ D(i-1);x+=h;y+=h;
lineto(x,y);
A(i-1);y+=2*h;
lineto(x,y);
C(i-1);x-=h;y+=h;
lineto(x,y);
D(i-1);
}
}

Rezultatul execuiei programului este prezentat n urmtoarea figur.
Algoritmi n programare 36

Teste de autoevaluare
9. S se scrie un subprogram recursiv pentru calcularea sumei elementelor unui vec-
tor.
10. S se scrie un subprogram recursiv pentru determinarea elementului minim dintr-un vec-
tor.
11. S se scrie un subprogram recursiv pentru determinarea elementului minim i a elementu-
lui maxim dintr-un vector.
12. S se scrie un subprogram recursiv pentru determinarea elementelor irului lui Fibonacci.
13. Scriei un subprogram pentru rezolvarea problemei cutrii binare n vectori sortai. Fie v
un vector de numere reale sortat cresctor i k un numr real dat. S se identifice (dac exist)
o valoare poz, astfel nct v[poz]=k.


Rspunsuri i comentarii la testele de autoevaluare
1. Pe lng rezultatele (oricte) care pot fi ntoarse prin parametrii, subprogramele de
tip funcie permit i ntoarcerea unui rezultat de tip simplu prin numele lor, ceea ce
ofere posibilitatea realizrii apelului ca operand ntr-o expresie, care va folosi rezultatul apelu-
lui pentru evaluare.

2. n limbajul C se pot scrie numai subprograme de tip funcie.

3.
#include<stdio.h>
#include<conio.h>
#include<alloc.h>

float** inmultire(float **a,float **b,int n)
{ int i,j,k; float **c;
c=(float **)malloc(n*sizeof(float *));
for(i=0;i<n;i++)
*(c+i)=(float *)malloc(n*sizeof(float));
for(i=0;i<n;i++)
for(j=0;j<n;j++)
for(k=0,c[i][j]=0;k<n;c[i][j]+=a[i][k]*b[k++][j]);
return c;
}

float** putere(float **a,int p,int n)
{ float **c,**ap;int l,m,i;
ap=(float **)malloc(n*sizeof(float *));
for(i=0;i<n;i++)
* material didactic pentru ID * 37
*(ap+i)=(float *)malloc(n*sizeof(float));
for(l=0;l<n;l++)
for(m=0;m<n;ap[l][m]=a[l][m],m++);
for(i=0;i<p-1;i++)
{ c=inmultire(a,ap,n);
for(l=0;l<n;l++)
for(m=0;m<n;ap[l][m]=c[l][m],m++);
}
return ap;
}

void main()
{ int i,j,p,n,l,m; float **a,**ap,f;
clrscr();
printf("\n n=");
scanf("%i",&n);
a=(float **)malloc(n*sizeof(float *));
for(i=0;i<n;i++)
*(a+i)=(float *)malloc(n*sizeof(float));
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{ scanf("%f ",&f);
*(*(a+i)+j)=f;
}
scanf("%i",&p);
ap=putere(a,p,n);
for(i=0;i<n;i++)
{ for(j=0;j<n;j++)
printf("%f ",*((*(ap+i)+j)));
printf("\n");
}
getch();
}
13.
#include <stdio.h>
#include <conio.h>
int cauta_binar(float *,int,int,float);

void main()
{ clrscr();
printf("Dimensiunea vectorului:");
int n;
scanf("%i",&n);
printf("Elementele vectorului\n");
float v[100];
for(unsigned i=0;i<n;i++)
scanf("%f",&v[i]);
printf("Cheia de cautare:");
float k;
scanf("%f",&k);
int c=cauta_binar(v,0,n-1,k);
if(c==-1)
printf("Cheia nu a fost gasita");
else printf("Cheia pe pozitia:%i",c);
getch();
}

int cauta_binar(float *v,int li,int ls,float k)
{ if(li>ls)
return -1;
int mij=(li+ls)/2;
if(v[mij]==k)
return mij;
if(v[mij]>k)
return cauta_binar(v,li,mij-1,k);
return cauta_binar(v,mij+1,ls,k);
}
Algoritmi n programare 38

Rezumat
n cadrul acestei uniti de nvare au fost studiate urmtoarele aspecte ale program-
rii calculatoarelor cu privire la lucrul cu subprograme:
cunotine teoretice despre subprograme, n general i n limbajul C;
construcia i apelul subprogramelor n limbajul C;
transferul datelor ntre apelator i apelat, prin variabile globale i prin parametri (prin
valoare i prin simularea transferului prin adres);
pointeri la funcii i trimiterea funciilor ca parametri ctre alte funcii;
funcii cu numr variabil de parametri;
subbrograme recursive.
Dup ncheierea studierii acestei uniti de nvare, studenii au cunotinele i abilit-
ile necesare lucrului cu subprograme n vederea rezolvrii problemelor complexe de progra-
mare prin rezolvarea separat a subproblemelor componente.



Bibliografia unitii de nvare

1. I. Gh. Roca, B. Ghilic-Micu, C. Cocianu, M. Stoica, C. Uscatu, M. Mircea - Programarea
calculatoarelor. Algoritmi n programare, Ed. ASE Bucureti, 2007
2. I. Gh. Roca, B. Ghilic-Micu, C. Cocianu, M. Stoica, C. Uscatu - Programarea calculatoa-
relor. tiina nvrii unui limbaj de programare. Teorie i aplicaii, Ed. ASE Bucureti,
2003
3. Liviu Negrescu - Limbajele C i C++ pentru nceptori, vol. I, II, Ed. Microinformatica,
Cluj-Napoca, 1994
4. I.Gh. Roca & colectiv - Bazele elaborrii programelor. Exerciii rezolvate i propuse, Ed.
ASE Bucureti, 1998
5. A. Iorgulescu - Metode numerice i programe Pascal, Ed. Inforec, Bucureti, 1996 (para-
grafele 2.2.1, 2.2.2, 2.2.3, 4.2.1, 4.2.2)
* material didactic pentru ID * 39



3. Articolul i fiierul



Cuprins

Obiectivele unitii de nvare ......................................................................................... 39
3.1. Articol: caracteristici generale i mod de declarare............................................ 39
3.2. Referirea articolului i a elementelor componente.............................................. 41
3.3. Articole cu structuri complexe .............................................................................. 44
3.4. Constante de tip articol .......................................................................................... 45
3.5. Fiierul i articolul .................................................................................................. 46
3.6. Metode de organizare a fiierelor i tipuri de acces ............................................ 47
3.7. Structura sistemului de fiiere sub MS-DOS/Windows ...................................... 49
3.8. Operaii de prelucrare a fiierelor ........................................................................ 51
3.8.1. Nivelul inferior de prelucrare a fiierelor .................................................... 52
3.8.2. Nivelul superior de prelucrare a fiierelor................................................... 55
Rspunsuri i comentarii la testele de autoevaluare ....................................................... 62
Rezumat............................................................................................................................... 62
Bibliografia unitii de nvare........................................................................................ 62


Obiectivele unitii de nvare

Dup studierea acestei uniti de nvare, studenii vor avea cunotine teoretice i
abiliti practice necesare pentru lucrul cu structuri de date interne eterogene i cu
structuri de date externe (fiiere de date). Concret, se vor asimila cunotine i abili-
ti de lucru privind:
tipul de dat articol;
tipurile de fiiere de date;
metode de organizare a fiierelor i tipuri de acces la datele coninute;
utilizarea articolelor interne pentru prelucrarea fiierelor de date;
operaii generale de prelucrare a fiierelor de date.


3.1. Articol: caracteristici generale i mod de declarare

Articolul este o structur de date eterogen, cu acces direct la elementele sale, ntre ca-
re exist o relaie de ordine ierarhic.
Articolul poate fi reprezentat sub form de arbore, ale crui noduri snt asociate com-
ponentelor structurii. Componentele de pe ultimul nivel snt scalare i se numesc date elemen-
tare sau cmpuri. Datele de pe celelalte niveluri, denumite date de grup, se constituie prin
agregarea datelor de pe nivelurile inferioare. Data de grup de cel mai nalt nivel (rdcina ar-
borelui) corespunde articolului n ansamblu. Conceptual, datele de grup de pe diverse niveluri
au aceleai proprieti ca i articolul, ceea ce permite ca aceast structur s fie construit re-
cursiv, prin descompunerea n structuri cu aceleai proprieti (figura 4.1).
Declararea mpreun a tipului articol i a variabilelor de acest tip se realizeaz con-
Algoritmi n programare 40
form sintaxei:

struct tip_articol{lista_cimpuri} var1, var2, , varn;

unde tip_articol este identificatorul asociat tipului articol, iar var1, var2,, varn snt identifi-
catorii asociai variabilelor de tipul articol declarat.
Unele elemente ale declaraiei pot lipsi (dar nu toate deodat). Dac lipsesc elementele
var1, var2,, varn, atunci tip_articol trebuie s fie prezent, fiind numai o declarare explicit
de tip nou, utilizabil ulterior la alte declarri. Dac lipsete tip_articol, atunci trebuie s fie
prezent lista de variabile (nevid), caz n care este vorba de o declarare de variabile de tip ar-
ticol, fr ns a declara i un tip utilizator nou. n continuare, tip_articol este un tip nou de
date, iar var1, var2,, varn snt variabile de tipul tip_articol. Variabilele pot fi declarate i ca
masive, ale cror elemente snt de tip articol: var1[dim1][dim2][dimn].


DATA
ZI LUNA AN
dat de grup (articol)
date elementare
NUME ADRESA DATA NATERII
PERSOANA
dat de grup (articol)
dat de grup (articol)
ZI LUNA AN
date elementare
b)
a)

Fig. 3.1. Exemple de structuri de articole

O variabil de tip articol poate fi declarat i ulterior definirii tipului:

struct tip_articol var1;

Descrierea constituie o definire implicit de un nou tip de dat. Este posibil definirea
explicit a unui nou tip de dat, adugnd cuvntul rezervat typedef n faa declarrii (n acest
caz nu mai pot fi declarate simultan i variabile).
Lista_cimpuri este o niruire de declaraii de cmpuri separate prin punct i virgul,
asemntoare declaraiilor de variabile, de forma tip_cimp nume_cimp. Cmpurile unei struc-
turi pot fi variabile simple, masive sau alte articole. Lista cmpurilor nu poate fi vid.

Exemplu
1. Definirea tipului de dat numr complex, a unei variabile simple i a unui masiv
unidimensional cu elemente de acest tip se poate face n oricare din urmtoarele variante
(pentru un numr complex se vor reine partea real i partea imaginar):
a) struct COMPLEX{float r,i;}a,b[100];
b) struct COMPLEX{float r,i;};
struct COMPLEX a,b[100];
c) struct COMPLEX{float r,i;};
COMPLEX a,b[100];
d) struct {float r,i;}COMPLEX;
COMPLEX a,b[100];
e) typedef struct {float r,i;} COMPLEX;
COMPLEX a,b[100];
f) typedef struct COMPLEX{float r,i;};
struct COMPLEX a,b[100];
* material didactic pentru ID * 41
g) typedef struct COMPLEX{float r,i;};
COMPLEX a,b[100];

Din punct de vedere practic, utilizarea tipului articol este strns legat de prelucrarea
fiierelor. n lucrul cu variabilele de tip articol se recomand declararea identificatorului de
tip. n acest mod, identificatorul de tip articol poate fi folosit n definirea mai multor variabile.
n procesul de descriere a unui articol, arborele se parcurge n preordine (de la rdcin spre
extremiti i de la stnga la dreapta).

Exemplu
2. Pentru exemplele din figura 3.1, declararea poate fi realizat prin definire recursiv,
astfel:
struct tip_data
{ unsigned zi;
char luna[3];
int an; };

struct persoana
{ char nume[30];
char adresa[50];
struct tip_data data_nasterii;
} angajat;

Dac nu ar fi existat declaraia tipului articol tip_data, atunci tipul persoana putea fi scris ast-
fel:
struct persoana
{ char nume[30];
char adresa[50];
struct
{ unsigned zi;
char luna[3];
int an;
} data_nasterii;
} angajat;

Variabilele de tip articol se reprezint intern ca succesiuni de cmpuri elementare, cu
reprezentarea intern i lungimea fizic specifice tipurilor lor. Lungimea zonei de memorie
rezervat pentru variabila de tip articol rezult din nsumarea lungimilor cmpurilor. Aceasta
nu poate depi 65520 octei (ca orice variabil de tip structurat). Pentru structura unui articol
i dovedete utilitatea operatorul sizeof, care asigur determinarea lungimii zonei de me-
morie asociate unei variabile sau unui tip de date.

Exemplu
3. Considernd declaraiile anterioare, expresia sizeof(data_nasterii) are valoarea 8,
iar sizeof(angajat) are valoarea 90.

Din punct de vedere fizic, identificatorii cmpurilor din descrierea articolului reprezin-
t deplasri fa de nceputul acestuia. Adresa fizic a unui cmp rezult din nsumarea adresei
articolului cu deplasarea sa. Structura arborescent a articolelor poate fi exprimat sugestiv i
prin machete, care evideniaz componentele, natura, lungimea declarat i lungimea fizic
ale acestora (figurile 3.2 i 3.3).


3.2. Referirea articolului i a elementelor componente

Datele de tip articol pot fi referite n dou moduri: global sau pe componente. Referi-
rea global este permis numai n operaia de atribuire, cu condiia ca ambele variabile (surs
i destinaie) s fie articole de acelai tip.
Referirea pe componente (prin numele lor) este o reflectare a faptului c articolul este
Algoritmi n programare 42
o structur cu acces direct. Referirea unor componente de tip articol din structura altui articol
este posibil numai n operaia de atribuire, n condiiile precizate anterior la referirea global.
n cele ce urmeaz se are n vedere numai referirea componentelor de tip dat elementar, si-
tuate pe ultimul nivel al structurii.
Referirea cmpurilor unei structuri se face prin calificare, folosind operatorul . (punct).
n referirea prin calificare, asigurarea identificrii unice a cmpurilor se realizeaz prin asocie-
rea numelui acestora cu numele articolului care le conine. Construcia rmne la aceast for-
m n cazul n care structura are numai dou niveluri: articolul i cmpurile elementare ale
acestuia.

Exemplu
4. Folosind tipul COMPLEX definit anterior, avem:
a.r , a.i - se refer partea real, respectiv imaginar a variabilei a
b[10].r - se refer partea real a celui de-al 11-lea element al vectorului b

#include <string.h>
main()
{ struct articol {char nume[40];
char adresa[30];
int an, luna, zi;}
struct articol pers;

strcpy(pers.nume, "Popescu Ion");
strcpy(pers.adresa, "Bucuresti, Pta. Romana 6");
pers.an=1979; pers.luna=3; pers.zi=15;
}
n articolele cu structur recursiv se realizeaz calificarea progresiv cu articolele de
pe nivelurile superioare, primul calificator fiind numele articolului rdcin. n lanul de cali-
ficri, numele articolului rdcin este nume de variabil, celelalte fiind nume de cmpuri ale
articolului. Dac anumite componente snt structuri de date de alte tipuri (de exemplu masive
sau iruri de caractere), n referirea elementelor lor se aplic, pe lng calificare, regulile spe-
cifice acestor structuri.

Exemplu
5. Referirea prin calificare a cmpurilor articolului angajat de tipul persoana (vezi
exemplele anterioare) se realizeaz astfel:
angajat.nume;
angajat.adresa;
angajat.data_nasterii.zi;
angajat.data_nasterii.luna;
angajat.data_nasterii.an

n aceste referiri, angajat este identificatorul variabilei articol, celelalte elemente snt identifi-
catori de cmpuri. Construciile angajat.nume i angajat.adresa corespund referirii globale a
cmpurilor respective, care snt iruri de caractere. Pentru a referi, de exemplu, primul caracter
din ir, se scrie: angajat.nume[0].

Exemplu
6. Se presupune un articol cu structura din figura 3.2.
Vnzri lunare Cod
Magazin Luna 1 Luna 2 Luna 12
ntreg real Real real
2 4 4 4
Fig. 3.2. Structura de articol pentru exemplul 6
Articolul se declar astfel:
* material didactic pentru ID * 43
struct magazin { int cod_magazin;
float vanzari_lunare[12];
} articol;
Articolul are 50 de octei, iar referirea cmpurilor se realizeaz astfel:
articol.cod_magazin
articol.vanzari_lunare[i], cu i=0,1,,11.

Exemplu
7. Se presupune un articol cu structura din figura 3.3.

Materia prim 1 ... Materia prim 30 Cod
produs
Numr
materii
prime
Cod Norma de
consum
... Cod Norma de
consum
ntreg ntreg ntreg real ... ntreg real
2 1 2 4 ... 2 4
Fig. 3.3. Structura de articol pentru exemplul 7

Cu toate c numrul de materii prime utilizate poate fi variabil de la un produs la altul, n des-
crierea articolului se alege valoarea maxim a acestuia:

struct a { int cod_mat; float norma; };
struct produs { int cod_produs;
unsigned char nr_mat;
struct a materii_prime[30];
} articol ;

Referirea cmpurilor se realizeaz astfel:
articol.cod_produs;
articol.nr_mat;
articol.materii_prime[i].cod_mat;
articol.materii_prime[i].norma;

Constantele de tip articol snt cu tip i pstreaz caracteristicile acestora. n momentul
compilrii se rezerv zone de memorie pentru acestea, iar cmpurile articolelor snt iniializate
cu valorile precizate de utilizator. Declararea constantelor presupune definirea anterioar a ti-
pului articol.
Valoarea iniial trebuie s fie de acelai tip cu cmpul cruia i corespunde. Cnd arti-
colul conine la rndul su alt articol, identificarea cmpului care se iniializeaz se face pe ni-
veluri, folosind perechi corespunztoare de acolade.

Exemple
8.
#include <stdio.h>
void main()
{
//exemplul 1
struct persoana
{ char nume[40];
char adresa[30];
struct
{ int zi, luna, an;} datan;
};
//exemplul 2
struct magazin
{ int cod_magazin;
float vanzari_lunare[12];
};
//exemplul 3
struct a { int cod_mat; float norma;};
Algoritmi n programare 44
struct produs
{ int cod_produs;
unsigned char nr_mat;
struct a materii_prime[30];
};

//Initializarea articolului din exemplul 1:
struct persoana p={"Popescu Ion", "Bucuresti, Magheru 14", 2, 4, 1960};

//sau cu evidentierea structurii data nasterii:
struct persoana p1={"Popescu Ion", "Bucuresti, Magheru 14", {2, 4, 1960}};
printf("\n%i",p1.datan.an);

//Initializarea articolului din exemplul 2:
struct magazin gigel_srl={200, 1,2,3,4,5,6,7,8,9,10,11,12};

//sau cu evidentierea structurii de masiv:
struct magazin gigel_srl1={200, {1,2,3,4,5,6,7,8,9,10,11,12}};
printf("\n%6.2f",gigel_srl1.vanzari_lunare[10]);

//Initializarea articolului din exemplul 3 (doar primele 4 materii
//prime, restul de 26 vor fi initializate automat cu valori nule:
struct produs z={243,5,{{2420,25.4},{3251,70.21},{1421,8.4},{51,7.2}}};
printf("\n%6.2f",z.materii_prime[2].norma); }

Teste de autoevaluare
1. Clasificai tipul de date articol, conform clasificrii tipurilor de date.



3.3. Articole cu structuri complexe

n activitatea de programare pot fi ntlnite aplicaii care reclam utilizarea articolelor
cu structur variabil. La iniializarea cmpurilor unui astfel de articol, constanta de tip articol
se asociaz unei singure structuri, deoarece zona de memorie rezervat pentru articol este uni-
c. Pentru acest tip de articol, limbajul pune la dispoziia utilizatorilor tipul predefinit reuniu-
ne (union), care se comport ca i tipul struct cu o singur diferen: la un moment dat al exe-
cuiei programului, n zona de memorie rezervat articolului nu este memorat dect unul dintre
cmpurile acestuia.
Declararea tipului reuniune se realizeaz astfel:

union nume_tip { tip_cimp1 cimp1;
tip_cimp2 cimp2;
................
tip_cimpn cimpn;};

Lungimea zonei de memorie rezervate pentru o variabil de tip reuniune va fi egal cu
maximul dintre lungimile cmpurilor componente. Gestiunea coninutului respectivei zone de
memorie va trebui realizat de ctre programator.

Exemplu
9. Se presupune un articol cu structura din figura 3.4.
Forma de nvmnt
zi id
Nume Data naterii An de
studiu
bursa valoare loc de munc data angajrii
char[40] zi luna an int char float char[30] zi lun an
Fig. 3.4. Articol cu structur variabil
Declararea i iniializarea cmpurilor unui student la zi pentru structura articolului din
* material didactic pentru ID * 45
figura 3.4 se realizeaz astfel:

#include <stdio.h>

void main()
{ //Declararea articolului cu structura variabila:
struct articol
{ char nume[40];
struct { int zi, luna, an;} datan;
int an_st;
char forma_inv;
union
{ struct {char bursa; float valoare;} zi;
struct {char loc_m[30];
struct {int zi, luna, an;} data_ang;
} id;
} parte_vb;
};

//Initializarea cimpurilor unui student la zi:
struct articol a={"Popescu Felix",{4,1,1974} ,1,'Z',{'D',250.5}};
printf("\nData nasterii: %i.%i.%i, Forma de inv.: %c, Val. bursa: %6.2f",
a.datan.zi, a.datan.luna, a.datan.an, a.forma_inv, a.parte_vb.zi.valoare);
}

Din punct de vedere fizic, existena prii variabile ntr-un articol genereaz, la compi-
lare, deplasri egale fa de nceputul articolului pentru toate variantele de descriere. Astfel,
pentru descrierea din exemplul de mai sus se genereaz deplasarea 49 fa de nceputul artico-
lului, att pentru cmpul bursa, ct i pentru loc_m.

Teste de autoevaluare
2. Descriei n limbajul C tipul de dat vehicul corespunztor urmtoarei reprezentri
tabelare. Alegei tipurile i dimensiunile potrivite pentru fiecare cmp.

propulsie
uman animal mecanic
mas
vitez
maxim
lungime lime
nr. lo-
curi
nr. roi
tip
animal
nr.
animale
tip com-
bustibil
cilindree putere
consum
(l/100km)


3.4. Constante de tip articol

Constantele de tip articol pot fi constante cu tip (variabile iniializate la compilare) i
constante obiect, pentru care n momentul compilrii se rezerv zone de memorie, iar cm-
purile articolelor snt iniializate cu valorile precizate de utilizator.
Valoarea iniial trebuie s fie de acelai tip cu cmpul cruia i corespunde. Cnd arti-
colul conine la rndul su alt articol, identificarea cmpului care se iniializeaz se face pe ni-
veluri, folosind perechi corespunztoare de acolade.
Constantele cu tip joac rol de variabile care se iniializeaz cu o valoare n faza de
compilare, ele putnd s-i modifice valoarea pe parcursul execuiei programului.

tip nume_const = {lista_valori};

Constantele obiect snt variabile iniializate la declarare, pentru care se rezerv me-
morie, dar coninutul lor nu poate fi modificat pe parcursul programului.
const tip nume_const = {lista_valori};

Algoritmi n programare 46
Exemplu
10. Constant cu tip.

#include<stdio.h>
void main()
{ struct persoana
{ char nume[40];
char adresa[30];
struct
{ int zi, luna, an;} datan;
};
persoana pers={"Popescu Ion", "Bucuresti; Magheru 14",
{2, 4, 1960}};
//constanta cu tip
pers.datan.zi=4;
}

Exemplu
11. Constant obiect.

#include<stdio.h>
void main()
{ struct persoana
{ char nume[40];
char adresa[30];
struct {int zi, luna, an;} datan;
};
const persoana pers={"Popescu Ion", "Bucuresti; Magheru 14",
{2, 4, 1960}};
//constanta obiect
// pers.datan.zi=4; genereaza eroare la compilare
}

Teste de autoevaluare
3. Iniializai constante cu tip i constante obiect de tipul vehicul, pe care l-ai definit
la tema de autoevaluare nr. 2.


3.5. Fiierul i articolul

Prelucrarea automat a datelor presupune un sistem de organizare a acestora dup me-
tode i procedee specifice. Organizarea datelor este un proces complex care include identifica-
rea, clasificarea i descrierea proprietilor acestora, gruparea lor n colecii, reprezentarea pe
purttori tehnici, definirea i realizarea procedurilor de prelucrare etc.
Deoarece datele se memoreaz, de obicei, pe purttori tehnici de informaii, dar se pre-
lucreaz numai cnd snt prezente n memoria intern, acestea trebuie organizate att extern ct
i intern. n organizarea extern a datelor se identific dou niveluri de abordare, dup cum se
are n vedere acest proces din perspectiva utilizatorului sau a purttorilor fizici externi pe care
se nregistreaz datele. Cele dou niveluri de abordare, numite logic, respectiv fizic, precum i
realizarea trecerii de la unul la cellalt, n condiiile specifice diverselor sisteme de calcul, se
bazeaz pe o serie de concepte, cum ar fi: fiierul i articolul, purttorul tehnic de date, meto-
da de organizare i modul de acces, operaiile de prelucrare etc.

Fiierul reprezint termenul generic care desemneaz structurile de date externe. El es-
te o mulime (colecie) de date omogene din punct de vedere al semnificaiei i al cerinelor de
prelucrare. n purttorul extern, fiierul are, pe lng partea de date, i alte informaii de identi-
ficare (etichete).
* material didactic pentru ID * 47
Privit din punctul de vedere al prelucrrii, un fiier este o colecie ordonat de date,
numite articole. Articolul este constituit dintr-o mulime ordonat de valori ale unor caracte-
ristici ce aparin, uzual, unei singure entiti (obiect, fenomen, proces etc.) din domeniul de
activitate abordat. De exemplu, ntr-un fiier care conine datele personale ale salariailor
dintr-o unitate economic, un articol grupeaz valorile caracteristicilor unei singure persoane.

Componentele articolului destinate diverselor caracteristici snt denumite cmpuri de
date. Depinznd de natura, ordinul de mrime i forma de reprezentare extern a valorilor aso-
ciate, fiecare cmp de date are o lungime, exprimat uzual n octei. Lungimea unui articol es-
te dat de suma lungimilor cmpurilor care l compun. Dup cum toate articolele dintr-un fii-
er au sau nu aceeai lungime, se face distincie ntre fiierele cu articole de lungime fix sau
variabil. Modul de implementare fizic a celor dou tipuri de fiiere difer de la un sistem la
altul i chiar de la un limbaj la altul.

Pe purttorul fizic extern, partea de date a fiierului se prezint ca o succesiune de oc-
tei cu un coninut binar fr semnificaie informaional. n momentul prelucrrii, prin des-
crieri i operaii adecvate, din succesiunea memorat extern se decupeaz" entiti (articole,
blocuri, linii sau cmpuri) cu structuri corespunztoare prelucrrii. Tipul entitii care se de-
cupeaz" depinde de tipul fiierului.


3.6. Metode de organizare a fiierelor i tipuri de acces

Principiile i regulile dup care se memoreaz articolele unui fiier pe purttorul ex-
tern, cu asigurarea proteciei i regsirii acestora, constituie metoda de organizare. n evoluia
organizrii datelor externe s-au cristalizat mai multe metode, dintre care, cele mai uzuale snt
secvenial, relativ i indexat. Principala difereniere ntre metodele de organizare o repre-
zint tipurile de acces admise.
Tipul de acces reprezint modalitatea de regsire (localizare) a articolelor din fiier.
Noiunea de acces trebuie aplicat att pentru operaia de scriere, ct i pentru cea de citire a
datelor.
Poziia din/n care se face citirea/scrierea n cadrul fiierului este indicat de un
pointer. Accesul la datele nregistrate pe un purttor tehnic poate fi secvenial sau direct, n
funcie de modul n care se stabilete pointerul.

Accesul secvenial este posibil la toi purttorii tehnici de date i presupune nscrierea
nregistrrilor n ordinea furnizrii lor sau regsirea n ordinea n care au fost nscrise n suport
(figura 3.5).

Traversare
A
1
A
2
... A
k-1
A
k
... A
n
EOF
P(A
k
)=f (P(A
k-1
))

Fig. 3.5. Principiul de realizare a accesului secvenial la articole

Pointerul de fiier avanseaz, n scriere i citire, de la o entitate (articol, bloc, linie sau
cmp) la alta. Dac pointerul se exprim prin deplasare fa de nceputul fiierului, atunci, ma-
tematic, acest lucru se poate exprima astfel:
P(A
1
) = 0;
P(A
k
) = f(P(A
k-1
)) = P(A
k-1
)+lart
k-1
; pentru k=2,n;
Algoritmi n programare 48
unde A
k
este articolul k i lart
k
este lungimea articolului k.

O problem important care se pune la consultarea (citirea) n acces secvenial este
controlul ajungerii la sfritul fiierului. Dup citirea ultimei entiti (articol, bloc, linie sau
cmp), pointerul indic marcatorul de sfrit de fiier - EOF (figura 3.6).

Poziia pointerului dup
citirea ultimului articol
A
1
A
2
... A
k-1
A
k
... A
n
EOF

Fig. 3.6. Pointerul dup citirea ultimului articol din fiier

n limbajele de programare se regsesc dou modaliti de sesizare a sfritului de fii-
er:
a) Sesizarea sfritului de fiier n cadrul operaiei de citire (limbajele FORTRAN, CO-
BOL, C). Sfritul este sesizat la citirea marcatorului de sfrit de fiier. Situaia din figura 5.2
nu este considerat sfrit de fiier. Abia la urmtoarea citire se ntmpl acest lucru (pointerul
de fiier avanseaz dup marcatorul de sfrit de fiier).
b) Sesizarea sfritului de fiier independent de operaia de citire (limbajele BASIC,
PASCAL). n acest caz, dac pointerul este pe marcatorul de sfrit de fiier (dup ultimul ar-
ticol, bloc, linie, cmp, ca n figura 5.2) se consider sfrit de fiier. Urmtoarea citire produ-
ce eroare de intrare/ieire (I/E).
Proiectarea algoritmilor de prelucrare a fiierelor este determinat de modalitatea n
care se sesizeaz sfritul de fiier.

Accesul direct este posibil numai la fiierele care au o anumit organizare, au ca enti-
tate de transfer articolul sau blocul i snt memorate pe discuri magnetice. Accesul direct se
bazeaz pe existena unui algoritm implementat n sistem care asigur regsirea (localizarea)
articolelor n funcie de o informaie de regsire. Valoarea pointerului este determinat direct,
fr s depind de valoarea sa anterioar: P(A
k
)=f(ir
k
), unde A
k
este articolul k, iar ir
k
este o
informaie de regsire a articolului k. n funcie de algoritmul i informaia de regsire, exist
dou tipuri de acces direct: dup cheie i dup numrul relativ al articolului.
n cazul accesului direct dup cheie, articolul este regsit prin aplicarea unui algoritm
asupra unei informaii de identificare de tip cheie: P(A
k
)=f(cheie
k
). n cazul accesului direct
dup numrul relativ - care se mai numete, simplu, acces relativ - (figura 3.7), articolul este
localizat n fiier prin numrul su, stabilit, n cadrul fiierului, de la valoarea zero:
P
*
(A
k
)=(k-1); P(A
k
)=P
*
(A
k
)lart. P
*
(A
k
) reprezint poziia exprimat n numr relativ, iar
P(A
k
) reprezint poziia exprimat prin deplasare, n octei, fa de nceputul fiierului (la
unele sisteme numrul relativ este stabilit de la unu: P
*
(A
k
)=k).
La scriere, articolul A
k
(numrul relativ k-1) se memoreaz pe poziia sa, celelalte k-1
articole anterioare putnd s nu existe (pe suport exist ns rezervat loc pentru ele). La citire,
articolul A
k
(cu numrul relativ k-1, kn) este localizat direct i coninutul lui se transfer n
memoria intern.

Fiierele organizate secvenial, cu articole de lungime variabil, admit numai accesul
secvenial. Fiierele organizate secvenial, cu articole sau blocuri de lungime fix, admit att
accesul secvenial ct i pe cel relativ. Acest lucru deriv din faptul c accesul relativ este rea-
lizat de sistem printr-o deplasare secvenial fa de nceputul acestuia, deplasare care este
egal cu valoarea expresiei: numr_relativ lungime_articol.
* material didactic pentru ID * 49

Numr relativ
A
1
A
2
... A
k-1
A
k
... A
n
EOF
Acces direct prin numrul relativ k-1
P(A
k
)=k-1
0 1 k k-1 n-1 ... ...

Fig. 3.7. Principiul de realizare a accesului direct prin numr relativ

Teste de autoevaluare
3. Dai exemple de fiiere aflate pe diferite tipuri de suport extern i specificai ce ti-
puri de acces snt permise n fiecare caz.


3.7. Structura sistemului de fiiere sub MS-DOS/Windows

Sistemul de operare MS-DOS utilizeaz o form logic arborescent de grupare a fii-
erelor de pe discuri n directoare i subdirectoare. Un director (subdirector) poate conine fii-
ere i/sau alte subdirectoare (figura 5.4). n limbajul curent folosit de practicieni se utilizeaz
noiunea de director i n cazul subdirectoarelor.
Un disc DOS conine un singur director rdcin, care la rndul lui are zero sau mai
multe subdirectoare i/sau fiiere. Subdirectoarele pot avea oricte niveluri de imbricare.
Frunzele arborelui snt, cel mai adesea, fiiere, dar pot fi i subdirectoare vide. Unitatea de
disc, directorul i subdirectorul n care se lucreaz la un moment dat se numesc curente.

Pentru ca un fiier s fie localizat n cadrul structurii arborescente se folosete un iden-
tificator extern (specificator) care are urmtoarea form sintactic:

[n:][cale][\]nume_fiier[.extensie] unde

n este numele unitii de disc (A:, B:, C: etc). Prin lips, se consider unitatea curent.
cale (path) este calea de acces de la directorul rdcin pn la subdirectorul dorit. Fieca-
re nume de director (subdirector) din interiorul cii este precedat de caracterul backslash (\).
Prin lips, se consider calea subdirectorului curent. Calea selectat la un moment dat poate
ncepe de la rdcin sau de la subdirectorul curent. Cnd calea ncepe cu caracterul backslash
(\) cutarea ncepe de la rdcin; n caz contrar, cutarea ncepe de la directorul curent.
nume_fiier este numele extern al fiierului, format din maxim 8 caractere alfanumerice,
mai puin unele caractere speciale, ca: ." \ / : ' > < + = ; , ). Exist o serie de nume prestabilite,
asociate unor dispozitive standard de intrare/ieire, care nu pot fi utilizate de programator pen-
tru propriile fiiere: CON, AUX, COM1, COM2, LPT1, LPT2, LPT3, NULL, PRN, CLOCK$
(dispozitiv pentru ceasul de timp real).
extensie este format din maxim trei caractere alfanumerice prin care utilizatorul are po-
sibilitatea s-i identifice fiiere cu coninuturi diferite. Prin lips nu se asum nici o valoare.

Fiecare subdirector conine dou intrri speciale marcate prin caracterul ".", respectiv
caracterele ".." n locul numelui de fiier. Prima intrare realizeaz autopunctarea, indicnd
faptul c entitatea este subdirector (nu fiier de date), a doua intrare puncteaz subdirectorul
printe. n construirea cii de acces se poate folosi succesiunea de dou puncte pentru a indica
subdirectorul printe.
Algoritmi n programare 50

F
1

Rdcina (pe discul C:\)
D
1
D
2
D
3
F
2
F
3
F
5
F
4
F
2
D
4
D
5
F
8
F
9
F
6
F
7

Fig. 3.8. Exemplu de structur arborescent de directori

Exemple
12. Pentru structura din figura 3.8:
C:\F1 Fiierul F1 din rdcin
C:\D2\F2 Fiierul F2 din subarborele C:\D2
C:\F2 Fiierul F2 din directorul rdcin
C:\D2\D4\F9 Fiierul F9 din subarborele C:\D2\D4
Pentru a indica fiierul F9 se poate folosi una din scrierile:
C:\D2\D4\F9 de oriunde
\D2\D4\F9 de oriunde din unitatea C:
..\D4\F9 din subdirectorul D5
F9 din subdirectorul D4.

Productorii de software au impus unele denumiri de extensii, care, dei opionale,
ofer posibilitatea simplificrii referirii fiierelor n unele comenzi sau aplicaii.

Exemple
13. Standard MS-DOS:
.COM program executabil;
.EXE program executabil;
.SYS driver de sistem;
.OBJ program obiect;
.BAT fiiere de comenzi DOS (prelucrri BATCH).
14. Standarde de firm:
.ARC arhiv compactat cu PKPAK sau ARC;
.ZIP arhiv compactat cu PKZIP sau WINZIP;
.DBF baz de date DBASE.
15. Formate ASCII:
.ASM program surs ASSEMBLER;
.BAS program surs BASIC;
.PAS program surs PASCAL;
.CBL program surs COBOL;
.C program surs C;
.TXT fiier text;
16. Formate grafice:
.JPG
.GIF
.PNG



* material didactic pentru ID * 51
3.8. Operaii de prelucrare a fiierelor

Asupra unui fiier se pot executa diverse operaii de prelucrare, numite i de gestiune,
care se mpart n operaii la nivel de fiier i la nivel de articol.

Operaiile la nivel de fiier se refer la aspecte ca: nscrierea fiierului n
[sub]directoare, validarea i interzicerea accesului la fiier (deschidere/nchidere), tergerea
fiierului din [sub]directoare (tergere) etc. Aceste operaii se regsesc, n totalitate, la prelu-
crarea fiierelor pe discuri magnetice. n cazul purttorilor nereutilizabili, singurele operaii
care au sens snt cele de deschidere/nchidere a fiierelor.

Operaiile la nivel de articol se refer la accesul la entitile de date ale fiierului (arti-
cole, blocuri, linii sau cmpuri) n vederea prelucrrii lor. Privite sub aspectul semnificaiei
pentru utilizator, aceste operaii se refer la: nscrierea iniial a entitilor pe purttorul tehnic
(populare), actualizarea fiierului prin includerea de noi entiti (adugare), modificarea valo-
rilor unor cmpuri din anumite entiti (modificare), eliminarea entitilor care nu mai snt ne-
cesare (tergere), regsirea entitilor n vederea satisfacerii unor cerine de informare (con-
sultare). n programele C, operaiile de I/E snt realizate cu ajutorul unei mulimi de funcii
specializate pentru cutare, scriere, citire etc.

n concluzie, dac din punctul de vedere al utilizatorului operaiile de prelucrare se de-
scriu relativ simplu, prin apeluri de funcii, realizarea efectiv a lor de ctre sistemul de calcul
este complex. n sistemul de operare MS-DOS snt incluse funcii de ntrerupere care, prin
intermediul BIOS (Basic Input Output System), lanseaz anumite operaii cu un echipament.
Din punct de vedere al reprezentrii datelor n suportul extern, se disting fiiere text,
n care toate datele snt sub form ASCII (un caracter/octet) i fiiere binare, n care toate da-
tele snt memorate n forma identic cu cea din memoria principal (MP).
Strns legat de lucrul cu cele dou tipuri de fiiere este modul n care se face transferul
datelor ntre memoria principal i suportul extern: transfer posibil cu conversie (n cazul fii-
erelor text) i transfer fr conversie (n cazul fiierelor binare).

Trebuie fcut remarca, deosebit de important, c din punct de vedere fizic fiierul se
reprezint n suportul extern ca o succesiune de octei. Aceast succesiune poate fi tra-
tat logic ca un fiier de un tip sau altul. Este sarcina programatorului s asigure su-
prapunerea corect a fiierului logic peste cel fizic. Din acest punct de vedere se poate spune
c prin fiier logic se nelege, prioritar, un mod de prelucrare i mai puin un mod de memo-
rare.

Indiferent de limbajul de programare folosit, operaiile necesare pentru prelucrarea fi-
ierelor snt:
descrierea fiierului (crearea tabelei care memoreaz caracteristicile fiierului);
asignarea fiierului intern (numele logic) la unul extern (fizic);
deschiderea fiierului;
operaii de acces la date (articole);
nchiderea fiierului.
Pentru lucrul cu fiiere trebuie identificate tipurile acestora, metodele de organizare,
modurile de acces i tipurile de articole acceptate.
Din punct de vedere al tipurilor de date, n C exist un singur tip de fiiere: flux de oc-
tei (niruire de octei, fr nici un fel de organizare sau semnificaie). Organizarea acestui
flux de octei este secvenial.
Algoritmi n programare 52
Accesul la fiiere se poate face secvenial sau direct (cu excepia fiierelor standard, la
care accesul este numai secvenial). n bibliotecile limbajului exist funcii predefinite pentru
prelucrarea fiierelor. Funciile de prelucrare la nivel superior a fiierelor trateaz fluxul de
octei acordndu-i o semnificaie oarecare. Putem spune c din punct de vedere al prelucrrii,
la acest nivel, ne putem referi la fiiere text i fiiere binare.

Exist fiiere standard, care snt gestionate automat de sistem, dar asupra crora se
poate interveni i n mod explicit. Acestea snt:
fiierul standard de intrare (stdin);
fiierul standard de ieire (stdout);
fierul standard pentru scrierea mesajelor de eroare (stderr);
fiierul standard asociat portului serial (stdaux);
fiierul standard asociat imprimantei cuplate la portul paralel (stdprn).

Fiierele standard pot fi redirectate conform conveniilor sistemului de operare, cu ex-
cepia lui stderr care va fi asociat ntotdeauna monitorului.
n lucrul cu fiiere (sau la orice apel de sistem), n caz de eroare n timpul unei operaii
se seteaz variabila errno, definit n errno.h, stddef.h i stdlib.h. Valorile posibile snt defini-
te n stdlib.h.

n limbajul C exist dou niveluri de abordare a lucrului cu fiiere: nivelul inferior de
prelucrare (fr gestiunea automat a zonelor tampon de intrare/ieire) i nivelul superior de
prelucrare (se folosesc funcii specializate de gestiune a fiierelor). n continuare, prin specifi-
cator de fiier se va nelege un nume extern de fiier, conform conveniilor sistemului de ope-
rare. Specificatorul de fiier poate s conin strict numele fiierului sau poate conine i calea
complet pn la el.

3.8.1. Nivelul inferior de prelucrare a fiierelor
Nivelul inferior de prelucrare este folosit rar, numai n programele de sistem. La acest
nivel, descrierea fiierelor se realizeaz n corpul programelor, caracteristicile acestora
obinndu-se din context. Maniera de prelucrare este asemntoare celei de la nivelul sistemu-
lui de operare. Nu exist un tip anume de dat, fiierul fiind referit printr-un index care indic
intrarea ntr-o tabel de gestiune a resurselor sistemului de operare. Acest index este de tip int
i se numete manipulator de fiier (handle). Manipulatorul este creat i gestionat de ctre sis-
temul de operare. Utilizatorul l folosete pentru a indica sistemului fiierul asupra crui do-
rete s fac prelucrri.
Pentru utilizarea acestui nivel, n programul C trebuie incluse bibliotecile standard
io.h, stat.h i fcntl.h.

Crearea i asignarea unui fiier nou se realizeaz prin apelul funciei creat, care are
urmtorul prototip:

int creat(const char* numef, int protecie);

Funcia returneaz manipulatorul fiierului nou creat; numef este un pointer spre un ir
de caractere care definete specificatorul de fiier, iar protecie definete modul de protecie a
fiierului creat (protecia este dependent de sistemul de operare). n biblioteca stat.h snt de-
finite urmtoarele valori pentru parametrul protecie: S_IREAD (citire), S_IWRITE (scriere),
S_IEXEC (execuie). Aceste valori pot fi combinate folosind operatorul | (sau logic pe bii).
Funcia creat poate fi apelat i pentru un fiier existent. Efectul produs este tergerea fiieru-
lui existent i crearea unuia gol, cu acelai nume; coninutul fiierului existent se pierde. n
* material didactic pentru ID * 53
caz de eroare se returneaz valoarea 1 i se seteaz variabila global errno, care definete ti-
pul erorii. Valorile obinuite pentru errno snt EBADF (manipulator eronat, nu a fost gsit fi-
ierul) sau EACCES (fiierul nu poate fi accesat).

Deschiderea unui fiier existent se realizeaz prin apelul funciei open, care are urm-
torul prototip:

int open(const char *path,int access[,unsigned mod]);

Funcia returneaz manipulatorul fiierului; numef este pointer spre un ir de caractere
care definete specificatorul de fiier; acces este modul de acces la fiier; constantele care de-
scriu modurile de acces la fiier snt descrise n fcntl.h. Cele mai importante snt:
O_RDONLY fiierul va fi accesat numai pentru citire; O_WRONLY fiierul va fi accesat
numai pentru scriere; O_RDWR fiierul va fi accesat att pentru citire ct i pentru scriere;
O_CREAT: fiierul va fi creat ca nou. Aceste moduri pot fi combinate folosind operatorul |.
Mod este folosit numai dac parametrul acces conine i valoarea O_CREAT, caz n care in-
dic modul de protecie a acestuia: S_IWRITE se permite scrierea n fiier; S_IREAD se
permite citirea din fiier; S_IREAD|S_IWRITE se permite att scrierea ct i citirea din fii-
er.

Citirea dintr-un fiier se realizeaz prin apelul funciei read, care are urmtorul antet:

int read(int nf, void* zonat, unsigned n);

Funcia returneaz numrul de octei citii din fiier; nf este manipulatorul de fiier
(alocat la crearea sau deschiderea fiierului), zonat este un pointer spre zona tampon n care se
face citirea (aceasta este definit de programator), iar n este dimensiunea zonei receptoare
(numrul maxim de octei care se citesc). Numrul maxim de octei care pot fi citii este
65534 (deoarece 65535 0xFFF se reprezint intern la fel ca -1, indicatorul de eroare). n
cazul citirii sfritului de fiier se va returna valoarea 0 (0 octei citii), iar la eroare se retur-
neaz -1 (tipul erorii depinde de sistemul de operare). Fiierul standard de intrare (stdin) are
descriptorul de fiier 0.

Scrierea ntr-un fiier se realizeaz prin apelul funciei write, care are urmtorul proto-
tip:

int write(int nf, void* zonat, unsigned n);

Funcia returneaz numrul de octei scrii n fiier; nf este manipulatorul de fiier
(alocat la crearea sau deschiderea fiierului), zonat este un pointer spre zona tampon din care
se face scrierea (aceasta este definit de programator); n este numrul de octei care se scriu.
Numrul maxim de octei care pot fi citii este 65534 (deoarece 65535 0xFFF se reprezin-
t intern la fel ca -1, indicatorul de eroare). n general, trebuie ca la revenirea din funcia
write, valoarea returnat s fie egal cu n; dac este mai mic, s-a produs o eroare (probabil
discul este plin). La scrierea n fiiere text, dac n fluxul octeilor care se scriu apare caracte-
rul LF, write va scrie n fiier perechea CR/LF. n caz de eroare, valoarea returnat este -1 i
se seteaz variabila errno. Fiierul standard de ieire (stdout) are manipulatorul 1 iar cel de
eroare (stderr) are manipulatorul 2.

nchiderea unui fiier se realizeaz prin apelul funciei close, care are urmtorul proto-
tip:
Algoritmi n programare 54
int close(int nf);

Funcia returneaz valoarea 0 (nchidere cu succes) sau -1 (eroare); nf este manipulato-
rul de fiier. De asemenea, nchiderea unui fiier se realizeaz automat, dac programul se
termin prin apelul funciei exit.

Poziionarea ntr-un fiier se realizeaz prin apelul funciei lseek, care are urmtorul
prototip:

long lseek(int nf, long offset, int start);

Funcia returneaz poziia fa de nceputul fiierului, n numr de octei; nf este mani-
pulatorul de fiier; offset este un parametru de tip long (numrul de octei peste care se va de-
plasa pointerul n fiier), iar start este poziia fa de care se face deplasarea: 0 (nceputul fii-
erului), 1 (poziia curent n fiier) sau 2 (sfritul fiierului). La eroare returneaz valoarea
-1L.

Exemple
17. Apelul
vb=lseek(nf, 0l, 2);
realizeaz poziionarea la sfritul fiierului (n continuare se poate scrie n fiier folosind
write).
18. Apelul
vb=lseek(nf, 0l, 0);
realizeaz poziionarea la nceputul fiierului.

tergerea unui fiier existent se realizeaz prin apelul funciei unlink, care are urmto-
rul prototip:

int unlink(const char* numef);

Funcia returneaz 0 (tergere cu succes) sau -1 (eroare); numef este un pointer spre un
ir de caractere care definete specificatorul de fiier. n caz de eroare se seteaz variabila er-
rno cu valoarea ENOENT (fiierul nu a fost gsit) sau EACCES (accesul interzis pentru
aceast operaie, de exemplu pentru fiiere read only). Pentru a putea terge un fiier read
only trebuie nti schimbate drepturile de acces la fiier, folosind funcia chmod:

int chmod(const char *cale, int mod);

unde cale este specificatorul de fiier iar mod noile permisiuni. Permisiunile snt aceleai ca la
funcia open. Rezultatul ntors de chmod are aceeai semnificaie ca i unlink.

Verificarea atingerii sfritului de fiier se face folosind funcia eof:

int eof(int nf);
unde nf este manipulatorul fiierului. Funcia returneaz valoarea 1 dac pointerul este pozi-
ionat pe sfritul fiierului, 0 n caz contrat i -1 n caz de eroare (nu este gsit fiierul errno
primete valoarea EBADF).

Exemplu
19.
#include <sys\stat.h>
#include <string.h>
* material didactic pentru ID * 55
#include <stdio.h>
#include <fcntl.h>
#include <io.h>

int main(void)
{ int handle;
char msg[] = "Acesta este un test";
char ch;

/* crearea unui fisier */
handle = open("TEST.$$$", O_CREAT | O_RDWR, S_IREAD | S_IWRITE);

/* scrierea unor date in fisier */
write(handle, msg, strlen(msg));

/* pozitionare la inceputul fisierului */
lseek(handle, 0L, SEEK_SET);

/* citire cite unui caracter din fisier pina la sfirsitul sau si afisare */
do {read(handle, &ch, 1);
printf("%c", ch);}
while (!eof(handle));

close(handle);
return 0;}

Bibliotecile limbajului conin i alte funcii pentru prelucrarea fiierelor la nivel inferi-
or, inclusiv variante ale funciilor anterioare, aprute odat cu dezvoltarea sistemelor de ope-
rare.

3.8.2. Nivelul superior de prelucrare a fiierelor
La acest nivel, un fiier se descrie ca pointer ctre o structur predefinit (FILE tabe-
la de descriere a fiierului (FIB)):

FILE* f;

Tipul FILE (descris n stdio.h) depinde de sistemul de operare.
Fiierul este considerat ca flux de octei, din care funciile de prelucrare preiau secven-
e pe care le trateaz ntr-un anumit fel (sau n care insereaz secvene de octei).
Funciile folosite la acest nivel pot fi mprite n trei categorii: funcii de prelucrare
generale, funcii de citire/scriere cu conversie i funcii de citire/scriere fr conversie. Funci-
ile de prelucrare general se aplic tuturor fiierelor, indiferent de tipul informaiei coninute;
prelucrarea efectuat de acestea nu are nici un efect asupra coninutului fiierului. Funciile
care lucreaz cu conversie se aplic fiierelor care conin informaie de tip text (linii de text,
separate prin perechea CR/LF, iar la sfrit se gsete caracterul CTRL-Z). Funciile care lu-
creaz fr conversie se aplic fiierelor care conin informaie binar.
Funciile de citire/scriere deplaseaz pointerul de citire/scriere al fiierului, spre sfri-
tul acestuia, cu un numr de octei egal cu numrul de octei transferai (fr a trece de sfri-
tul de fiier).

Funcii de prelucrare general
Deschiderea i asignarea se realizeaz prin apelul funciei fopen. Funcia returneaz
un pointer spre o structur de tip FILE (n care snt nscrise date referitoare la fiierul deschis)
sau NULL dac fiierul nu se poate deschide:

FILE* fopen(const char* nume_extern,const char* mod);

Algoritmi n programare 56
Parametrul nume_extern constituie specificatorul de fiier iar, mod este un ir de caractere ca-
re specific modul de deschidere a fiierului. Asignarea se realizeaz prin expresie de atribui-
re de tipul:

nume_intern=fopen(sir_nume_extern,sir_mod);

Exemplu
19.
FILE* f;
f = fopen("PROD.DAT","r");

Modurile n care poate fi deschis un fiier snt prezentate n tabelul 3.1.

Tabelul 3.1. Modurile de deschidere a unui fiier
Mod Scop
a
Deschide un fiier existent pentru adugare la sfrit (extindere) sau l creeaz dac nu
exist. Este permis numai scrierea. Numai pentru fiiere text.
r Deschide un fiier existent numai pentru citire
w
Suprascrie un fiier existent sau creeaz unul nou, permindu-se numai operaia de
scriere
a+
Deschide un fiier existent pentru adugare la sfrit (extindere) sau l creeaz dac nu
exist. Snt permise citiri i scrieri. Numai pentru fiiere text.
r+ Deschide un fiier existent pentru citire i scriere
w+
Suprascrie un fiier existent sau creeaz unul nou, permindu-se att citiri ct i scri-
eri.

La opiunile de mai sus se poate aduga b pentru fiiere binare sau t pentru fiiere text.
Dac nu este prezent nici litera b nici litera t, modul considerat depinde de valoarea variabi-
lei _fmode: dac valoarea este O_BINARY, se consider fiier binar; dac valoarea este
O_TEXT, se consider fiier text. De obicei implicit este valoarea O_TEXT.
Modurile uzuale pentru deschiderea fiierelor snt prezentate n tabelul 3.2.

Tabelul 3.2. Moduri uzuale pentru deschiderea fiierelor
Operaia de gestiune Fiiere text Fiiere binare
Creare
w wb
Consultare
r rb
Actualizare
r+b
Creare i actualizare
w+ rwb, w+b
Extindere
a

nchiderea fiierelor se realizeaz prin apelul funciei fclose, care are urmtorul proto-
tip:

int fclose(FILE* f);

Funcia nchide fiierul primit ca parametru i returneaz valoarea 0 n caz de succes sau -1, n
caz de eroare. nainte de nchiderea fiierului, snt golite toate zonele tampon asociate lui. Zo-
nele tampon alocate automat de sistem snt eliberate.

Revenirea la nceputul fiierului se realizeaz prin funcia rewind, cu prototipul:

void rewind(FILE *f);

Executarea funciei are ca efect poziionarea la nceputul fiierului f (care era deschis anteri-
* material didactic pentru ID * 57
or), resetarea indicatorului de sfrit de fiier i a indicatorilor de eroare (se nscrie valoarea
0). Dup apelul lui rewind poate urma o operaie de scriere sau citire din fiier.

Testarea sfritului de fiier, se realizeaz prin apelul macrodefiniiei feof:

int feof(FILE* f);

Macro-ul furnizeaz valoarea indicatorului de sfrit de fiier asociat lui f. Valoarea acestui
indicator este setat la fiecare operaie de citire din fiierul respectiv. Valoarea ntoars este 0
(fals) dac indicatorul are valoarea sfrit de fiier i diferit de zero (adevrat) n caz contrar.

Apelul lui feof trebuie s fie precedat de apelul unei funcii de citire din fiier. Dup
atingerea sfritului de fiier, toate ncercrile de citire vor eua, pn la apelul funciei
rewind sau nchiderea i redeschiderea fiierului .

Golirea explicit a zonei tampon a unui fiier se realizeaz prin apelul funciei fflush,
care are urmtorul prototip:

int fflush(FILE* f);

Dac fiierul f are asociat o zon tampon de ieire, funcia scrie n fiier toate informaiile din
acesta, la poziia curent. Dac fiierul are asociat o zon tampon de intrare, funcia l gole-
te. n caz de succes returneaz valoarea zero, iar n caz de eroare valoarea EOF (definit n
stdio.h).

Exemplu
21. nainte de a citi un ir de caractere de la tastatur, zona tampon trebuie golit pen-
tru a preveni citirea unui ir vid (datorit unei perechi CR/LF rmase n zona tampon de la o
citire anterioar a unei valori numerice). tergerea se realizeaz prin apelul:
fflush(stdin);

Aflarea poziiei curente n fiier se realizeaz prin apelul uneia din funciile fgetpos
sau ftell:

int fgetpos(FILE* f,fpos_t* poziie);

Dup apel, la adresa poziie se afl poziia pointerului de citire/scriere din fiierul f, ca numr
relativ al octetului curent. Primul octet are numrul 0. Valoarea returnat poate fi folosit pen-
tru poziionare cu funcia fsetpos. n caz de succes funcia ntoarce valoarea 0, iar n caz de
eroare o valoare nenul i seteaz variabila errno la valoarea EBADF sau EINVAL.

long ftell(FILE* f);

returneaz poziia n fiierul f a pointerului de citire/scriere n caz de succes sau -1L n caz
contrar. Dac fiierul este binar, poziia este dat n numr de octei fa de nceputul fiieru-
lui. Valoarea poate fi folosit pentru poziionare cu funcia fseek.

Modificarea poziiei pointerului de citire/scriere se poate face prin poziionare relativ:

int fseek(FILE* f,long deplasare,int origine);

unde deplasare reprezint numrul de octei cu care se deplaseaz pointerul n fiierul f, iar
Algoritmi n programare 58
origine reprezint poziia fa de care se deplaseaz pointerul. Parametrul origine poate fi:
SEEK_SET (0) poziionare fa de nceputul fiierului; SEEK_CUR (1) poziionare fa
de poziia curent; SEEK_END (2) poziionare fa de sfritul fiierului. Funcia returneaz
valoarea 0 n caz de succes (i uneori i n caz de eec). Se semnaleaz eroare prin returnarea
unei valori nenule numai n cazul n care f nu este deschis.
Poziionarea absolut se face cu funcia:

int fsetpos(FILE* f,const fpos_t poziie);

Pointerul de citire/scriere se mut n fiierul f la octetul cu numrul indicat de parametrul pozi-
ie (care poate fi o valoare obinut prin apelul lui fgetpos).
Ambele funcii reseteaz indicatorul de sfrit de fiier i anuleaz efectele unor even-
tuale apeluri anterioare ale lui ungetc asupra acelui fiier.

Redenumirea sau mutarea unui fiier existent se poate realiza prin apelul funciei re-
name, care are urmtorul prototip:

int rename(const char* n_vechi,const char* n_nou);

unde n_vechi reprezint vechiul nume al fiierului, iar n_nou reprezint numele nou.
Dac numele vechi conine numele discului (de exemplu C:), numele nou trebuie s conin
acelai nume de disc. Dac numele vechi conine o cale, numele nou nu este obligat s conin
aceeai cale. Folosind o alt cale se obine mutarea fiierului pe disc. Folosind aceeai cale
(sau nefolosind calea) se obine redenumirea fiierului. Nu snt permise wildcard-uri (?, *) n
cele dou nume.
n caz de succes se ntoarce valoarea 0. n caz de eroare se ntoarce -1 i errno prime-
te una din valorile: ENOENT nu exist fiierul, EACCES nu exist permisiunea pentru
operaie sau ENOTSAM dispozitiv diferit (mutarea se poate face doar pe acelai dispozitiv).

tergerea unui fiier existent se poate realiza prin apelul funciei unlink, prezentat an-
terior, sau remove, care are urmtorul prototip:

int remove(const char* cale);

unde cale reprezint specificatorul fiierului (trebuie s fie nchis).

Funcii de citire/scriere fr conversie
Funciile efectueaz transferuri de secvene de octei ntre memoria intern i un fiier
de pe disc, fr a interveni asupra coninutului sau ordinii octeilor respectivi.

Citirea dintr-un fiier binar se realizeaz prin apelul funciei fread, care are urmtorul
prototip:
size_t fread(void* ptr,size_t dim,size_t n,FILE* f);

Funcia citete din fiierul f, de la poziia curent, un numr de n entiti, fiecare de dimensiu-
ne dim, i le depune, n ordinea citirii, la adresa ptr. fread returneaz numrul de entiti citite.
n total se citesc, n caz de succes, n*dim octei. n caz de eroare sau cnd se ntlnete sfritul
de fiier, funcia returneaz o valoare negativ sau 0; size_t este definit n mai multe header-e
(ntre care stdio.h) i este un tip de dat folosit pentru a exprima dimensiunea obiectelor din
memorie. Este compatibil cu tipul unsigned.

* material didactic pentru ID * 59
Exemplu
22.
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 fiier binar din care se citete un articol de tip struct com-
plex care se depune n variabila articol.

Scrierea ntr-un fiier binar se poate realiza prin apelul funciei fwrite, care are urm-
torul prototip:

size_t fwrite(const void* ptr,size_t dim,size_t n,FILE* f);

Funcia scrie n fiierul f, ncepnd cu poziia curent, un numr de n entiti contigue, fiecare
de dimensiune dim, aflate n memorie la adresa ptr; fwrite returneaz numrul entitilor scri-
se cu succes. n caz de eroare se returneaz o valoare negativ.

Exemplu
23.
struct complex {int x,y} articol;
FILE *pf;
pf=fopen("NR_COMPL.DAT","wb");
fwrite(& articol,sizeof (articol),1,pf);

Exemplul anterior creeaz un fiier binar nou n care scrie o secven de octei coninnd re-
prezentarea binar a unei date de tip struct complex.

Exemplu
24. S se scrie funcia care calculeaz numrul de articole dintr-un fiier binar,
cunoscnd lungimea n octei a unui articol. Funcia are ca parametri fiierul i lungimea n oc-
tei a unui articol. Prin numele funciei se ntoarce numrul de articole din fiier.
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;
}

Funcii de citire/scriere cu conversie
Funciile efectueaz transferuri de secvene de octei ntre memoria intern i un fiier
de pe disc, convertind secvena de la reprezentarea intern (binar) la reprezentarea extern
(ASCII) i invers.

Transferul de caractere se efectueaz prin urmtoarele funcii:

int fgetc(FILE* f);
int fputc(int c, FILE *f);
int getc(FILE* f);
int putc(int c, FILE *stream);

Algoritmi n programare 60
Funcia fgetc i macrodefiniia getc returneaz urmtorul caracter din fiierul f (dup
ce l convertete la reprezentarea de tip ntreg fr semn). Dac s-a ajuns la sfritul fiierului,
funcia va ntoarce EOF (valoarea -1). Tot EOF va ntoarce i dac snt probleme la citirea din
fiier.
Funcia fputc i macrodefiniia putc scriu caracterul c n fiierul f. n caz de eroare se
returneaz valoarea c, altfel se returneaz EOF.
Funcia ungetc pune caracterul c n zona tampon de citire asociat fiierului f. La ur-
mtoarea citire cu fread sau getc acesta va fi primul octet/caracter citit. Un al doilea apel al
funciei ungetc, fr s fie citit primul caracter pus n flux, l va nlocui pe acesta. Apelarea
funciilor 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 funciile:

char* fgets(char* s,int n,FILE* f);
int fputs(const char* s,FILE* f);

Funcia fgets citete un ir de caractere din fiierul f i l depune la adresa s. Transferul
se ncheie atunci cnd s-au citit n-1 caractere sau s-a ntlnit caracterul newline. La terminarea
transferului, se adaug la sfritul irului din memorie caracterul nul \0. Dac citirea s-a ter-
minat prin ntlnirea caracterului newline, acesta va fi transferat n memorie, caracterul nul fi-
ind adugat dup el (spre deosebire de gets, care nu l reine). La ntlnirea sfritului de fiier
(fr a fi transferat vreun caracter) sau n caz de eroare fgets returneaz NULL. n caz de suc-
ces returneaz adresa irului citit (aceeai cu cea primit n parametrul s).
Funcia fputs scrie n fiierul 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 funciile:

int fprintf(FILE* f,const char* format[,]);
int fscanf(FILR* f,const char* format[,]);

Cele dou funcii lucreaz identic cu printf i scanf. Singura diferen const n fiierul
n/din care se transfer datele. Dac printf i scanf lucreaz cu fiierele standard stdin i
stdoud, pentru fprintf i fscanf este necesar precizarea explicit a fiierului cu care se lucrea-
z, prin parametrul f.

Dei nu lucreaz cu fiiere n mod direct, se pot folosi i funciile

int sprintf(char *s,const char *format[,...]);
int sscanf(const char *s,const char *format[,...]);

Aceste funcii lucreaz identic cu printf i scanf, diferena constnd n entitatea din/n
care se transfer datele. n locul fiierelor standard, acest funcii folosesc o zon de memorie
de tip ir de caractere, a crei adres este furnizat n parametrul s. irul de la adresa s poate fi
obinut prin transfer fr format dintr-un fiier text (pentru sscanf) sau poate urma s fie scris
ntr-un fiier text prin funcia fputs.

Tratarea erorilor
Pentru tratarea erorilor se folosesc urmtoarele funcii:

* material didactic pentru ID * 61
void clearerr (FILE* f);

Funcia reseteaz indicatorii de eroare i indicatorul de sfrit de fiier pentru fiierul f (se n-
scrie valoarea 0). Odat ce indicatorii de eroare au fost setai la o valoare diferit de 0, opera-
iile de intrare/ieire vor semnala eroare pn la apelul lui clearerr sau rewind.

int ferror (FILE* nume_intern);

ferror este o macrodefiniie care returneaz codul de eroare al ultimei operaii de intrare/ieire
asupra fiierului nume_intern (0 dac nu s-a produs eroare).

Exemplu
25. Exemplul urmtor creeaz un fiier nou din care ncearc s citeasc date
#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 la citirea din test.ttt\n");
//reseteaza indicatorii de eroare si sfarsit de fisier
clearerr(f);
}
fclose(f);
return 0;
}

Exemplu
26. S se scrie un program care calculeaz i afieaz valoarea unei funcii introduse
de la tastatur ntr-un punct dat. Funcia se introduce ca ir de caractere i poate conine ape-
luri de funcii standard C. Programul creeaz un fiier surs C (n care este scris forma func-
iei, ca subprogram C), apoi compileaz i execut un alt program, care va include subpro-
gramul creat. Descrierea funciei introduse de la tastatur trebuie s conin maxim 200 carac-
tere. (Exemplul a fost scris n mediul Borlandc 3.11.)
a) Fiierul 382_a.cpp conine programul care realizeaz citirea formei funciei, compilarea i
execuia programului care calculeaz valoarea funciei.

#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 382_b.cpp>>
tmp.txt");
execl("382_b ",NULL);
}
Algoritmi n programare 62
b) Fiierul 382_b conine programul care face citete punctul x, calculeaz valoarea func-
iei n acest punct i o afieaz.

#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();
}

Teste de autoevaluare
4. Ce este un fiier?
5. Care snt operaiile de baz pentru prelucrarea unui fiier de date?
6. Scriei un program care preia un text de la tastatur i l scrie ntr-un fiier nou creat n di-
rectorul curent.


Rspunsuri i comentarii la testele de autoevaluare
1. Articolul este o dat complex, eterogen, cu acces direct la componente. n func-
ie de modul de utilizare, un articol poate fi alocat static sau dinamic.


Rezumat

n cadrul acestei uniti de nvare au fost studiate urmtoarele aspecte ale program-
rii calculatoarelor cu privire la articole i fiiere de date:
tipul de dat intern articol;
tipuri de fiiere;
utilizarea articolelor interne pentru prelucrarea fiierelor externe;
operaii generale de prelucrare a fiierelor de date.
Dup ncheierea studierii acestei uniti de nvare, studenii snt au cunotinele i
abilitile necesare lucrului cu structuri de date externe, indispensabile n cadrul aplicaiilor de
informatic economic.



Bibliografia unitii de nvare

1. I. Gh. Roca, B. Ghilic-Micu, C. Cocianu, M. Stoica, C. Uscatu, M. Mircea - Programarea
calculatoarelor. Algoritmi n programare, Ed. ASE Bucureti, 2007
2. I. Gh. Roca, B. Ghilic-Micu, C. Cocianu, M. Stoica, C. Uscatu - Programarea calculatoa-
relor. tiina nvrii unui limbaj de programare. Teorie i aplicaii, Ed. ASE Bucureti,
2003
3. Liviu Negrescu - Limbajele C i C++ pentru nceptori, vol. I, II, Ed. Microinformatica,
Cluj-Napoca, 1994
4. I.Gh. Roca & colectiv - Bazele elaborrii programelor. Exerciii rezolvate i propuse, Ed.
ASE Bucureti, 1998
5. B. Ghilic-Micu, I. Gh. Roca, C. Apostol, M. Stoica - Algoritmi n programare, Ed. ASE,
Bucureti, 2002
* material didactic pentru ID * 63



4. Algoritmi de prelucrare a fiierelor de date



Cuprins

Obiectivele unitii de nvare ......................................................................................... 63
4.1. Caracteristici generale ale algoritmilor de prelucrare a fiierelor .................... 63
4.2. Algoritmi de prelucrare a fiierelor binare care nu necesit actualizare............ 68
4.3. Algoritmi de prelucrare a fiierelor binare care necesit actualizare ................. 76
4.3.1. Codificarea extern prin numere relative ..................................................... 76
4.3.2. Codificarea intern prin numere relative...................................................... 78
4.3.3. Corespondena intern dintre chei i numere relative ................................. 79
4.4. Sortarea fiierelor binare memorate dens ............................................................. 89
4.5. Interclasarea fiierelor binare memorate dens ..................................................... 93
4.6. Prelucrarea masivelor memorate n fiiere binare ............................................... 94
4.6.1. Prelucrarea vectorilor..................................................................................... 94
4.6.2. Prelucrarea matricelor ................................................................................... 95
Rspunsuri i comentarii la testele de autoevaluare ....................................................... 96
Bibliografia unitii de nvare........................................................................................ 97


Obiectivele unitii de nvare

Dup studierea acestei uniti de nvare, studenii vor avea cunotine teoretice i
abiliti practice necesare prelucrrii fiierelor de date. Vor fi asimilate abilitile
necesare prelucrrii fiierelor organizate secvenial, relativ i indexat. Studenii vor
putea s efectueze toate operaiile de prelucrare a fiierelor de date: creare, consultare, actua-
lizare.


4.1. Caracteristici generale ale algoritmilor de prelucrare a fiierelor

Din punct de vedere al operaiilor de gestiune solicitate de diverse aplicaii, fiierele
binare se pot grupa n: fiiere care nu snt actualizate (inute la zi) i fiiere care snt actualizate.
De obicei, fiierele din prima grup se regsesc n aplicaii matematice sau ca fiiere temporare
i de tranzacii n aplicaii de gestiune economic. Fiierele din cea de-a doua grup snt, de
obicei, fiiere permanente (principale) n aplicaii de gestiune economic i au particulariti de
proiectare referitoare, n special, la asigurarea tergerii i adugrii de articole.

Organizarea datelor n fiiere memorate pe medii magnetice externe presupune proiec-
tarea unor algoritmi specifici operaiilor de gestiune a acestora, denumii generic algoritmi de
prelucrare a fiierelor de date. Datorit complexitii aplicaiilor care prelucreaz fiiere este
recomandat aplicarea metodei modularizrii algoritmilor i programelor. Modularizarea pre-
supune ca, pe baza analizei problemei, s se descompun rezolvarea ei n pri distincte, nu-
mite module, astfel nct fiecare dintre acestea s ndeplineasc anumite funcii. Descompune-
rea se poate realiza n mai multe faze (pe mai multe niveluri), prin metoda top-down. Criteriile
Algoritmi n programare 64
de descompunere n module depind, n mare msur, de experiena programatorilor. Ele se re-
fer, n principal, la: omogenizarea funciilor; utilizarea diverselor structuri de date; separarea
funciilor de intrare/ieire de funciile de prelucrare; utilizarea unor module deja existente; uti-
lizarea eficient a resurselor calculatorului (timp UC, memorie intern, periferie) etc. Module-
le se implementeaz n program prin subprograme interne sau externe.

De cele mai multe, ori o aplicaie necesit existena mai multor fiiere active simultan,
cu rol diferit (de intrare, de ieire, de intrare/ieire). Indiferent de numrul fiierelor utilizate,
n marea majoritate a algoritmilor, logica prelucrrii este coordonat, la un moment dat, de un
singur fiier, obligatoriu de intrare, parcurs secvenial, numit fiier conductor (sau director).
Fiierul conductor are proprietatea c articolele lui pot fi citite logic independent de prelucra-
rea altor fiiere. Altfel spus, un fiier nu este conductor dac prelucrarea articolelor sale este
dependent de existena (de citirea) articolului altui fiier. Accesul la datele memorate n fiie-
rul conductor se realizeaz la nivel de articol. De aceea, algoritmii de prelucrare, indiferent
de operaia de gestiune, necesit utilizarea unei structuri repetitive pentru parcurgerea (paria-
l sau integral) a fiierului respectiv.

Algoritmii de prelucrare cu fiier conductor pot fi reprezentai prin schema logic ge-
neralizat, conceput modularizat, redat n figura 4.1.

Fig. 4.1. Schema logic general a unui algo-
ritm de prelucrare cu fiier conductor
Modulul NCEPUT se realizeaz o sin-
gur dat, naintea prelucrrii primului articol
al fiierului conductor i cuprinde urmtoa-
rele grupe de operaii:
Operaii iniiale standard, obligatorii
oricrui algoritm i care includ: punerea n
coresponden a fiierelor logice cu fiiere
fizice, deschiderea fiierelor, i, pentru
anumite variante, iniializarea unei variabi-
le logice pentru sfrit de fiier (SF) i citi-
rea primului articol.
Operaii iniiale specifice, facultative,
existena lor depinznd de particularitile
problemei abordate i care includ, n prin-
cipal: iniializri de variabile de total, afi-
ri ale antetului, titlului i/sau a capului
de tabel pentru situaii de ieire etc.


Modulul PRELUCRARE se execut repetitiv i cuprinde, pe de o parte, totalitatea ope-
raiilor de prelucrare a articolului curent al fiierului conductor - operaii specifice fiecrei
probleme - i, pe de alt parte, citirea unui articol din fiierul conductor. Ordinea celor dou
operaii (citire i prelucrare) depinde de varianta de algoritm aleas.

Modulul SFRIT se execut o singur dat, dup prelucrarea ultimului articol al fiie-
rului conductor i include urmtoarele grupe de operaii: operaii finale standard,
corespunznd nchiderii fiierelor implicate n prelucrare; operaii finale specifice, care depind
de natura problemei i includ, de regul: afiarea variabilelor de total, a statisticilor privind
operaiile de gestiune executate, nchiderea situaiilor de ieire etc.

* material didactic pentru ID * 65
Modalitatea de detectare/tratare a sfritului de fiier conduce la existena mai multor variante
ale schemei generale de prelucrare cu fiier conductor, prin forme particulare ale condiiei
sfrit_de_prelucrare. n funcie de variantele alese, se pot construi scheme logice valabile
pentru toate tipurile de fiiere sau numai pentru fiierele binare.

Scheme valabile pentru toate tipurile de fiiere
Detectarea sfritului de fiier, cu macrodefiniia feof, caz n care testarea sfritului de
fiier trebuie s urmeze dup o operaie de citire a unui articol. Algoritmul trebuie s conin o
citire iniial n modulul NCEPUT i o citire curent la sfritul modulului PRELUCRARE -
(figura 4.2). Acest algoritm se poate aplica fiierelor vide sau nevide.

Fig. 4.2. Detectarea sfritului de fiier (orice
fiier)

Fig. 4.3. Detectarea sfritului de fiier (fiier
binar)

Scheme logice valabile numai pentru fiiere binare
Detectarea sfritului de fiier prin operaia de citire, verificnd rezultatul ntors de
funcia de citire (fread). Dac rezultatul este mai mic dect numrul de blocuri de date care
trebuie citite, nseamn c s-a ajuns la sfritul fiierului. ntruct, uzual, la o operaie de citire
se citete un articol ntreg, n cazul atingerii sfritului de fiier, rezultatul ntors de funcia
fread va fi 0. Rezultatul poate fi preluat ntr-o variabil pentru a fi folosit n condiia de termi-
nare a prelucrrii (figura 4.3) sau poate fi verificat direct, folosind apelul funciei fread n ex-
presia (condiia) care controleaz sfritul prelucrrii (figura 4.4). n ambele variante fiierul
conductor este binar, vid sau nevid.

Prelucrarea unui numr cunoscut de articole, prin determinarea n modulul NCE-
PUT a numrului de articole din fiierul conductor (figura 4.5). Limbajul C nu ofer o func-
ie standard pentru calcularea numrului de articole dintr-un fiier binar, deoarece, din punctul
de vedere al limbajului, fiierele nu conin articole. Din punctul de vedere al utilizatorului,
cunoscnd dimensiunea unui articol, se poate calcula numrul de articol de fiier, mprind
lungimea acestuia la lungimea unui articol (ambele msurate n numr de octei). Lungimea
fiierului este egal cu poziia curent, atunci cnd pointerul de citire se afl la sfritul fiieru-
lui. Pentru aflarea numrului de articole, se folosete secvena urmtoare:

p=ftell(f);
fseek(f,0,SEEK_END);
l=ftell(f);
nr=l/sizeof(tip_articol);
fseek(f,p,SEEK_SET);
Algoritmi n programare 66
unde: variabila p, de tip long reine poziia curent n fiier; f este fiierul a crui lungime tre-
buie calculat; variabila l reine poziia curent (n numr de octei fa de nceputul fiierului,
deci lungimea fiierului msurat n octei); variabila nr va primi ca valoare numrul de arti-
cole din fiie; tip_articol este tipul articolelor din fiier (din punctul de vedere al utilizatoru-
lui). mprirea se face exact, deoarece fiierul conine un numr ntreg de articole utilizarea
acestei secvene asupra unui fiier care conine articole de alt tip (sau are coninut de alt na-
tur) va duce la rezultate incorecte.




Fig. 4.4. Detectarea sfritului de fiier (fiier
binar)

Fig. 4.5. Prelucrarea unui fiier cu dimensiu-
ne cunoscut

Caracteristica general a algoritmilor de prelucrare cu fiier conductor este parcurge-
rea secvenial a fiierului conductor i efectuarea unor prelucrri n funcie de fiecare articol
citit din acesta. Problema care se pune este detectarea sfritului de fiier. n C, macrodefiniia
feof nu face dect s furnizeze valoarea indicatorului de sfrit de fiier, care este setat de ope-
raia de citire; n program, citirea trebuie s apar naintea verificrii sfritului de fiier. For-
ma general a algoritmului este:

<citire articol>
while(!feof(f))
{ <prelucrare articol citit>
<citire articol>
}

Exemplu
1. Crearea i consultarea unui fiier text care memoreaz elemente ntregi, folosind
funcia feof pentru gestionarea sfritului de fiier. La crearea fiierului, fiier conductor este
fiierul standard de intrare. La afiare, conductor este fiierul f.

#include<stdio.h>
#include<conio.h>

void main()
{ FILE *f;
int x; long dim;
clrscr(); f=fopen("numere.dat","w+");
* material didactic pentru ID * 67
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();}

Exemplu
2. Acelai exemplu, folosind fiier 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();}

Fiierele utilizate ntr-o aplicaie informatic au rol diferit n procesul prelucrrii, n
funcie de scopul lor: de intrare, de ieire, de intrare/ieire, temporare, de tip list etc. Aceste
caracteristici conduc la algoritmi specifici fiecrei operaii de gestiune n parte (creare, popu-
lare, consultare i actualizare), fiind ns variante derivate din schema general a unui algo-
ritm de prelucrare cu fiier conductor. Deoarece aplicaiile informatice din domeniul econo-
mic, social, administrativ etc. utilizeaz, cu predilecie, fiiere cu articole de aceeai structur
(sau un numr mic de structuri diferite), alegnd limbajul C, se poate aprecia c cele mai per-
formante snt fiierele binare, ale cror articole snt date declarate ca structuri (folosind tipul
de date struct).
Aceast alegere este motivat din urmtoarele puncte de vedere:
descrierea articolelor este apropiat att descrierii naturale a structurii unei entiti din
lumea real (format din cmpuri cu nume, lungime, reprezentare intern proprie, semnificaie
i factor de repetabilitate diferite), ct i descrierii din alte limbaje;
exist posibilitatea de a descrie explicit mai multe structuri pentru articolele aceluiai fi-
ier (articole cu structur variabil);
operaiile de acces la nregistrri se realizeaz cu vitez mare, datorit lipsei conversiilor
la transferul ntre memoria principal i memoria extern.

Fiierele cu coninut de tip text snt recomandate a fi utilizate ca fiiere de ieire, pen-
tru realizarea de liste, situaii finale, rapoarte etc., fiind rezidente pe disc, n general, pn la
Algoritmi n programare 68
listarea lor la imprimant. Fiierele cu coninut de tip text pot constitui i sursa de creare a fi-
ierelor binare, dac acestea au fost populate cu date, fie prin editoare de texte, fie prin alte
limbaje (Cobol, Fortran, Basic, Pascal), sisteme de gestiune a bazelor de date (DBase, Fox-
Pro, Oracle etc.), constituind unicul mijloc de compatibilitate direct.

Teste de autoevaluare
1. Explicai cum se detecteaz sfritul de fiier n limbajul C i ce influen are acest
aspect asupra algoritmilor de prelucrare a fiierelor.


4.2. Algoritmi de prelucrare a fiierelor binare care nu necesit actualizare

Asupra fiierelor binare care nu necesit actualizare se realizeaz, de obicei, operaiile
de creare (populare) i consultare. Dintre operaiile de actualizare pot fi realizate, fr mari
complicaii, modificarea i adugarea dens de articole.

Popularea fiierelor se realizeaz prin preluarea datelor fie din alte fiiere primare (cu
coninut binar sau de tip text), fie de la tastatur (popularea interactiv). n ultimul caz, cel mai
des ntlnit n practic, fiierul conductor corespunde mulimii datelor introduse de la tastatur.
Articolele snt preluate cmp cu cmp, neexistnd posibilitatea citirii unei variabile de tip articol
i, n plus, introducerea unei date este adesea nsoit de proceduri de validare specifice, cu
reintroducerea ei n cazul unei erori.

Sfritul introducerii datelor de la tastatur (i implicit al procesului de populare a
fiierului) poate fi:
De tip chestionar, prin consultarea utilizatorului, privind continuarea sau nu a introducerii
articolelor. Pentru un volum mare de date, varianta prezint dezavantajul mririi timpului de
prelucrare.
Convenional, prin introducerea pentru primul cmp din articol a unei valori prestabilite, cu
semnificaie de sfrit de prelucrare.
Standard, prin introducerea caracterului CTRL-Z, cu rol de sfrit de fiier text.

Schema logic a algoritmului de prelucrare este similar celei din figura 4.2., cu
urmtoarele particulariti:
- modulul NCEPUT are ca ultime operaii, afiarea numelui primului cmp din articol i
citirea valorii sale;
- modulul PRELUCRARE ncepe cu citirea urmtorului cmp, urmat de citirea
celorlalte cmpuri (eventual cu validrile stabilite) i se termin cu afiarea numelui primului
cmp i cu citirea valorii acestuia (pentru articolul urmtor) (similar operaiei din modulul
NCEPUT).

O alt problem a populrii fiierelor binare o reprezint aezarea articolelor pe suportul
extern. Din acest punct de vedere se ntlnesc dou modaliti:
Populare dens, prin care articolele se scriu unul dup altul, n ordinea n care au fost
furnizate, fr a se lsa locuri libere (acces secvenial). Pentru fiierele care nu necesit
actualizare acesta este tipul recomandat.
Populare aleatoare, prin care articolele snt scrise n casetele (virtuale) ale cror numere
relative snt furnizate explicit de utilizator (acces direct). Scrierea unui articol se realizeaz dup
poziionarea pe numrul relativ dorit. La populare, nr_relativ nu este limitat dect de spaiul
existent pe suportul extern. Metoda are dezavantajul c necesit evidena articolelor vide. n
* material didactic pentru ID * 69
cazul fiierelor care nu necesit actualizare, popularea aleatoare se recomand numai dac, dup
creare, fiierul este dens.

Pentru poziionarea pe articolul cu numrul relativ n se folosete funcia fseek astfel:

fseek(f, n*sizeof(tip_articol), SEEK_SET);

unde n este numrul relativ al articolului iar tip_articol este tipul de dat care i corespunde.

Exemplu
3. S se creeze cu populare dens un fiier PRODUSE.DAT, cu informaii despre
producia cantitativ dintr-un an la o societate comercial. Articolele au urmtoarea structur
logic:
Cod
produs
Denumire
Produs
Pre
Mediu
Cantiti lunare
1 2 ... 12

Articolele snt introduse de la terminal, cmp cu cmp. Terminarea introducerii datelor este
marcat standard, prin introducerea caracterului CTRL-Z.

#include <stdio.h>

typedef struct { int cod;
char denumire[20];
float pret_mediu;
int cant[12];
} PRODUS;
void main()
{ FILE* f;
PRODUS x;
char nume_fisier[20];
int i;

//---INCEPUT---
printf("\n\nNumele fisierului: ");
gets(nume_fisier);
if(!(f=fopen(nume_fisier,"wb"))) printf("\n\nNu poate fi creat fisierul cu
numele %s",nume_fisier);
else
{ printf("\nCod produs: ");
scanf("%d",&x.cod);
//---Aici se termina operatiile initiale---

while(!feof(stdin))
{
//---PRELUCRARE ARTICOL---
printf("Denumire produs: ");
fflush(stdin);
gets(x.denumire);
printf("Pret mediu: ");
scanf("%f",&x.pret_mediu);
printf("Cantitate lunara:\n");
for(i=0;i<12;i++)
{ printf(" - luna %d: ",i+1);
scanf("%d",&x.cant[i]);
}
fwrite(&x,sizeof(PRODUS),1,f);
//---Aici se incheie prelucrarea articolului---
printf("\nCod produs: ");
scanf("%d",&x.cod);
}
//---SFIRSIT---
Algoritmi n programare 70
fclose(f);
}
}

Observaii: dac se dorete crearea fiierului de date cu populare n acces direct,
programul este similar, cu urmtoarele diferene:
cmpul COD indic numrul relativ al articolului n fiier i nu va fi memorat (nu va
face parte din declaraia tipului PRODUS), fiind redundant;
scrierea articolului va fi precedat de apelul funciei

fseek(f,codt*sizeof(PRODUS),SEEK_SET);

unde codt este o variabil independent n care se citete codul de la terminal.

Consultarea fiierelor are numeroase variante, n funcie de scopul prelucrrii. Dup
modul de regsire a articolelor n cadrul fiierului, ea poate fi secvenial, direct sau mixt.
Consultarea secvenial presupune regsirea articolelor n ordinea n care au fost scrise
pe suportul tehnic de informaii. Dup numrul articolelor prelucrate, consultarea secvenial
poate fi: integral, cnd se prelucreaz toate articolele fiierului, ncepnd cu primul i terminnd
cu ultimul; cu selecie, cnd se prelucreaz numai acele articole care au una sau mai multe
caracteristici comune (valori identice pentru acelai cmp). Dup numrul de caracteristici,
selecia poate fi simpl, dubl, multipl. Pentru consultarea secvenial se poate utiliza oricare
din tipurile de algoritmi prezentai anterior.

Exemplu
4. S se afieze pe ecran coninutul fiierului creat la exemplul anterior.

#include <stdio.h>
typedef struct { int cod;
char denumire[20];
float pret_mediu;
int cant[12];
} PRODUS;
void main()
{ FILE* f;
PRODUS x;
char nume_fisier[20];
int i;
//---INCEPUT---
printf("\n\nNumele fisierului: ");
gets(nume_fisier);
if(!(f=fopen(nume_fisier,"rb"))) printf("\n\nNu poate fi deschis fisierul
cu numele %s",nume_fisier);
else
{ fread(&x,sizeof(PRODUS),1,f);
//---Aici se termina operatiile initiale---
while(!feof(f))
{
//---PRELUCRARE ARTICOL---
printf("\n\nCod produs:\t\t%d",x.cod);
printf("\nDenumire produs:\t%s",x.denumire);
printf("\nPret mediu:\t\t %7.2f",x.pret_mediu);
printf("\nCantitati lunare:\t");
for(i=0;i<12;i++)
printf("%3d ",x.cant[i]);
//---Aici se incheie prelucrarea articolului---
fread(&x,sizeof(PRODUS),1,f);
}
//---SFIRSIT---
fclose(f);
* material didactic pentru ID * 71
}
}

Teste de autoevaluare
2. Folosind fiierul creat la exemplul 3, scriei un program care determin luna (lunile)
din an n care producia valoric a societii a nregistrat valoarea maxim.


Exemplu
5. Obinerea unei situaii cu mai multe grade de total. Pentru aceasta se stabilesc
cmpuri asociate gradelor de total, numite caracteristici de grupare sau caracteristici de
control. O caracteristic de control este un cmp al articolului din fiierul de date, care are
aceeai valoare pentru mai multe nregistrri. Astfel, articolele care au valoare comun pentru o
caracteristic de grupare se pot ordona pe submulimi, formnd o grup de control. Fiierul
poate constitui, n ansamblul su, caracteristica de grupare de cel mai nalt nivel, pentru care se
poate calcula totalul general.
Numrul maxim de grade de total este superior cu unu numrului de caracteristici de
control stabilite. ntre caracteristicile de grupare se stabilete o relaie de ordine ierarhic. Pentru
prelucrarea fiierului, cu utilizare minim de memorie, articolele trebuie sortate dup carac-
teristicile de control. Acest tip de prelucrare intr n categoria consultrilor secveniale integrale
i urmeaz algoritmul de principiu din figurile 4.2 sau 4.3. Prelucrarea unui fiier sortat dup
criteriile enunate, presupune existena unor operaii standard, executate la schimbarea valorii
fiecrei caracteristici de control stabilite:
operaii iniiale ale unei grupe de control prin care se iniializeaz variabila de total
specific grupei; se salveaz valoarea caracteristicii primului articol din grup; alte operaii
iniiale specifice grupei;
operaii finale ale unei grupe de control prin care se afieaz totalul calculat pentru
caracteristica ce se schimb; se cumuleaz totalul grupei curente la totalul grupei ierarhic
superioare; alte operaii finale specifice grupei;
condiia de prelucrare a unei grupe de control conine, pe lng condiia specific, toate
celelalte condiii din amonte.
Raportul final este listat la imprimant, fie direct, ca fiier de ieire, fie creat pe suport
magnetic, ca fiier text, n vederea imprimrii ulterioare. Structura unei pagini a raportului i
controlul trecerii la o nou pagin trebuie asigurate de programator.

n figura 4.6 se prezint structura de principiu a unui program de obinere a unui raport
final, cu control dup dou caracteristici i trei grade de total, unde cmp_1 i cmp_2 snt
caracteristicile de control (cmpuri din articol), v1 i v2 snt variabile de lucru pentru salvarea
caracteristicilor, val_art e valoarea care intereseaz din fiecare articol (cmp al articolului sau
valoare calculat pe baza unor cmpuri ale articolului) iar TOTG, TOT1 i TOT2 snt variabile
pentru calculul gradelor de total. Analog, se poate extinde pentru oricte caracteristici i grade
de total.

Algoritmi n programare 72
START
STOP
Da
Citete
articol
!feof(f)
Citete
articol
Nu
Operaii iniiale
generale
Operaii finale
generale
Operaii iniiale
Grupa 1
TOTG=0
TOT1=0
v1=cmp_1
! feof(f) i
v1==cmp_1
Da
TOT2=0
v2=cmp_2
! feof(f) i
v1==cmp_1 i
v2==cmp_2
Operaii iniiale
Grupa 2
Prelucrare articol
Da
TOT2+=val_art
Operaii finale
Grupa 2
TOT1+=TOT2
TOTG+=TOT1
Operaii finale
Geupa 1
Nu
Nu

Fig. 4.6. Schema logic problema cu grade de total


Teste de autoevaluare
3. Fie un fiier binar organizat relativ, cu articole avnd urmtoarea structur:

Note
Nr. matricol Nume i prenume Facultate An de studiu Grupa
1 2 20
int char[30] char[10] int int int int int

Datele se refer la situaia colar a studenilor dintr-o universitate. Convenim c vectorul de
note conine valoarea zero acolo nu exist not. Scriei un program care creeaz un raport (ntr-
un fiier text), cu studenii grupai dup urmtoarele caracteristici: facultate, an de studiu, grupa.
n cadrul grupei studenii vor fi trecui n ordine alfabetic. Pentru fiecare student se nscrie
numrul matricol, numele i prenumele i media. Se va calcula media pentru fiecare grup (ca
medie a studenilor din grup), pentru fiecare an din cadrul unei faculti (ca medie a mediilor
grupelor componente), pentru fiecare facultate (ca medie a mediilor anilor de studiu) i media
general. Cte caracteristici de grupare i cte grade de total snt implicate n acest program?
(Pentru rezolvare va trebui studiat nti sortarea fiierelor binare).

* material didactic pentru ID * 73
Consultarea n acces direct presupune regsirea articolului dup numrul relativ.
ntruct fiierele snt considerate ca fluxuri de octei, trebuie calculat poziia articolului dorit n
fiier ca produs ntre numrul su relativ i dimensiunea unui articol n octei
(nr*sizeof(tip_articol)). Secvena care realizeaz acest lucru este:

fseek(f,nr*sizeof(tip_articol), SEEK_SET);
fread(&art,sizeof(tip_articol), 1, f);

Numrul relativ este furnizat de utilizator i trebuie s aparin domeniului 0..dimensiune
fiier-1 (dimensiunea calculat ca numr de articole). Pentru evitarea situaiilor n care numrul
relativ se afl n afara acestui domeniu, se va include n program validarea apartenenei
numrului relativ la intervalul acceptat. Algoritmul de consultare n acces direct a unui fiier are
un alt fiier conductor (de exemplu tastatura).

Exemplu
6. Secvena general pentru prelucrarea n acces direct.
{
// citire nume fisier extern
f=fopen(nume_fisier, "rb");
// calculare numar de articole din fisier
printf("\nNr. relativ: ");
scanf("%d",&r); //citirea numarului relativ al articolului
while(!feof(stdin))
{ if(r>=nr_art) printf("\n Articol inexistent !");
else
{ fseek(f,r*sizeof(tip_articol),SEEK_SET);
fread(&art,sizeof(tip_articol),1,f);
// ------------------------
//PRELUCRARE ARTICOL
//------------------------
}
printf("\nNr. Relativ (sau CTRL-Z): ");
scanf("%d",&r);
}
fclose(f);
}

Consultarea n acces mixt utilizeaz o combinaie ntre accesul direct i cel secvenial,
n vederea prelucrrii unui grup de articole, memorate contiguu n fiier i selectabile printr-o
condiie. Pentru fiierele binare, metoda poate fi aplicat dac se dorete selectarea articolelor
dintre dou limite ale numerelor relative (limita inferioar - l
i
i limita superioar - l
s
).
Algoritmul trebuie s verifice relaia 0l
i
l
s
dimensiune fiier, dup care parcurgerea fiierului
poate fi realizat prin orice tip de structur repetitiv.

Exemplu
7. Secvena general pentru prelucrarea n acces mixt.
{
// citire nume fisier extern
f=fopen(nume_fisier, "rb");
// calculare numar articole din fisier
printf("\nLimita inferioara: ");
scanf("%d",&li); // citirea nr. relativ al primului articol
// din secventa
printf("\nLimita superioara: ");
scanf("%d",&ls); // citirea nr. relativ al ultimului articol
// din secventa
if((0<li)&&(li<=ls)&&(ls<=nr_art))
{ fseek(f,li*sizeof(tip_articol),SEE_SET);
for(i=li;i<=ls;i++)
{ fread(&art,sizeof(tip_articol),1,f);
Algoritmi n programare 74
// -----------------------
// Prelucrare articol
// -----------------------
}
}
else printf(" Nu este indeplinita conditia de limite");
fclose(f)
}

Adugarea de articole se realizeaz, n general, cu tranzacii de la terminal, similar
operaiei de populare. Pentru o corect exploatare ulterioar, adugarea trebuie s fie dens.
Acest lucru poate fi realizat astfel:
Adugare la sfrit (extindere), dup ultimul articol scris. Operaia se realizeaz
similar populrii n acces secvenial, dup poziionarea pe marcatorul de sfrit de fiier,
apelnd funcia fseek: fseek(f,0,SEEK_END);

Exemplu
8. Secvena general pentru adugarea datelor la sfritul fiierului.

{ // citire nume fisier extern
f=fopen(nume_fisier, "rb");
fseek(f,0,SEEK_END); // pozitionare dupa ultimul
// articol scris
printf("Cimp 1: ");
scanf("%d ",&art.cimp_1);
while(!feof(stdin))
{ // -----------------------------------------------
// Preluare de la tastatura a celorlalte
// cimpuri din articol
// -----------------------------------------------
printf("Cimp 1: ");
scanf("%d ",&art.cimp_1);
}
fclose(f)
}

Inserarea unor articole. Se aplic n cazul n care articolele snt scrise n fiier n
ordinea cresctoare (descresctoare) a valorilor unui anumit cmp. n acest caz, noul articol va fi
inserat ntre dou articole, astfel:
se caut (cu un algoritm secvenial, binar etc.) poziia k n care trebuie inserat noul articol;
se copiaz, glisnd cu o poziie spre dreapta, toate articolele de la sfritul fiierului pn la
articolul cu numrul relativ k;
se scrie n acces direct noul articol, n poziia k.

Exemplu
9. Secvena general pentru inserarea articolelor pe anumite poziii.

{ // articolele fisierului snt in ordinea crescatoare a valorii cimpului 1

// citire nume fisier extern *)
f=fopen(nume_fisier, "rb+ ");

// calculare numar de articole din fisier
printf("\nCimp 1: "); // introducerea cimpului dupa care
// sint sortate articolele
scanf("%d ",&art_nou.cimp_1);

while(!feof(stdin)) // adaugarea mai multor articole
{ // -----------------------------------
// Preluare de la tastatura a celorlalte
* material didactic pentru ID * 75
// cimpuri din articolul de adaugat
// -----------------------------------

// secventa de cautare a pozitiei
// in care se va insera articolul }
fseek(f,0,SEEK_SET); // pozitionare pe inceput de fisier
fread(&art_existent,sizeof(tip_articol),1,f);
while((!feof(f))&&(art_existent.cimp_1<art_nou.cimp_1)
fread(&art_existent,sizeof(tip_articol),1,f);
if(!feof(f))
{ k=ftell(f)-sizeof(tip_articol); //articolul se va insera in pozitia k
for(i=nr_art-1;i>=k;i--)
{ fseek(f,i*sizeof(tip_articol),SEK_SET);
fread(&art_existent,sizeof(tip_articol),1,f);
fwrite(&art_existent,sizeof(tip_articol),1,f);
}
}
else k=nr_art; // articolul se adauga la sfirsitul fisierului
fseek(f,k*sizeof(tip_articol),SEK_SET);
fwrite(&art_nou,sizeof(tip_articol),1,f);
printf("\nCimp 1: "); // introducerea cimpului dupa care
// sint sortate articolele
scanf("%d ",&art_nou.cimp_1);rite('Cimp 1: ')
}
fclose(f);
}

Modificarea valorii unor cmpuri din articol se realizeaz n mai multe etape:
se citete articolul care se modific (fseek i fread);
se modific (n zona articol din memoria principal) cmpurile cu valorile dorite, introduse,
n general, de la tastatur;
se repoziioneaz pe articolul respectiv cu
fseek(f,ftell(f)-sizeof(tip_articol),SEEK_SET);
se scrie articolul modificat, cu funcia fwrite.

O problem important rmne selectarea cmpurilor care se modific, pentru fiecare
articol n parte.
O variant simpl este afiarea vechii valori, urmat de introducerea noii valori, n
variabile independente de tip ir de caractere. n cazul n care irul introdus este vid (s-a apsat
numai ENTER), respectivul cmp, prin convenie, nu se modific. Altfel, cmpului respectiv i se
va atribui valoarea citit n variabila independent, eventual prin conversie, pentru cmpurile
numerice.

Din punct de vedere tehnic, orice cmp poate fi modificat. Din punct de vedere logic
ns, nu e nevoie sau e chiar imposibil s modificm unele cmpuri. n aplicaii se
prevede posibilitatea modificrii numai pentru acele cmpuri a cror modificare este
normal din punctul de vedere al problemei care se rezolv.


Exemplu
10. Secvena general pentru modificarea unui articol.

// ------------------------------
// cautare articol de modificat
// ------------------------------ *)
fread(&art,sizeof(tip_articol),1,f);

printf("Codul: %d - ",art.cod); //afisare vechea valoare
fflush(stdin);
Algoritmi n programare 76
gets(cods); // citire noua valoare; cods este de tip sir
if(strlen(cods))
{ art.cod=atoi(cods); // conversie din ASCII in binar
printf("Denumire: %s - ",art.den); // afisare vechea valoare
gets(dens); // citire noua valoare
if(strlen(dens)
strcpy(dens,art.den); // copiere noua valoare
// ----------------------------------
// Introducerea celorlalte cimpuri
// din articol
// ----------------------------------
// repozitionare pe articol
feek(f,ftell(f)-sizeof(tip_articol),SEEK_SET);
// rescriere articol modificat
fwrite(&art,sizeof(tip_articol),1,f);
}

O alt variant se poate realiza prin folosirea unei machete de ecran n care se afieaz
valorile actuale ale fiecrui cmp de modificat, se poziioneaz succesiv cursorul la nceputul
fiecrui cmp, cu dou rspunsuri posibile ale utilizatorului: <ENTER>, caz n care se menine
actuala valoare, respectiv o tast diferit de <ENTER>, reprezentnd primul caracter al noii
valori.

Teste de autoevaluare
4. Fie fiierul creat la exemplul 3. Scriei un program care nregistreaz n fiier
producia realizat de societatea comercial ntr-o anumit lun a anului, pentru un
anumit produs. Programul trebuie s ofere posibilitatea repetrii operaiei pentru mai multe
produse i diverse luni. Datele se preiau de la tastatur iar terminarea prelucrrii este marcat
standard.


4.3. Algoritmi de prelucrare a fiierelor binare care necesit actualizare

Prelucrarea fiierelor binare care necesit actualizare trebuie s asigure posibilitatea
tergerii articolelor i s elimine riscul de suprascriere a articolelor adugate. Pentru aceasta,
trebuie proiectate structuri particulare de articole i concepute operaii de gestiune specifice.

Fr a epuiza multitudinea soluiilor de rezolvare a problemelor de gestiune a fiierelor
care necesit actualizare, n continuare, se prezint cteva soluii posibile. n orice situaie,
limitrile de regsire prin acces secvenial sau relativ a articolelor n fiier reduc aria folosirii
limbajului n probleme de gestiune. Marele inconvenient l constituie lipsa accesului dup cheie,
cel care corespunde cel mai bine gestiunii n sistemele reale.

n cele ce urmeaz se analizeaz trei tipuri de probleme: probleme n care se utilizeaz
asocierea extern a numrului relativ la articolul corespunztor (codificare prin numr relativ);
probleme n care se utilizeaz asocierea intern a numrului relativ la articolul corespunztor iar
acesta poate emana extern (se genereaz nomenclatoare dup fiecare actualizare de fiier);
probleme n care se utilizeaz extern coduri (chei) i intern numere relative.

4.3.1. Codificarea extern prin numere relative
Nomenclatorul de articole conine numrul relativ al fiecruia dintre ele. Nomenclatorul
este elaborat extern (automat sau neautomat). Orice operaie de regsire n acces relativ
presupune introducerea din exterior a numrului relativ. La crearea iniial, fiecare articol este
nscris n poziia indicat de numrul su relativ predefinit. Asigurarea tergerii i adugrii
* material didactic pentru ID * 77
controlate poate fi fcut n diverse moduri.

Extinderea articolelor logice cu un indicator de stare (un octet), ajungndu-se la forma din
figura 4.7.

IS Articol propriu-zis

Fig. 4.7. Structura articolului care include indicatorul de stare

Indicatorul de stare (notat IS) poate lua una din cele dou valori posibile (de exemplu 0
pentru articol inactiv inexistent sau ters, 1 pentru articol prezent). Cu aceast convenie,
operaiile de acces la articole se realizeaz n urmtoarele condiii: scrierea n fiier este permis
numai pentru articolele cu IS=0; citirea din fiier este permis numai pentru articolele cu IS=1.

Preformarea presupune deschiderea fiierului ca nou (crearea unui fiier nou) i scrierea
unui numr de articole (la limit, zero) cu IS=0. Includerea operaiei de preformare conduce la
dispariia distinciei dintre populare i adugare. Datorit faptului c fiierul se deschide ca
existent, orice operaie de scriere a unui nou articol se trateaz ca adugare. ntr-un sistem de
programe, deschiderea cu modul wb a unui fiier se realizeaz o singur dat, n procedura de
preformare.

Scrierea n acces direct presupune furnizarea numrului relativ (nr) al articolului. n
funcie de valoarea lui nr se disting urmtoarele situaii:
- dac nr<dimensiune fiier, se citete articolul respectiv din fiier i adugarea este
permis numai dac IS=0;
- dac nr>=FileSize(f), are loc extinderea fiierului cu preformarea articolelor cu
numerele relative cuprinse n domeniul dimensiune fiier..nr-1. Noul articol se scrie pe poziia
nr.
Se remarc faptul c scrierea n acces direct permite preformarea iniial cu zero
articole.
Scrierea n acces secvenial se face fr verificare de existen. Scrierea are loc n
poziia dat de pointerul curent. Procedura face IS=1. Utilizarea ei se recomand numai la
popularea dens.
Citirea n acces direct presupune furnizarea numrului relativ (nr). Ea verific dac
IS=1.
Citirea n acces secvenial analizeaz articolele ncepnd cu cel de la pointerul curent.
Articolele cu IS=0 snt ignorate, pn la ntlnirea primului articol cu IS=1 sau pn se ajunge la
sfrit de fiier.
tergerea se realizeaz n acces direct. Ea presupune citirea articolului i dac tergerea
este permis (IS=1), se modific indicatorul de stare (IS=0) i se scrie articolul pe vechiul loc.
Rescrierea realizeaz scrierea unui articol n poziia ftell(f)-sizeof(tip_articol), dac
vechiul articol din aceast poziie are IS=1.

Teste de autoevaluare
5. Fie structura logic de articol de la tema de autoevaluare 3. Considernd numrul
matricol cheie relativ, scriei un program care creeaz i populeaz un fiier
organizat relativ cu articole referitoare la studenii universitii.

Folosirea articolului zero ca tabel de ocupare n fiier.
Fiecrui articol din fiier i corespunde cte un octet n primul articol: articolului cu
numrul relativ i i corespunde octetul a[i]. Primul articol are structura char a[max], unde max
este o constant care indic numrul maxim de articole pe care le poate avea fiierul pe durata
Algoritmi n programare 78
existenei sale. Dac articolul i este prezent, a[i]=1; dac articolul i este inactiv (inexistent sau
ters), a[i]=0.
Cu aceast structur, operaiile de acces la articole se realizeaz n urmtoarele condiii:
scrierea n fiier a articolului cu numrul relativ i este permis numai dac a[i]=0; citirea din
fiier a articolului cu numrul relativ i este permis numai dac a[i]=1.
tergerea articolului i presupune verificarea existenei sale (a[i]=1) i realizarea
operaiei a[i]=0. Adugarea unui articol i presupune verificarea inexistenei lui (a[i]=0),
nscrierea articolului i realizarea operaiei a[i]=1.

Utilizarea acestei modaliti necesit ncrcarea iniial n memoria principal a
articolului cu numrul relativ zero. n programele care realizeaz tergeri sau/i adugri,
nainte de nchiderea fiierului trebuie rescris articolul zero n fiier.

Datorit restriciei impuse pentru numrul de articole din fiier, acest model de gestiune
a articolelor este ineficient pentru multe probleme. Se pot concepe algoritmi prin care n tabela
de ocupare n fiier fiecrui articol i corespunde un bit, n loc de un octet. n acest fel numrul
maxim de articole ce pot fi adugate n fiier se mrete de 8 ori.

4.3.2. Codificarea intern prin numere relative
nscrierea articolelor n fiiere, chiar cea iniial, se face n primele articole inactive,
asociindu-se astfel intern un numr relativ fiecrui articol.
Deosebirea esenial ntre aceast soluie i cea prezentat anterior, const n modul de
realizare a adugrii secveniale. Dup fiecare sesiune de actualizare va trebui listat
nomenclatorul de coduri interne (numere relative). Articolelor din fiier li se asociaz structura
din figura 4.7. Preformarea, consultarea, modificarea i tergerea snt similare celor prezentate
n 4.3.1. Adugarea unui articol se realizeaz n condiii diferite, dup cum aceast operaie are
loc printre articolele existente, respectiv dup ultimul articol (extindere). n ambele situaii,
condiiile de realizare snt determinate de modul de acces folosit: secvenial sau direct.

Adugarea n acces secvenial se bazeaz pe presupunerea c utilizatorul nu impune o
coresponden prestabilit ntre coninut i numrul articolului, adic n ali termeni, c se
accept o codificare automat. Adugarea n acces secvenial poate fi utilizat n dou variante:

Cu verificarea existenei de articole libere, caz n care se adaug noul articol n prima
poziie gsit disponibil (IS=0), eventual la sfrit (extindere), dac nu mai exist articole libere
n interior. Aceast variant presupune existena unei soluii de gestiune a articolelor libere (n
urma preformrii sau a tergerii logice).
Dintre soluiile posibile pot fi menionate:

Folosirea articolului zero pentru colectarea numrului articolelor libere, ntr-o
structur de forma celei din figura 4.8.

nal al[1] al[2] ... al[nal]
Articolul 0
WORD WORD WORD ... WORD
Fig. 4.8. Structura articolului zero, pentru gestiunea articolelor libere

n aceast soluie, nal este numrul articolelor libere i al[i], cu i=1..nal, reprezint
poziiile relative ale articolelor libere. Soluia prezint avantajul timpului redus de cutare i de
atribuire a unei poziii pentru noul articol. Numrul de articole libere ce pot fi gestionate n acest
mod este limitat de descrierea articolelor principale ale fiierului. De exemplu, dac articolul
* material didactic pentru ID * 79
principal are 128 de octei, aceast soluie permite gestionarea a 63 de articole libere (dac se
impune pentru articolul zero aceeai lungime ca i pentru celelalte articole; pentru primul articol
se poate accepta i o dimensiune diferit mai mare dar nu cu mult mai mare i oricum este o
dimensiune stabilit de la nceput, care nu mai poate fi mrit la nevoie). La tergerea logic a
unui articol se realizeaz incrementarea valorii lui nal, iar al[nal] primete ca valoare numrul
relativ al articolului ters.

Folosirea articolului zero ca nceput al unei liste simple (sau dublu) nlnuite a
articolelor libere, ntr-o structur de principiu de forma celei din figura 4.9.

pal ual
0 au 0 au 0 au ...
...

Fig. 4.9. Gestionarea articolelor libere prin liste

n aceast soluie, articolul zero puncteaz pe primul (pal) i pe ultimul (ual) articol
liber, iar fiecare articol puncteaz pe urmtorul (au).

Numrul articolelor libere care pot fi gestionate n acest mod este oarecare. La
adugarea unui nou articol, se verific dac exist articole libere (pal<>0) i dac exist, se
atribuie primul articol din list articolului de adugat, actualizndu-se componenta articolului
zero. La tergerea unui articol, trebuie asigurat includerea sa n lista articolelor libere, operaia
fiind posibil la oricare din capetele listei.

Cutarea secvenial a primului articol liber, fr organizarea unei gestiuni a acestora.
Dei mai costisitoare ca timp de cutare, aceasta este soluia cea mai simpl sub aspectul
programrii, eliminnd necesitatea unei structuri distincte a articolului zero i operaiile
legate de ntreinerea coleciei sau listei articolelor libere.
n concluzie, este de preferat ultima variant atunci cnd timpul de cutare nu este
prohibitiv.

Fr verificarea existenei de articole libere, caz n care articolul este adugat direct la
sfrit (extindere). Aceast variant este avantajoas cnd are loc introducerea de la nceput a
majoritii articolelor. Ea poate fi asociat cu preformarea cu zero articole, fiecare sesiune de
adugare de noi articole fiind realizat prin extinderea fiierului.

Adugarea n acces direct presupune o codificare anterioar (preluarea numrului relativ din
nomenclatorul editat dup fiecare creare/ adugare secvenial) i se realizeaz identic cu
operaia de scriere direct prezentat n 4.3.1.

4.3.3. Corespondena intern dintre chei i numere relative
Majoritatea aplicaiilor de gestiune economic utilizeaz fiiere de date n care articolele
trebuie regsite dup valorile unui cmp de identificare, numit cheie. Problema corespondenei
ntre chei i numerele relative ale articolelor din fiierul de date se poate rezolva prin
intermediul unui fiier binar suplimentar, cu rol de tabel de indexuri. O astfel de organizare se
numete indexat. Articolele fiierului tabel de indexuri au structura din figura 4.10.
Algoritmi n programare 80
IS Cheie Numr relativ (nr)
Fig. 4.10. Structura articolului din tabela de indexuri

Indicatorul de stare (IS) are rol identic cu cel prezentat n 4.3.1. Cheie este un cmp n
care se memoreaz valoarea cheii articolului existent logic n fiierul de date, al crui numr
relativ corespunztor este memorat n cmpul nr. Articolele tabelei de indexuri snt, n orice
moment, sortate cresctor dup valorile cmpului cheie. Articolele din fiierul de date snt
memorate aleator. O parte dintre acestea nu-i regsesc corespondent n tabela de indexuri, fiind
considerate terse. Orice operaie de acces la articolele fiierului de date se realizeaz numai
prin intermediul tabelei, gestionat automat de funciile unei biblioteci specializate i care este
netransparent utilizatorului (bibliotec utilizator, nu face parte din limbaj).

Operaiile de acces la nivel de fiier snt deschiderea i nchiderea fiierului de date. La
rndul ei, deschiderea poate fi pentru creare (ca fiier nou) sau pentru consultare i ntreinere
(ca fiier vechi). Procedurile realizeaz, pe lng operaiile asupra fiierului de date i
gestionarea automat a tabelei de indexuri: formarea numelui su extern, asignarea numelui
fizic la numele logic, deschiderea ca fiier nou sau vechi, nchiderea. Operaiile de gestiune ce
se pot realiza cu fiierele de date astfel organizate snt:

Crearea n acces secvenial presupune furnizarea articolelor sortate strict cresctor dup
valorile cmpului ales drept cheie. Articolele snt scrise cu ajutorul funciei de scriere n acces
secvenial. Eroarea de cheie invalid poate aprea la tentativa de scriere a unui articol a crui
cheie este mai mic sau egal dect ultima nscris n fiierul de date.

Crearea n acces direct se realizeaz cu funcia de scriere n acces direct, articolele fiind
furnizate n orice ordine. Eroarea de cheie invalid apare la tentativa de scriere a unui articol a
crui cheie este egal cu una din cele prezente n fiier.

Consultarea n acces secvenial presupune regsirea articolelor n ordinea strict cresctoare
a valorilor cheii. Ea se realizeaz cu ajutorul funciei de citire n acces secvenial, care
detecteaz i sfritul fiierului de date.

Consultarea n acces mixt permite selectarea unui grup de articole, memorate logic
contiguu n fiier, selecie realizat pe baza valorilor cheii primului i ultimului articol din
grupul dorit. Accesul mixt presupune poziionarea pe primul articol prin citirea n acces direct
(sau poziionare i citire n acces secvenial), urmat de exploatarea n acces secvenial, pn la
gsirea cheii ultimului articol dorit, sau pn la sfritul fiierului.

Adugarea de articole se realizeaz utiliznd funcia de scriere n acces direct. Articolele
pot fi furnizate n orice ordine a valorilor cheii. Eroarea de cheie invalid apare la tentativa de
scriere a unui articol a crui cheie este egal cu una deja existent.

Modificarea unor cmpuri din articol se realizeaz n urmtoarele etape:
citirea articolului de modificat (n acces secvenial sau direct);
modificarea, n zona articol corespunztoare, a cmpurilor dorite, cu excepia cmpului
cheie;
rescrierea articolului, cu procedura de rescriere. Eroarea de cheie invalid apare n cazul
tentativei de rescriere a unui articol a crui cheie este diferit de cea a articolului citit
anterior.

* material didactic pentru ID * 81
tergerea n acces secvenial elimin articolul curent din fiierul de date. n general,
articolul trebuie mai nti identificat printr-o citire (n acces secvenial sau direct) sau prin
poziionare. Procedura returneaz eroare n cazul tentativei de tergere dup ultimul articol
existent.

tergerea n acces direct elimin articolul a crui cheie este precizat. Operaia nu trebuie
precedat de citirea articolului i returneaz eroare n cazul furnizrii unei chei inexistente n
fiier. n aplicaii, este preferabil tergerea n acces secvenial, deoarece permite (datorit citirii
care o precede), vizualizarea articolului i luarea unei decizii n condiii de siguran.

Exemplu
11. Exemplul urmtor descrie funcii, tipuri de date i variabile publice pentru
prelucrarea unui fiier organizat indexat. Pentru aceste exemplu, fiierul de date este format din
articole cu urmtoarea structur:

cheie denumire pre cantitate
Fig. 4.11. Structura articolului din tabela de indexuri

Exemplul poate fi adaptat pentru orice alt structur, modificnd corespunztor structura
articolului. n acest exemplu, fiierul index va fi o variabil global, accesibil tuturor
subprogramelor. Tipurile definite snt urmtoarele:

typedef struct{ char cheie[7];
char den[35];
float pu;
float cant;
} ARTICOL; //tipul articol din fisierul de date

typedef struct{ char is;
char cheie[7];
long nr_rel;
} ART_INDEX; //tipul articol din tabela de indexuri

FILE* ind; //fisierul index
char nume_index[20]; //numele extern al fisierului index

Pentru implementarea operaiilor de gestiune specifice unui fiier organizat indexat snt
necesare urmtoarele subprograme:

Funcia de deschidere a tabelei index ca fiier nou, cu prototipul

void new_index(char *nume);

Funcia primete ca parametru numele extern al fiierului de date (nume) i creeaz un fiier
nou, tabela de indexuri, cu extensia .idx.

Funcia de deschidere a tabelei de indexuri, pentru consultare i ntreinere, cu
prototipul

void open_index(char *nume);

Funcia primete ca parametru numele extern al fiierului de date (nume), i deschide ca exis-
tent tabela de indexuri, cu extensia .idx.

Algoritmi n programare 82
Funcia de nchidere a tabelei de indexuri, cu prototipul

void closeindex();

Funcia realizeaz nchiderea tabelei de indexuri asociate fiierului de date.

Funcia pentru citirea n acces secvenial a unui articol din fiierul de date, cu prototipul

int ReadSec(fisier f,articol *a);

Funcia are ca parametri numele intern al fiierului de date i adresa unde se depune articolul
citit, dac acest lucru este posibil i returneaz
- 1, dac citirea a fost posibil;
- 0, n caz contrar.
Citirea unui articol din fiierul de date este realizat prin intermediul tabelei de inde-
xuri, astfel: este citit un articol din tabel, de la poziia curent a pointerului de fiier i apoi
este citit articolul cu numrul relativ dat de cmpul nr_rel al articolului citit din fiierul de in-
dexuri. Dac, n tabela de indexuri, pointerul de fiier indic sfritul de fiier, atunci citirea
nu este posibil i funcia returneaz valoarea 0. Prin apelul repetat al funciei ReadSec, dac
tabela de indexuri are poinetrul plasat naintea primului articol, snt obinute articolele din fi-
ierul de date n ordinea strict cresctoare a valorii cheii.

Funcia pentru citirea n acces direct a unui articol din fiierul de date, cu prototipul

int ReadKey(fisier f,articol *a,char *Key);

Funcia are ca parametri numele intern al fiierului de date, adresa unde se depune articolul ci-
tit, dac acest lucru este posibil, precum i cheia articolului care va fi citit i returneaz
- 1, dac citirea a fost posibil;
- 0, n caz contrar.
Funcia apeleaz modulul de cutare binar n tabela de indexuri a cheii Key, SeekKey.
Dac cheia este gsit, citete articolul cu numrul relativ corespunztor articolului din tabela
de indexuri i returneaz valoarea 1, altfel returneaz valoarea 0.

Funcia pentru scrierea n acces secvenial a unui articol n fiierul de date, cu prototipul

int WriteSec(fisier f,articol a);

Funcia are ca parametri numele intern al fiierului de date i articolul ce va fi scris, dac acest
lucru este posibil, i returneaz
- 1, dac scrierea a fost posibil;
- 0, n caz contrar.
Funcia adaug un articol n fiierul de date, concomitent cu extinderea tabelei de in-
dexuri cu o nou nregistrare, a crei cheie este mai mare dect cele existente. n cazul n care
cheia este mai mic sau egal cu a ultimului articol din tabel, este returnat valoarea 0, co-
respunztoare situaiei n care scrierea nu este posibil.

Funcia pentru scrierea n acces direct a unui articol n fiierul de date, cu prototipul

int WriteKey(fisier f,articol a);

Funcia are ca parametri numele intern al fiierului, articolul ce va fi scris, dac acest lucru es-
* material didactic pentru ID * 83
te posibil, i returneaz
- 1, dac scrierea a fost posibil;
- 0, n caz contrar.
Funcia adaug un articol la sfritul fiierului de date. Cheia acestuia, a.cheie, poate
avea orice valoare (care nu exist deja n tabela de indexuri). Iniial, tabela se extinde cu un
nou articol i apoi este reordonat (prin apelul funciei Sort). n cazul n care cheia articolului
de scris este deja prezent n tabela de indexuri, articolul nu este scris n fiier i funcia retur-
neaz valoarea 0. Cutarea cheii n tabela de indexuri pentru stabilirea posibilitii scrierii este
realizat prin apelul funciei SeekKey.

Funcia pentru tergerea n acces secvenial a unui articol, cu prototipul

int DeleteSec();

Funcia returneaz
- 1, dac tergerea a fost posibil;
- 0, n caz contrar.
Funcia terge logic articolul curent din fiierul de date. tergerea se realizeaz fizic n
tabela de indexuri. Iniial, indicatorul de stare este setat pe 0 i apoi se elimin articolul din
tabel, prin apelul funciei Sort. Funcia returneaz valoarea 0, corespunztoare situaiei de
eroare, dac pointerul curent al tabelei de indexuri indic marcatorul de sfrit de fiier.

Funcia pentru tergerea n acces direct a unui articol, cu prototipul

int DeleteKey(char *Key);

Funcia primete ca parametru de intrare cheia articolului care va fi ters i returneaz
- 1, dac tergerea a fost posibil;
- 0, n caz contrar.
Funcia terge logic din fiierul de date articolul a crui cheie este primit ca parame-
tru. tergerea este realizat fizic din tabela de indexuri, analog tergerii n acces secvenial.
Funcia returneaz valoarea 0, corespunztoare situaiei de eroare, dac Key nu este regsit n
tabela de indexuri. Cutarea este realizat prin apelul funciei SeekKey.

Pentru implementarea funciilor descrise mai sus, snt utilizate urmtoarele funcii au-
xiliare:

Funcia pentru sortarea tabelei de indexuri, cu eliminarea articolelor cu stare 0, cu
prototipul

void Sort();

Funcia realizeaz sortarea articolelor tabelei de indexuri, cresctor dup cmpul cheie, pre-
cum i tergerea fizic a tuturor articolelor cu indicator de stare 0.

Funcia pentru cutarea articolului cu cheie dat, cu prototipul

int SeekKey(char *Key)

Funcia primete ca parametru de intrare cheia articolului cutat i returneaz
- 1, dac articolul a fost gsit;
Algoritmi n programare 84
- 0, n caz contrar.
Funcia realizeaz cutarea binar n tabela de indexuri, dup cmpul cheie. Dac arti-
colul cu cheia Key este gsit, funcia las pointerul de fiier pe acel articol (o citire secvenial
ulterioar determinnd obinerea articolului corespunztor din fiierul de date).

Exemplu
Textul surs care implementeaz toate aceste funcii C este prezentat n continuare (n
exemplele care urmeaz, aceste text va fi considerat salvat n fiierul index1.cpp).

#include <stdio.h>
#include <string.h>

#define fisier FILE*
typedef struct{ char cheie[7];
char den[35];
float pu;
float cant;
} ARTICOL; //tipul articol din fisierul de date

typedef struct{ char is;
char cheie[7];
long nr_rel;
} ART_INDEX; //tipul articol din tabela index

fisier ind; //fisierul index
char nume_index[20]; //numele extern al fisierului index

void Sort()
{ ART_INDEX a,b;
fisier ind1;
long i,j;
ind1=fopen("temp.idx","wb+");
rewind(ind);
fread(&a,sizeof(a),1,ind);
while(!feof(ind))
{ if(a.is)fwrite(&a,sizeof(a),1,ind1);
fread(&a,sizeof(a),1,ind);
}
fclose(ind);
fseek(ind1,0,SEEK_END);
long n=ftell(ind1)/sizeof(a);
for(i=0;i<n-1;i++)
{ fseek(ind1,i*sizeof(a),SEEK_SET);
fread(&a,sizeof(a),1,ind1);
for(j=i+1;j<n;j++)
{ fseek(ind1,j*sizeof(a),SEEK_SET);
fread(&b,sizeof(a),1,ind1);
if(strcmp(a.cheie,b.cheie)>0)
{ fseek(ind1,i*sizeof(a),SEEK_SET);
fwrite(&b,sizeof(a),1,ind1);
fseek(ind1,j*sizeof(a),SEEK_SET);
fwrite(&a,sizeof(a),1,ind1);
}
}
}
rewind(ind1);
ind=fopen(nume_index,"wb+");
fread(&a,sizeof(a),1,ind1);
while(!feof(ind1))
{ if(a.is)fwrite(&a,sizeof(a),1,ind);
fread(&a,sizeof(a),1,ind1);
}
fclose(ind1);
remove("temp.idx");
}
* material didactic pentru ID * 85

/* cautarea articolului cu cheia Key si plasarea pointerului de fisier in ta-
bela de indexuri pe articolul respectiv*/

int SeekKey(char *Key)
{ long ls=0, ld, m, n;
ART_INDEX a;
int gasit=0;
fseek(ind,0,SEEK_END);
n=ftell(ind)/sizeof(ART_INDEX);
ld=n-1;
while((ls<=ld)&&(!gasit))
{ m=(ls+ld)/2;
fseek(ind,m*sizeof(a),SEEK_SET);
fread(&a,sizeof(a),1,ind);
if(strcmp(a.cheie,Key)==0) gasit=1;
else if(strcmp(a.cheie,Key)>0) ld=m-1;
else ls=m+1;
}
if(gasit) fseek(ind,m*sizeof(a),SEEK_SET);
return gasit;
}

void new_index(char *nume)
{ strcpy(nume_index,nume);
strcat(nume_index,".idx");
ind=fopen(nume_index,"wb+");
}

void open_index(char *nume)
{ strcpy(nume_index,nume);
strcat(nume_index,".idx");
ind=fopen(nume_index,"rb+");
}

void close_index()
{ fclose(ind);
}

int ReadSec(fisier f,ARTICOL *a)
{ ART_INDEX a1;
int r;
fread(&a1,sizeof(a1),1,ind);
if(feof(ind))r=0;
else { fseek(f,a1.nr_rel*sizeof(*a),SEEK_SET);
fread(a,sizeof(*a),1,f);
r=1;
}
return r;
}

int ReadKey(fisier f,ARTICOL *a,char *Key)
{ ART_INDEX a1;
int r;
if(SeekKey(Key))
{ fread(&a1,sizeof(a1),1,ind);
fseek(f,a1.nr_rel*sizeof(*a),SEEK_SET);
fread(a,sizeof(*a),1,f);
r=1;
}
else r=0;
return r;
}

int WriteSec(fisier f,ARTICOL a)
{ ART_INDEX a1, ai;
long n, nl;
int r;
Algoritmi n programare 86
fseek(ind,0,SEEK_END);
n=ftell(ind)/sizeof(a1);
if(n>0)
{ fseek(ind,(n-1)*sizeof(a1),SEEK_SET);
fread(&a1,sizeof(a1),1,ind);
if(strcmp(a1.cheie,a.cheie)>0) r=0;
else { ai.is=1;
strcpy(ai.cheie,a.cheie);
fseek(f,0,SEEK_END);
n1=ftell(f)/sizeof(a);
ai.nr_rel=n1;
fseek(ind,0,SEEK_END);
fwrite(&ai,sizeof(ai),1,ind);
fwrite(&a,sizeof(a),1,f);
r=1;
}
}
else r=0;
return r;
}

int WriteKey(fisier f,ARTICOL a)
{ char Key[7];
ART_INDEX a1;
long n;
strcpy(Key,a.cheie);
if(SeekKey(Key)) r=0;
else { a1.is=1;
strcpy(a1.cheie,a.cheie);
fseek(f,0,SEEK_END);
n=ftell(f)/sizeof(a);
a1.nr_rel=n;
fwrite(&a,sizeof(a),1,f);
fseek(ind,0,SEEK_END);
fwrite(&a1,sizeof(a1),1,ind);
Sort();
r=1;
}
return r;
}

int DeleteSec()
{ ART_INDEX a1;
long pos=ftell(ind);
fread(&a1,sizeof(a1),1,ind);
if(feof(ind)) r=0;
else { fseek(ind,pos,SEEK_SET);
a1.is=0;
fwrite(&a1,sizeof(a1),1,ind);
Sort();
r=1;
}
return r;
}

int DeleteKey(char *Key)
{ int r;
if(SeekKey(Key))
r=DeleteSec();
else r=0;
return r;
}

Exemplu
12. Scriei programul C pentru crearea n acces direct unui fiier binar cu articole
avnd structura:
cheie denumire pre cantitate
* material didactic pentru ID * 87
Datele snt preluate de la tastatur pn la apsarea combinaiei CTRL/Z pentru cmpul cheie.
Fiierul creat este organizat indexat.

#include "index1.cpp"
#include <conio.h>
void main()
{ ARTICOL a;
char nume[20],nume1[20];
char x[7];
fisier f;
clrscr();
printf(" numele fisierului de date in care adaugati:");
fflush(stdin);
gets(nume);
strcpy(nume1,nume);
strcat(nume1,".dat");
f=fopen(nume1,"rb+");
if(f==NULL)
{ printf("Fisierul va fi creat");
f=fopen(nume1,"wb+");
new_index(nume);
}
else open_index(nume);
printf("\nAdaugarea in acces direct dupa cheie\n");
printf("Introduceti cheia:");
fflush(stdin);
gets(a.cheie);
while(!feof(stdin))
{ printf("Denumire produs:");
fflush(stdin);
gets(a.den);
printf("Pret produs:");
scanf("%f",&a.pu);
printf("Cantitate:");
scanf("%f",&a.cant);
if(WriteKey(f,a))
printf("Articol adaugat");
else printf("Exista articol");
getch();
clrscr();
printf("Introduceti cheia:");
fflush(stdin);
gets(a.cheie);
}
fclose(f);
close_index();
getch();
}

Exemplu
13. Se presupune creat i populat fiierul de date din exemplul anterior. Scriei pro-
gramul C pentru tergerea acelor articole ale cror chei snt introduse de la tastatur. ncheie-
rea introducerii datelor este marcat standard.

#include "index1.cpp"
#include <conio.h>

void main()
{ ARTICOL a;
char nume[20],nume1[20];
char Key[7];
fisier f;
char r;
int i;
clrscr();
Algoritmi n programare 88
printf(" numele fisierului de date din care stergeti:");
fflush(stdin);
gets(nume);
strcpy(nume1,nume);
strcat(nume1,".dat");
f=fopen(nume1,"rb+");
if(f==NULL)
printf("Fisierul nu exista!!");
else
{ open_index(nume);
printf("\nStergerea in acces direct dupa cheie\n");
printf("Introduceti cheia:");
fflush(stdin);
gets(Key);
while(!feof(stdin))
{ if(ReadKey(f,&a,Key))
{ printf("Articolul:\n");
printf("Denumire:%20s\n",a.den);
printf("Pret:%7.2f\n",a.pu);
printf("Cantitate:%8.2f\n\n",a.cant);
printf("Doriti stergerea?(D/Altceva)");
r=getch();
if(r=='D')
{ i=DeleteKey(Key);
printf("Stergere efectuata");
}
else printf("Stergerea nu a fost efectuata");
}
else printf("Nu exista articol");
getch();
clrscr();
printf("Introduceti cheia:");
fflush(stdin);
gets(a.cheie);
}
fclose(f);
close_index();
getch();
}
}

Exemplu
14. Scriei programul C pentru afiarea informaiilor memorate n fiierul creat mai
sus. Articolele snt afiate n ordine cresctoare a cmpului cheie.

#include "index1.cpp"
#include <conio.h>
void main()
{ ARTICOL a;
char nume[20],nume1[20];
char x[7];
fisier f;
clrscr();
printf(" numele fisierului de date care este consultat:");
fflush(stdin);
gets(nume);
strcpy(nume1,nume);
strcat(nume1,".dat");
f=fopen(nume1,"rb+");
if(f==NULL) printf("Fisierul nu exista!!");
else { open_index(nume);
while(ReadSec(f,&a))
{ printf("Cheie:");
puts(a.cheie);
printf("\nDenumire produs:");
puts(a.den);
* material didactic pentru ID * 89
printf("Pret produs:");
printf("7.2%f\n",a.pu);
printf("Cantitate:");
printf("%8.2f\n\n",a.cant);
getch();
}
fclose(f);
close_index();
getch();
}
}


4.4. Sortarea fiierelor binare memorate dens

Operaia de sortare a unui fiier binar presupune aranjarea articolelor n ordinea
cresctoare (descresctoare) a valorilor unei zone, numit cheie de sortare. n cazul n care
cheia de sortare este format dintr-un singur cmp din cadrul articolului, operaia se numete
sortare simpl. Sortarea multipl presupune aranjarea articolelor dup valorile a dou sau mai
multe cmpuri, alctuind, prin juxtapunere, cheia de sortare. Juxtapunerea cmpurilor (nu
neaprat adiacente n cadrul articolului) se realizeaz pe lungimea efectiv a lor, alctuind
forma canonic a cheii de sortare. De exemplu, dac NUME i PRENUME snt dou cmpuri
distincte, declarate de tip ir de caractere, forma canonic a cheii de sortare dup nume i
prenume este dat de lungimea efectiv a fiecrei date de tip ir.

Dac pentru sortarea simpl cheia de sortare poate fi nsui cmpul din articol, pentru
cea multipl este necesar o zon auxiliar de memorie, n care se construiete cheia de sortare,
n forma canonic.
Sortarea unui fiier se poate realiza cu aducerea lui integral n memorie (sortare n
memorie) sau cu aducerea n memorie a cte unui articol (sortare "direct pe disc"). Indiferent de
modul utilizat, sortarea poate fi realizat printr-unul din algoritmii cunoscui pentru masivele de
date: sortare prin interschimbare, prin selecie, prin inserie etc.

Sortarea n memorie este o metod rapid i presupune: citirea ntregului fiier n
memoria principal, ntr-o structur intern de date (vector, arbore bina de sortare); sortarea
efectiv dup cheia de sortare (n cazul folosirii unui vector, operaia nu este necesar dac se
folosete arbore de sortare); recrearea fiierului pe disc.

Atenie: datorit dimensiunii mari a fiierelor de date i dimensiunii limitate a
memoriei, aceasta metod este contraindicat. Metoda se poate aplica numai fiierelor
de dimensiune mic.
Aceast metod poate fi implementat n mai multe variante:

Sortarea cu vehicularea ntregului articol, presupune memorarea ntregului fiier ntr-
un vector de articole. Compararea pentru sortare se va realiza pe cmpul cheie de sortare, ns
interschimbarea se realizeaz la nivelul ntregului articol.

Exemplu
15. Sortarea cu vehicularea ntregului articol.

typedef struct { char grupa;
char nume_student[30];
float medie;
} STUDENT;
Algoritmi n programare 90
void main()
{ FILE* f;
STUDENT x[250], aux;
int i,j,n;
f=fopen("STUDENT.DAT","rb+");
fseek(f,0,SEEK_END);
n:=ftell(f)/sizeof(STUDENT);
rewind(f);

// citirea fisierului initial in memorie
for(i=0;i<n;i++)
fread(&x[i],sizeof(STUDENT),1,f);

//sortarea
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(x[i].medie>x[j].medie)
{ aux:=x[i]; //interschimbarea articolelor
x[i]:=x[j]; //nu se poate folosi atribuirea mereu
x[y]:=aux;
}
rewind(f);

//rescrierea fiierului pe disc
for(i=0;i<n;i++)
fwrite(&x[i],sizeof(STUDENT),1,f);
fclose (f); }

Sortarea cu vehicularea cheii i indexului, presupune memorarea ntr-un vector numai a
valorii cheii de sortare, mpreun cu numrul relativ al articolului din fiierul iniial (indexul).
Interschimbarea se va realiza la nivelul cheii de sortare, rezultnd n final ordinea n care
articolele vor fi scrise n fiier. Deoarece articolele, n ntregime, snt rezidente pe disc, fiierul
sortat va fi creat cu un alt nume fizic, n acces secvenial, prelund articolele din fiierul iniial,
n acces direct. Cheile de sortare i indexurile pot fi memorate n vectori distinci sau ntr-unul
singur, cu elemente de tip articol.

Exemplu
16. Sortare cu vehicularea cheii i indexului.

typedef struct { char grupa;
char nume_student[30];
float medie;
} STUDENT;

typedef struct { float medie;
int index;
} CHEIE;
void main()
{ FILE *f,*g;
STUDENT y;
CHEIE aux,x[250];
int i,j,n;
f=fopen("STUDENT.DAT","rb");
fseek(f,0,SEEK_END);
n:=ftell(f)/sizeof(STUDENT);
rewind(f);
g=fopen("STUDENTS.DAT","wb");

// ----- incarcare chei si indexuri in memorie -----
for(i=0;i<n;i++)
{ fread(&y,sizeof(STUDENT),1,f);
x[i].medie=y.medie;
x[i].index=i;
}
* material didactic pentru ID * 91

// ----- sortare vector de chei --------------------
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(x[i].medie>x[j].medie)
{ aux=x[i];
x[i]:=x[j];
x[j]:=aux
}

// ----- creare fisier nou, sortat -----------------
for(i=0;i<n;i++)
{ fseek(f,x[i].index*sizeof(STUDENT),SEEK_SET);
fread(&y,sizeof(STUDENT),1,f);
fwrite(&y,sizeof(STUDENT),1,g);
}
fclose(f);
fclose(g);
unlink(f);
rename("STUDENTS.DAT","STUDENT.DAT");
}

Sortarea numai cu vehicularea indexului este o metod mai bun dect precedenta,
deoarece micoreaz timpul de execuie, prin eliminarea interschimbrii valorilor cheii de
sortare (mai ales cnd aceasta este multipl). Valorile cheii de sortare i numrului relativ
corespunztor indexului se memoreaz n vectori distinci. Comparaiile se realizeaz pentru
valorile cheii, dar interschimbarea se efectueaz numai pentru indexuri. Se va crea un alt fiier
fizic.

Exemplu
17. Sortare cu vehicularea indexului.

typedef struct { char grupa;
char nume_student[30];
float medie;
}STUDENT;

void main()
{ FILE *f,*g;
float x[250];
int index[250];
int i,j,n;
STUDENT y;
f=fopen("STUDENT.DAT","rb");
fseek(f,0,SEEK_END);
n:=ftell(f)/sizeof(STUDENT);
rewind(f);
g=fopen("STUDENTS.DAT","wb");

// ------------------------------------------
for(i=0;i<n;i++)
{ fread(&y,sizeof(STUDENT),1,f);
x[i]=y.medie;
index[i]=i;
}

// ------------------------------------------
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(x[i]>x[j])
{ aux=index[i];
index[i]=index[j];
index[j]=aux
}
Algoritmi n programare 92

// -------------------------------------------
for(i=0;i<n;i++)
{ fseek(f,index[i]*sizeof(STUDENT),SEEK_SET);
fread(&y,sizeof(STUDENT),1,f);
fwrite(&y,sizeof(STUDENT),1,g);
}
fclose(f);
fclose(g)
}

Sortarea pe disc se aplic fiierelor mari, la care este imposibil aducerea n memoria
principal chiar i a minimului de informaii necesare sortrii. n acest caz, operaia se va realiza
"direct" pe mediul magnetic, cu aducerea n memorie doar a dou articole (pentru comparaii) i
scrierea n acces direct n acelai fiier, prin utilizarea numrului relativ al articolelor prelucrate.
Timpul de prelucrare va fi substanial mai mare dect la metodele de sortare n memorie,
deoarece operaiile de intrare/ieire snt costisitoare din punct de vedere al resursei timp
calculator. Se poate aplica oricare din algoritmii de sortare cunoscui, cu meniunea c indicii i
i j vor fi utilizai pentru controlul numrului relativ al articolelor n fiier.

Exemplu
18. Sortarea prin interschimbare.

do
{ vb=0;
for(i=0;i<nr_art-1;i++)
{ fseek(f,sizeof(STUDENT)*i,SEEK_SET);
fread(&x,sizeof(STUDENT),1,f);
fread(&y,sizeof(STUDENT),1,f);
if(x.medie>y.medie)
{ fseek(f,sizeof(STUDENT)*i,SEEK_SET);
fwrite(&y,sizeof(STUDENT),1,f);
fwrite(&x,sizeof(STUDENT),1,f);
vb=1;
}
while(vb);

Exemplu
19. Sortare prin selecie.

for(i=0;i<nr_art-1;i++)
{ fseek(f,sizeof(STUDENT)*i,SEEK_SET);
fread(&x,sizeof(STUDENT),1,f);
for(j=i+1;j<nr_art;j++)
{ fseek(f,sizeof(STUDENT)*j,SEEK_SET);
fread(&y,sizeof(STUDENT),1,f);
if(x.medie>y.medie)
{ fseek(f,sizeof(STUDENT)*i,SEEK_SET);
fwrite(&y,sizeof(STUDENT),1,f);
fseek(f,sizeof(STUDENT)*j,SEEK_SET);
fwrite(&x,sizeof(STUDENT),1,f);
}
}
}

Teste de autoevaluare
6. Scriei un program care sorteaz fiierul descris la testul de autoevaluare 3 dup
urmtoarele criterii: facultate, an de studiu, grup, alfabetic. (Acest test trebuie
rezolvat nainte de a putea rezolva testul 3)

* material didactic pentru ID * 93
4.5. Interclasarea fiierelor binare memorate dens

Interclasarea este operaia prin care, din dou sau mai multe mulimi ordonate, se obine
o nou mulime, ordonat dup acelai criteriu. Interclasarea fiierelor apare ca necesitate n
aplicaiile economice, mai ales n faza de post-populare a fiierelor mari de date, create simultan
pe submulimi de mai muli utilizatori i necesitnd, n final, reunirea acestora ntr-unul singur.
Condiia apriori interclasrii este ca toate fiierele pariale s fie sortate dup valorile
aceluiai cmp, pe baza cruia se va realiza, prin comparri succesive, operaia de interclasare.
Cmpul poart denumirea de cheie de interclasare. Interclasarea a n fiiere se poate realiza
simplu prin aplicarea de n-1 ori a operaiei de interclasare a dou fiiere (figura 6.12).

1
Fiier 1
n 4 3 2
...
Fiier 2
Fiier 3
Fiier n-1
...
Interclasare 1 ..
Fiier
final
Interclasare 2 ...
Interclasare 3 ...
Interclasare 3 .

Fig. 4.12. Interclasarea a n fiiere

Se obin astfel n-1 fiiere intermediare (fiier i), din care numai ultimul se pstreaz,
celelalte (mpreun cu fiierele iniiale) se terg, fie n finalul procesului, fie la sfritul fiecrei
etape intermediare (recomandat). Interclasarea a dou fiiere este similar operaiei aplicate
pentru doi vectori. Dimensiunea fiierului rezultat este suma dimensiunilor fiierelor iniiale.

Exemplu
20. Se prezint structura principial a unui program pentru interclasarea a dou fiiere
binare. Cheile de interclasare se afl n cmpul c aparinnd articolelor art_1 i art_2,
corespunztoare fiierelor de intrare f i g, considerate populate dens.

{
//---------------------------------
//citire nume externe ale fisierelor
//---------------------------------
f=fopen(nume_fisier_intrare_1, "rb");
g=fopen(nume_fisier_intrare_2, "rb");
h=fopen(nume_fisier_iesire, "wb");
fread(&art_1,sizeof(tip_articol),1,f);
fread(&art_2,sizeof(tip_articol),1,g);
while((!feof(f)&&(!feof(g)))
if(art_1.c>art_2.c)
{ fwrite(&art_1,sizeof(tip_articol),1,h);
Algoritmi n programare 94
fread(&art_1,sizeof(tip_articol),1,f);
}
else
{ fwrite(&art_2,sizeof(tip_articol),1,h);
fread(&art_2,sizeof(tip_articol),1,g);
}
while(!feof(f))
{ fwrite(&art_1,sizeof(tip_articol),1,h);
fread(&art_1,sizeof(tip_articol),1,f);
}
while(!feof(g))
{ fwrite(&art_2,sizeof(tip_articol),1,h);
fread(&art_2,sizeof(tip_articol),1,g);
}
fclose(f);
fclose(g);
fclose(h)
}


4.6. Prelucrarea masivelor memorate n fiiere binare

Una din aplicaiile des ntlnite n lucrul cu fiiere este memorarea masivelor de date de
dimensiuni foarte mari, care fac imposibil aducerea lor integral n memoria intern. Problema
principal a prelucrrii masivelor (vectori, matrice etc.) memorate n fiiere binare, o constituie
determinarea poziiei unui anumit element de masiv n cadrul fiierului. Indiferent de numrul
de dimensiuni ale masivului i de modalitile de memorare a elementelor sale n cadrul
fiierului, legtura ntre elementul de masiv care se refer i numrul relativ al articolului care l
conine se realizeaz pe baza funciei rang.
n cazul masivelor memorate n fiiere, prelucrarea acestora depinde de unele
caracteristici particulare:
numrul de dimensiuni ale masivului;
ordinea de memorare n fiier (n ordine lexicografic sau invers lexicografic);
modul de memorare (dens sau nedens);
ordinea de parcurgere a masivului.

4.6.1. Prelucrarea vectorilor
De regul, vectorii se memoreaz dens. Numrul relativ al articolului depinde de rangul
elementului n cadrul vectorului, astfel:
nr_relativ = rang(x
i
)+1 = i+1, pentru i=0..n-1, dac articolul cu numrul relativ 0, fie nu este
utilizat (caz n care dimensiunea vectorului este n = dimensiune fiier-1), fie memoreaz
numrul efectiv de componente ale vectorului;
nr_relativ = rang(x
i
) = i, pentru i=0..n, dac vectorul se memoreaz ncepnd cu primul
articol (caz n care dimensiunea vectorului este n =dimensiunea fiierului).

Exemplu
21. S se determine media aritmetic a elementelor unui vector foarte mare, memorat
ntr-un fiier binar.

#include<stdio.h>
void main()
{ FILE* vector;
float element, medie;
long i,n;
vector=fopen("VECTOR.DAT","rb");
fseek(vector,0,SEEK_END);
n=ftell(f)/sizeof(float);
* material didactic pentru ID * 95
rewind(f);
medie=0;
for(i=0;i<n;i++)
{ fread(&element,sizeof(float),1,vector);
medie+=element;
}
medie/=n;
printf("\nMedia: %7.3f",medie);
fclose(vector);
}

4.6.2. Prelucrarea matricelor
O matrice poate fi memorat ntr-un fiier binar nedens (similar memorrii n MP) sau
dens, n ordine lexicografic sau invers lexicografic. Numrul relativ al elementului a
ij
se
determin pe baza funciei rang, astfel:
rang(a
ij
) = i * nr_coloane + j, n cazul memorrii lexicografice, unde nr_coloane este fie
numrul coloanelor efective (populare dens), fie numrul coloanelor rezervate (populare
nedens);
rang(a
ij
) = j * nr_linii + i, n cazul memorrii invers lexicografice, unde nr_linii este fie
numrul liniilor efective (populare dens), fie numrul liniilor rezervate (populare nedens).

Fie m i n numrul liniilor, respectiv coloanelor efective i mr i nr numrul liniilor,
respectiv coloanelor rezervate (mr i nr corespund dimensiunilor maxime din declaraia unui
masiv aflat n memoria principal). Pentru ca fiierul s conin informaii complete despre
matrice, trebuie s memoreze, pe lng elementele ei, i:
m (sau n), n cazul memorrii dense. Cnd se memoreaz m, n se determin mprind
dimensiunea fiierului (mai puin primul articol, unde se afl m) la m; cnd se memoreaz n,
m se determin mprind dimensiunea fiierului (mai puin primul articol, unde se afl n) la
n. Funcia rang depinde de m sau n, dup cum matricea este memorat invers lexicografic
sau lexicografic;
n i nr, n cazul memorrii nedense n ordine lexicografic. m se determin mprind
dimensiunea fiierului (mai puin primele dou articole, unde se afl n i nr) la nr, iar mr
nu are relevan. Funcia rang depinde de nr;
m i mr, n cazul memorrii nedense n ordine invers lexicografic. N se determin
mprind dimensiunea fiierului (mai puin primele dou articole, unde se afl m i mr) la
mr, iar nr nu are relevan. Funcia rang depinde de mr.
Funcia rang se calculeaz i se utilizeaz numai dac problema de rezolvat implic
parcurgerea matricei n alt ordine dect cea n care este memorat n fiier, deci consultarea
acestuia se realizeaz n acces direct.

Exemplu
22. S se afieze elementul maxim de pe fiecare coloan a unei matrice de dimensiuni m
x n, memorate dens, ntr-un fiier binar, n ordine lexicografic. Primul articol conine numrul
de coloane.

Observaie: primul articol are dimensiune diferit de celelalte: numrul de coloane este
de tip ntreg iar elementele matricei snt reale. Din dimensiunea total a fiierului, primii
sizeof(int) octei snt ocupai de numrul de coloane, restul constituie matricea propriu
zis. La calcularea poziiei unui element n matrice trebuie inut cont de faptul c matricea nu
ncepe la nceputul fiierului ci dup sizeof(int) octei.

#include<stdio.h>
void main()
{ FILE *f;
Algoritmi n programare 96
float max, element;
long i,j,r,m,n;
f=fopen("MATRICE.DAT", "rb");
fread(&n,sizeof(int),1,f); //citire numar de coloane
fseek(f,0,SEEK_END);
m=(ftell(f)-sizeof(int))/(sizeof(float)*n);
for(j=0;j<n;j++)
{ //pozitonare pe primul element din coloana j
fseek(f,j*sizeof(float)+sizeof(int),SEEK_SET);
fread(&element,sizeof(float),1,f);
max=element;
for(i=1;i<m;i++)
{ r=i*n+j; //rangul elementului in matrice
fseek(f,r*sizeof(float)+sizeof(int),SEEK_SET);
fread(&element,sizeof(float),1,f);
if(element>max) max=element;
}
printf("\Maximul pe coloana %2d este %7.3f",j,max);
}
fclose(f);
}

Exemplu
23. S se determine elementul maxim de pe fiecare coloan a unei matrice de dimensi-
uni m x n, memorat nedens ntr-un fiier binar, n ordine lexicografic. Primele dou articole
conin numrul de coloane efective i, respectiv, numrul rezervat de coloane.
Rezolvarea este similar cu exemplul anterior, cu urmtoarele modificri:
din dimensiunea total a fiierului, primii 2*sizeof(int) octei snt ocupai de dimensiunile
matricei (numr de coloane efectiv respectiv rezervat), iar restul constituie matricea
propriu zis. La calcularea poziiei unui element n matrice trebuie inut cont de faptul c
matricea nu ncepe la nceputul fiierului ci dup 2*sizeof(int) octei.
La calcularea rangului unui element (i implicit a poziiei sale n fiier) se folosete
numrul de coloane rezervare, nu numrul de coloane efective.

Teste de autoevaluare
7. Scriei un program care determin produsul scalar dintre doi vectori cu elemente de
tip float memorai n dou fiiere binare.
8. Scriei un program care determin produsul dintre un vector i o matrice, ambele masive fi-
ind memorate n fiiere binare (ambele au elemente de tip float).
9. Scriei un program care determin produsul dintre dou matrice cu elemente de tip float,
memorate n fiiere binare.

Teme
1. Alegei o structur de date care s descrie ct mai bine produsele aflate n vnzare
ntr-un magazin de dimensiuni mici. Definii tipul articol corespunztor n limbajul
C.
2. Folosind structura logic de date de mai sus, scriei o aplicaie care s realizeze toate opera-
iile necesare de gestiune a datelor referitoare la produse. Datele vor fi pstrate ntr-un fiier
binar organizat relativ.
3. Folosind structura logic de la tema 1 i exemplul 11 de mai sus, scriei o aplicaie care s
realizeze toate operaiile necesare de gestiune a datelor referitoare la produse. Datele vor fi
pstrate ntr-un fiier binar organizat indexat.


Rspunsuri i comentarii la testele de autoevaluare
2. Trebuie calculate 12 sume, corespunztor celor 12 luni ale anului. Se iniializeaz
* material didactic pentru ID * 97
cele 12 sume cu zero, apoi se parcurge secvenial fiierul i, la fiecare articol, se adaug pro-
ducia valoric a fiecrei luni la suma corespunztoare. La terminarea parcurgeri fiierului se
determin valoarea maxim dintre cele 12 sume. Ea va indica luna (lunile) cerute.

3. Snt trei caracteristici de grupare i patru grade de total. Rezolvarea se face conform sche-
mei logice din figura 4.6, adugnd nc un nivel de grupare universitatea e compus din fa-
culti, o facultate lucreaz pe mai muli ani de studiu, n cadrul fiecrui an snt organizate
mai multe grupe.

4. Se cere de fapt realizarea operaiei de modificare a datelor din fiier. Se caut produsul n
fiier, secvenial, dup codul su i se modific valoarea corespunztoare lunii introduse de la
tastatur.

5. Structura logic a articolului trebuie extins prin adugarea unui cmp cu rol de indicator de
stare, ajungnd la structura fizic a articolelor din fiier.


Rezumat
n cadrul acestei uniti de nvare au fost studiai algoritmii pentru efectuarea tuturor
operaiilor de prelucrare a fiierelor de date: creare, consultare, cutare, modificare,
tergere. Au fost analizai algoritmi de prelucrare a fiierelor care nu necesit actualizare pre-
cum i a fiierelor care necesit actualizare. Algoritmii studiai descriu modul de rezolvare a
prelucrrilor pentru fiierele organizate secvenial, relativ i indexat.
De asemenea, au fost studiate metode de organizare a masivelor n fiiere de date i
algoritmi de prelucrare a lor.
Prin combinarea operaiilor individuale se pot construi algoritmi compleci care s re-
zolve toate problemele de gestiune a volumului mare de date aferent aplicaiilor de informati-
c economic.



Bibliografia unitii de nvare

1. I. Gh. Roca, B. Ghilic-Micu, C. Cocianu, M. Stoica, C. Uscatu, M. Mircea - Programarea
calculatoarelor. Algoritmi n programare, Ed. ASE Bucureti, 2007
2. I. Gh. Roca, B. Ghilic-Micu, C. Cocianu, M. Stoica, C. Uscatu - Programarea calculatoa-
relor. tiina nvrii unui limbaj de programare. Teorie i aplicaii, Ed. ASE Bucureti,
2003
3. I.Gh. Roca & colectiv - Bazele elaborrii programelor. Exerciii rezolvate i propuse, Ed.
ASE Bucureti, 1998
4. B. Ghilic-Micu, I. Gh. Roca, C. Apostol, M. Stoica - Algoritmi n programare, Ed. ASE,
Bucureti, 2002
5. Liviu Negrescu - Limbajele C i C++ pentru nceptori, vol. I, II, Ed. Microinformatica,
Cluj-Napoca, 1994

Algoritmi n programare 98



Bibliografie




1. I. Gh. Roca, B. Ghilic-Micu, C. Cocianu, M. Stoica, C. Uscatu, M. Mircea - Programarea
calculatoarelor. Algoritmi n programare, Ed. ASE Bucureti, 2007
2. I. Gh. Roca, B. Ghilic-Micu, C. Cocianu, M. Stoica, C. Uscatu - Programarea calculatoa-
relor. tiina nvrii unui limbaj de programare. Teorie i aplicaii, Ed. ASE Bucureti,
2003
3. A. Iorgulescu - Metode numerice i programe Pascal, Ed. Inforec, Bucureti, 1996 (para-
grafele 2.2.1, 2.2.2, 2.2.3, 4.2.1, 4.2.2)
4. I.Gh. Roca & colectiv - Bazele elaborrii programelor. Exerciii rezolvate i propuse, Ed.
ASE Bucureti, 1998
5. B. Ghilic-Micu, I. Gh. Roca, C. Apostol, M. Stoica - Algoritmi n programare, Ed. ASE,
Bucureti, 2002
6. Liviu Negrescu - Limbajele C i C++ pentru nceptori, vol. I, II, Ed. Microinformatica,
Cluj-Napoca, 1994

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