Sunteți pe pagina 1din 225

i

Cristian IOSIFESCU




Programarea
calculatoarelor i
limbaje de
programare


ii



iii

Cuprins
1. NOIUNI INTRODUCTIVE..................................................................................... 1
1.1 Abordarea problemelor .............................................................................................................. 1
1.2 Algoritmi....................................................................................................................................... 1
1.2.1 Proprietile fundamentale ale algoritmilor ............................................................................ 1
1.2.2 Reprezentarea algoritmilor .................................................................................................... 2
1.3 Algoritmul programatorului ....................................................................................................... 4
1.3.1 Definirea i analiza problemei................................................................................................ 4
1.3.2 Proiectarea algoritmului ......................................................................................................... 4
1.3.3 Implementarea (codificarea) algoritmului .............................................................................. 5
1.3.4 Testarea i depanarea programului....................................................................................... 5
1.3.5 Elaborarea documentaiei...................................................................................................... 8
1.3.6 Exploatarea i ntreinerea..................................................................................................... 8
1.4 Abstractizare i rafinare ............................................................................................................. 8
1.5 Limbajul C/C++ ............................................................................................................................ 9
1.5.1 Originile limbajului C.............................................................................................................. 9
1.6 Structura unui program C sau C++ ......................................................................................... 11
1.6.1 Preprocesorul....................................................................................................................... 12
1.6.2 Funcia main ........................................................................................................................ 13
1.7 Harta zonelor de memorie ale unui program C...................................................................... 13
1.8 Primele programe...................................................................................................................... 14
2. DATE, OPERATORI I EXPRESII ....................................................................... 16
2.1 Vocabularul ................................................................................................................................ 16
2.2 Unitile lexicale ale limbajului C............................................................................................. 16
2.2.1 Identificatori.......................................................................................................................... 16
2.2.2 Cuvinte cheie ....................................................................................................................... 17
2.2.3 Operaii de intrare/ieire ...................................................................................................... 17
2.3 Date n limbajul C...................................................................................................................... 18
2.3.1 Numele unei date................................................................................................................. 18
2.3.2 Tipuri de date....................................................................................................................... 19
2.3.3 Variabile............................................................................................................................... 21
2.3.4 Modificatori de acces ........................................................................................................... 25
2.3.5 Clase de memorare ............................................................................................................. 26
2.3.6 Iniializarea variabilelor n declaraii..................................................................................... 28
2.3.7 Constante............................................................................................................................. 28
2.4 Operatori i expresii.................................................................................................................. 31
2.4.1 Operatori .............................................................................................................................. 32
2.4.2 Expresii ................................................................................................................................ 38
2.4.3 Conversii de tip .................................................................................................................... 40
3. STRUCTURI DE CONTROL ................................................................................ 42
3.1 Adevrat i fals n C.................................................................................................................. 42
3.2 Structura secvenial................................................................................................................ 42
3.2.1 Instruciunea vid................................................................................................................. 42
3.2.2 Instruciunea expresie.......................................................................................................... 43
3.2.3 Instruciunea compus (instruciunea bloc)......................................................................... 43
3.3 Structura de decizie (alternativ, de selecie) ........................................................................ 43
3.3.1 Instruciunea if................................................................................................................... 43
3.3.2 Structura de selecie cu ramuri multiple - instruciunea switch ........................................ 46
3.4 Structuri ciclice (repetitive) ...................................................................................................... 47
3.4.1 Implementarea structurilor ciclice cu test iniial ................................................................... 47
3.4.2 Implementarea structurilor ciclice cu test final..................................................................... 50
3.4.3 Exerciii ................................................................................................................................ 50
3.5 Instruciuni de salt .................................................................................................................... 53
3.5.1 Instruciunea return .......................................................................................................... 53
3.5.2 Instruciunea goto............................................................................................................... 54
3.5.3 Instruciunea break ............................................................................................................ 55
3.5.4 Instruciunea continue...................................................................................................... 55
3.6 Instruciuni expresie ................................................................................................................. 57


iv
3.7 Instruciuni bloc ........................................................................................................................ 57
4. TABLOURI ........................................................................................................... 58
4.1 Tablouri unidimensionale......................................................................................................... 58
4.1.1 Iniializarea tablourilor unidimensionale............................................................................... 59
4.2 iruri ........................................................................................................................................... 60
4.2.1 Iniializarea irurilor.............................................................................................................. 60
4.3 Tablouri bidimensionale........................................................................................................... 61
4.3.1 Iniializarea tablourilor bidimensionale................................................................................. 62
4.4 Tablouri multidimensionale ..................................................................................................... 63
4.4.1 Iniializarea de tablouri nedimensionate .............................................................................. 63
4.5 Exemple...................................................................................................................................... 64
5. POINTERI............................................................................................................. 67
5.1 Variabile pointer ........................................................................................................................ 67
5.1.1 Declararea variabilelor pointer............................................................................................. 67
5.1.2 Operatorii pentru pointeri ..................................................................................................... 67
5.1.3 Pointeri generici ................................................................................................................... 69
5.2 Operaii cu pointeri ................................................................................................................... 69
5.2.1 Adunarea sau scderea....................................................................................................... 69
5.2.2 Compararea valorilor variabilelor pointer............................................................................. 70
5.3 Pointeri i tablouri..................................................................................................................... 70
5.3.1 Pointeri i iruri de caractere ............................................................................................... 71
5.3.2 Pointeri i tablouri multidimensionale .................................................................................. 73
5.4 Tablouri de pointeri................................................................................................................... 74
5.5 Pointeri la pointeri..................................................................................................................... 75
5.6 Modificatorul const n declararea pointerilor........................................................................ 76
6. FUNCII................................................................................................................ 77
6.1 Structura unei funcii ................................................................................................................ 77
6.2 Apelul i prototipul funciilor ................................................................................................... 78
6.3 Regulile de competen ale unei funcii ................................................................................. 79
6.4 Transferul parametrilor unei funcii ........................................................................................ 79
6.4.1 Transferul parametrilor prin valoare .................................................................................... 79
6.4.2 Transferul parametrilor prin pointeri .................................................................................... 81
6.4.3 Transferul parametrilor prin referin................................................................................... 82
6.5 Apelul funciilor folosind tablouri............................................................................................ 83
6.5.1 Funcii care returneaz pointeri ........................................................................................... 86
6.6 Funcii de tip void .................................................................................................................... 87
6.7 Funcii cu parametri implicii ................................................................................................... 87
6.8 Funcii cu numr variabil de parametri ................................................................................... 88
6.9 Transferul parametrilor ctre funcia main............................................................................. 88
6.10 Ce returneaz funcia main()? ............................................................................................. 89
6.11 Funcii recursive...................................................................................................................... 90
6.12 Pointeri ctre funcii................................................................................................................ 92
6.13 Probleme de implementare .................................................................................................... 94
6.13.1 Parametri i funcii de uz general ...................................................................................... 94
6.13.2 Eficien ............................................................................................................................. 94
6.13.3 Biblioteci i fiiere .............................................................................................................. 95
7. TIPURI DE DATE DEFINITE DE UTILIZATOR.................................................... 97
7.1 Structuri ..................................................................................................................................... 97
7.1.1 Transmiterea structurilor n funcii ....................................................................................... 99
7.1.2 Pointeri ctre structuri ........................................................................................................ 100
7.2 Cmpuri de bii ........................................................................................................................ 102
7.3 Uniuni ....................................................................................................................................... 103
7.4 Enumerri................................................................................................................................. 104
7.5 Declaraii de tip........................................................................................................................ 108
8. PREPROCESORUL........................................................................................... 109
8.1 Preprocesorul C ...................................................................................................................... 109
8.2 Directiva #define...................................................................................................................... 109
8.2.1 Definirea de macrocomenzi tip funcie .............................................................................. 110


v
8.3 Directiva #error ..................................................................................................................... 111
8.4 Directiva #include................................................................................................................. 111
8.5 Directive de compilare condiional...................................................................................... 112
8.5.1 Directivele #if, #else, #endif, #elif................................................................... 112
8.5.2 Directivele #ifdef i #ifndef ........................................................................................ 114
8.5.3 Directiva #undef............................................................................................................... 115
8.5.4 Utilizarea operatorului defined........................................................................................ 115
8.6 Directiva #line ....................................................................................................................... 115
8.7 Directiva #pragma................................................................................................................... 116
8.8 Operatorii de preprocesare # i ## ....................................................................................... 116
8.9 Nume predefinite de macrocomenzi ..................................................................................... 116
8.10 Comentariile........................................................................................................................... 117
9. BIBLIOTECA STANDARD................................................................................. 118
9.1 Funcii de intrare/ieire: <stdio.h>..................................................................................... 118
9.1.1 Operaii I/O pentru consol................................................................................................ 119
9.1.2 Operaii cu fiiere............................................................................................................... 123
9.2 Funcii pentru caractere i iruri de caractere..................................................................... 133
9.2.1 Funcii de testare i conversie a caracterelor: <ctype.h> .............................................. 133
9.2.2 Funcii pentru iruri de caractere: <string.h> ............................................................... 134
9.3 Funcii matematice: <math.h>.............................................................................................. 135
9.3.1 Funcii aritmetice................................................................................................................ 135
9.3.2 Funcii trigonometrice directe i inverse ............................................................................ 135
9.3.3 Funcii exponeniale i logaritmice..................................................................................... 136
9.4 Funcii utilitare: <stdlib.h>................................................................................................. 136
9.5 Operaii cu directoare............................................................................................................. 137
9.6 Funcii pentru dat i or: <time.h>.................................................................................... 137
9.7 Valori limit dependente de implementare: <limits.h> i <float.h> .......................... 139
9.8 Moduri de alocare a memoriei ............................................................................................... 140
9.8.1 Alocarea memoriei n mod dinamic ................................................................................... 140
10. GESTIUNEA ECRANULUI N MOD TEXT....................................................... 143
10.1 Setarea ecranului n mod text .............................................................................................. 144
10.2 Definirea unei ferestre .......................................................................................................... 144
10.3 tergerea unei ferestre......................................................................................................... 144
10.4 Gestiunea cursorului ............................................................................................................ 145
10.5 Determinarea parametrilor ecranului .................................................................................. 145
10.6 Modurile video alb/negru...................................................................................................... 146
10.7 Setarea culorilor .................................................................................................................... 146
10.8 Gestiunea textelor................................................................................................................. 147
11. GESTIUNEA ECRANULUI N MOD GRAFIC.................................................. 154
11.1 Setarea modului grafic ......................................................................................................... 154
11.2 Gestiunea culorilor................................................................................................................ 157
11.3 Starea ecranului .................................................................................................................... 159
11.4 Gestiunea textelor................................................................................................................. 160
11.5 Gestiunea imaginilor............................................................................................................. 163
11.6 Tratarea erorilor..................................................................................................................... 169
11.7 Desenare i colorare............................................................................................................. 172
12. SORTARE I CUTARE ................................................................................. 182
12.1 Sortarea.................................................................................................................................. 182
12.1.1 Clase de algoritmi de sortare........................................................................................... 182
12.1.2 Aprecierea algoritmilor de sortare ................................................................................... 182
12.1.3 Sortare prin metoda bulelor ............................................................................................. 183
12.1.4 Sortarea prin selecie....................................................................................................... 184
12.1.5 Sortarea prin inserare...................................................................................................... 185
12.1.6 Algoritmi de sortare superiori........................................................................................... 185
12.1.7 Sortarea prin metoda Shell .............................................................................................. 186
12.1.8 Sortarea prin metoda rapid (QuickSort)......................................................................... 187
12.2 Cutarea................................................................................................................................. 191
12.2.1 Metode de cutare........................................................................................................... 191


vi
13. LISTE, COZI, STIVE I ARBORI ..................................................................... 193
13.1 Liste ........................................................................................................................................ 193
13.1.1 Liste simplu nlnuite ...................................................................................................... 194
13.1.2 Liste dublu nlnuite........................................................................................................ 198
13.2 Cozi ......................................................................................................................................... 201
13.2.1 Cozi circulare ................................................................................................................... 204
13.3 Stive........................................................................................................................................ 205
13.4 Arbori binari ........................................................................................................................... 207
Manuale electronice...................................................................................................................... 213



vii

Lista exemplelor
Exemplul 1.1 Aria unui dreptunghi ......................................................................................3
Exemplul 1.2 Se citesc 2 valori reale. S se afieze valoarea maximului dintre cele 2
numere.................................................................................................................................3
Exemplul 1.3 Algoritm maxim perechi numere. ..................................................................3
Exemplul 2.1: Constante caracter.....................................................................................30
Exemplul 2.2: iruri de caractere......................................................................................31
Exemplul 3.1 Instruciunea if..........................................................................................45
Exemplul 3.2 Instruciunea if - calculul valorii unei funcii...............................................45
Exemplul 3.3 Calculator de buzunar - construcia if-else ...........................................46
Exemplul 3.4 Calculator de buzunar - instruciunea switch............................................47
Exemplul 3.5 Cicluri ..........................................................................................................50
Exemplul 3.6 Suma i produsul primelor n numere naturale ............................................51
Exemplul 3.7 Maximul unui ir de numere naturale..........................................................52
Exemplul 3.8 Conversia unui numr din baza 10 ntr-o alt baz de numeraie...............52
Exemplul 3.9 Calculul unei serii ........................................................................................53
Exemplul 3.10 Citire caractere..........................................................................................57
Exemplul 4.1 Citirea i afiarea elementelor unei matrici .................................................62
Exemplul 4.2 Interschimbarea elementelor unui vector ....................................................64
Exemplul 4.3 Citirea i afiarea elementelor unei matrici .................................................64
Exemplul 4.4 Operaii cu matrici .......................................................................................65
Exemplul 5.1.....................................................................................................................68
Exemplul 5.2.....................................................................................................................68
Exemplul 5.3.....................................................................................................................69
Exemplul 5.4 Legtura dintre pointeri i vectori ................................................................71
Exemplul 5.5 Legtura dintre pointeri i irurile de caractere ...........................................72
Exemplul 5.6 Pointeri - vector...........................................................................................72
Exemplul 5.7 S se testeze programul urmtor, urmrind cu atenie rezultatele obinute.
...........................................................................................................................................74
Exemplul 6.1 Domeniul de vizibilitate a unei variabile ......................................................78
Exemplul 6.2: Apelul unei funcii .......................................................................................78
Exemplul 6.3: Parametri formali i parametri efectivi. .......................................................80
Exemplul 6.4: Expresii ca parametri efectivi .....................................................................80
Exemplul 6.5: Valoare returnat prin referin ..................................................................83
Exemplul 6.6: Modificatorul de acces const n lista declaraiilor parametrilor formali ai
unei funcii..........................................................................................................................83
Exemplul 6.7: Tablouri ca parametri - elementul minim dintr-un vector ............................84
Exemplul 6.8: Funcii care returneaz pointeri..................................................................86
Exemplul 6.9: Funcii care returneaz pointeri..................................................................86
Exemplul 6.10: Program Salut nume................................................................................89
Exemplul 6.11: S se implementeze un program care afieaz argumentele transmise
ctre funcia main..............................................................................................................89
Exemplul 6.12: S se implementeze recursiv funcia care calculeaz n!, unde n este
introdus de la tastatur: .....................................................................................................90
Exemplul 6.13: irul lui Fibonacci .....................................................................................91
Exemplul 6.14 Calculul derivatei unei funcii ntr-un punct................................................92
Exemplul 6.15 Pointeri ctre funcii ..................................................................................93
Exemplul 7.1 Structuri - elevi ..........................................................................................104


viii
Exemplul 9.1: S se scrie un program care creeaz un fiier text n care se vor scrie
caracterele introduse de la tastatur (citite din fiierul standard de intrare), pn la
ntlnirea caracterului ^Z = Ctrl+Z....................................................................................126
Exemplul 9.2: S se scrie un program care citete un fiier text, caracter cu caracter, i
afieaz coninutul acestuia.............................................................................................126
Exemplul 9.3...................................................................................................................127
Exemplul 9.4 S se scrie un program care creeaz un fiier text n care se vor scrie
irurile de caractere introduse de la tastatur. .................................................................128
Exemplul 9.5 S se scrie un program care citete un fiier text, linie cu linie, i afieaz
coninutul acestuia...........................................................................................................128
Exemplul 9.6 S se scrie un program care creeaz un fiier binar n care se vor introduce
numere reale, nenule. ......................................................................................................129
Exemplul 9.7 S se scrie un program ce citete dintr-un fiier binar numere reale, nenule.
.........................................................................................................................................130
Exemplul 10.1 S se scrie o funcie care afieaz parametrii ecranului. ........................146
Exemplul 10.2 S se scrie un program care seteaz pe rnd modurile text, definite cu
ajutorul constantelor simbolice: BW40, C40, BW80, C80 i C4350 i afieaz parametrii
ecranului pentru fiecare din modurile respective..............................................................147
Exemplul 10.3 S se scrie un program care afieaz texte n modurile video intens i
video normal. ...................................................................................................................148
Exemplul 10.4 S se scrie un program care afieaz toate combinaiile de culori posibile
pentru fond i caractere. Se consider c se dispune de un adaptor color EGA/VGA. ...148
Exemplul 10.6 S se scrie o funcie care afieaz o fereastr limitat de un chenar i pe
fondul creia se afieaz un ntreg. Cursorul devine invizibil la afiarea ferestrei. Funcia
are prototipul: ...................................................................................................................149
Exemplul 10.7 S se scrie un program care afieaz ferestre pe ecran n mod aleator.
Ferestrele sunt de dimensiune fix, dar au poziii aleatoare pe ecran. De asemenea, ele
pot avea chenar format dintr-o linie simpl sau dubl sau s nu aib chenar. Culorile de
fond i de afiare a caracterelor sunt aleatoare. Ferestrele se numeroteaz i numrul
ferestrei se afieaz n fereastr. Prima fereastr afiat se numeroteaz cu 1. ............151
Exemplul 11.1 S se scrie un program care seteaz modul grafic n dou feluri: ..........156
Exemplul 11.2 S se scrie un program care afieaz codurile culorilor pentru paleta
implicit............................................................................................................................158
Exemplul 11.3 S se scrie un program care afieaz urmtoarele informaii: ................159
Exemplul 11.4 S se scrie un program care afieaz texte folosind toate cele 5 fonturi,
caracterele avnd pe rnd dimensiunile 1, 2, 3 i 4. n cazul fonturilor diferite de
DEFAULT_FONT, se vor afia texte ale cror caractere se vor afla n rapoartele: 4/3 n
lime i 2/1 n nlime. ...................................................................................................162
Exemplul 11.5 S se scrie un program care afieaz texte cadrate n toate variantele
definite de funcia settextjustify..............................................................................163
Exemplul 11.6 S se scrie un program care realizeaz urmtoarele:.............................166
Exemplul 11.7 S se scrie un program care realizeaz urmtoarele:.............................167
Exemplul 11.8 S se scrie un program care realizeaz urmtoarele:.............................168
Exemplul 11.9 S se scrie un program care afieaz parametri implicii ai modului grafic
setat prin apelul funciei initgraph: ..............................................................................170
Exemplul 11.10 S se scrie un program care traseaz linii orizontale folosind cele 4 stiluri
standard i ambele grosimi. .............................................................................................176
Exemplul 11.11 S se scrie un program care traseaz urmtoarele figuri: ....................176
Exemplul 11.12 S se scrie un program care coloreaz figurile geometrice trasate n
programul precedent........................................................................................................177


ix
Exemplul 11.13 S se scrie un program care afieaz 15 dreptunghiuri colorate, pe trei
rnduri, folosind toate cele 15 culori ale paletei diferite de culoarea de fond. Sub fiecare
dreptunghi se listeaz indicele culorii dreptunghiului, n tabloul care definete paleta
curent de culori. Dup afiarea celor 15 dreptunghiuri se poate regla monitorul aa nct
fiecare dreptunghi s fie vizibil. ........................................................................................178
Exemplul 11.14 S se scrie un program care afieaz dreptunghiuri utiliznd toate
haurile standard. ............................................................................................................179
Exemplul 11.15 S se scrie un program care traseaz un cerc folosind ecuaiile
parametrice ale cercului:..................................................................................................179
Exemplul 11.16 S se scrie un program care deplaseaz o imagine pe ecran. .............180
Exemplul 12.1 Program de sortare cu utilizarea diverselor metode prezentate...............188
Exemplul 13.1 Program simplu de planificare a ntlnirilor .............................................202
Exemplul 13.2 Calculator postfix pentru expresii ntregi .................................................206
Exemplul 13.3 Creare i afiare arbore ..........................................................................208


Noiuni introductive

1
1. Noiuni introductive
1.1 Abordarea problemelor
Programarea reprezint tiina i arta rezolvrii problemelor [1]. Pentru a fi un bun
programator trebuie s fii un bun rezolvitor al problemelor, iar pentru aceasta trebuie s tii
s "ataci" problemele ntr-un mod metodic, de la prima definire i evaluare a problemei
pn la soluia final, testare i documentaie. La nceput, cnd te vei confrunta cu o
problem de programare, vei fi tentat s te aezi la calculator i s ncepi s o codifici pe
msur ce i vine o idee de rezolvare a sa. Oricum, este bine s reziti acestei tentaii. O
astfel de abordare poate merge pentru probleme simple, dar nu va merge pentru
problemele complexe gsite n practic.
n acest capitol vei nva o metod sistematic care v va face s devenii un bun
rezolvitor de probleme i prin urmare un bun programator. Numim aceast metod
algoritmul programatorului. Mai precis, vei studia paii cerui de rezolvarea oricrei
probleme de programare utiliznd metoda structurat top/down. Vei fi introdui n
conceptul abstractizrii care permite ca problemele s fie vzute n termeni generali.
Plecnd de la o soluie abstract iniial, vei defini mai n detaliu pas cu pas soluia, pn
cnd aceasta atinge un nivel care poate fi codificat direct ntr-un program pentru
calculator. Pe msur ce acumulai experien vei vedea c "secretul" unei programri de
succes este o bun planificare prin intermediul analizei abstracte i a unei dezvoltri
incrementale, fapt ce va conduce la proiectarea de programe structurate ntr-o manier
top/down. O astfel de modalitate de proiectare a programelor este sprijinit foarte bine de
limbajele structurate ca C.
1.2 Algoritmi
Algoritmul este un set ordonat de pai executabili, descrii fr echivoc, care
definesc un proces finit.
Algoritmii nu sunt folosii exclusiv n programare [2]. Orice set de instruciuni, ca acelea pe
care le putei gsi ntr-o partitur muzical, ntr-o reet culinar sau n ghidul de
asamblare a unui dispozitiv, poate fi considerat un algoritm. Pentru ca o main de calcul
s poat rezolva o anumit problem, programatorul trebuie mai nti s stabileasc un
algoritm care s conduc la efectuarea la sarcinii respective.
1.2.1 Proprietile fundamentale ale algoritmilor
Caracterul finit: orice algoritm bine proiectat se termin ntr-un numr finit de pai;
Caracterul unic i universal: orice algoritm trebuie s rezolve toate problemele dintr-o
clas de probleme;
Caracterul discret: fiecare aciune se execut la un moment dat de timp;
Caracterul determinist: ordinea aciunilor n execuie este determinat n mod unic de
rezultatele obinute la fiecare moment de timp.
Realizabilitatea: orice algoritm trebuie s poat fi codificat ntr-un limbaj de
programare;
Nerespectarea acestor caracteristici generale conduce la obinerea de algoritmi
neperformani, posibil infinii sau nerealizabili.
Capitolul 1
1.2.2 Reprezentarea algoritmilor
Reprezentarea (descrierea) unui algoritm nu se poate face n absena unui limbaj comun
celor care vor s l neleag. De aceea s-a stabilit o mulime bine definit de primitive
(blocuri elementare care stau la baza reprezentrii algoritmilor). Fiecare primitiv se
caracterizeaz prin sintax i semantic. Sintaxa se refer la reprezentarea simbolic a
primitivei; semantica se refer la semnificaia primitivei. Exemplu de primitiv: aer-din
punct de vedere sintactic este un cuvnt format din trei simboluri (litere); din punct de
vedere semantic este o substan gazoas care nconjoar globul pmntesc.
Algoritmii se reprezint prin:
scheme logice;
pseudocod.
1.2.2.1 Reprezentarea algoritmilor prin scheme logice
Primitivele utilizate n schemele logice sunt simboluri grafice, cu funciuni (reprezentnd
procese de calcul) bine precizate. Aceste simboluri sunt unite prin sgei (arce) orientate
care indic ordinea de execuie a proceselor de calcul.
Simboluri de nceput i sfrit.
Simbolul START desemneaz
nceputul unui program sau al unui
subprogram. Simbolul STOP
desemneaz sfritul unui program
sau al unui subprogram. Prezena
lor este obligatorie.

2
Simbolul paralelogram: semnific
procese (operaii) de intrare/ieire
(citirea sau scrierea-afiarea)
Simbolul dreptunghi: semnific o
atribuire (modificarea valorii unei date).
CITETE a,b AFIEAZ a,b
a6 Condiie
A
START STOP
F
Simbolul romb este utilizat pentru decizii. Se testeaz dac condiia din blocul de
decizie este adevrat (A) sau fals (F).

Cu ajutorul acestor simboluri grafice se poate reprezenta orice algoritm.
Repetarea unei secvene se realizeaz prin combinarea simbolurilor de decizie i de
atribuire.
1.2.2.2 Reprezentarea algoritmilor prin pseudocod
Pseudocodul este inspirat din limbajele de programare, nefiind ns att de formalizat ca
acestea. Pseudocodul reprezint o punte de legtur ntre limbajul natural i limbajele de
programare. Nu exist un standard pentru regulile lexicale. Limbajul pseudocod permite
comunicarea ntre oameni, i nu comunicarea om-main (precum limbajele de
programare). Pseudocodul utilizeaz cuvinte cheie (scrise cu majuscule subliniate) cu
urmtoarele semnificaii:

Sfrit algoritm: SFRIT
nceput algoritm: NCEPUT
Citire (introducere) date: CITETE lista
Scriere (afiare) date: SCRIE lista
Atribuire:
Structura de decizie (alternativ): DAC condiie
ATUNCI aciune1
ALTFEL aciune2
Noiuni introductive

3
Structuri repetitive cu test iniial: CT TIMP condiie
REPET aciune
sau:
PENTRU contor = val_ini LA val_fin [PAS]
REPET aciune;
Structuri repetitive cu test final:
REPET aciune CT TIMP condiie
sau:
REPET aciune PN CND condiie

Pe lng cuvintele cheie, n reprezentarea algoritmilor n pseudocod pot apare i propoziii
nestandard a cror detaliere va fi realizat ulterior.
n cazul n care se realizeaz un algoritm modularizat, pot apare cuvintele cheie:
SUBALGORITM nume (lista_intrri)
CHEAM nume (lista_valori_efective_de_intrare)

Exemple:
Se vor prezenta n continuare algoritmii de rezolvare pentru cteva probleme simple.

Exemplul 1.1 Aria unui dreptunghi
Se citesc 2 valori numerice reale, care
reprezint dimensiunile (lungimea i
limea unui dreptunghi). S se
calculeze i s se afieze aria
dreptunghiului.
ALGORITM arie_dreptunghi
NCEPUT
CITETE L,l
aria <- L*l
AFIEAZ aria
SFRIT algoritm

Exemplul 1.2 Se citesc 2 valori reale.
S se afieze valoarea maximului dintre
cele 2 numere.

ALGORITM max_2_nr_v1
NCEPUT
CITETE a, b
DAC a >= b
ATUNCI AFIEAZ a
ALTFEL AFIEAZ b
SFRIT algoritm
ALGORITM max_2_nr_v2
NCEPUT
CITETE a, b
DAC a >= b
ATUNCI max<-a
ALTFEL max<-b
AFIEAZ max
SFRIT algoritm

Exemplul 1.3 Algoritm maxim perechi
numere.
S se citeasc cte 2 numere ntregi,
pn la ntlnirea perechii de numere 0,
0. Pentru fiecare pereche de numere
citite, s se afieze maximul.
ALGORITM max_perechi1
(Structura cu test iniial v1)
NCEPUT
CITETE a,b
CT TIMP(a0 sau b0)REPET
NCEPUT
DAC (a>=b)
ATUNCI AFIEAZ a
ALTFEL AFIEAZ b
CITETE a,b
SFRIT ciclu
SFRIT algoritm

ALGORITM max_perechi2 ALGORITM max_perechi3
Capitolul 1

4
(Structura cu test iniial v2)
NCEPUT
a5 (orice valoare diferit de 0)
CT TIMP (a0 sau b0) REPET
NCEPUT
CITETE a, b
DAC (a>=b)
ATUNCI AFIEAZ a
ALTFEL AFIEAZ b
SFRIT ciclu
SFRIT algoritm
(Structura cu test final)
NCEPUT
REPET
NCEPUT
CITETE a,b
DAC (a>=b)
ATUNCI AFIEAZ a
ALTFEL AFIEAZ b
SFRIT ciclu
CT TIMP (a0 sau b0)
SFRIT algoritm
1.3 Algoritmul programatorului
Algoritmul programatorului este o reet, pentru dumneavoastr ca programatori, pe care
este bine s o utilizai n dezvoltarea programelor. El const n:
Definirea i analiza problemei (nelegerea problemei i specificarea cerinelor
acesteia). Se stabilete CE trebuie s fac aplicaia, i nu CUM. Se stabilesc datele de
intrare (identificarea mediului iniial) i se stabilesc obiectivele (identificarea mediului
final, a rezultatelor);
Proiectarea (conceperea unei metode de rezolvare a problemei printr-o metod
algoritmic);
Implementarea (codificarea algoritmului ales ntr-un limbaj de programare);
Testarea (verificarea corectitudinii programului) i depanarea aplicaiei obinute;
Elaborarea documentaiei programului.
Exploatarea i ntreinerea.
1.3.1 Definirea i analiza problemei
Putei afirma c acest pas este un pas esenial n rezolvarea oricrei probleme. Totui,
este pasul care se trece cu vederea cel mai des, mai ales n programarea calculatoarelor.
Lipsa unei burse definiii a problemei conduce de cele mai multe ori la soluii greoaie,
nclcite n special n cazul unor aplicaii mai complexe.
Care sunt elementele care trebuie considerate ca parte a acestei etape n scrierea
programului?. Trebuie avute n vedere datele de ieire (prin tipul lor: date numerice,
caracter sau i una i alta, modul de prezentare - afiare sub form de text sau grafic) -
care reprezint rezultatul programului, datele de intrare (prin tip, mod de introducere: de la
tastatur sau cu ajutorul unui sistem automat de recunoatere) i tipul de prelucrare care
se efectueaz asupra acestora.
Toate aceste aspecte trebuie avute n vedere atunci cnd se urmrete definirea unei
probleme de programare. Pe scurt se poate spune c definirea problemei presupune
considerarea cerinelor de intrare, ieire i de procesare. ntotdeauna aplicaia va dicta
modul n care trebuie efectuat definirea problemei.
1.3.2 Proiectarea algoritmului
Aceast etap a algoritmului programatorului este probabil cea mai important.
Imaginai-v c ai ncerca s construii o cas fr a avea un set de schie corespunztor.
Rezultatul ar putea fi catastrofal! Acelai lucru se poate ntmpla i dac ncercai s
scriei un program fr un plan bun. Atunci cnd se dezvolt un produs soft, gsirea unei
soluii presupune utilizarea unui set de algoritmi. n aceasta etap, care cade exclusiv n
sarcina programatorului, paii soluiei sunt descrii cu ajutorul unei scheme logice sau prin
pseudocod.
Noiuni introductive

5
1.3.3 Implementarea (codificarea) algoritmului
Codificarea programului trebuie s fie una dintre cele mai simple sarcini din ntregul
proces de programare, dac definirea problemei i gsirea unui algoritm au fost efectuate
n mod corespunztor. Limbajul de programare pe care l vei folosi va fi determinat de
natura problemei, de limbajele la care avea acces i de caracteristicile sistemului
dumneavoastr. Codificarea const n scrierea efectiv a programului surs ntr-un limbaj
formal de programare prin transcrierea pailor algoritmului n codul limbajului de
programare. Programele surs sunt fiiere text care conin instruciuni (cu sintactica i
semantica proprii limbajului utilizat). Programul (fiierul) surs este creat cu ajutorul unui
editor de texte i va fi salvat pe disc (programele surs C primesc, de obicei, extensia .c,
iar cele C++, extensia .cpp). Pentru a putea fi executat, programul surs trebuie ulterior
compilat i linkeditat.
Am dori s reamintim c procesul de scriere a programelor este ntr-adevr un proces
mecanic i trebuie s ocupe locul al doilea ca importan dup gsirea algoritmului ce
ofer o soluie problemei studiate. n viitor calculatoarele i vor genera propriul cod
plecnd de la algoritmii construii n mod corespunztor. Cercetarea tiinific din domeniul
inteligentei artificiale a condus la realizarea unor pachete de programe care sunt capabile
s "genereze programe''. Ceea ce trebuie s reinei, este c n viitor, calculatoarele vor fi
probabil capabile s-i genereze propriul cod, dar cu toate acestea va fi nevoie de
creativitatea fiinei umane pentru gsirea i dezvoltarea unui algoritm.
1.3.4 Testarea i depanarea programului
Vei afla n curnd, c doar n ocazii rare un program funcioneaz corect, fr erori,
imediat dup codificare. Desigur, o bun definire a problemei i un algoritm corect elimin
multe erori din program. Totui, de cele mai multe ori exist erori care rmn nedetectate,
indiferent ct de bine sunt efectuai paii precedeni ai algoritmului programatorului.
Eliminarea unor astfel de erori poate s se dovedeasc o sarcin mare consumatoare a
timpului programatorului.
Nu exist o procedur magic pentru depanarea programelor, dar o metod sistematic
poate s fac procesul mai uor. Paii de baz n depanare sunt:
stabilirea faptului c programul are o eroare;
localizarea i determinarea tipului i cauzei erorii;
eliminarea erorii.
Primul lucru pe care trebuie s-l facei, este s v dai seama dac programul
dumneavoastr are sau nu vreo eroare. Uneori acest lucru este foarte evident atunci cnd,
spre exemplu, calculatorul se blocheaz. Alteori programul funcioneaz corect pn cnd
unul dintre utilizatori introduce informaii pe care nu le-ai luat n considerare. Cele mai
subtile erori apar atunci cnd programul pare s genereze rezultate corecte, dar Ia o
privire mai atent se constat contrariul.
Urmtorul pas n procesul de depanare este localizarea i determinarea cauzei erorii.
Izolarea poziiei n care se produce eroarea este uneori cea mai dificil problem a
depanrii. Acesta este momentul n care trebuie s facei apel la un instrument foarte util,
i anume depanatorul (debugger-ul).
Eliminarea erorii este ultimul pas al procesului de depanare. Cunoaterea erorii,
cunotinele dumneavoastr legate de limbajul C, aceast carte, depanatorul integrat i
manualele TURBO C-ului toate sunt instrumente preioase n eliminarea acesteia.
Atunci cnd scriei programe n C exist patru lucruri pe care le putei face pentru a testa
i depana programul dumneavoastr:
verificarea preliminar,
compilarea/linkeditarea programului,
rularea programului i
Capitolul 1
utilizarea depanatorului.
1.3.4.1 Verificarea preliminar
Aceasta verificare este similar cu a face corectura mici scrisori sau a unui manuscris.
Ideea este s urmrii mental programul pentru a vedea dac logica acestuia este corect.
Trebuie s considerai diferite date de intrare i s notai rezultatele generate n urma
execuiei programului. n particular ncercai s determinai cum se va comporta programul
dac introducei date pe care n mod normal nu le-ai introduce. De exemplu, s
presupunem c programul cere ca utilizatorul s introduc o valoare a crei rdcin
ptrat trebuie gsit. Desigur utilizatorul NU ar trebui s introduc o valoare negativ,
deoarece rdcina ptrat a unei valori negative este un numr imaginar. Totui, cum va
funciona programul dac utilizatorul va face acest lucru?. O alt valoare care ntotdeauna
trebuie considerat ca mrime de intrare este valoarea zero, n special cnd este utilizat
n operaii aritmetice cum ar fi mprirea.
Cnd vei scrie primele dumneavoastr programe vei fi tentat s srii peste aceast faz
a verificrii preliminate, deoarece de abia ateptai s executai programul pe care l-ai
scris. Totui, pe msura ce ctigai experien, v vei da seama repede ct de mult timp
economisii urmnd aceast procedur.
1.3.4.2 Compilarea/linkeditarea programului
1.3.4.2.1 Compilarea
Procesul de compilare este realizat cu ajutorul compilatorului, care translateaz codul
surs n cod obiect (cod main), pentru ca programul s poat fi neles de calculator. n
cazul limbajului C, n prima faz a compilrii este invocat preprocesorul. Acesta
recunoate i analizeaz mai nti o serie de instruciuni speciale, numite directive
procesor. Verific apoi codul surs pentru a constata dac acesta respect sintaxa i
semantica limbajului. Dac exist erori, acestea sunt semnalate utilizatorului. Utilizatorul
trebuie s corecteze erorile (modificnd programul surs). Abia apoi codul surs este
translatat n cod de asamblare, iar n final, n cod main, binar, propriu calculatorului.
Acest cod binar este numit cod obiect i de obicei este memorat ntr-un alt fiier, numit
fiier obiect. Fiierul obiect va avea, de obicei, acelai nume cu fiierul surs i extensia
.obj.
1.3.4.2.2 Linkeditarea
Dup ce programul surs a fost translatat n program obiect, el este va fi supus operaiei
de linkeditare. Scopul fazei de linkeditare este acela de a obine o form final a
programului, n vederea execuiei acestuia. Linkeditorul leag modulele obiect, rezolv
referinele ctre funciile externe i rutinele din biblioteci i produce cod executabil,
memorat ntr-un alt fiier, numit fiier executabil (acelai nume, extensia .exe)
Cod executabil
*.exe Linkeditor
Cod
obiect
*.obj
(Preprocesor)
Compilator
Cod surs
*.c
Figura 1.1 Etapele necesare obinerii fiierului executabil

n mod obinuit, la compilare pot apare diferite tipuri de erori cum ar fi: erorile de sintax,
pe care le-ai fcut n scrierea programului, i care reprezint o violare a regulilor limbajului
de programare (cum ar fi de exemplu utilizarea caracterului "." n locul caracterului ";"). n
fiierul surs pot exista de asemenea i erori de tip. O eroare de tip apare atunci cnd

6
Noiuni introductive

7
ncercai s utilizai tipuri diferite, de exemplu tipul caracter n locul unei date de tip
numeric.
O eroare de sintax este orice nclcare a regulilor limbajului de programare, iar o
eroare de tip apare atunci cnd se utilizeaz un tip de dat n locul altuia.
n timpul compilrii, compilatorul va genera mesaje de eroare i de avertisment i va
poziiona cursorul pe ecranul monitorului n poziia din program, n care a fost detectat
eroarea. Dac nu nelegei un anumit mesaj de eroare, apsai doar tasta F1 pentru a
primi explicaii suplimentare legate de acea eroare. Programul nu poate fi compilat mai
departe de punctul n care a fost detectat eroarea pn cnd aceasta nu este corectat.
Odat ce eroarea a fost corectat programul trebuie compilat din nou. Dac alte erori sunt
depistate ele trebuie corectate, programul recompilat i aa mai departe pn cnd
ntregul program este compilat cu succes.
Dup ce compilatorul nu mai semnaleaz erori, trebuie editate legturile cu alte rutine care
sunt necesare pentru execuia programului. Erorile n faza de editare a legturilor
(linkeditare) apar atunci cnd aceste rutine nu pot fi accesate sau nu sunt gsite n
directorul indicat.
O eroare la editarea legturilor apare atunci cnd una dintre rutinele accesate nu
poate fi localizat de compilator.
1.3.4.3 Rularea programului
Odat compilat i editarea legturilor efectuat, trebuie s executai sau s rulai
programul. Totui, doar pentru c programul a fost compilat i legturile editate cu succes
nu nseamn c va funciona corect n toate condiiile posibile. Erorile obinuite care pot
s apar n acest stadiu sunt erori logice i erori de execuie. Aceste tipuri de erori sunt
cel mai greu de depistat. O eroare logic apare arunci cnd, de exemplu, o bucl i spune
calculatorului s repete o operaie, dar nu i spune cnd s se opreasc. Acest tip de bucl
se numete bucl infinit. O astfel de eroare nu va genera un mesaj de eroare, deoarece
calculatorul face ceea ce i se spune.
O eroare de execuie apare cnd programul ncearc s efectueze o operaie ilegal, n
contradicie cu regulile matematice sau ale compilatorului folosit. Dou erori de execuie
comune sunt mprirea cu zero i extragerea rdcinii ptrate dintr-o valoare negativ. O
eroare obinuit dar de aceast dat impus de compilator, este ncercarea de utilizare a
unui numr ntreg mai mare dect posibilitile de reprezentare ale calculatorului. Cele mai
multe compilatoare C limiteaz domeniul numerelor ntregi la intervalul [-32768, 32767]. n
cazul n care un ntreg depete aceste limite rezultatele nu pot fi anticipate.
Uneori, cnd apare o eroare de execuie programul poate fi abandonat automat cu
afiarea unui mesaj de eroare corespunztor. Alteori programul pare s funcioneze corect
dei datele obinute sunt greite. n aceste situaii s-ar putea s fie necesar consultarea
manualelor compilatorului pentru determinarea cu exactitate a naturii erorii. Oricum
eroarea trebuie depistat i eliminat naintea unei alte ncercri de executare a
programului.
O eroare logic apare atunci cnd compilatorul face ceea ce i se spune, dar nu este
ceea ce doreai de fapt. O eroare de execuie apare atunci cnd programul ncearc
s efectueze o operaie care nu este n conformitate cu regulile matematice sau cele
particulare ale compilatorului folosit
Capitolul 1

8
Un alt tip de erori, din pcate foarte des ntlnite n programele inginereti, se refer la
unitile de msur ale mrimilor fizice. Calculele efectuate de ctre programe se
efectueaz exclusiv cu numere/valori i nicidecum cu mrimi fizice. De exemplu, dac n
calcule considerm viteza unui corp v=5, calculatorul nu va ti dac aceast valoare
reprezint m/s sau km/h. Coerena sistemului de uniti de msur pentru mrimile fizice
folosite n calcule revine n exclusivitate programatorului, i este bine ca toate mrimile
fizice s fie exprimate de la nceput n uniti ale SI: m, kg, s.
1.3.4.4 Utilizarea depanatorului
Unul dintre cele mai importante instrumente de programare pe care le avei la dispoziie
este depanatorul (debugger). El v permite s examinai ndeaproape modul n care
funcioneaz programul dumneavoastr. Mediul C include un depanator integrat care
permite execuia pas cu pas a programelor i n acelai timp vizualizarea rezultatelor
curente.
1.3.5 Elaborarea documentaiei
Unul din ultimii pai al algoritmului programatorului, este foarte adesea trecut cu vederea,
dar este un pas toarte important n special cnd programele urmeaz s fie vndute unor
utilizatori. Efortul necesar elaborrii documentaiei poate fi uurat dac etapele precedente
ale algoritmului programatorului au fost efectuate n mod corespunztor. n aceste condiii
documentaia poate fi simpla nregistrare a rezultatelor obinute n etapele anterioare. O
bun documentaie trebuie s includ cel puin urmtoarele:
o descriere narativ a definirii problemei care va include tipul de intrare, ieire i
prelucrare implicate de program;
algoritmul;
un listing al programului comentat. Comentarea unui program este o parte
important din cadrul ntregului proces de elaborare a documentaiei. Fiecare
program trebuie s includ comentarii la nceputul acestuia prin care s se
precizeze ceea ce face, algoritmii speciali pe care i utilizeaz i un scurt rezumat al
definirii problemei. n plus, trebuie incluse numele programatorului, data la care a
fost scris programul, sau data ultimei modificri;
exemple de date de intrare i de ieire;
rezultatele testrii i depanrii;
instruciuni de utilizare.
Documentaia trebuie s fie bine structurat i ntr-o form agreabil. Trebuie s fie uor
de neles de dumneavoastr, dar i de ctre oricare alt persoan care ar dori s utilizeze
sau s modifice programul n viitor. O ultima remarc: elaborarea documentaiei trebuie s
fie un proces n continu desfurare. Ori de cte ori modificai programul trebuie s avei
grij ca documentaia s fie actualizat n mod corespunztor.
1.3.6 Exploatarea i ntreinerea
Const n activitatea de personalizare (logo-uri, antete, capuri de tabele, etc.) sau
modificare a aplicaiei, la cererea beneficiarului sau n urma unor deficiene constatate pe
parcursul utilizrii aplicaiei.
1.4 Abstractizare i rafinare
n acest moment, trebuie s introducem un concept foarte important n programare, i
anume abstractizarea. Acest concept ne permite s vedem problema n termeni generali,
fr s ne de preocupm detalii i n consecin, ofer posibilitatea generalizrii n
rezolvarea problemelor.
Noiuni introductive

9
Abstractizarea permite generalizarea n rezolvarea problemelor prin abordarea
acestora n termeni generali, fr s in seama de detaliile soluiei
Cnd ncepei s scriei un nou program, pentru nceput trebuie s avei n minte
imaginea de ansamblu a problemei. Odat ce ai fcut acest lucru, mai trziu, putei
rafina n mod gradat soluia oferind mai multe detalii, pn cnd ajungei la ceea ce v
dorii. Procesul de adugare treptat de noi detalii unei soluii generale a unei probleme
se numete rafinare incremental.
Rafinarea incremental este procesul de adugare treptat a detaliilor n generarea
unei soluii pn n momentul n care ea poate fi codificat cu uurin.
Conceptele de abstractizare i rafinare incremental v permit s controlai problema n
spiritul metodei divide ei impera i s o rezolvai ntr-o manier top-down. Aceast
strategie s-a dovedit de succes pentru toate tipurile de probleme, n special n programare.
n programare generm o soluie sau un algoritm, i n mod gradat l rafinm producnd
algoritmi mai detaliai, pn cnd ajungem la un nivel care poate fi codificat cu uurin
ntr-un limbaj de programare.
1.5 Limbajul C/C++
1.5.1 Originile limbajului C
C a fost inventat i implementat pentru prima oar de ctre Dennis Ritchie pe un sistem
DEC PDP-11 care folosea sistemul de operare UNIX [3]. C este rezultatul unui proces de
dezvoltare care a nceput cu un limbaj denumit BCPL. BCPL a fost pus la punct de ctre
Martin Richards i a stat la baza unui program denumit B, inventat de ctre Ken
Thompson. B a dus la dezvoltarea limbajului C, n anii 70.
Timp de mult vreme, standardul de facto pentru limbajul C a fost versiunea furnizat
mpreun cu varianta 5 a sistemului de operare UNIX. Aceasta a fost descris pentru
prima oar n volumul [4]. Odat cu creterea popularitii calculatoarelor personale, au
fost create o mulime de implementri ale limbajului C. Printr-o coinciden de
domeniul miraculosului, mare parte dintre acestea s-au dovedit de un mare grad de
compatibilitate. (Aceasta nseamn c un program scris pentru una din aceste variante
putea fi compilat cu succes folosind o alt variant.) Cu toate acestea, din cauza
inexistenei unui standard, au existat i neconcordane. Pentru a rezolva aceasta
problem, n vara lui 1983 a fost creat o comisie care s stabileasc un standard ANSI
(American National Standards Institute) care s defineasc definitiv limbajul C. Standardul
ANSI C a fost adoptat, n cele din urm, n decembrie 1989, iar primele copii ale acestuia
au devenit accesibile publicului la nceputul lui 1990. n prezent, toate principalele
compilatoare de C sunt compatibile cu standardul ANSI C. Acest standard mai conine i
informaii privind caracteristicile vechii versiuni de C ncorporat n UNIX. Cu alte cuvinte,
indiferent de compilatorul de C folosit sau de mediul n care este folosit acesta, cartea de
fa ofer un material cu aplicabilitate imediat.

C este adesea denumit limbaj de nivel mediu (middle-level language). Aceasta nu
nseamn c C ar fi mai puin puternic, mai dificil de folosit sau mai puin extins dect un
limbaj de nivel nalt cum ar fi BASIC sau Pascal, i nici nu implic faptul c C ar fi tot att
de dificil ca limbajul de asamblare (i problemele asociate acestuia). C este conceput ca
limbaj de nivel mediu ntruct combin cele mai reuite elemente ale limbajelor de nivel
Capitolul 1

10
nalt cu gradul de control i flexibilitatea oferite de ctre limbajul de asamblare. Lista
urmtoare prezint modul n care C se ncadreaz n spectrul limbajelor de calculator.

Limbaje de nivel nalt: Ada, Modula-2, Pascal, COBOL, FORTRAN, BASIC
Limbaje de nivel mediu: C++, C, FORTH
Limbaje de nivel sczut: Macro-asamblor, Limbaj de asamblare

n calitate de limbaj de nivel mediu, C permite manevrarea biilor, a octeilor i adreselor
de memorie, adic a elementelor de baz n funcionarea unui calculator. n ciuda acestui
fapt, codul C este de asemenea foarte portabil.
Portabilitatea semnific uurina de a adapta programele scrise pentru o anumit
categorie de calculatoare sau sisteme de operare la alte calculatoare sau sisteme de
operare.
De exemplu, dac un program scris pentru DOS poate fi convertit cu uurin astfel nct
s poat fi rulat sub Windows, acel program este portabil.
Toate limbajele de programare de nivel nalt accept conceptul de tipuri de date (data
types). Un tip de date definete un set de valori pe care o variabil le poate stoca
mpreun cu un set de operaii la care poate fi supus variabila respectiv. Cele mai
comune tipuri de date sunt cele ntregi, de tip caracter sau reale. Dei limbajul C include
cinci tipuri de date, el nu este un limbaj puternic tipizat, cum sunt Pascal i Ada. C permite
aproape toate tipurile de conversii. De exemplu, datele de tip caracter i ntreg se pot
substitui reciproc n cadrul unei expresii.
Spre deosebire de limbajele de nivel nalt, C nu execut aproape nici o depistare a erorilor
n timpul rulrii. De exemplu, limbajul nu verific dac limitele unui tablou sunt depite.
Aceste verificri revin n sarcina programatorului.
n aceeai ordine de idei, C nu necesit o compatibilitate strict ntre tipul unui parametru
i cel al unui argument. Dup cum poate tii, un limbaj de nivel nalt pretinde ca tipul unui
argument s fie (mai mult sau mai puin) identic cu tipul parametrului care va primi
argumentul. Nu este cazul limbajului C. Acesta permite unui argument s fie de orice tip,
dac poate fi convertit convenabil la tipul parametrului. n plus, C asigur toate conversiile
automate n acest scop.
C se deosebete de alte programe prin aceea c permite manevrarea direct a biilor, a
octeilor, a cuvintelor i a pointerilor. Aceasta l face indicat pentru programarea la nivel de
sistem, acolo unde aceste operaiuni sunt obinuite.
Un alt aspect important al lui C este c dispune de numai 32 de cuvinte-cheie (din care 27
aparin standardului de facto elaborat de Kernighan i Ritchie, iar alte 5 au fost adugate
de comisia de standardizare ANSI), care reprezint comenzile care alctuiesc limbajul C.
Un limbaj de nivel nalt are, n mod normal, un numr de cuvinte-cheie de cteva ori mai
mare. Ca termen de comparaie, gndii-v c majoritatea versiunilor de BASIC au cu
mult peste 100 de cuvinte-cheie!
C a fost creat, modificat i testat practic de ctre programatori "de meserie". Rezultatul
final este acela c limbajul C ofer programatorului exact ceea ce i dorete acesta:
restricii puine, mesaje de eroare limitate, structuri de bloc, funcii de sine stttoare i un
set compact de cuvinte-cheie.

Limbajul C++ (C incrementat) apare la nceputul anilor 80 i l are ca autor pe Bjarne
Stroustrup. El este o variant de limbaj C mbuntit, mai riguroas i mai puternic,
completat cu construciile necesare aplicrii principiilor programrii orientate pe obiecte
(OOP - Object Oriented Programming). Limbajul C++ pstreaz toate elementele
limbajului C, beneficiind de eficiena i flexibilitatea acestuia. Limbajul C++ este un
Noiuni introductive

11
superset al limbajului C. Incompatibilitile sunt minore, de aceea, modulele C pot fi
ncorporate n proiecte C++ cu un efort minim.
1.6 Structura unui program C sau C++
Un program scris n limbajul C (sau C++) este compus din unul sau mai multe fiiere
surs.
Un fiier surs este un fiier text care conine codul surs (n limbajul C) al unui
program.
Fiecare fiier surs conine una sau mai multe funcii i eventual, referine ctre unul sau
mai multe fiiere header (antet).
Funcia principal a unui program este numit main. Execuia programului ncepe cu
execuia acestei funcii, care poate apela, la rndul ei, alte funcii. Toate funciile folosite n
program trebuie descrise n fiierele surs (cele scrise de ctre programator), n fiiere
header (funciile pre-definite, existente n limbaj), sau n biblioteci de funcii.
Un fiier header este un fiier aflat n sistem sau creat de ctre programator, care
conine declaraii i definiii de funcii i variabile.
Aciunile din fiecare funcie sunt codificate prin instruciuni. Exist mai multe tipuri de
instruciuni, care vor fi discutate n capitolul urmtor.
O instruciune este orice expresie valid (de obicei, o atribuire sau un apel de
funcie), urmat de simbolul ";".
Uneori, ca instruciune poate apare instruciunea nul (doar ";"), sau instruciunea
compus (privit ca o succesiune de instruciuni simple, ncadrate ntre acoladele
delimitatoare {}).
O expresie este o structur corect sintactic, format din operanzi i operatori.
Un program C se salveaz de obicei cu extensia C i implicit compilarea din mediul de
programare Borland C se va face cu compilatorul de C. Dac programul este ns salvat
cu extensia CPP, atunci compilarea se va face cu compilatorul C++.
Un program C obinuit are urmtoarea structur [5] (textul dintre /* i */ reprezint
comentarii):
/*directive de preprocesare:*/
/*includeri de fiiere sau biblioteci*/
/*definiii de macrocomenzi*/
/*directive de compilare condiionat*/
/*definiii de tipuri de date*/
/*declaraii de variabile globale*/
/*definiii de funcii sau/i descrierea unor functii*/
main() /*antetul funciei principale main*/
{ /*nceputul corpului funciei main*/
/*declaraii de variabile locale*/
/*instruciunile funciei principale */
return 0; /*valoarea returnat de funcia main*/
} /*sfritul corpului funciei main*/
/*descrierea funciilor care au definiiile mai sus*/
Capitolul 1

12
Trebuie fcut o precizare nc de la nceput: spre deosebire de alte limbaje cum ar fi
Pascal-ul, compilatoarele pentru C i C++ fac distincie ntre litere mari i mici.
1.6.1 Preprocesorul
Aa cum am menionat, n faza de compilare a fiierului surs este invocat nti
preprocesorul. Acesta trateaz directivele speciale - numite directive preprocesor - pe care
le gsete n fiierul surs. Directivele preprocesor sunt identificate prin simbolul #, care
trebuie s fie primul caracter, diferit de spaiu, dintr-o linie. Directivele preprocesor sunt
utilizate la includerea fiierelor header, la definirea numelor constantelor simbolice, la
definirea macro-urilor, sau la realizarea altor funcii (de exemplu, compilarea condiionat.
1.6.1.1 Includeri
La nceputul unui program C sau C++ se includ de obicei fiiere antet (cu extensia h), dar
se pot include i fiiere cu funcii C sau C++ (cu extensia C sau CPP).
Fiierele antet conin definiiile unor funcii a cror implementare se face separat n fiiere
cu extensiile C, CPP, obj sau lib. Fiierele *.obj conin cod C sau C++ n forma compilat,
iar fiierele *.lib conin biblioteci de funcii C i C++. Cele mai des folosite fiiere antet din
C sunt stdio.h (Standard Input/Output) i conio.h (Console Input/Output), care
conin definiiile funciilor standard de intrare/ieire (citiri, scrieri), respectiv definiii de
funcii consol I/O din DOS (de exemplu funcia clrscr()), care cur ecranul n modul
text).
O includere ncepe cu semnul # (diez, sharp), urmat de cuvntul include i de numele
fiierului care este inclus, care este dat ntre semnele < (mai mic) i > (mai mare), sau
ntre ghilimele.
Un fiier C sau C++ care se include NU trebuie s conin funcia main()!
1.6.1.2 Macrocomenzi
Macrocomenzile simple constau n atribuirea de nume simbolice unor constante.
Exemplu:
#define TRUE 1
#define FALSE 0
#define N 100
#define PI 3.14159
Tratarea acestor directive preprocesor are ca efect atribuirea valorii ntregi 1 numelui
(constantei simbolice) TRUE, i a valorii 0 numelui simbolic FALSE. Ca urmare, naintea
compilrii propriu-zise, n programul surs, apariiile numelor TRUE i FALSE vor fi
nlocuite cu valorile 1, respectiv 0. N i PI sunt constante obinuite, prima este tipul ntreg,
iar a doua este o constant real.

Macrocomanda de tip funcie reprezint o generalizare a conceptului de constant, n
sensul c putem avea expresii constante, care se nlocuiesc n codul executabil n
momentul compilrii. Definirea unei macrocomenzi de tip funcie ncepe cu #define. Dm
un exemplu:
#define suma(x,y) x+y
Un apel de forma suma(1.7, a) se va nlocui la compilare n codul executabil cu 1.7+a.
nlocuirea se face n fiecare loc n care este apelat macrocomanda. De aceea,
comportamentul unei macrocomenzi este mai degrab ca cel al unei constante dect ca al
unei funcii, dei apelul ei seamn cu cel al unei funcii.
Comportamentul macrocomenzilor poate conduce la erori de programare pentru cei care
nu i stpnesc modul de funcionare. De exemplu, valoarea expresiei suma(1,2)*5 este
Noiuni introductive
11, i nu 15, deoarece, nlocuirea direct a apelului suma(1,2) la compilare cu 1+2
conduce la expresia 1+2*5, care are valoarea 11, ci nu la expresia (1+2)*5 cu valoarea 15.
Frumuseea macrocomenzilor const ns n faptul c nu lucreaz cu tipuri de date
prestabilite, astfel n exemplul de mai sus macrocomanda suma va putea fi folosit pentru
orice tip de date, atta timp ct ntre valorile x i y se poate aplica operatorul +.
1.6.2 Funcia main
n limbajele C i C++ nu exist noiunea de procedur, ci din categoria subprogramelor
exist numai funcii. O funcie care are ca tip returnat void (vid) funcioneaz ca o
procedur. Dac o funcie nu are parametri, dup nume i se pun paranteze rotunde, adic
().
n orice program trebuie s existe o unic funcie main din interiorul creia se ncepe
execuia programului.
Funcia main poate avea ca tip returnat void sau int. Dac tipul returnat este int,
atunci n interiorul funciei main pot aprea instruciuni de forma return val_int; care
au ca efect ntreruperea execuiei programului i returnarea ctre sistemul de operare a
valori ntregi val_int. Ultima instruciune din funcia main este de obicei return 0;, ceea
nseamn c programul s-a terminat cu succes. Dac apare vreo eroare pe parcursul
execuiei programului care nu poate fi tratat (memorie insuficient, imposibilitate de
deschide a unui fiier etc.), se poate prsi programul cu o instruciune de forma return
val_int;, unde val_int este o valoare ntreag nenul.
Funcia main poate s nu aib nici un parametru, sau poate avea 2 parametri. Dac
funcia main are doi parametri, atunci primul este de tip int, care reprezint numrul de
parametrii n linie de comand cu care s-a executat programul, iar al doilea este un vector
de iruri de caractere, n care sunt memorai parametrii din linia de comand a
programului. Primul ir de caractere din vector (elementul de pe poziia 0) este chiar
numele executabilului programului.
Dac la execuia programului din interiorul mediului de programare C sunt necesari
parametri n linie de comand, atunci acetia se pot completa la Arguments... din meniul
Run. Aceti parametri nu vor fi cunoscui n afara mediului de programare. Execuia unui
program executabil cu parametri n exteriorul mediului de programare se face ca i orice
comand a sistemului de operare:

13
denumire_executabil
parametri_desprii_prin_spaii
1.7 Harta zonelor de memorie ale unui program C
Un program C compilat creeaz i folosete patru zone de
memorie distincte logic, care ndeplinesc funcii distincte. Prima
regiune este aceea care stocheaz codul programului. A doua
regiune reprezint zona de memorie n care sunt stocate
variabilele globale. Celelalte zone reprezint stiva i zona de
manevr. Stiva (stack) este folosit n mai multe scopuri, n
timpul executrii programului: memoreaz adresele de revenire ale apelurilor la funcii,
argumentele funciilor i variabilele locale. De asemenea, va memora starea curent a
unitii centrale de prelucrare. Zona de manevr (heap) este o regiune de memorie liber
pe care programul, prin intermediul funciilor de alocare dinamic ale limbajului C, le
folosete pentru stocarea unor articole de genul listelor nlnuite i a arborilor.
Figura 1.2 Harta zonelor
de memorie
Stiv (stack)


Zon de manevr
(heap)
Variabile globale
Codul programului
Aspectul exact al programului dvs. poate varia de la un compilator la altul i de la un
mediu de programare la altul. De exemplu, majoritatea compilatoarelor de C pentru familia
Capitolul 1
de procesoare 8086 folosesc modaliti diferite de organizare a memoriei, datorit
caracterului segmentat al arhitecturii memoriei a procesoarelor familiei 8086. Dei aspectul
fizic exact al fiecreia dintre cele patru regiuni de memorie difer n funcie de tipul de
CPU i de modul de implementare a limbajului C, Error! Reference source not found.
prezint conceptual modul de apariie a programelor C n memoria calculatorului.
1.8 Primele programe
n aceast seciune sunt prezentate i explicate trei programe cu scopul de a asigura un
suport de baz pentru prezentrile din capitolele urmtoare.
Prin tradiie, primul program C este un mic exemplu dintr-o lucrare devenit clasic -
The C programming language, de Brian W Kernigham i Dennis M Ritchie.
#include <stdio.h> //includerea antetului bibliotecii standard
main() //definirea funciei main care nu are argumente
{ //nceputul corpului funciei main
printf("Hello, world\n"); //apelul funciei printf
return 0; //ntoarcerea codului de eroare 0
} //sfritul corpului funciei main
Acest program afieaz un mesaj de salut.
Prima linie indic faptul c se folosesc funcii de intrare/ieire dintr-o bibliotec. Descrierea
modului de utilizare (numele, tipul argumentelor, tipul valorii returnate etc.) a acestora se
afl n fiierul cu numele stdio.h.
A doua linie declar funcia principal main care va conine instruciunile programului. n
acest caz singura instruciune este un apel al funciei printf care afieaz un mesaj la
terminal. Mesajul text este dat ntre ghilimele i se termin cu un caracter special new-line
('\n').
Instruciunea return pred controlul sistemului de operare la terminarea programului i
comunic acestuia codul 0 pentru terminare. Prin convenie aceast valoare semnific
terminarea normal a programului - adic nu au aprut erori n prelucrarea datelor. Corpul
funciei main apare ntre acolade.
Al doilea program ateapt de la terminal
introducerea unor numere ntregi nenule i determin
suma lor. n momentul n care se introduce o valoare
zero, programul afieaz suma calculat.
n cadrul funciei main se declar dou variabile s i n
care vor memora valori ntregi. Variabila s (care va
pstra suma numerelor introduse) este iniializat cu
valoarea 0. n continuare se repet o secven de dou
instruciuni, prima fiind o operaie de intrare i a doua
o adunare.
Primul argument al funciei scanf
- formatul de introducere "%d" -
indic faptul c se ateapt
introducerea unei valori ntregi n
format zecimal de la terminal (tastatur). Al doilea argument indic
unde se va depune n memorie valoarea citit; de aceea este
necesar s se precizeze adresa variabilei n (cu ajutorul
operatorului &).
n a doua instruciune la valoarea variabilei s se adun valoarea
variabilei n. Operatorul += are semnificaia "adun la".

14
#include <stdio.h>
main()
{
int s,n;
s = 0;
do{
scanf("%d",&n);
s += n;
}
while (n!=0);
printf("%d\n",s);
return 0;
}
#include <stdio.h>
main()
{
int n,i;
double a[100], p;
scanf("%d",&n);
for(i=0; i<n; i++)
scanf("%lf",&a[i]);
p = 1;
for (i=0; i<n; i++)
if (a[i]>0)
p *= a[i];
printf("%lf\n",p);
return 0;
}
Noiuni introductive
Aceast secven se repet (do) ct timp (while) valoarea introdus (n) este nenul.
Operatorul != are semnificaia "diferit de". n final funcia printf afieaz pe terminal
valoarea variabilei s n format zecimal.

Al treilea program ateapt de la terminal introducerea unei valori naturale n, dup care
mai ateapt introducerea a n valori reale (dubl precizie): a
0
, a
1
, ..., a
n1
. n continuare se
parcurge aceast list i se determin produsul valorilor strict pozitive. n final programul
afieaz produsul calculat.
n cadrul funciei main se declar dou variabile n i i care vor memora valori ntregi. Se
declar de asemenea un tablou unidimensional a care va memora 100 de valori de tip real
(dubl precizie), i o variabil p care va memora produsul cerut. Variabila n pstreaz
numrul de valori reale din lista a. Se citete de la terminal o valoare n. n continuare se
introduc valorile reale a
i
(i = 0, 1, ..., n - 1). Formatul de introducere "%lf" indic faptul c
se ateapt introducerea unei valori reale de la terminal, care va fi depus la locaia de
memorie asociat variabilei a
i
. n locul construciei &a[i] se poate folosi forma echivalent
a+i.
Pentru a introduce toate valorile a
i
se efectueaz un ciclu for, n cadrul cruia variabila i
(care controleaz ciclul) ia toate valorile ntre 0 (inclusiv) i n (exclusiv) cu pasul 1.
Trecerea la urmtoarea valoare a variabilei i se face cu ajutorul operatorului ++.
n continuare variabila p, care va memora produsul valorilor cerute, se iniializeaz cu 1.
Fiecare valoare a
i
este verificat (instruciunea if) dac este strict pozitiv i n caz
afirmativ este nmulit cu valoarea p. Operatorul *= are semnificaia "nmulete cu".

Cu sperana c aceste cteva exemple au deschis apetitul cititorului pentru programare,
vom trece n continuare la explicarea n detaliu a principalelor elemente ale limbajului de
programare C/C++.


15
Capitolul 2

16
2. Date, operatori i expresii
2.1 Vocabularul
n scrierea programelor n limbajul C/C++ pot fi folosite doar anumite simboluri care
alctuiesc alfabetul limbajului. Acesta cuprinde:
Literele mari sau mici de la A la Z (a-z);
Caracterul de subliniere ( _ underscore), folosit, de obicei, ca element de legtur ntre
cuvintele compuse;
Cifrele zecimale (0-9);
Simboluri speciale (Blanc ! " # % & ' ( ) * + , . / : ; < = > ? [ \ ] ^ _ ~ { | }). Acestea pot fi:
o Caractere:
operatori (Exemple: +, *, !=);
delimitatori (Exemple: blank (spaiu), tab \t, newline \n, cu rolul de a separa
cuvintele);
o Grupuri (perechi de caractere). Grupurile de caractere, numire adesea separatori,
pot fi:
( ) - ncadreaz lista de argumente ale unei funcii sau sunt folosite n
expresii pentru schimbarea ordinii de efectuare a operaiilor (n ultimul caz, fiind
operator);
{ } - ncadreaz instruciunile compuse;
// - Indic nceputul unui comentariu care se poate ntinde pn la sfritul
liniei;
/* */ - Indic nceputul i sfritul unui comentariu care poate cuprinde
mai multe linii;
" " - ncadreaz o constant ir (un ir de caractere);
' ' - ncadreaz o constant caracter (un caracter imprimabil sau o
secven escape).
[ ] - ncadreaz dimensiunile tablourilor sau indicii elementelor acestora
2.2 Unitile lexicale ale limbajului C
Unitile lexicale (cuvintele) limbajului C reprezint grupuri de caractere cu o semnificaie
de sine stttoare; exist ase tipuri de uniti lexicale i anume: identificatori, cuvinte-
cheie, constante, iruri, operatori i separatori.
2.2.1 Identificatori
Identificatorii reprezint numele unor date (constante sau variabile), sau ale unor
funcii.
Identificatorul este format dintr-un ir de litere (mari sau mici), cifre sau caracterul de
subliniere (underscore), fr spaii ntre ele, trebuie s nceap cu o liter sau cu
caracterul de subliniere i s fie sugestivi.
Exemple: viteza, greutate_neta, Viteza, Viteza1, GreutateNeta
Identificatorii pot conine litere mici sau mari, dar limbajul C este senzitiv la majuscule i
minuscule (case-sensitive). Astfel, identificatorii viteza i Viteza sunt diferii. Nu pot fi
Date, operatori i expresii

17
folosii ca identificatori cuvintele cheie. Identificatorii pot fi standard (ca de exemplu numele
unor funcii predefinite: scanf, clear, etc.) sau alei de utilizator.
2.2.2 Cuvinte cheie
Cuvintele cheie sunt identificatori rezervai ai limbajului crora programatorul nu le
poate da o alt utilizare.
Un cuvnt-cheie dintr-un program scris n C are o semnificaie bine determinat i nu
poate fi folosit pentru alte scopuri, n sensul c nu poate fi folosit ca variabil sau ca nume
de funcie.
Tabelul 2.1 ofer lista celor 32 de cuvinte-cheie, care, combinate cu sintaxa formal a
limbajului, formeaz limbajul de programare C. Dintre acestea, 27 au fost definite nc de
la varianta original de C. Urmtoarele cinci au fost adugate de comisia de standardizare
ANSI C: enum, const, signed, void i volatile.
Tabelul 2.1 Cuvintele-cheie ale limbajului C
auto double int struct
break else long switch
case enum register typedef
char extern return union
const float short unsigned
continue for signed void
default goto sizeof volatile
do if static while
Suplimentar, multe compilatoare de C au mai adugat i alte cuvinte-cheie, care contribuie
la o exploatare superioar a mediului de operare al acestora. De exemplu, multe
compilatoare includ cuvinte-cheie pentru administrarea structuri de memorie a familiei
de procesoare 8086, pentru facilitarea programrii inter-limbaje i pentru accesarea
ntreruperilor. Iat o list a celor mai des folosite cuvinte-cheie extinse:
asm _cs ds _es
_ss edeel far huge
interrupt near pascal
E posibil ca i compilatorul dvs. s accepte alte extensii care s permit utilizarea la
maximum a mediului su specific de lucru.
Toate cuvintele-cheie folosite de limbajul C se scriu obligatoriu cu litere mici. n C,
majusculele sunt diferite de literele mici; de exemplu, else este un cuvnt-cheie timp ce
ELSE nu este.
2.2.3 Operaii de intrare/ieire
Limbajele C/C++ nu posed instruciuni de intrare/ieire, deci de citire/scriere (ca limbajul
PASCAL, de exemplu). n limbajul C aceste operaii se realizeaz cu ajutorul unor funcii
(de exemplu, printf i scanf - descrise detaliat n Capitolul 11.1.1), iar n limbajul C++
prin suprancrcarea operatorilor (definirea unor noi proprieti ale unor operatori existeni,
fr ca proprietile anterioare s dispar), mai precis a operatorilor >> i << . Vom folosi
n continuare abordarea limbajului C++, fiind, n momentul de fa, mai simpl. n limbajul
C++ sunt predefinite urmtoarele dispozitive logice de intrare/ieire:
cin - console input - dispozitivul de intrare (tastatura);
cout - console output - dispozitivul de ieire (monitorul).
Transferul informaiei se realizeaz cu operatorul >> pentru intrare i operatorul <<
pentru ieire. Utilizarea dispozitivelor de intrare/ieire cu operatorii corespunztori
Capitolul 2

18
determin deschiderea unui canal de comunicaie a datelor ctre dispozitivul respectiv.
Dup operator se specific informaiile care vor fi citite sau afiate.
Exemple:
cout<<var; /* afieaz valoarea variabilei var pe monitor*/
cin>>var; /* citete valoarea variabilei var de la tastatur */
Sunt posibile operaii multiple, de tipul:
Exemple:
cout << var1 << var2 << var3;
cin >> var1 >> var2 >> var3;
n acest caz, se efectueaz succesiv, de la stnga la dreapta, scrierea, respectiv citirea
valorilor variabilelor var1, var2 i var3.

Operatorul >> se numete operator extractor (extrage valori din fluxul datelor de intrare,
conform tipului acestora), iar operatorul << se numete operator insertor (insereaz
valori n fluxul datelor de ieire, conform tipului acestora). Tipurile de date citite de la
tastatur pot fi toate tipurile numerice, caracter sau ir de caractere. Tipurile de date
transferate ctre ieire pot fi: toate tipurile numerice, caracter sau ir de caractere.
Operanzii operatorului extractor (>>) pot fi doar nume de variabile. Operanzii operatorului
insertor (<<) pot fi nume de variabile (caz n care se afieaz valoarea variabilei),
constante (iruri) sau expresii. Utilizarea dispozitivelor i operatorilor de intrare/ieire n
C++ impune includerea fiierului iostream.h.
Exemple:
char c;
cout<<"Astept un caracter:"; //afiarea constantei sir de caractere, deci a
mesajului
cin>>c; //citirea valorii variabilei c, de tip caracter
int a, b, e; double d;
cin>>a>>b>>e>>d; //citirea valorilor variabilelor a, b, e, d de tip int, int, int, double
cout<<"a="<<a<<"Valoarea expresiei a+b este:"<<a+b<<'\n';
2.3 Date n limbajul C
Aa cum s-a vzut, un program realizeaz o prelucrare (termen care trebuie considerat
ntr-un sens foarte general) de informaie. n program datele apar fie sub forma unor
constante (valori cunoscute anticipat, care nu se modific), fie sub form de variabile.
Constantele i variabilele sunt obiectele informaionale de baz manipulate ntr-un
program.
Fiecare categorie de date este caracterizat de atributele:
Nume; Tip; Valoare; Clas de memorare.
2.3.1 Numele unei date
Numele unei date este un identificator i, ca urmare, trebuie s respecte regulile specifice
identificatorilor (vezi 2.2.1). De asemenea, numrul de caractere care intr n compunerea
unui identificator este nelimitat, ns, implicit, numai primele 32 de caractere sunt luate n
considerare. Aceasta nseamn c doi identificatori care au primele 32 de caractere
identice, difereniindu-se prin caracterul 33, vor fi considerai identici.
Date, operatori i expresii

19
2.3.2 Tipuri de date
Tipul unei date const ntr-o mulime de valori pentru care s-a adoptat un anumit mod de
reprezentare n memoria calculatorului i o mulime de operatori care pot fi aplicai acestor
valori. Tipul unei date determin lungimea zonei de memorie ocupat de acea dat. n
general, lungimea zonei de memorare este dependent de calculatorul pe care s-a
implementat compilatorul. Tabelul 2.2. prezint lungimea zonei de memorie ocupat de
fiecare tip de dat pentru compilatoarele sub MS-DOS i UNIX/LINUX. Tipurile de baz
sunt:
void vid, care fie declar o funcie care nu returneaz nici o valoare, fie creeaz
pointeri generici
char un singur octet (1 octet/byte = 8 bii), capabil s conin codul unui caracter
din setul local de caractere;
int numr ntreg, reflect n mod tipic mrimea natural din calculatorul utilizat;
float numr real n virgul mobil, simpl precizie;
double numr real n virgul mobil, dubl precizie.
2.3.2.1 Modificarea tipurilor de baz
n afar de tipul void, tipurile fundamentale de date pot fi precedate de diveri
modificatori. Un modificator se utilizeaz pentru a schimba sensul tipului de baz n
vederea unei adaptri mai precise la anumite situaii. lat lista modificatorilor:
signed unsigned long short
Modificatorii signed, short, long i unsigned pot fi aplicai tipurilor de baz caracter i
ntreg. Totui, modificatorul long poate fi aplicat i tipului de date double.
Tabelul 2.2 prezint toate combinaiile de tipuri de date care ader la standardul ANSI C,
precum i domeniile minimale de valori i dimensiunile aproximative n bii.
Tabelul 2.2 Tipurile de date care ader la standardul ANSI C, dimensiunile aproximative n bii i
domeniile minimale de valori
Tip Dimens
aprox n bii
Domeniu minimal de valori
char 8 de la -127 la 127
unsigned char 8 de la 0 la 255
signed char 8 de la -127 la 127
int 16 de la -32767 la 32767
unsigned int 16 de la 0 la 65535
signed int 16 Similar cu int
short int 16 Similar cu int
unsigned short int 16 de la 0 la 65535
signed short int 16 Similar cu short int
long int 32 de la -2.147.483.647 la 2.147.483.647
signed long int 32 Similar cu long int
unsigned long int 32 de la 0 la 4.294.967.295
float 32 6 zecimale exacte
double 64 10 zecimale exacte
long double 80 10 zecimale exacte
Utilizarea modificatorului signed pentru variabile de tip ntreg este permis, dar este
inutil, deoarece declaraia implicit de ntreg presupune un numr cu semn (signed).
Cea mai important utilizare a acestui modificator este de a modifica datele de tip char n
variantele de implementare n care char este considerat implicit ca neavnd semn.
Unele variante de implementare permit aplicarea lui unsigned tipurilor de date n virgul
mobil (ca n unsigned double). Acest procedeu reduce ns portabilitatea codului
Capitolul 2

20
surs i n general nu este recomandat. Tipurile de date suplimentare sau extinse care nu
au fost definite de ctre standardul ANSI C nu vor fi probabil recunoscute pe orice variant
de implementare a programului C.

S considerm, de exemplu, tipul int, folosit pentru date ntregi (pozitive sau negative).
Evident c mulimea valorilor pentru acest tip va fi, de fapt, o submulime finit de numere
ntregi. Dac pentru memorarea unei date de tip int se folosesc 2 octei de memorie,
atunci valoarea maxim pentru aceasta va fi
1
2
x2
16
- 1, deci 2
15
- 1 (32767), iar valoarea
minim va fi -
1
2
x2
16
, deci -2
15
(-32768). ncercarea de a calcula o expresie de tip int a
crei valoare se situeaz n afara acestui domeniu va conduce la o eroare de execuie.
Mulimea valorilor pentru o dat de tip unsigned int (ntreg fr semn) va fi format din
numerele ntregi situate n intervalul [0, 2
16
- 1].

Diferena ntre ntregii cu semn (signed) i cei fr semn (unsigned) rezid n modul n
care este interpretat bitul de cel mai mare ordin al ntregului. Dac precizai un ntreg cu
semn, compilatorul de C va genera un cod care presupune faptul c bitul de cel mai mare
ordin al ntregului va fi folosit ca indicator de semn (sign flag). Dac acesta are valoarea 0,
numrul este pozitiv; n caz contrar, numrul este negativ.
n general, numerele negative sunt reprezentate folosind metoda complementului fa de
doi, care inverseaz toi biii din numrul respectiv (n afar de indicatorul de semn),
adaug 1 la acel numr i seteaz valoarea indicatorului de semn la 1.
ntregii cu semn sunt foarte importani pentru o mare varietate de algoritmi, dar dispun
numai de jumtate din mrimea frailor lor fr semn. De exemplu, iat 32767 (care ocup
2 octei/16 bii):
01111111 11111111
Dac bitul de cel mai mare ordin (care are acum valoarea 0) este setat la 1 atunci, dac
numrul este declarat ca fiind de tip:
int, numrul va fi interpretat drept -1.
unsigned int (ntreg fr semn), numrul devine 65535.

Fr a detalia foarte mult modul de reprezentare a datelor reale (de tip float sau
double), vom sublinia faptul c, pentru acestea, este important i precizia de
reprezentare. Deoarece calculatorul poate reprezenta doar o submulime finit de valori
reale, n anumite cazuri, pot apare erori importante.
Numerele reale pot fi scrise sub forma: N = mantisa x baza
exponent
, unde: baza reprezint
baza sistemului de numeraie; mantisa (coeficientul) este un numr fracionar normalizat (
n faa virgulei se afl 0, iar prima cifr de dup virgul este diferit de zero); exponentul
este un numr ntreg. Deoarece forma intern de reprezentare este binar, baza = 2. n
memorie vor fi reprezentate doar mantisa i exponentul. Numrul de cifre de dup virgul
determin precizia de exprimare a numrului.
Lungimea zonei de memorie ocupate de o dat de un anumit tip (pe ci octei este
memorat data) poate fi aflat cu ajutorul operatorului sizeof.
Exemplu:
printf("Un int este memorat pe %d octeti.\n", sizeof(int));
Instruciunea are ca efect afiarea pe monitor a mesajului: Un int este memorat pe 2
octei.

Date, operatori i expresii

21
n header-ul <values.h> sunt definite constantele simbolice (cum ar fi: MAXINT,
MAXSHORT, MAXLONG, MINDOUBLE, MINFLOAT, etc.) care au ca valoare limitele inferioar
i superioar ale intervalului de valori pentru tipurile de date enumerate (de exemplu
MAXINT reprezint valoarea ntregului maxim care se poate memora, etc.).
2.3.3 Variabile
O variabil este o locaie cunoscut de memorie utilizat pentru a stoca o valoare
care poate fi modificat prin program.
Variabilele sunt date (obiecte informaionale) ale cror valori se pot modifica n timpul
execuiei programului i sunt utilizate pentru memorarea valorilor introduse pentru datele
de intrare sau a rezultatelor; ele sunt caracterizate de atributele: nume, tip, valoare i clas
de memorare. Dac la o constant ne putem referi folosind caracterele componente, la o
variabil ne vom referi prin numele ei. Numele unei variabile ne permite accesul la
valoarea ei, sau schimbarea valorii sale, dac este necesar acest lucru. Numele unei
variabile este un identificator ales de programator. Ca urmare, trebuie respectate regulile
enumerate n paragraful legat de identificatori.
Dac o dat nu are legturi cu alte date (de exemplu o relaie de ordine), vom spune c
este o dat izolat. O dat izolat este o variabil simpl. Dac datele se grupeaz ntr-un
anumit mod (n tablouri - vectori, matrice - sau structuri), variabilele sunt compuse
(structurate).
Toate variabilele care vor fi folosite n program, trebuie declarate nainte de utilizare.
2.3.3.1 Declararea variabilelor
Modul general de declarare a variabilelor este:
tip_variabile list_nume_variabile;
Se specific tipul variabilei(lor) i o list format din unul sau mai muli identificatori ai
variabilelor de tipul respectiv. ntr-un program n limbajul C, declaraiile de variabile pot
apare n orice loc n programul surs. La declararea variabilelor, se rezerv n memorie un
numr de octei corespunztor tipului variabilei, urmnd ca ulterior, n acea zon de
memorie, s fie memorat o anumit valoare.
Exemple:
int i, j;/*declararea var. simple i, j, de tip int. Se rezerv pentru i i j cte 16 bii (2
octei)*/
char c; /* declararea variabilei simple c, de tip char. Se rezerv un octet. */
float lungime; /* declararea variabilei simple lungime de tip float; se rezerv 4
octei */
2.3.3.2 Unde se declar variabilele
Variabilele se declar n trei locuri de baz:
n interiorul funciilor - variabilele locale,
n definiia parametrilor funciilor - parametrii formali, i
n exteriorul tuturor funciilor - variabilele globale.
Poriunea de cod n care este accesibil o variabil reprezint domeniul de
vizibilitate al variabilei respective.
Timpul de via al unei variabile este durata de execuie a blocului, funciei sau
programului n care aceasta este definit.
Capitolul 2

22
2.3.3.2.1 Variabilele locale
Variabilele declarate n interiorul unor blocuri sau funcii sunt denumite variabile
locale.
n anumite lucrri dedicate limbajului C, aceste variabile sunt cunoscute i sub denumirea
de variabile automate (automatic variables). n aceast carte se va folosi termenul mai des
uzitat de variabile locale. Cu alte cuvinte, variabilele locale nu sunt recunoscute n
exteriorul blocului de cod propriu. Nu uitai c un bloc de cod ncepe cu o acolad de
deschidere i se ncheie cu o acolad de nchidere.
Variabilele locale exist numai att timp ct blocul de cod n interiorul cruia au fost
declarate este executat. Altfel spus, o variabil este creat la intrarea n blocul su propriu
de cod i este distrus la ieire.
Cel mai comun bloc de cod n interiorul cruia se declar variabilele locale este funcia. De
exemplu, s considerm urmtoarele dou funcii:
void func1(void)
{ int x; x = 10;}

void func2(void)
{ int x; x = -199;}
Variabila ntreag x este declarat de dou ori, o dat n func1() i a doua oar n
func2(). Variabila x din func1() nu are nici o legtur cu variabila x din func2(), i
aceasta deoarece fiecare x este cunoscut numai codului din acelai bloc n care s-a fcut
declaraia variabilei.
Majoritatea programatorilor declar toate variabilele locale folosite de o funcie imediat
dup acolada de deschidere a funciei i nainte de orice alte declaraii. Cu toate acestea
exist i posibilitatea de a declara variabilele locale din interiorul oricrui bloc de cod.
Blocul definit de ctre o funcie nu este dect un caz special.
De exemplu,
void f(void)
{
int t;
scanf("%d", &t);
if(t==1) {
char s[80]; /*este creat numai dup intrarea n acest bloc*/
printf("dati numele:");
gets(s) ;
/* programul face ceva... */
n acest exemplu, variabila local s a fost creat la intrarea n blocul de cod if a fost
distrus la ieire. Mai mult, s este cunoscut numai n interiorul blocului i nu se poate
face referin la aceasta n alt parte, nici mcar n alte zone a funciei care o conine.
Un avantaj al declarrii unei variabile locale n interiorul unui bloc condiional este c
memoria pentru variabil va fi alocat numai dac va fi necesar. Aceasta deoarece
variabilele locale nu-i fac simit prezena pn n momentul n care este accesat blocul
n interiorul cruia au fost declarate.
Declararea variabilelor n interiorul blocului de cod care le folosete previne i efectele
secundare nedorite. Din moment ce variabila nu exist n exteriorul blocului unde a fost
declarat, nu poate fi modificat n mod accidental. Cu toate acestea, atunci cnd fiecare
funcie execut o sarcin logic bine definit, nu este necesar s protejai" variabilele din
interiorul unei funcii fa de codul care a creat funcia. Din acest motiv, variabilele care
sunt utilizate de ctre o funcie sunt n general declarate la nceputul funciei respective.
Date, operatori i expresii

23
Dac nu se precizeaz altfel, variabilele locale sunt stocate n stiv. Caracterul dinamic, n
permanent schimbare, al stivei ca zon de memorie explic de ce variabilele locale nu
sunt capabile, n general, s-i pstreze valorile ntre dou apelri ale funciei.
O variabil local poate fi iniializat la o valoare cunoscut. Aceast valoare va fi atribuit
variabilei la fiecare accesare a blocului de cod n care variabila respectiv a fost declarat.
De exemplu, programul care urmeaz afieaz numrul 4 de zece ori:
#include <stdio.h>
void f(void);

void main(void)
{int i;
for(i = 0; i<10; i++) f();
}

void f(void)
{int j = 4;
printf("%d", j);
j++; /* aceast linie nu are un efect de durat */
}
2.3.3.2.2 Parametri formali
Dac o funcie folosete argumente, trebuie s declare variabilele care vor accepta valorile
argumentelor. Aceste variabile sunt denumite parametrii formali ai funciei. Ele se
comport la fel ca orice alte variabile locale din interiorul funciei. Dup cum se va vedea
n urmtorul fragment de program, declaraiile acestora survin dup numele funciei i n
interiorul unor paranteze:
/*D rezultatul 1 dac c este parte a irului s i 0 n caz contrar */
e_parte(char *s, char c)
{while(*s)
if(*s==c)return 1;
else s++;
return 0;
}
Funcia e_parte() are doi parametri: s i c. Aceast funcie are valoarea 1 dac
caracterul indicat n c este inclus n irul s i 0 n caz contrar.
Trebuie s indicai C-ului care este tipul de variabile din care fac parte parametrii formali,
declarndu-i aa cum s-a artat mai sus. Apoi acestea se pot folosi n interiorul funciei ca
variabile locale normale. Nu uitai c, n calitate de variabile locale, acestea sunt de
asemenea dinamice i se distrug la prsirea funciei.
Asigurai-v c parametrii formali pe care i declarai sunt de acelai tip cu argumentele
folosite la apelarea funciei. Dac exist o nepotrivire, putei obine rezultate neateptate.
Spre deosebire de multe alte limbaje, C va ncerca s se adapteze la ceea ce ai cerut,
chiar dac este neobinuit sau suspect. Ca programator, trebuie s v asigurai c nu vor
surveni astfel de erori.
Dei C asigur aa-numitele prototipuri de funcie (function prototypes), pe care le putei
folosi pentru a verifica dac argumentele folosite la apelarea funciei sunt compatibile cu
parametrii acesteia, exist totui anse de apariie a unor probleme. (Adic prototipurile de
funcie nu elimin nepotrivirile de tip ntre argument i parametru.) De asemenea, trebuie
s introducei n mod explicit prototipurile de funcii n program pentru a beneficia de
avantajele suplimentare ale acestora, ntruct nu au un caracter automat.
Ca i n cazul variabilelor locale, putei efectua atribuiri ale parametrilor formali ai unei
funcii sau i putei folosi n orice expresie recunoscut de C. Chiar dac aceste variabile
Capitolul 2

24
primesc valoarea argumentelor transmise funciei, le putei folosi ca pe orice alte variabile
locale.
2.3.3.2.3 Variabile globale
Variabilele declarate n afara oricrei funcii sunt variabile globale.
Spre deosebire de variabilele locale, variabilele globale sunt recunoscute de ctre toate
componentele programului i pot fi folosite de orice fragment de cod. De asemenea,
acestea i pstreaz valoarea n timpul execuiei programului. Pot fi accesate de ctre
orice expresie, indiferent de blocul de cod n care se afl coninut aceasta.
n programul urmtor, variabila cont a fost declarat n exteriorul oricror funcii. Dei
declaraia sa survine naintea funciei main(), ar fi putut fi amplasat oriunde nainte de
prima sa utilizare, din moment ce nu este coninut n nici o funcie. Dei, cel mai indicat
este ca variabilele globale s fie declarate la nceputul programului.
#include <stdio.h>
int cont; /* cont este global */

void func1(void);
void func2(void);

void main(void)
{
cont = 100;
func1();
}

void func1(void)
{
int temp;
temp = cont;
func2();
printf ("cont este %d", cont,; /* va scrie 100 */
}

void func2(void)
{
int cont;
for(cont=l ; cont<10; putchar('.'); cont++)
putchar('.');
}
Dac privim cu atenie la acest program, observm c, dei nici main() i nici func1()
nu au declarat variabila cont, ambele o pot folosi. Cu toate acestea, func2() a declarat
o variabil local denumit cont. Atunci cnd func2() face referire la cont, se refer
numai la variabila sa local, nu la cea global. Dac o variabil local i una global au
acelai nume, toate trimiterile la numele acelei variabile din interiorul blocului de cod n
care a fost declarat variabila local se vor referi numai la variabila local i nu vor avea
efect asupra variabilei globale. Este convenabil, dar dac omitei acest lucru se poate
ntmpla ca programul dvs. s se poarte ciudat, chiar dac este corect n aparen.
Zona de stocare a variabilelor globale este o regiune fix de memorie, special alocat n
acest scop de ctre compilatorul de C. Variabilele globale sunt utile atunci cnd un mare
numr de funcii din programul dvs. folosesc aceleai date. Totui, este bine s evitai
Date, operatori i expresii

25
folosirea unor variabile globale inutile. Acestea vor ocupa memorie pe toat durata
execuiei programului, nu numai atunci cnd este nevoie de ele. n plus, utilizarea unei
variabile globale acolo unde ar fi suficient o variabil local reduce gradul de generalitate
al unei funcii, fiindc se bazeaz pe ceva care trebuie definit n exteriorul funciei. n fine,
utilizarea unui numr mare de variabile globale poate duce la erori de program, datorit
unor efecte secundare necunoscute i nedorite. Acest aspect este evideniat n cadrul
limbajului BASIC standard, unde toate variabilele sunt globale. O problem major n
calea crerii de programe de anvergur n BASIC rezid n schimbarea accidental a
valorii unei variabile din cauza utilizrii sale undeva n alt zon a programului. Aceasta se
poate ntmpla i n C, dac programele folosesc prea multe variabile globale.
Unul din principalele motive de utilizare ale unui limbaj structurat este compartimentarea
codului i a datelor. n C, aceasta se realizeaz prin intermediul utilizrii variabilelor locale
i a funciilor. De exemplu, n continuare se prezint dou moduri de a scrie funcia
prod() care calculeaz produsul a doi ntregi.
General Particular
prod(int x, int y)
{
return(x*y)
}
int x, y;
prod(void)
{
return(x*y);
}
Ambele funcii returneaz produsul variabilelor x i y. Cu toate acestea, versiunea
generalizat sau parametrizat poate fi folosit pentru calculul produsului oricror dou
numere, n timp ce versiunea particular poate fi folosit numai pentru calculul produsului
variabilelor globale x i y.
2.3.4 Modificatori de acces
C definete doi modificatori de acces (de asemenea cunoscui i sub numele de
calificatori) care controleaz modul de accesare sau modificare a variabilelor.
Aceti calificatori sunt const i volatile. Ei trebuie s precead modificatorii de tip i
numele tipurilor la care se refer.
2.3.4.1 Calificatorul const
Variabilele de tipul const nu pot fi schimbate prin program. (Totui, unei variabile de tip
const i se poate atribui o valoare iniial.) Compilatorul are toat libertatea s amplaseze
variabilele de acest tip n memoria nemodificabil de ctre utilizator (ROM). De exemplu,
const int a=10;
creeaz o variabil ntreag denumit a, cu o valoare iniial egal cu 10, pe care
programul dvs. nu are permisiunea de a o modifica. O variabil de tip const i primete
valoarea fie n urma unei iniializri explicite, fie prin mijloace dependente de echipament.
Calificatorul const poate fi folosit pentru a proteja obiectele indicate de ctre argumentele
unei funcii mpotriva modificrii lor de ctre acea funcie. Aceasta nseamn c atunci
cnd un pointer este transmis unei funcii, respectiva funcie poate modifica variabila
indicat prin pointer. Cu toate acestea, dac pointerul este precizat ca fiind de tip const
n declaraia de parametri, codul funciei nu va putea modifica indicaia acestuia. n
genere, cnd o funcie coninut n biblioteca standard nu trebuie s modifice un obiect
indicat de ctre un argument, este declarat drept const.
De asemenea, putei utiliza const pentru a verifica dac programul nu modific vreo
variabil. Nu uitai, o variabil de tip const poate fi modificat de ctre ceva situat n afara
programului. De exemplu, un dispozitiv hardware i poate stabili propria valoare. Astfel,
prin declararea unei variabile ca fiind de tip constant, putei ti c orice modificri aduse
Capitolul 2

26
respectivei variabile survin dintr-o cauz extern.
2.3.4.2 Calificatorul volatile
Modificatorul volatile indic compilatorului c valoarea unei variabile poate fi modificat
utiliznd ci pe care programul nu le specific n mod explicit. De exemplu, adresa unei
variabile globale poate fi transmis rutinei de ceas a sistemului de operare i utilizat
pentru a memora timpul real al sistemului. n aceast situaie, coninutul variabilei este
modificat chiar i n absena unor declaraii de atribuire specifice. Acesta este un aspect
important, deoarece majoritatea compilatoarelor de C optimizeaz n mod automat
anumite expresii, presupunnd coninutul unei variabile neschimbat dac aceasta nu
apare n partea stng a unei declaraii de atribuire, deci s-ar putea s nu fie reexaminat
la fiecare referire. De asemenea, unele compilatoare schimb ordinea evalurii unei
expresii n timpul unui proces de compilare. Modificatorul volatile previne aceste
modificri.
Cei doi modificatori, const i volatile, pot fi folosii mpreun. De exemplu, dac se
presupune c 0x30 este valoarea unui port care poate fi schimbat numai de ctre
influene externe, urmtoarea declaraie va preveni orice risc de efect secundar accidental:
const volatile unsigned char *port=0x30;
2.3.5 Clase de memorare
Clasa de memorare se specific la declararea variabilei, prin unul din urmtoarele 4
cuvinte cheie:
auto register extern static.
Clasa de memorare determin timpul de via i domeniul de vizibilitate unei variabile.
Specificatorul de memorare precede restul declaraiei de variabil. Forma sa general
este:
specificator_de_memorare tip nume_variabila
Exemplu:
auto int a; static int x;
extern double y; register char c;
2.3.5.1 Clasa de memorare auto
Dac o variabil local este declarat fr a se indica n mod explicit o clas de
memorare, clasa de memorare considerat implicit este auto. Pentru acea variabil se
aloc memorie automat, la intrarea n blocul sau n funcia n care ea este declarat. Deci
domeniul de vizibilitate al variabilei este blocul sau funcia n care aceasta a fost definit.
Timpul de via este durata de execuie a blocului sau a funciei.
2.3.5.2 Clasa de memorare register
Variabilele din clasa register au acelai domeniu de vizibilitate i timp de via ca i
cele din clasa auto. Deosebirea fa de variabilele din clasa auto const n faptul c
pentru memorarea variabilelor register, compilatorul utilizeaz regitrii interni ai CPU
(ceea ce conduce la creterea eficienei). Specificatorul register poate fi aplicat numai
variabilelor locale i parametrilor formali ai unei funcii. n consecin, nu este permis
utilizarea acestui modificator pentru variabile globale. Unei variabile pentru care se
specific drept clas de memorare register, nu i se poate aplica operatorul de
refereniere.
lat un exemplu care folosete variabile crora li s-a aplicat modificatorul register.
Date, operatori i expresii

27
Aceast funcie calculeaz rezultatul lui m
e
pentru numere ntregi:
int_pwr(register int m, register int e)
{
register int temp;
temp = 1;
for( ; e; e--) temp= temp*m;
return temp;
}
n acest exemplu, e, m, i temp sunt declarate ca variabile cu specificator de tip
register, fiindc toate sunt utilizate n cadrul ciclului. Faptul c acest tip de variabile
sunt optime din punctul de vedere al vitezei le face ideale pentru controlul ciclurilor sau
chiar pentru a fi utilizate n interiorul acestora.
Numrul de variabile register, cu vitez optimizat, permise n interiorul unui bloc de
cod, este determinat att de mediu, ct i de varianta de implementare a compilatorului.
Nu trebuie s v facei griji dac declarai prea multe variabile ca avnd ataat
specificatorul register, deoarece compilatorul va elimina automat specificatorul la
atingerea numrului limit permis. (Aceasta asigur portabilitatea codului C pentru o mare
familie de procesoare.)
2.3.5.3 Clasa de memorare extern
O variabil global declarat fr specificarea unei clase de memorare, este considerat
ca avnd clasa de memorare extern. Domeniul de vizibilitate este din momentul
declarrii pn la sfritul fiierului surs. Timpul de via este durata execuiei fiierului. O
variabil din clasa extern este iniializat automat cu valoarea 0.
2.3.5.4 Clasa de memorare static
Variabilele de tip static sunt variabile permanente n interiorul propriei lor funcii sau
propriului lor fiier. Spre deosebire de variabilele globale, acestea nu sunt recunoscute n
exteriorul funciei sau fiierului propriu, dar i menin valoarea ntre dou apelri.
Specificatorul static are efecte diferite asupra variabilelor locale i globale.

Variabilele static locale au ca domeniu de vizibilitate blocul sau funcia n care sunt
definite, iar ca timp de via - durata de execuie a programului. Se iniializeaz automat cu
0.
O variabil local cu modificatorul static este o variabil local care i pstreaz
valoarea ntre dou apeluri succesive.
Variabilele locale cu modificatorul static sunt foarte importante pentru crearea de funcii
de sine-stttoare, fiindc diferitele tipuri de rutine trebuie s rein o valoare ntre dou
apelri. Un exemplu de funcie care beneficiaz de variabile locale cu modificator de tip
static este un generator de serii de numere, care produce o valoare nou bazndu-se
pe valoarea precedent. Pentru pstrarea acestei valori s-ar fi putut folosi o variabil
global. Cu toate acestea, de fiecare dat cnd funcia respectiv este folosit ntr-un
program, devine necesar declararea acelei variabile globale i asigurarea c aceasta nu
interfereaz cu alte variabile globale deja amplasate. De asemenea, utilizarea unei
variabile globale ar ngreuna considerabil inserarea acestei funcii ntr-o bibliotec. O
soluie mai indicat ar fi aceea de a declara variabile care memoreaz numrul generat ca
fiind de tip static, dup cum se arat n urmtorul fragment de program:
serii(void)
{
static int serie_numere;
Capitolul 2

28

serie_numere = serie_numere+23;
return serie numere;
}
n acest exemplu, variabila serie_numere exist i ntre dou apelri succesive ale
funciei, n loc de a fi creat i distrus, adic aa cum se comport o variabil local
normal. Aceasta nseamn c fiecare apel la funcia serii() poate genera un nou
termen al seriei bazat pe numrul precedent, fr a declara acea variabil ca fiind de tip
global.
Variabilele static globale au ca domeniu de vizibilitate punctul n care au fost definite pn
sfritul fiierului surs, iar ca timp de via - durata execuiei programului. la

Variabilele cu modificator static permit ascunderea" unor poriuni de program fa de
alte poriuni, ceea ce se poate dovedi extrem de avantajos atunci cnd lucrai cu un
program foarte mare i complex. n esen, modificatorul static permite variabile care
sunt cunoscute numai acelor funcii care au nevoie de acestea, fr a perturba alte funcii.
2.3.6 Iniializarea variabilelor n declaraii
n momentul declarrii unei variabile, acesteia i se poate atribui o anumit valoare. n
acest caz, n memorie se rezerv numrul de locaii corespunztor tipului variabilei
respective, iar valoarea va fi memorat n acele locaii. Forma unei declaraii de variabile
cu atribuire este:
tip_variabil nume_variabil=expresie;
z expresia, iar rezultatul acesteia este atribuit variabilei specificate. Se evaluea
Exemple:
char backslash=\\; //declararea i iniializarea variabilei simple backslash
int a=7*9+2; /* declararea variabilei simple a, de tip int i iniializarea ei cu
valoarea 65*/
float pi=3.14;/*declararea i iniializarea variabilei pi*/
eclararea i iniializarea variabilei simple z short int z=3; //d
char d=\011;
char LinieNoua=\n;
double x=9.8, y=0;
2.3.7 Constante
O constant este un literal (o form extern de reprezentare) numeric, caracter sau
ir de caractere.
Numele i valoarea unei constante sunt identice. Valoarea unei constante nu poate fi
schimbat n timpul execuiei programului n care a fost utilizat. Tipul i valoarea ei sunt
determinate n mod automat, de ctre compilator, pe baza caracterelor care compun
literalul.
2.3.7.1 Constante numerice ntregi
Co ui din cifre), fr punct zecimal. nstantele ntregi sunt literali numerici (comp
Co nstante ntregi n baza 10, 8 sau 16
o Constante ntregi zecimale (n baza 10). Exemple: 45, 78 // constante
ntregi (n baza 10), tip int
Date, operatori i expresii

29
o Constante ntregi octale. Dac n faa numrului apare cifra zero (0), acest
lucru indic faptul c acea constant este de tipul int, n baza opt
(constant octal). Exemple: 056, 077 // constante ntregi octale, tip int
o Constante ntregi hexazecimale. Dac n faa numrului apar caracterele
zero (0) i x (sau X), acest lucru indic faptul c acea constant este de tipul
int, n baza 16 (constant hexazecimal). Amintim c n baza 16 cifrele
sunt: 0-9, A (sau a) cu valoare 10, B (sau b) cu valoare 11, C (sau c) cu
valoare 12, D (sau d) cu valoare 13, E (sau e) cu valoare 14, F (sau f) cu
valoare 15. Exemple: 0x45, 0x3A, 0Xbc // constante ntregi
hexazecimale, tip int
Constante ntregi, de tipuri derivate
o Dac secvena de cifre este urmat de L sau l, tipul constantei este long
int. Exemple: 145677L, 897655l // tip zecimal long int
o Dac secvena de cifre este urmat de U sau u, tipul constantei este
unsigned int. Exemple: 65555u //tip zecimal unsigned int
o Dac secvena de cifre este urmat de U(u) i L(l), tipul constantei este
unsigned long int. Exemple: 7899UL //tip zecimal unsigned long int
2.3.7.2 Constante numerice reale
Dac o constant numeric conine punctul zecimal, ea este de tipul double.
Exemplu: 3.1459 //tip double
Dac numrul este urmat de F sau f, constante este de tip float. Exemplu
0.45f //tip float
Dac numrul este urmat de L sau l, este de tip long double. Exemplu: 9.788L
//tip long double
Dac numrul este urmat de caracterul e sau E i de un numr ntreg (cu sau fr
semn), constanta este n notaie tiinific. n aceast form extern de
reprezentare, numrul din faa literei E reprezint mantisa, iar numrul ntreg care
urmeaz caracterului E reprezint exponentul. n forma extern de reprezentare,
baza de numeraie este 10, deci valoarea constantei va fi dat de mantisa x
10
exponent
. Exemplu: 1.5e-2 //tip double, n notaie tiinific, valoare 1.5 x 10
-2

2.3.7.3 Constante caracter
Constantele caracter sunt ncadrate ntre apostrofuri. Exemplu: 'a' //tip char
O constant caracter are ca valoare codul ASCII (American Standard Code for Information
Interchange) al caracterului pe care l reprezint. Acest set de caractere are urmtoarele
proprieti:
1. Fiecrui caracter i corespunde o valoare ntreag distinct (ordinal);
2. Valorile ordinale ale literelor mari sunt ordonate i consecutive ('A' are codul ASCII
65, 'B' - codul 66, 'C' - codul 67, etc.);
3. Valorile ordinale ale literelor mici sunt ordonate i consecutive ('a' are codul ASCII
97, 'b' - codul 98, 'c' - codul 99, etc.);
4. Valorile ordinale ale cifrelor sunt ordonate i consecutive ('0' are codul ASCII 48, '1'
- codul 49, '2' - codul 50, etc.).

Constante caracter corespunztoare caracterelor imprimabile
Capitolul 2
O constant caracter corespunztoare unui caracter imprimabil
se reprezint prin caracterul respectiv inclus ntre apostrofuri.
Exemple n tabelul alturat.
Excepii de la regula de mai sus constituie caracterele
imprimabile apostrof (') i backslash (\). Caracterul backslash se
reprezint: '\\', iar caracterul apostrof se reprezint: '\''.
Constant
caracter
Valoare
A 65
a 97
0 48
* 42

Constante caracter corespunztoare caracterelor neimprimabile
Pentru caracterele neimprimabile, se folosesc secvene escape. O secven escape
furnizeaz un mecanism general i extensibil pentru reprezentarea caracterelor invizibile
sau greu de obinut. n Tabelul 2.3. sunt prezentate cteva caractere escape utilizate
frecvent.
Tabelul 2.3 Constante caracter corespunztoare caracterelor neimprimabile
Codul Codul
ASCII
Denumire
caracter
Semnificaia
\" 34 Ghilimele
\' 39 Apostrof
\\ 92 Backslash (linie nclinat spre stnga)
\0 NULL
\a 7 BEL Alert (activare sunet)
\b 8 BS Revenire cu un spaiu (Backspace)
\f 12 FF Avans hrtie (Form Feed)
\n 10 LF Rnd nou (Line Feed)
\N Constant n octal (unde N este constanta n octal)
\r 13 CR Retur de car (Carriage return)
\t 9 HT Spaiu de tabulare orizontal
\v 11 VT Spaiu de tabulare vertical
\xN Constant n hexazecimal (unde N este o
constant n hexazecimal)
O constant caracter pentru o secven escape poate apare ns, i sub o form n care
se indic codul ASCII, n octal, al caracterului dorit: \ddd, unde d este o cifr octal.
Exemple:
\11 (pentru \t) reprezint constanta caracter backspace, cu codul 9 n baza 10, deci
codul 11 n baza 8.
\15 (pentru \r) reprezint constanta caracter CR, cu codul 13 n baza 10, deci codul 11 n
baza 8.
Exemplul 2.1: Constante caracter
S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <stdio.h>
void main(void)
{
printf("Un caracter este memorat pe %d
octet\n",sizeof(char));
printf("Caracterul escape \\n este memorat pe %d octet\n
",sizeof(char));
printf("Caracterul escape '\\n\' este memorat pe %d octet\n
",sizeof(char));
cout<<"Caracterul '9' este memorat pe "<<sizeof('9')<<"
octet\n";
cout<<'B';cout<<' ';cout<<'c';cout<<'\t';
cout<<'\t';cout<<'9';cout<<'\b';cout<<'\a';

30
cout<<'L';cout<<'\v';cout<<'L';
Date, operatori i expresii

31
cout<<'\'';cout<<'\t';cout<<'\"';cout<<'\\';cout<<'\n';
cout<<'\a';cout<<'\7';
}
2.3.7.4 Constante ir de caractere
Constanta ir de caractere este o succesiune de zero sau mai multe caractere,
ncadrate de ghilimele.
n componena unui ir de caractere, poate intra orice caracter, deci i caracterele escape.
Lungimea unui ir este practic nelimitat. Dac se dorete continuarea unui ir pe rndul
urmtor, se folosete caracterul backslash.
Caracterele componente ale unui ir sunt memorate ntr-o zon continu de memorie (la
adrese succesive). Pentru fiecare caracter se memoreaz codul ASCII al acestuia. Dup
ultimul caracter al irului, compilatorul plaseaz automat caracterul NULL (\0), caracter
care reprezint marcatorul sfritului de ir. Numrul de octei pe care este memorat un ir
va fi, deci, mai mare cu 1 dect numrul de caractere din ir.
Exemple:
Acesta este un sir de caractere //constant ir memorat pe 32 octei
Sir de caractere continuat\
pe randul urmtor! //constant ir memorat pe 45 octei
Sir \t cu secvene escape\n //constant ir memorat pe 26 octei
\n //constant caracter memorat pe un octet
\n //constant ir memorat pe 2 octei (codul caracterului escape i
terminatorul de ir)
a\a4 /*ir memorat pe 4 octei:
Pe primul octet: codul ASCII al caracterului a
Pe al doilea octet: codul ASCII al caracterului escape \a
Pe al treilea octet: codul ASCII al caracterului 4
Pe al patrulea octet: terminatorul de ir NULL, cod ASCII 0 */
Exemplul 2.2: iruri de caractere
S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void main()
{ cout<<"Sirul \"Ab9d\" este memorat pe:"<<sizeof("Ab9d")<<"
octeti\n";
cout<<"Sirul \"Abcd\\t\" este memorat pe:"<<sizeof("Abcd\t")<<"
octeti\n";
cout<<"Sirul \"\n\" este memorat pe "<<sizeof("\n")<<"
octeti\n";
cout<<"Sirul \"\\n\" este memorat pe "<<sizeof("\n")<<"
octeti\n";
cout<<"Sirul \"ABCDE\" se memoreaz pe "<<sizeof("ABCDE")<<"
octeti\n";}
2.4 Operatori i expresii
Datele (constante sau variabile) legate prin operatori, formeaz expresii. Operatorii care
pot fi aplicai datelor (operanzilor) depind de tipul operanzilor, datorit faptului c tipul unei
date const ntr-o mulime de valori pentru care s-a adoptat un anumit mod de
Capitolul 2

32
reprezentare n memoria calculatorului i o mulime de operatori care pot fi aplicai acestor
valori. Operatorii pot fi:
unari (necesit un singur operand);
binari (necesit doi operanzi);
ternari (trei operanzi).
O expresie este o combinaie corect din punct de vedere sintactic, format din
operanzi i operatori.
Expresiile, ca i operanzii, au tip i valoare.
2.4.1 Operatori
Limbajul C definete patru clase de operatori: aritmetici, relaionali, logici i pe bii
(bitwise). n plus, C mai dispune de anumii operatori speciali pentru anumite operaii.
2.4.1.1 Operatorul de atribuire
Operatorul de atribuire (de asignare) este un operator binar care se aplic tuturor tipurilor
de variabile i care poate fi folosit n interiorul oricrei expresii valide n C. Forma general
a unui operator de atribuire este:
nume_variabila = expresie;
unde expresie poate fi ceva simplu (cum ar fi o constant) sau complicat, conform
cerinelor dvs. Destinaia, sau membrul stng al atribuirii trebuie s fie o variabil sau un
pointer, nu o funcie sau o constant.
n literatura de specialitate de C sau n mesajele de eroare ale compilatorului vei ntlni
termenii de Ivalue sau rvalue. Pe scurt, Ivalue este orice obiect care poate fi inserat n
partea stng a unei declaraii de atribuire. Din raiuni practice, Ivalue" este asimilat cu
variabil". Termenul de rvalue" se refer la expresia din partea dreapt a unei atribuiri i
se refer pur i simplu la valoarea unei expresii.
2.4.1.1.1 Conversii de tip folosite n atribuiri
Cnd variabilele de un tip sunt combinate cu variabilele de alt tip va surveni o conversie de
tip. ntr-o declaraie de atribuire, regula de conversie de tip este simpl: valoarea
membrului drept (partea rezervat expresiei) al atribuirii este convertit la tipul membrului
stng (destinaia).
n Tabelul 2.4 se gsete un sumar al conversiilor de tip care apar la atribuiri. Nu uitai c
o conversie de la int la float, sau de la float la double .a.m.d. nu contribuie la
creterea preciziei sau a acurateei. Aceste conversii nu fac altceva dect s modifice
forma sub care este prezentat valoarea. Suplimentar, unele compilatoare de C (i unele
procesoare) ntotdeauna trateaz o variabil de tip char ca fiind pozitiv, indiferent de
valoarea acesteia, la conversia ntr-unul din tipurile int sau float. n general, variabilele
de tip char se folosesc pentru caractere, iar cele de tip int, short sau signed char
atunci cnd dorii s evitai problemele de portabilitate.
Tabelul 2.4 Conversii de tip care apar la atribuiri
Tipul destinaiei Tipul expresiei Posibile pierderi de informaie
signed char char Dac valoarea >127, destinaia este negativ
char short int Cei mai semnificativi 8 bii
char int Cei mai semnificativi 8 bii
char long int Cei mai semnificativi 24 de bii
int long int Cei mai semnificativi 16 bii
Date, operatori i expresii

33
Tipul destinaiei Tipul expresiei Posibile pierderi de informaie
int float Partea zecimal i posibil mai mult
float double Precizie, rezultat rotunjit
double long double Precizie, rezultat rotunjit

Pentru a folosi Tabelul 2.4 la efectuarea unei conversii care nu a fost prezentat, procedai
la cte o conversie o dat, pn cnd terminai. De exemplu, pentru a converti o variabil
de tip double la una de tip int, mai nti convertii de la double la float i apoi de la
float la int.
2.4.1.1.2 Atribuiri multiple
C permite atribuirea aceleiai valori mai multor variabile folosind mai multe atribuiri n
cadrul aceleiai declaraii. De exemplu, urmtorul fragment de program atribuie lui x, y i z
valoarea zero:
x = y = z = 0;
Asociativitatea operatorului are loc de la dreapta la stnga.
2.4.1.2 Operatori aritmetici
2.4.1.2.1 Operatori aritmetici unari
Tabelul 2.5 Operatori aritmetici unari
Operator Semnificaie Exemple
- Minus unar (schimb semnul operandului) -a
++
Operator de incrementare (adun 1 la
valoarea operandului)
a++ sau ++a
--
Operator de decrementare (scade 1 din
valoarea operandului)
a-- sau --a

Operatorul "-" unar schimb semnul operandului i poate fi aplicat datelor ntregi, reale,
caracter. Exemplu: b=-a;
Operatorii de incrementare i decrementare pot fi aplicai datelor numerice sau caracter.
Ambii operatori pot fi folosii n form prefixat, naintea operandului, (++a, respectiv --a)
sau postfixat, dup operand (a++, respectiv a--). Utilizarea acestor operatori n expresii,
n form prefixat sau postfixat, determin evaluarea acestora n moduri diferite, astfel:
y=++x este echivalent cu: x=x+1; apoi y=x;
y=x++ este echivalent cu: y=x; apoi x=x+1;
y=--x este echivalent cu: x=x-1; apoi y=x;
y=x-- este echivalent cu: y=x; apoi x=x-1;
2.4.1.2.2 Operatori aritmetici binari
Tabelul 2.6 Operatori aritmetici binari
Operator Semnificaie Exemple
+ Adunarea celor doi operanzi a+b
- Scderea celor doi operanzi a-b
* nmulirea celor doi operanzi a*b
/ mprirea celor doi operanzi a/b
% Operatorul modulo (rest) a%b

Capitolul 2

34
Operatorul modulo (care furnizeaz restul mpririi ntregi a operatorului stng la
operatorul drept) se aplic numai operanzilor ntregi (de tip int sau char). Ceilali
operatori aritmetici binari pot fi aplicai datelor ntregi sau reale.
Dac ntr-o expresie cu 2 operanzi i un operator binar aritmetic, ambii operanzi sunt
ntregi, rezultatul expresiei va fi tot un numr ntreg. De exemplu, la evaluarea expresiei
9/2, ambii operanzi fiind ntregi, rezultatul furnizat este numrul ntreg 4.
Operatorii prezentai respect o serie de reguli de preceden (prioritate) i asociativitate,
care determin precis modul n care va fi evaluat expresia n care acetia apar.
Precedena operatorilor poate fi schimbat cu ajutorul parantezelor.
2.4.1.2.3 Operatori aritmetici binari compui cu atribuire
Tabelul 2.7 Operatori aritmetici compui cu atribuire
Operator Semnificaie Exemple
+= a=a+b a+=b
-= a=a+b a-=b
*= a=a*b a*=b
/= a=a/b a/=b
%= a=a%b a%=b
Aceti operatori se obin prin combinarea operatorilor aritmetici binari cu operatorul de
atribuire i sunt folosii sub forma urmtoare:
expresie1 operator= expresie2;
Rezultatul obinut este acelai cu rezultatul obinut prin:
expresie1 = expresie1 operator expresie2;
Toi aceti operatorii modific valoarea operandului stng prin adunarea, scderea,
nmulirea sau mprirea acestuia prin valoarea operandului drept.
Construcia x+=1 genereaz acelai rezultat ca expresia x=x+1.
Observaiile referitoare la operatorii aritmetici binari sunt valabile i pentru operatorii
aritmetici binari compui. Operatorii aritmetici binari compui au aceeai prioritate i
asociativitate ca i operatorul de atribuire.
2.4.1.3 Operatori relaionali binari
Tabelul 2.8 Operatori relaionali binari
Operator Semnificaie Exemple
== Egal cu a==b
!= Diferit de a!=b
< Mai mic a<b
<= Mai mic sau egal a<=b
> Mai mare a>b
>=
Mai mare sau egal a>=b
Primii doi operatori mai sunt numii operatori de egalitate. Operatorii relaionali servesc la
compararea valorilor celor doi operanzi i nu modific valorile operanzilor. Rezultatul unei
expresii n care apare unul din operatorii relaionali binari este ntreg i are valoarea zero
(0) dac relaia este fals, sau valoarea unu (1) (sau diferit de 0 n cazul compilatoarelor
sub UNIX), dac relaia este adevrat. Aceti operatorii pot fi aplicai datelor de tip ntreg,
real sau caracter.
Observaie: Deosebirea dintre operatorii == (relaional, de egalitate) i = (de atribuire)
const n faptul c primul nu modific valoarea nici unuia dintre operanzii si, pe cnd cel
de-al doilea modific valoarea operandului stng.
Date, operatori i expresii

35
2.4.1.4 Operatori logici pe cuvnt
Tabelul 2.9 Operatori logici pe cuvnt
Operator Semnificaie Exemple
! NOT (negaie logic) !(a==b)
&& AND (conjuncie, i logic) (a>b) && (b>c)
|| OR (disjuncie, sau logic) (a>b) || (b>c)
Aceti operatori pot fi aplicai datelor de tip ntreg, real sau caracter. Evaluarea unei
expresii n care intervin operatorii logici se face n conformitate cu Tabelul 2.10.
Tabelul 2.10 Evaluarea unei expresii n care intervin operatorii logici
x y !x x&&y x||y
adevrat (1) adevrat (1) fals (0) adevrat (1) adevrat (1)
adevrat (1) fals (0) fals (0) fals (0) adevrat (1)
fals (0) adevrat (1) adevrat (1) fals (0) adevrat (1)
fals (0) fals (0) adevrat (1) fals (0) fals (0)
Expresia !expresie are valoarea 0 (false) dac expresia-operand are o valoare diferit
de zero i valoarea unu (adevrat) dac expresia-operand are valoarea zero.
Expresia expresie1||expresie2 are valoarea diferit de 0 (true) dac FIE
expresie1, FIE expresie2 au valori diferite de zero.
Expresia expresie1 && expresie2 are valoarea diferit de 0 (true) dac AMBELE
expresii-operand (expresie1 i expresie2) au valori diferite de zero.

Dei C nu conine un operator de tip SAU exclusiv (exclusive OR sau XOR), putei crea cu
uurin o funcie care s execute aceast operaiune folosind operatorii logici disponibili.
Rezultatul unei operaiuni XOR este "adevrat" dac i numai dac un operand (dar nu
amndoi) este adevrat"
Urmtorul program conine funcia xor() care returneaz rezultatul unei operaiuni de
SAU exclusiv efectuate pe cele dou argurmente ale sale.
#include <stdio.h>
int xor(int a, int b) ;

void main(void)
{
printf("%d", xor(1,0)); printf("%d", xor(1,1));
printf("%d", xor(0,1)); printf("%d", xor(0,0));
}
xor(int a, int b) /* Efectueaz o operaiune logica XOR. */
{ return (a||b) && !(a&&b);}
2.4.1.5 Operatori logici pe bii
Tabelul 2.11 Operatori logici pe bii
Operator Semnificaie Exemple
~ Negaie (Complement fa de unu) ~a
& AND (Conjuncie, I logic pe bit) a & 0377
| OR (Disjuncie, SAU logic pe bit) a | 0377
^ XOR (Sau exclusiv logic pe bit) a^b
<< Deplasare la stnga 0377 << 2
>> Deplasare la dreapta 0377 >> 2
Aceti operatori nu se aplic numerelor reale, ci numai datelor de tip ntreg sau caracter.
Primul operator este unar, ceilali binari. Operatorii acioneaz la nivel de bit, la nivelul
reprezentrii interne (n binar) n conformitate cu Tabelul 2.12.
Capitolul 2

36
Tabelul 2.12 Evaluarea unei expresii n care intervin operatorii logici pe bii
x y x&y x|y x^y ~x
1 1 1 1 0 0
1 0 0 1 1 0
0 1 0 1 1 1
0 0 0 0 0 1

Operatorul ~ are aceeai prioritate ca i ceilali operatori unari. El furnizeaz complementul
fa de unu al unui ntreg, adic va schimba fiecare bit de pe 1 n zero i invers. Operatorii
de deplasare pe bit (<< i >>) efectueaz deplasarea la stnga sau la dreapta a
operandului stng, cu numrul de bii indicai de operandul drept. Astfel, x<<2 deplaseaz
biii din x la stnga, cu dou poziii, introducnd zero pe poziiile rmase vacante. Dac
prin deplasarea la stnga se depete numrul de bii alocai tipului respectiv de dat, o
parte din biii din stnga se pierd, astfel nct valoarea variabilei se modific. La
deplasarea ulterioar a biilor ctre dreapta, pe poziiile libere aprute n stnga se
introduc zerouri.
Operatorul binar ^ i gsete o utilizare tipic n expresii ca: x&^077, care mascheaz
ultimii 6 bii ai lui x pe zero.
Operatorul & este adesea utilizat n expresii ca x&0177, unde seteaz toi biii pe zero, cu
excepia celor de ordin inferior din x.
Operatorul | este utilizat n expresii ca: x&MASK, unde seteaz pe unu biii care n x i
masca MASK sunt setai pe unu.
Observaie: Operatorii logici pe bit & i | sunt diferii de operatorii logici pe cuvnt && i ||.
Deplasarea la stnga a unei date cu n poziii este echivalent cu nmulirea valorii acesteia
cu 2
n
. Deplasarea la dreapta a unei date fr semn cu n poziii este echivalent cu
mprirea valorii acesteia cu 2
n
.
Combinnd operatorii logici pe bii cu operatorul de atribuire, se obin operatorii: &=
,
^=
,
|=
,
<<=
,
>>=
.

2.4.1.6 Operatori speciali
2.4.1.6.1 Operatorul condiional
Este un operator ternar (necesit 3 operanzi), utilizat n construcii de forma:
expresie1?expresie2:expresie3
Se evalueaz expresie1. Dac aceasta are o valoare diferit de zero, atunci tipul i
valoarea ntregii expresii vor fi aceleai cu tipul i valoarea expresie2. Altfel (dac
expresie1 are valoarea zero), tipul i valoarea ntregii expresii vor fi aceleai cu tipul i
valoarea expresie3. Deci operatorul condiional este folosit pentru a atribui ntregii
expresii tipul i valoarea expresie2 sau a expresie3, n funcie de o anumit condiie.
Acest lucru este echivalent cu:
DAC expresie1 diferit de zero
ATUNCI evalueaz expresie2
ALTFEL evalueaz expresie3
Exemplu:
int semn=(x<0)?-1:1
Dac x<0, atunci semn=-1, altfel semn=1.
2.4.1.6.2 Operatorul virgul
Este utilizat n construcii de forma:
expresie1, expresie2
Date, operatori i expresii

37
Operatorul virgul se folosete pentru evaluarea succesiv de la stnga la dreapta a mai
multor expresii. Partea stng a operatorului virgul este ntotdeauna considerat de tip
void. Aceasta nseamn c expresia din dreapta devine valoarea total a ntregii expresii
separate prin virgul. De exemplu,
x = (y=3, y+1)
mai nti atribuie lui y valoarea 3 i apoi i atribuie lui x valoarea 4. Parantezele sunt
necesare ntruct operatorul virgul are cea mai mic prioritate, mai redus deci dect
operatorul de atribuire.
Tipul i valoarea ntregii expresii este dat de tipul i valoarea expresiei2.
Exemplu:
int x, c, y;
printf(Astept val. ptr. y:); scanf("%d", &y);
x=(c=y, c<=5); /* c va primi valoarea lui y (citit); se verific dac c este
mai mic sau egal cu 5. Dac nu, x=0; daca da, x=1 sau x=valoare diferit
de zero)*/
x++, y--; //nti este incrementat x, apoi este decrementat y
2.4.1.6.3 Operatorul activ la compilare sizeof()
Este un operator unar, care are ca rezultat numrul de octei pe care este memorat o
dat de un anumit tip. Operandul este un tip sau o dat (constant sau variabil) de un
anumit tip.
Exemple:
printf(%d",sizeof(int)); // afieaz numrul de octei pe care este memorat un
ntreg (2)
printf(%d",sizeof(ab6*));// afieaz numrul de octei pe care este
memorat constanta ir ab6* (5)
2.4.1.6.4 Operatorul adres &
Acest operator unar, aplicat identificatorului unei variabile, furnizeaz adresa la care este
memorat aceasta. Poate fi aplicat oricrui tip de date i se mai numete operator de
refereniere.
Exemplu:
int a;
printf(Adresa la care este memorata variabila a este:%p",&a);
2.4.1.6.5 Operatorul *
Este un operator unar, numit i operator de defereniere. Se aplic unei expresii de tip
pointer i este folosit pentru a accesa coninutul unei zone de memorie spre care indic
(pointeaz) operatorul.
Un pointer este adresa de memorie a unei variabile. Operatorii & (adres) i * sunt
complementari.
2.4.1.6.6 Operatorii punct (.) i sgeat (->)
Operatorii punct (.) i sgeat (->) fac referire la termenii individuali ai structurilor i ai
uniunilor. Structurile i uniunile sunt tipuri de date colective care pot fi menionate sub un
singur nume.
Operatorul punct este folosit atunci cnd se lucreaz cu o structur sau uniune. Operatorul
sgeat este folosit la utilizarea unui pointer de structur sau uniune.
2.4.1.6.7 Operatori de acces la membri structurilor
Capitolul 2

38
Operatorii ::, .* i ->* permit accesul la componentele unei structuri. Ei vor fi studiai ntr-
un alt capitol.
2.4.1.6.8 Operatorii parantez
Parantezele rotunde () se utilizeaz n expresii, pentru schimbarea ordinii de efectuare a
operaiilor, sau la apelul funciilor. La apelul funciilor, parantezele rotunde ncadreaz lista
parametrilor efectivi. Din acest motiv, parantezele rotunde sunt numite i operatori de apel
de funcie.
2.4.1.6.9 Operatorii de indexare
Operatorii de indexare sunt parantezele ptrate []. Acestea includ expresii ntregi care
reprezint dimensiunea unui tablou sau indicii elementelor unui tablou.
2.4.1.6.10 Prioritatea operatorilor
Tabelul 2.13 prezint ierarhia tuturor operatorilor (grupai pe categorii) folosii n limbajul C
cu prioritile lor i regulile de asociativitate. Operatorii dintr-o categorie au aceeai
prioritate. Reinei c toi operatorii, cu excepia operatorilor unari, a acelor combinai cu
atribuire i a operatorului ?, se asociaz de la stnga la dreapta. Operatorii unari (*, &, -) i
operatorul ? se asociaz de la dreapta la stnga.
Tabelul 2.13 Prioritatea operatorilor
Nr.
Clas de
operatori
Operatori Asociativitate
1. Primari
() [] . -> ::
de la stnga la dreapta
2. Unari
! (NOT pe cuvnt) ~ (NOT pe bit) ++
-- sizeof (tip)
de la stnga la dreapta

- (unar) *(defereniere) &
(refereniere)
de la dreapta la stnga
3. Multiplicativi
* / %
de la stnga la dreapta
4. Aditivi
+ -
de la stnga la dreapta
5. Deplasare pe bit
<< >>
de la stnga la dreapta
6. Relaionali
< <= > >=
de la stnga la dreapta
7. De egalitate
== !=
de la stnga la dreapta
8. & (I logic pe bit) de la stnga la dreapta
9. ^ (XOR pe bit) de la stnga la dreapta
10. | (SAU logic pe bit) de la stnga la dreapta
11. && (I logic pe cuvnt) de la stnga la dreapta
12. || (SAU logic pe cuvnt) de la stnga la dreapta
13. Condiional
?:
de la dreapta la stnga
14. De atribuire
= += -= *= %=
&= ^= |= <<= >>=
de la dreapta la stnga
15. Virgul
,
de la stnga la dreapta
2.4.2 Expresii
Prin combinarea operanzilor i a operatorilor se obin expresii. Tipul unei expresii este dat
de tipul rezultatului obinut n urma evalurii acesteia. La evaluarea unei expresii se aplic
regulile de prioritate i asociativitate a operatorilor din expresie. Ordinea de aplicare a
operatorilor poate fi schimbat prin folosirea parantezelor. La alctuirea expresiilor, este
indicat evitarea expresiilor n care un operand apare de mai multe ori.

Uneori expresiile devin relativ complicate, astfel nct uneori este util un algoritm ajuttor
de citire a lor:
Date, operatori i expresii

39
1. Gsii variabila care se declar
2. Folosii regula SEAO (Spiral Exterioar Anti-Orar)
3. La ntlnirea: spunei:
a. * pointer ctre
b. [] ir de
c. () funcie cu parametri care ntoarce
4. Citii mpreun "structur S", "uniune U" i "enumerare E"
5. Citii mpreun mai multe perechi "[]"
6. Rmnei n cadrul unei perechi de paranteze rotunde "()" pn la citirea (n una
sau mai multe treceri) tuturor elementelor dintre ele.

Exemple:
Instruciune Semnificaie
int *p[15];
p este un ir de 15 pointeri ctre ntregi.
double (*p) [30];
p este un pointer ctre un tablou de 30 de valori
de tip double
short **ab[5][10];
ab este un tablou de 5x10 pointeri ctre pointeri
ctre short int
long *f(int,float);
f este o funcie cu 2 parametri, unul ntreg i
unul float care ntoarce un pointer ctre un long
int (*pf)(void);
pf este un pointer ctre o funcie fr parametri
care ntoarce un int
struct s(*fpa[8])(void);
fpa este un ir de 8 pointeri ctre funcii fr
parametri care ntorc structuri de tip s
char (*(*fprp)(void))[6];
fprp este un pointer ctre o funcie fr
parametri care ntoarce un pointer ctre un
tablou de 6 caractere.
int *(*(*ptf)(int))(char);
ptf este un pointer ctre o funcie cu un
parametru ntreg care ntoarce un pointer ctre o
funcie cu un parametru de tip char care
ntoarce un pointer ctre un ntreg.
Capitolul 2

short * *ab[5][10] ;
double(*p )[30]; int *p[15] ;
long * f(int,float) ;
char(*(*fprp )(void))[6]; int *(*(*ptf )(int))(char) ;
int (*pf )(void); struct s (*fpa[8])(void);
Figura 2.1 Scheme de citire a expresiilor
2.4.3 Conversii de tip
La evaluarea expresiilor, se realizeaz conversii ale tipului operanzilor. Conversiile sunt:
Automate sau cerute de evaluarea expresiilor;
Cerute de programator (prin construciile cast), explicite.
2.4.3.1 Conversii de tip automate sau cerute de evaluarea expresiilor
Dac ntr-o expresie au fost combinate constante i variabile de diferite tipuri, toate vor fi
convertite la acelai tip.
Compilatorul de C va converti toi operanzii aducndu-i la tipul operandului celui mai mare,
operaie cunoscut sub numele de avansare de tip (type promotion). Mai nti, toate
valorile de tip char i short int sunt automat avansate la tipul int. (Acest proces este
denumit avansare integral). Dup ncheierea acestei operaiuni, toate celelalte conversii
sunt efectuate operaie cu operaie, dup cum este artat n urmtorul algoritm de
conversie de tip:

DAC un operand este de tip long double
ATUNCI al doilea este convertit n long double
ALTFEL DAC un operand este de tip double
ATUNCI al doilea este convertit n double
ALTFEL DAC un operand este de tip float
ATUNCI al doilea este convertit n float
ALTFEL DAC un operand este de tip unsigned long
ATUNCI al doilea este convertit n unsigned long
ALTFEL DAC un operand este de tip long
ATUNCI al doilea este convertit n long
ALTFEL DAC un operand este de tip unsigned int
ATUNCI al doilea este convertit n unsigned int

Suplimentar, mai exist un caz special: dac un operand este de tip long i cellalt este

40
Date, operatori i expresii

41
de tip unsigned int i dac valoarea celui de-al doilea nu poate fi reprezentat printr-o
variabil de tip long, atunci ambii operanzi vor fi convertii n unsigned long.
Dup aplicarea regulilor de conversie, fiecare pereche de operanzi este de acelai tip, iar
rezultatul fiecrei operaii va fi de acelai tip cu operanzii.
2.4.3.2 Conversiile explicite (cerute de programator)
O anumit expresie poate fi forat s fie de un anumit tip folosind operatorul cast (tip).
Acesta este un operator unar care convertete tipul operandului su la tipul specificat ntre
paranteze. Aspectul general al operatorului cast este
(tip) expresie
unde tip este un tip valid de date recunoscut de C.
Exemplu:
int a; (float)a; // convertete operandul a (care era de tip ntreg) n float

Capitolul 3
3. STRUCTURI DE CONTROL
Algoritmul proiectat pentru rezolvarea unei anumite probleme trebuie implementat ntr-un
limbaj de programare; prelucrarea datelor de ctre calculator se realizeaz cu ajutorul
instruciunilor. O instruciune este o construcie valid (care respect sintaxa limbajului)
urmat de ;. Standardul ANSI C mparte instruciunile din C n urmtoarele grupuri:
Selecie Iteraie Salt
Etichet Expresie Bloc
Ordinea n care se execut instruciunile unui program definete aa-numita structur de
control a programului.
Limbajele moderne sunt alctuite pe principiile programrii structurate. Orice algoritm
poate fi realizat prin combinarea a trei structuri fundamentale:
structura secvenial;
structura alternativ (de decizie, de selecie);
structura repetitiv (ciclic).
3.1 Adevrat i fals n C
Multe instruciuni n C depind de o expresie condiional care determin ce aciune va
trebui efectuat. O expresie condiional d o valoare de adevrat sau de fals. n C, spre
deosebire de majoritatea limbajelor de calculator, o valoare adevrat" poate fi orice
valoare nenul, inclusiv numere negative. O valoare fals" este egal cu zero. Aceast
metod de abordare a conceptelor de adevrat i fals permite codarea extrem de eficient
a unei mari varieti de rutine.

42
3.2 Structura secvenial
Aciune 1
Structura secvenial este o niruire de secvene de prelucrare
(instruciuni), plasate una dup alta, n ordinea n care se dorete
execuia acestora.
Aciune 2
Reprezentarea structurii secveniale cu ajutorul pseudocodului:
instruc_1;
instruc_2;
. . . . .
instruc_n;
Implementarea structurii secveniale se realizeaz cu ajutorul
urmtoarelor instruciuni: instruciunea vid, instruciunea
expresie i instruciunea compus.
3.2.1 Instruciunea vid
Sintaxa: ;
Instruciunea vid nu are nici un efect. Se utilizeaz n construcii n care se cere prezena
unei instruciuni, dar nu se execut nimic (de obicei, n instruciunile repetitive).
Exemple:
. . . . . .
int j;
;
Figura 3.1 Schema
logic pentru
structura secvenial

Aciune n
STRUCTURI DE CONTROL
for(;;)
{ . . . . }
3.2.2 Instruciunea expresie
Sintaxa:
expresie; sau: apel_funcie;
Exemple:
int b, a=9;
double c;
b=a+9;
cout<<a;
c=sqrt(a); //apelul functiei sqrt - radical
clrscr();//apelul functiei predefinite care sterge ecranul;
3.2.3 Instruciunea compus (instruciunea bloc)
Sintaxa:
{
declaratii;
instruc_1;
instruc_2;
. . . .
}
ntr-un bloc se pot declara i variabile care pot fi accesate doar n corpul blocului.
Instruciunea bloc este utilizat n locurile n care este necesar prezena unei singure
instruciuni, ns procesul de calcul este mai complex, deci trebuie descris n mai multe
secvene.
3.3 Structura de decizie (alternativ, de selecie)
n limbajul C, implementarea structurii de decizie simpl se face prin intermediul
instruciunii if, iar celei de decizie cu ramuri multiple prin intermediul instruciunii switch.
3.3.1 Instruciunea if
Reprezentarea cu ajutorul pseudocodului: Sintaxa:
DAC condiie
ATUNCI instruciune1;
ALTFEL instruciune2;
if(expresie)
instruciune1;
[else
instruciune2;]
La ntlnirea instruciunii if, se evalueaz
expresie (care reprezint o condiie) din
paranteze. Dac valoarea expresiei este 1
(condiia este ndeplinit) se execut
instruciune1; dac valoarea expresiei este 0
(condiia nu este ndeplinit), se execut
instruciune2. Deci, la un moment dat, se
execut doar una dintre cele dou instruciuni: fie
instruciune1, fie instruciune2. Dup execuia
instruciunii if se trece la execuia instruciunii
care urmeaz acesteia.
ACIUNE 2 ACIUNE 1
Condiie
A F
Figura 3.2Reprezentarea structurii de
decizie cu ajutorul schemei logice

43
Capitolul 3
Observaii:
1. instruciune1 i instruciune2 pot fi instruciuni compuse (blocuri), sau chiar
alte instruciuni if (if-uri imbricate).
2. Ramura else este opional.
3. Deoarece instruciunea if testeaz valoarea numeric a expresiei (condiiei), este
posibil prescurtarea: if(expresie), n loc de if(expresie!=0).
4. Pentru claritatea programelor surs se recomand alinierea instruciunilor prin
utilizarea tabulatorului orizontal.
5. n cazul n care instruciunile din cadrul if-else sunt simple, se poate folosi
operatorul condiional.
3.3.1.1 Instruciunea if imbricat
Un if imbricat este un if care este obiectul aciunii unui alt if. n C, o instruciune else
se refer la cea mai apropiat instruciune if care se afl n acelai bloc cu else i care
nu este deja asociat cu un else. De exemplu,
if (i)
{
if (j) instruciune 1;
if(k) instruciune 2; /* acest if */
else instruciune 3; /* este asociat cu acest else */
}
else instruciune 4; /* asociata cu if(i) */
Dup cum s-a artat, instruciunea else din final nu este asociat cu if(j), fiindc nu
este coninut n acelai bloc cu aceasta, ci cu if(i). De asemenea, instruciunea else
din interior este asociat cu if(k), care este instruciunea if cea mai apropiat.
Standardul ANSI C precizeaz c trebuie acceptate cel puin 15 nivele de imbricare. n
practic, majoritatea compilatoarelor permit un numr mai mare.
3.3.1.2 Scara if-else-if
O structur des folosit n programare o constituie scara if-else-if, denumit astfel datorit
aspectului su. Forma sa general este
if(expresie) instruciune;
else
if(expresie) instruciune;
else
if(expresie) instruciune;

else instruciune;
Condiiile sunt luate n considerare de sus n jos. De ndat ce este gsit o condiie
adevrat, este executat instruciunea asociat acesteia i restul scrii este omis. Dac
nici una dintre condiii nu este adevrat, atunci va fi executat instruciunea final else.
Cu alte cuvinte, dac nici unul din testele condiionale nu se confirm, se va executa
ultima instruciune else. Dac aceasta nu exist i toate celelalte condiii sunt false, nu
are loc nici o aciune.
Dei alineatele din scara anterioar sunt corecte din punct de vedere tehnic, acestea pot
duce la o aliniere excesiv de adnc. Din acest motiv, scara if-else-if este de obicei
aezat astfel:
if (expresie)
instruciune;
else if(expresie)
instruciune;

44
STRUCTURI DE CONTROL

45
else if(expresie)
instruciune;

else
instruciune;
3.3.1.3 Exerciii
Exemplul 3.1 Instruciunea if
S se citeasc de la tastatur un numr real. Daca acesta se afl n intervalul [-1000,
1000], s se afieze 1, dac nu, s se afieze -1.
#include <iostream.h>
void main()
{
int afis; double nr;
cout<<Astept numar:; cin>>nr;
afis = (nr>=-1000 && nr<=1000 ? 1 : -1);
//sau:
/* if(nr>=-1000 && nr<=10000)
afis = 1;
else afis= -1; */
cout<<afis;
}
Exemplul 3.2 Instruciunea if - calculul valorii unei funcii
S se calculeze valoarea funciei f(x), tiind c x este un numr real introdus de la
tastatur:
f(x) =

- 6x + 20 dac - < x 7
x + 30 dac -7 < x 0
x dac x>0
. Se prezint dou versiuni de program:
#include <iostream.h>
#include <math.h>
void main()
{
double x,f;cout<<x=;cin>>x;
if(x<=7) f= -x*6 +20;
if(x>=-7 && x<=0) f= x+30;
if(x>0) x=sqrt(x);
cout<<f=<<f<<\n;
}
#include <iostream.h>
#include <math.h>
void main()
{
double x,f;cout<<x=;cin>>x;
if(x<=-7)
f= -x* 6 +20;
else
if(x<=0)
f= x+30;
else x=sqrt(x);
cout<<f=<<f<<\n;
}
Capitolul 3
Uneori, construcia if-else este utilizat pentru a compara valoarea unei variabile cu
diferite valori constante, ca n programul urmtor:

Exemplul 3.3 Calculator de buzunar - construcia if-else
Se citete un caracter reprezentnd un operator aritmetic binar simplu. n funcie de
caracterul citit, se afieaz numele operaiei pe care acesta o poate realiza.
#include <iostream.h>
void main()
{
char oper;
cout<<Introdu operator aritmetic,
simplu, binar:; cin>>oper;

46
if (oper == +)
cout<<Operatorul de adunare!\n;
else if (oper==- )
cout<<Operatorul de scadere!\n;
else if (oper==* )
cout<<Operatorul de
inmultire!\n;
else if (oper==/ )
cout<<Operatorul de
impartire!\n;
else if (oper==% )
cout<<Operatorul rest!\n;
else cout<<Operator ilegal!!!\n;
}
3.3.2 Structura de selecie cu ramuri multiple -
instruciunea switch
n unele cazuri este necesar luarea unei decizii avnd
la dispoziie mai multe variante. Instruciunea switch permite acest lucru.
ACIUNE 2
ACIUNE 1
Condiie
ACIUNE n
break
break
Figura 3.3 Schema logic pentru
structura selecie cu ramuri multiple
Reprezentarea cu ajutorul
pseudocodului:
Sintaxa:
DAC expresie=expr_const_1
instruc_1;
[ieire;]
ALTFEL DAC expresie=expr_const_2
instruc_2;
[ieire;]
. . . . .. . . . . .
ALTFEL DAC expresie=expr_const_n-1
instruc_n-1;
[ieire;]
ALTFEL instruc_n;
switch (expresie)
{
case expr_const_1: instruc_1;
[break;]
case expr_const_2: instruc_2;
[break;]
. . . . .. . . . . .
case expr_const_n-1: instruc_n-1;
[break;]
[ default:instruc_n; ]
}
Se testeaz dac valoarea pentru expresie este una dintre constantele specificate
(expr_const_1, expr_const_2, etc.) i se execut instruciunea de pe ramura
corespunztoare. n schema logic test_expresie este una din condiiile: expresie =
expr_const_1, expresie = expr_const_2, etc.
Este evaluat expresie (expresie aritmetic), iar valoarea ei este comparat cu valoarea
expresiilor constante 1, 2, etc. (expresii constante = expresii care nu conin variabile). n
situaia n care valoarea expresie este egal cu valoarea expr_const_k, se execut
instruciunea corespunztoare acelei ramuri (instruc_k). Dac se ntlnete
STRUCTURI DE CONTROL

47
instruciunea break, parcurgerea este ntrerupt, deci se va trece la execuia primei
instruciuni de dup switch. Dac nu este ntlnit instruciunea break, parcurgerea
continu. Break-ul cauzeaz deci, ieirea imediat din switch.
n cazul n care valoarea expresiei nu este gsit printre valorile expresiilor constante, se
execut cazul marcat cu eticheta default (cnd acesta exist). Expresiile expresie,
expr_const_1, expr_const_2,etc., trebuie s fie ntregi. Iat trei aspecte important
de reinut relativ la instruciunea switch:
o Instruciunea switch difer de instruciunea if prin aceea c switch poate
efectua numai teste de egalitate, n timp ce if poate evalua orice tip de expresie
relaional sau logic.
o n cadrul unei instruciuni switch nu pot exista dou constante case cu valori
identice. Bineneles, o instruciune switch inclus ntr-o alt instruciune switch
exterioar poate conine constante case identice.
o Dac constantele de tip caracter sunt folosite ntr-o instruciune switch, acestea
vor fi n mod automat convertite n numere ntregi.
Instruciunea switch este adesea folosit pentru a prelucra comenzi provenite de la
tastatur, cum ar fi selecia meniurilor.
Exemplul 3.4 Calculator de buzunar - instruciunea switch
S rescriem programul pentru Exemplul 3.3, utiliznd instruciunea switch.
#include <stdio.h>
#include <conio.h>

void main()
{
char oper;
printf("Introdu operator aritmetic, simplu, binar:");
scanf("%c",&oper);
switch(oper)
{
case '+': printf("Operatorul de adunare!\n"); break;
case '-': printf("Operatorul de scadere!\n"); break;
case '*': printf("Operatorul de inmultire!\n"); break;
case '/': printf("Operatorul de impartire!\n"); break;
case '%': printf("Operatorul rest!\n"); break;
default : printf("Operator ilegal!\n");
}
getch();
3.4 Structuri ciclice (repetitive)
Exist dou categorii de instruciuni ciclice: cu test iniial i cu test final.
3.4.1 Implementarea structurilor ciclice cu test iniial
Structura ciclic cu test iniial este implementat prin instruciunile while i for.
3.4.1.1 Instruciunea while
Reprezentarea structurii ciclice cu test iniial cu
ajutorul pseudocodului:
Sintaxa:
CT TIMP expresie REPET
NCEPUT
instruciune;
while (expresie)
instructiune;
Capitolul 3
SFRIT
La ntlnirea acestei instruciuni, se
evalueaz expresie. Dac aceasta
are valoarea 1 - sau diferit de 0 -
(condiie ndeplinit), se execut
instruciune. Se revine apoi n
punctul n care se evalueaz din nou
valoarea expresiei. Dac ea este tot 1,
se repet instruciune, .a.m.d.
Astfel, instruciunea (corpul ciclului) se
repet att timp ct expresie are
valoarea 1. n momentul n care
expresie ia valoarea 0 (condiie
nendeplinit), se iese din ciclu i se
trece la urmtoarea instruciune de dup while.
Figura 3.4 Schema logic pentru structura
ciclic cu test iniial
ACIUNE 2 ACIUNE 1
Condiie
A F
Observaii:
1. n cazul n care la prima evaluare a expresiei, aceasta are valoarea zero, corpul
instruciunii while nu va fi executat
niciodat.
2. Instruciune din corpul ciclului while
poate fi compus (un bloc), sau o alt
instruciune ciclic.
3. Este de dorit ca instruciunea din corpul
ciclului while s modifice valoarea
expresiei. Dac nu se realizeaz acest lucru,
corpul instruciunii while se repet de un
numr infinit de ori.

48
Exemplu:
int a=7;
while (a==7)
cout<<Buna ziua!\n; // ciclu infinit;
se repet la infinit afiarea mesajului
3.4.1.2 Instruciunea for
n majoritatea limbajelor de programare de nivel
nalt, instruciunea for implementeaz
structura ciclic cu numr cunoscut de pai. n limbajul C instruciunea for poate fi
utilizat ntr-un mod mult mai flexibil.
evaluare expr. 3
ACIUNE 1
expr. 2
A F
evaluare expr. 1
Figura 3.5 Schema logic pentru
structura ciclic cu numr cunoscut de
pai
Reprezentarea cu ajutorul
pseudocodului:
Sintaxa:
evaluare expresie1
CT TIMP expresie2 REPET
NCEPUT
instruciune
evaluare expresie3
SFRIT
for (expresie1; expresie2; expresie3)
instructiune;
STRUCTURI DE CONTROL

49
3.4.1.3 Variaii ale ciclului for
n paragraful anterior au fost descrise cele mai des folosite aspecte ale ciclului for.
Limbajul C mai pune ns la dispoziie o gam ntreag de variaii care mresc
flexibilitatea i domeniul de aplicabilitate al ciclului for.
3.4.1.3.1 Folosirea operatorului virgul
Una din cele mai folosite variaii folosete operatorul virgul pentru a permite existena a
dou sau mai multe variabile de control al ciclului. (Reamintim c operatorul virgul se
folosete pentru evaluarea succesiv a unui numr de expresii n genul f asta i asta".)
De exemplu, variabilele x i y controleaz ciclul descris n exemplul urmtor i ambele sunt
iniializate n interiorul instruciunii for:
for(x=0, y=0; x+y<10; ++x) {
y = getchar ( );
y = y - '0'; /* scade codul ASCII pentru 0 din y */
}
Virgulele separ cele dou instruciuni de iniializare. De fiecare dat cnd se repet ciclul,
x este incrementat i valoarea lui y este dat de la tastatur. Att x ct i y trebuie s aib
acele valori necesare pentru ncheierea ciclului. Chiar dac valoarea lui y este stabilit de
la tastatur, valoarea sa iniial trebuie s fie 0 pentru ca valoarea sa s fie definit
anterior primei evaluri a expresiei condiionale. (Dac y nu ar fi fost definit, ar fi putut n
mod accidental conine chiar valoarea 10, ceea ce ar fi dus la o valoare de adevr fals a
testului condiional i la neexecutarea ciclului.)
3.4.1.3.2 Cicluri infinite
Dei pentru crearea unui ciclu infinit poate fi folosit orice instruciune de ciclu, n mod
tradiional se folosete instruciunea for. Deoarece nici una dintre cele trei expresii care
formeaz ciclul for nu este necesar, un ciclu infinit poate fi creat lsnd liber zona
rezervat expresiei condiionale, dup cum se arat n continuare:
for( ; ; ) printf("Acest ciclu va rula la infinit. \n");
Putei insera o expresie de iniializare i una de incrementare, dar programatorii n C
folosesc cel mai adesea construcia for(;;) pentru a simboliza un ciclu infinit. De fapt,
structura for(;;) nu asigur un ciclu infinit, fiindc instruciunea break din C, care poate
aprea oriunde n interiorul corpului ciclului, determin ncheierea imediat a acestuia
(despre break vom discuta mai trziu n acest capitol). Programul va continua cu linia
imediat urmtoare ciclului, dup cum se va arta n continuare:
ch = '\0'
for( ; ; )
{
ch = getchar(); /* scrie un caracter */
if(ch=='A') break; /* ciclul se incheie */
}
printf("ati tastat un A");
Acest ciclu va fi executat pn cnd utilizatorul va introduce un A de la tastatur.
Un alt ciclu infinit, nedorit de aceast dat, se obine cu instruciunea
for(;;);
n care ";" de la sfrit nseamn instruciunea vid, deci ciclul nu va face nimic la
nesfrit.
3.4.1.3.3 Cicluri for fr coninut
Capitolul 3
Dup cum a fost definit prin sintaxa C, o instruciune poate fi fr coninut. Deci coninutul
ciclului for (sau al oricrui ciclu) poate fi de asemenea vid. Acest fapt poate fi folosit
pentru a mbunti eficiena anumitor algoritmi i pentru a
crea cicluri pentru ntrziere.

50
Eliminarea spaiilor dintr-un flux de intrare este o
necesitate des ntlnit n programare. De exemplu, un
program de baze de date poate permite o interogare de
genul afieaz toate balanele mai mici dect 400". Baza
de date necesit introducerea separat a fiecrui cuvnt,
fr spaii. Aceasta nseamn c baza de date recunoate
cuvntul afieaz" dar nu i afieaz". Ciclul din
exemplul urmtor elimin spaiile de nceput din fluxul
indicat de ctre str.
for( ; *str==' '; str++);
Dup cum putei vedea, acest ciclu nu are coninut i nici nu are nevoie. Ciclurile de
ntrziere (time delay) apar adesea n programe. Linia de program urmtoare indic modul
de utilizare a unui asemenea ciclu folosind instruciunea for:
for(t=0; t<O_VALOARE; t++);
3.4.2 Implementarea structurilor ciclice cu test final
3.4.2.1 Instruciunea do-while
Reprezentarea cu ajutorul pseudocodului: Sintaxa:
REPET
NCEPUT
instruciune;
SFRIT
CT TIMP condiie
do instructiune;
while(expresie);
Se execut instruciune. Se evalueaz apoi expresie. Dac aceasta are valoarea 1,
se execut instruciune. Se testeaz din nou valoarea expresiei. Se repet
instruciune ct timp valoarea expresiei este 1 (condiia este ndeplinit). n cazul
instruciunii do-while, corpul ciclului se execut cel puin o dat.
3.4.3 Exerciii
Exemplul 3.5 Cicluri
Se citete cte un caracter, pn la ntlnirea caracterului @. Pentru fiecare caracter citit,
s se afieze un mesaj care s indice dac s-a citit o liter mare, o liter mic, o cifr sau
un alt caracter. S se afieze cte litere mari au fost introduse, cte litere mici, cte cifre i
cte alte caractere. Se prezint trei modaliti de implementare (cu instruciunea while,
cu instruciunea for i cu instruciunea do-while).
#include <iostream.h>
#include <conio.h>
void main()
{ char c; clrscr();
int lmic=0, lmare=0, lcif=0;
int altcar=0;
cout<<"Astept car.:"; cin>>c;
while (c!='@'){
if (c>='A' && c<='Z') {
Observaii legate de implementare:
Variabila c (tip char) memoreaz
caracterul introdus la un moment dat,
de la tastatur.
Variabilele ntregi lmic, lmare, lcif
i altcar sunt utilizate pe post de
contor pentru litere mari, mici, cifre,
respectiv alte caractere.
Condiie
ACIUNE 1
A F
Figura 3.6 Schema logic
pentru structura ciclic cu
test final
STRUCTURI DE CONTROL

51
cout<<"Lit. mare!\n";
lmare++; }
else if (c>='a' && c<='z') {
cout<<"Lit. mica!\n";
lmica++; }
else if (c>='0' && c<='9') {
cout<<"Cifra!\n";
lcif++; }
else {
cout<<"Alt car.!\n";
altcar++; }
cout<<"Astept car.:";cin>>c;
}
cout<<"Ati introdus \n";
cout<<lmare<<" litere mari, ";
cout<<lmic<<" litere mici\n";
cout<<lcif<<" cifre i \n";
cout<<altcar<<" alte caractere\n";
getch();}
Aciunea care se repet ct timp
caracterul citit este diferit de constanta
caracter '@' const din mai multe
aciuni simple: citirea unui caracter (cu
afiarea n prealabil a mesajului "Atept
car.:"; testarea caracterului citit
(operatorii relaionali pot fi aplicai
datelor de tip char).
Ca urmare, aciunea din corpul
instruciunii while a fost implementat
printr-o instruciune bloc.
Tot instruciuni bloc au fost utilizate pe
fiecare ramur a instruciunii if
(afiare mesaj referitor la caracter i
incrementare contor).
#include <iostream.h>
#include <conio.h>
void main()
{ char c;clrscr();
intlmic=0,lmare=0,lcif=0;int
altcar=0;
cout<<"Astept caract.:"; cin>>c;
for( ; c!='@'; ){
// corp identic
}
cout<<"Ati introdus \n";
cout<<lmare<<" litere mari, ";
cout<<lmic<<" litere mici\n";
cout<<lcif<<" cifre si \n";
cout<<altcar<<" alte carctere\n";
getch();
}
Pentru implementarea aceluiai
algoritm se poate utiliza instruciunea
for. n cadrul acesteia, expresie1 i
expresie3 lipsesc, ns prezena
instruciunilor vide este obligatorie.
int lmic=0, lmare=0, lcif=0;
int altcar=0;
cout<<"Astept caract.:";cin>>c;
do {
//corp do-while
} while (c!='@');
cout<<"Ati introdus \n";
//. . .
Variant de implementare care
utilizeaz instruciunea do-while:
Exemplul 3.6 Suma i produsul primelor n numere naturale
S se calculeze suma i produsul primelor n numere naturale, n fiind introdus de la
tastatur. Se vor exemplifica modalitile de implementare cu ajutorul instruciunilor do-
while, while, i for. (Se observ c: S =
k=1
n
k , P =
k=1
n
k .
//while //do - while
Capitolul 3
int n, S=0, P=1, k=1;
printf("n= "); scanf("%d",&n);
while(k<=n)
{ S+=k; P*=k; k++;}
printf("P= %d\tS= %d",P,S);
int n, S=0, P=1, k=1;
printf("n= "); scanf("%d",&n);
do
{ S+=k; P*=k; k++;}
while(k<=n);
printf("P= %d\tS= %d",P,S);

Pentru a ilustra multiplele posibiliti oferite de instruciunea for, prezentm variantele
// for varianta1
int S=0, P=1, k;
for (k=1; k<=n; k++)
{ S+=k; P*=k; }
printf("P= %d\tS= %d",P,S);
// for varianta2
int S=0, P=1;
for (int k=1; k<=n; k++)
{ S+=k; P*=k; }
printf("P= %d\tS= %d",P,S);
// for varianta3
for (int S=0, P=1, k=1; k<=n; k++)
{ S+=k; P*=k; }
printf("P= %d\tS= %d",P,S);
// for varianta4
for (int S=0, P=1, k=1; k<=n;
S+=k, P*=k, k++)
; //instruc vida
printf("P= %d\tS= %d",P,S);;
Exemplul 3.7 Maximul unui ir de
numere naturale
S se citeasc un ir de numere
reale, pn la ntlnirea numrului
900. S se afieze maximul
numerelor citite.

52
Se presupune c primul element
din irul de numere are valoarea
maxim. Se memoreaz valoarea
sa n variabila max. Se parcurge
apoi irul, comparndu-se valoarea
fiecrui element cu valoarea
variabilei max. n cazul n care se gsete un element cu o valoare mai mare dect a
variabilei max, se reine noua valoare (max=n).
// Maximul unui sir
#include <iostream.h>
void main()
{double n;
cout<<"Introdu nr:"; cin>>n;
double max=n;
while (n!=900)
{ if (n>=max) max=n;
cout<<"Introdu nr:"; cin>>n;
}
cout<<"Max ir este:"<<max<<'\n';
}
Exemplul 3.8 Conversia unui numr din baza 10 ntr-o alt baz de numeraie
S se scrie un program care realizeaz conversia numrului N ntreg, din baza 10 ntr-o
alt baz de numeraie, b<10 (N i b citite de la tastatur). Conversia unui numr ntreg
din baza 10 n baza b se realizeaz prin mpriri succesive la b pn cnd ctul devine 0,
i memorarea resturilor, n ordine invers. De exemplu:
547:8=68 rest 3; 68:8=8 rest 4; 8:8=1 rest 0; 1:8=0 rest 1 547
10
= 1043
8

#include <iostream.h>
void main()
{ int nrcif=0,N,b,rest,Nv,p=1;
long Nnou=0;
cout<<"\nIntroduceti baza<10, b=";cin>>b;
cout<<"Introduceti numarul in baza 10, nr=";cin>>N;
Nv=N;
STRUCTURI DE CONTROL

53
while(N!=0)
{
rest=N%b; N/=b;
cout<<"nr="<<N<<'\n';
cout<<"rest="<<rest<<'\n';
nrcif++;
Nnou+=rest*p;
p*=10;
cout<<"Nr. nou="<<Nnou<<'\n';
}
cout<<"Numarul de cifre este "<<nrcif<<'\n';
cout<<"Nr. in baza 10 "<<Nv;
cout<<" convertit in baza "<<b<<" este "<<Nnou<<'\n';
}
Exemplul 3.9 Calculul unei serii
S se calculeze seria urmtoare cu o eroare mai mic dect EPS (EPS introdus de la
tastatur):

k=1


x
k
k
, x [0,1], x citit de la tastatur. Vom aduna la suma S nc un termen T,
ct timp valoarea acestuia este mai mare sau egal cu EPS. Pentru calculul lui x
k
se va
utiliza funcia pow(x, k), aflat n biblioteca <math.h>, sau se ine cont de relaia de
recuren T
k+1
= Tx
k
k+1
, cu T
1
= x
#include <iostream.h>
#include <math.h>
void main()
{
double x,T,S=0,EPS=1e-03;long k=0;
cout<<"x="; cin>>x;
do
{
k++; T=pow(x,k)/k; S+=T;
cout<<"Termenul "<<k<<":\tT="<<T<<"\tS="<<S<<'\n';
}
while(T>=EPS);
}
3.5 Instruciuni de salt
C dispune de patru instruciuni de salt care execut o ramur necondiional:
return, goto, break i continue.
Dintre acestea, return i goto pot fi folosite oriunde n program. Instruciunile break i
continue pot fi folosite mpreun cu oricare dintre instruciunile repetitive. Dup cum s-a
artat mai devreme n acest capitol, instruciunea break se poate folosi mpreun cu
switch.
3.5.1 Instruciunea return
Instruciunea return este folosit pentru a obine rezultatul unei funcii. Este considerat
drept instruciune de salt ntruct determin executarea programului s revin (s execute
un salt napoi) la punctul n care s-a fcut apelarea funciei. Dac instruciunii return i
este asociat o valoare, acea valoare devine valoarea calculat prin acea funcie. Dac nu
Capitolul 3

54
este specificat nici o valoare calculat a funciei, se presupune returnarea unei valori
inutile. (Unele compilatoare C vor returna valoarea zero dac nu este indicat nici o
valoare, dar nu contai pe asta.) Forma general a instruciunii return este
return expresie;
Nu uitai, expresie este opional. Cu toate acestea, dac exist, ea va deveni valoarea
returnat de funcia respectiv.
n cadrul unei funcii putei folosi instruciuni return la discreie. Cu toate acestea, o
funcie va fi stopat din execuie la ntlnirea primei instruciuni return. Acolada de la
sfritul unei funcii determin de asemenea revenirea din aceasta. Situaia este analog
cu un return cruia nu i s-a precizat nici o valoare.
O funcie declarat de tip void nu poate conine o instruciune return care specific o
valoare. (Din moment ce o funcie de tip void nu are valoare calculat, este de bun sim
faptul c o instruciune return interioar acesteia nu poate returna o valoare.)
3.5.2 Instruciunea goto
Din moment ce limbajul C dispune de o zestre bogat de structuri de control i permite
funciuni suplimentare de control folosind instruciunile break i continue, instruciunea
goto nu este deosebit de necesar. Nu exist situaii de programare care necesit
imperios instruciunea goto. Este mai degrab un obicei care, dac este folosit inspirat,
poate fi de folos n cteva situaii de programare extrem de limitate. Ca atare, goto nu va
fi folosit n afara acestui paragraf. Instruciunea goto necesit o etichet pentru a putea
opera.
O etichet este un identificator permis din C, urmat de dou puncte.
Forma general a instruciunii goto este
goto etichet;

etichet:
unde etichet este orice etichet corect, situat nainte sau dup goto. Se obinuiete
s se spun c eticheta prefixeaz instruciunea care urmeaz dup ea. La ntlnirea
instruciunii goto, se realizeaz un salt la instruciunea prefixat de eticheta al crei nume
se afl dup cuvntul cheie goto.
Deoarece o etichet este local n corpul unei funcii rezult c ea este nedefinit n afara
corpului funciei respective. n felul acesta, o instruciune goto poate realiza un salt numai
la o instruciune din corpul aceleai funcii n care este ea utilizat. Deci, o instruciune
goto nu poate face salt din corpul unei funcii la o instruciune din corpul altei funcii.

De exemplu poate fi creat un ciclu de la 1 la 100 folosind instruciunea goto i o etichet,
dup cum se va arta n continuare:
x = 1;
ciclu1:
x++;
if(x<100) goto ciclu1;
Menionm c nu se justific utilizarea abuziv a acestei instruciuni. Se recomand a fi
utilizat pentru a simplifica ieirea din cicluri imbricate.
STRUCTURI DE CONTROL

55
3.5.3 Instruciunea break
Instruciunea break poate fi folosit n dou scopuri. n primul rnd, se poate folosi pentru
a ncheia execuia unei instruciuni case aflate ntr-o instruciune switch (despre care s-a
vorbit n paragraful aferent din acest capitol). De asemenea, mai poate fi folosit pentru
ncheierea imediat a unui ciclu, prin omiterea testului condiional al acestuia.
Atunci cnd instruciunea break apare n interiorul unui ciclu, acesta este ncheiat imediat
i programul va continua cu instruciunea imediat urmtoare ciclului. De exemplu,
#include <stdio.h>
void main(void) {
int t;
for(t=0; t<100; t++)
{ printf("%d", t); if(t==10) break; }
}
scrie pe ecran numerele de la 0 la 10. Apoi ciclul se ncheie, fiindc instruciunea break
determin ieirea imediat din ciclu, ignornd testul condiional t<100.
Programatorii folosesc adesea instruciunea break n acele cicluri n care o anumit
condiie special poate determina ncheierea imediat. De exemplu, n cele ce urmeaz
apsarea unei taste poate stopa executarea funciei cautare():
cautare(char *nume)
{
do {
/* caut nume... */
if(kbhit()) break;
} while(!gsit); /* coinciden */
}
Funcia kbhit() returneaz zero dac nu apsai o tast. n caz contrar, returneaz o
valoare diferit de zero. Datorit diferenelor dintre mediile de operare, standardul ANSI C
nu definete funcia kbhit(), dar compilatorul dvs. o are inclus aproape sigur (poate
sub un nume uor diferit).
O instruciune break are efect numai n ciclul cel mai interior. De exemplu,
for(t=0; t<100); ++t)
{cont = 1;
for(;;)
{
printf ("%d", cont);
cont++;
if(cont==10) break;
}
}
tiprete numerele de la 1 la 10 de 100 de ori. De fiecare dat cnd compilatorul
ntlnete instruciunea break, se d controlul ciclului for exterior.
O instruciune break folosit n interiorul switch va afecta numai instruciunea switch
respectiv. Ea nu va afecta un posibil ciclu n care s-ar putea gsi instruciunea switch.
3.5.4 Instruciunea continue
Instruciunea continue este oarecum asemntoare instruciunii break. ns, n loc de a
fora ncheierea programului, continue foreaz urmtoarea iteraie a ciclului, prin
omiterea oricror linii de program dintre cele dou iteraii. Pentru ciclul for, instruciunea
continue determin testul condiional i apoi poriunile de incrementare ale ciclului de
executat. Pentru instruciunile while i do-while, programul trece la testele condiionale.
Capitolul 3
De exemplu, programul care urmeaz numr spaiile incluse n irul introdus de ctre
utilizator:
/* Numr spaiile */
#include <stdio.h>
void main(void)
{
char s [80], *str;
int spatiu;
printf("Introduceti un sir: ");
gets(s);
str=s;
for(spatiu=0; *str; str++) {
if(*str != ' ') continue; spatiu++;
}
printf("%d spatii\n", spaiu);
}
Fiecare caracter este testat pentru a se vedea dac este spaiu. Dac nu, instruciunea
continue foreaz reluarea ciclului for. Dac caracterul este un spaiu, valoarea
variabilei spaiu este incrementat.
Exemplul urmtor prezint modul de a folosi instruciunea continue pentru a urgenta
ieirea dintr-un ciclu, fornd efectuarea mai devreme a testului condiional:
void cod(void)
{
char gata, ch;
gata = 0;
while(!gata) {
ch = getchar();
if(ch=='$' {
gata = 1; continue; }
putchar(ch+1)! /* deplaseaz alfabetul cu o poziie n sus */
}
}
Aceast funcie codific un mesaj, prin nlocuirea tuturor literelor tastate cu literele
urmtoare n alfabet. De exemplu, A devine B. Funcia i va ncheia execuia n momentul
n care tastai simbolul $. Dup introducerea acestuia nu va mai rezulta nici un fel de dat
de ieire, fiindc testul condiional, activat de instruciunea continue, va descoperi c
variabila gata este adevrat i va determina ncheierea executrii ciclului.

while do while for

while (expresie1){
instructiune1;
instructiune2;
if (expresie2)
break;
else
continue;
instructiune3;
}

do{
instructiune1;
instructiune2;
if (expresie2)
break;
else
continue;
instructiune3;
}
while (expresie1);

for(expr1;expr2;expr3)
{
instructiune1;
instructiune2;
if (expresie2)
break;
else
continue;
instructiune3;
}



56
STRUCTURI DE CONTROL

57
Figura 3.7 Modul de utilizare a instruciunilor break i continue
Exemplul 3.10 Citire caractere
S revenim la programul realizat pentru Exemplul 3.5, care folosete instruciunea do-
while. Dac primul caracter citit este chiar caracterul @, se realizeaz testarea acestuia;
ca urmare, se afieaz mesajul "Alt car.!" i se incrementeaz valoarea contorului
altcar. Dac nu se dorete ca acest caracter s fie testat i numrat, n corpul
instruciunii do while putem face un test suplimentar.
int lmic=0,lmare=0,lcif=0,altcar=0;
cout<<"Atept caract.:";cin>>c;
do {
if (c == '@') break; //ieire din do while
//corp do-while
} while (c!='@');
cout<<"Ai introdus \n";
//. . .
3.6 Instruciuni expresie
Capitolul anterior se ocup pe larg de expresii. Cu toate acestea, trebuie menionate i aici
unele amnunte. Reinei c o instruciune de tip expresie nu este altceva dect o expresie
corect n C, urmat de punct i virgul, ca n exemplul urmtor:
func(); /* apelarea unei functii */
a = b+c; /* instruciune de atribuire */
b+f(); /* instruciune corecta, dar ciudata */
; /* instruciune vida */
Prima instruciune de mai sus execut apelarea unei funcii. A doua este o atribuire. A
treia, dei arat bizar, poate fi evaluat de ctre compilatorul de C, fiindc funcia f()
poate ndeplini o sarcin util. Exemplul final indic faptul c C permite ca o instruciune
s nu conin nimic (uneori mai este denumit i instruciune nul).
3.7 Instruciuni bloc
Instruciunile bloc nu sunt altceva dect grupuri de instruciuni legate ntre ele i tratate
unitar. Instruciunile care alctuiesc un bloc sunt interconectate din punct de vedere logic.
Un bloc ncepe cu o acolad de deschidere i se ncheie cu o acolad de nchidere.
Instruciunile bloc sunt folosite cel mai adesea pentru a crea o destinaie multi-instruciune
pentru o alt instruciune, cum ar fi if. Totui, o instruciune bloc poate fi plasat n orice
loc normal pentru alt instruciune. De exemplu, programul urmtor este absolut corect,
dei e puin neobinuit:
#include <stdio.h>
void main(void)
{
int i;
{ /* o instruciune bloc */
i = 120;
printf("%d", i);
}
}

Capitolul 4

58
4. TABLOURI
Numim tablou o colecie (grup, mulime ordonat) de date, de acelai tip, situate ntr-
o zon de memorie continu (elementele tabloului se afl la adrese succesive).
Tablourile sunt variabile compuse (structurate), deoarece grupeaz mai multe elemente.
Variabilele tablou au nume, iar tipul tabloului este dat de tipul elementelor sale. Elementele
tabloului pot fi referite prin numele tabloului i indicii (numere ntregi) care reprezint
poziia elementului n cadrul tabloului.
n funcie de numrul indicilor utilizai pentru a referi elementele tabloului, putem ntlni
tablouri unidimensionale (vectorii) sau multidimensionale (matricile sunt tablouri
bidimensionale). Tabloul cel mai des folosit n C este irul (string), care este un tablou
unidimensional de caractere care se ncheie cu un zero.
4.1 Tablouri unidimensionale
Ca i variabilele simple, variabilele tablou trebuie declarate nainte de utilizare. Modul de
declarare:
tip nume_tablou[dim_1];
unde: tip reprezint tipul elementelor tabloului; dim_1 este un numr ntreg sau expresie
constant ntreag (a crei valoare este evaluat la compilare) care reprezint numrul de
elemente coninute n tablou.
Tablourile unidimensionale sunt tablouri cu un singur indice (vectori). Dac tabloul conine
dim_1 elemente, indicii elementelor au valori ntregi din intervalul [0, dim_1-1].
La ntlnirea declaraiei unei variabile tablou, compilatorul aloc pentru pstrarea valorilor
elementelor sale o zon de memorie continu, a crei mrime depinde direct de tipul i
dimensiunea acestuia. Pentru un tablou unidimensional, dimensiunea total n octei se
calculeaz dup cum se arat mai jos:
total octei = sizeof(tip) * dimensiune tablou
C nu are facilitatea de verificare a depirii limitelor pentru tablouri. Putei suprascrie peste
oricare din capetele tabloului i putei scrie peste datele altei variabile sau chiar direct n
liniile de program, fr a primi vreun mesaj de eroare. Ca programator, este de datoria
dvs. s asigurai verificarea depirii limitelor acolo unde este nevoie.
Exemple:
int vect[20]; // declararea tabloului vect, de maximum 20 de elemente, de
tipul int. Se rezerv 20*sizeof(int)=20 * 2 = 40 octei

#define MAX 10
char tabc[MAX]; // declararea tabloului tabc, de maximum MAX (10) elemente
de tip char

Numele tabloului poate fi utilizat n diferite expresii i valoarea lui este chiar adresa de
nceput a zonei de memorie care i-a fost alocat. Un element al unui tablou poate fi utilizat
ca orice alt variabil (n exemplul urmtor, atribuirea de valori elementelor tabloului
vector). Se pot efectua operaii asupra fiecrui element al tabloului, nu asupra ntregului
tablou.

Exemplu:
double alpha[5], beta[5], gama[5];
TABLOURI

59
int i=2;
alpha[2*i-1] = 5.78;
alpha[0]=2*beta[i]+3.5;
gama[i]=aplha[i]+beta[i]; //permis
gama=alpha+beta; //nepermis
4.1.1 Iniializarea tablourilor unidimensionale
Variabilele tablou pot fi iniializate n momentul declarrii:
tip nume_tablou[dim_1] = {list_valori};
Valorile din lista de valori sunt separate prin virgul, iar ntreaga list este inclus ntre
acolade:
Exemple:
// Declararea tabloului vector
int vector[6];
// Iniializarea elementelor tabloului
//1 - element cu element
vector[0]=100; vector[1]=101; vector[2]=102;
vector[3]=103; vector[4]=104; vector[5]=105;
//2- global
int vector[6]={100,101,102,103,104,105};
vector 100 101 102 103 104 105
[0] [5]
//valori n funcie de o variabila
double x=9.8;
double a[5]={1.2, 3.5, x, x-1, 7.5};
La declararea unui vector cu iniializarea elementelor sale, numrul maxim de elemente
ale tabloului poate fi omis, caz n care compilatorul determin automat mrimea tabloului,
n funcie de numrul elementelor iniializate.
Exemplu:
char tab[]={ A, C, D, V};
float data[5]={1.2, 2.3, 3.4};
Adresa elementului de indice i dintr-un tablou unidimensional poate fi calculat astfel:
adresa_elementului_i = adresa_de_baz + i* lungime_element

Exemple:
// Citirea elementelor unui vector:
double a[5]; int i, n;
cout<<Dim. Max. =; cin>>n;
for (i=0; i<n; i++)
{
cout<<a["<<i<<]=; //afiarea unui mesaj prealabil citirii fiecrui element
cin>>a[i]; //citirea valorii elementului de indice i
}
// Afiarea elementelor unui vector:
for (i=0; i<n i++)
cout<<a[i]<< ;
// Vectorul sum (c) a vectorilor a i b, cu acelai numr de elemente:
Capitolul 4

60
for (i=0; i<n i++)
c[i]=a[i]+b[i];
// Produsul scalar (p) al vectorilor
i=0
i
*b
i
a i b, cu acelai numr de elemente: p =
n-1
a
double p=0; // Initializarea sumei cu 0
for(i=0; i<n i++)
p += a[i] * b[i];
4.2 iruri
are au ca ultim element un irurile sunt tablouri unidimensionale de caractere, c
terminator de ir, caracterul NULL (zero ASCII), \0.
Din acest motiv, este necesar s declarai irurile de caractere ca fiind cu un caracter mai
lungi dect cel mai lung ir pe care l pot memora. De exemplu, pentru a declara un tablou
ir care poate memora un ir de 10 caractere, vei scrie
char sir[11];
Aceasta aloc spaiu pentru caracterul nul de la finele tabloului. Dei C nu dispune de un
tip de dat ir, permite existena constantelor ir. O constant ir este o list de caractere
ncadrate de ghilimele. De exemplu "ce mai faci". Nu este necesar s inserai manual
zeroul de la sfritul constantelor ir; compilatorul C va efectua automat aceast operaie.
4.2.1 Iniializarea irurilor
i forma: rurile de caractere permit o iniializare rapid de
char nume_sir[dimensiune] = "sir"
De iializeaz irul ir cu fraza "mi place C": exemplu, urmtoarea linie de program in
char sir[12] = "Imi place C";
Ceea ce este exact acelai lucru cu a scrie:
char str[12] = {'I','m','i',' ','p','l','a','c','e','
','C','\0'};
Fiindc n C toate irurile se ncheie cu un zero, trebuie s v asigurai c tabloul pe care l
declarai este suficient de lung pentru a include zeroul. lat de ce ir are 12 caractere, dei
fraza "mi place C" nu are dect 11. Cnd se folosete constanta ir, compilatorul
insereaz automat caracterul zero de ncheiere.
Exemple:
char tab_c[5] = {a,b,c,d,e}; // tablou de caractere
char sir_c[5] = {a,b,c,d,\0}; // irul de caractere cu
elementele abcd
Limbajul C permite iniializarea unui tablou de caractere printr-o constant ir (ir ntre
ghilime echivalent
cu:
[] = abcd;
c,d,\0};
le), care include automat caracterul NULL. Deci, ultima iniializare este
char sir_c[5] = abcd; sau cu char sir_c

c,d,e}; char tab_c[5] = {a,b,
] = {a,b, char sir_c[5
TABLOURI

61
eaz abcd
; nu conine terminatorul de
t c
; // afieaz al treilea element din irul sir_c1
sir_c1[1]=K; // elementului din ir de indice 1 i se atribuie valoarea
char sir_c1[5] = abcd;
char s[10];
cout<<sir_c<<\n; //afi
cout<<tab_c<<\n //eroare: tabloul de caractere
ir, deci nu poate fi afia a ir
cout<<s<<\n; // eroare: tablou neiniializat
cout<<sir_c1[2]
K;

Pentru manipularea irurilor, C dispune de o varietate de funcii care se gsesc n
biblioteca <string.h>. Aceste funcii sunt descrise detaliat n capitolul dedicat bibliotecii
standard.
4.3 Tablouri bidimensionale
clararea acestora se face cu sintaxa: De
tip nume_tablou[dim_1][dim_2];
unde: tip reprezint tipul elementelor tabloului; dim_1,dim_2, sunt numere ntregi sau
nstante ntregi (a cror valoare este evaluat la compilare) care reprezint
limitele superioare ale indicilor tabloului.
Exemp
expresii co
le:
double matrice[2][3]; // declararea tabloului bidimensional matrice,
dere conceptual, elementele unui tablou bidimensional sunt plasate n
spaiu pe dou direcii. Matricea in ral a tablourilor
bidimensionale.
n matematic: A
mxn
=

a a
m

n C: A
mxn
=

a
m-1 n-1

m-1 n-1
ac notm cu k poziia n memorie a unui element, valoarea lui k = i * m + j (unde m este
maximum 2 linii i maximum 3 coloane, tip double

Din punct de ve
reprez t o aplicaie natu

a
11
a
12
a
13
a
1n
a
21
a
22
a
23
a
2n


a
m1 m2 3
a
mn

a
00
a
01
a
02
a
0 n-1
a
10
a
11
a
12
a
1 n-1

a
m-1 1
a
m-1 2
a
m-1 3

n memorie, elementele unei matrici sunt memorate pe linii:


a
00
,a
01
,a
02
,,a
0 n-1
,a
10
,a
11
,a
12
,,a
1 n-1
,,,,,,a
m-1 1
,a
m-1 2
,a
m-1 3
,,a
D
numrul maxim de linii, i este indicele de linie, j este indicele de coloan).

n cazul unui tablou bidimensional, formula urmtoare calculeaz numrul de octei de
memorie necesari pentru stocarea acestuia:
octei = dimensiunea primului indice * dimensiunea indicelui al doilea * sizeof(tip de baz)
Ca atare, presupunnd c ntregii ocup fiecare cte doi octei, un tablou de ntregi cu
dimensiunile 10 x 5 va avea nevoie de 10*5*2 adic de 100 de octei de memorie.
Cnd un tablou bidimensional este folosit ca argument al unei funcii, este transmis efectiv
numai pointerul primului element. Cu toate acestea, parametrul care primete un tablou
bidimensional trebuie s defineasc mcar dimensiunea din dreapta a tabloului. Aceasta
Capitolul 4

62
un
tablou bidimensional de ntregi de dimensiuni 10,10 va fi declarat dup cum urmeaz:
deoarece compilatorul de C trebuie s cunoasc lungimea fiecrui rnd dac trebuie s
aplice corect indicii fiecrui termen al tabloului. De exemplu, o funcie care primete
void func1 (int x[][10])
{

}
Dac dorii, putei preciza i dimensiunea din stnga, dar nu este absolut necesar.
Indiferent de situaie, compilatorul trebuie s cunoasc dimensiunea parametrului din
dreapta, pentru a putea executa corect expresii de genul x[2][4] aflate n interiorul funciei.
Dac nu este cunoscut lungimea rndurilor, compilatorul nu-i poate da seama unde
tur elementele unei matrici de maxim 10 linii i 10 coloane. S
se
ncepe cel de-al treilea rnd.
Exemplul 4.1 Citirea i afiarea elementelor unei matrici
S se citeasc de la tasta
afieze matricea citit.
#include <iostream.h>
void main(void)
{
int a[10][10]; int nr_lin, nr_col;
cout<<"Nr. linii:"; cin>>nr_lin;
cout<<"Nr. coloane:"; cin>>nr_col;int i, j;
//citirea elementelor unei matrici
for (i=0; i<nr_lin; i++)
for (j=0; j<nr_col; j++) {
cout<<"A["<<i<<","<<j<<"]="; //afiarea unui mesaj prealabil citirii
cin>>A[i][j];
}
//afiarea elementelor matricii
for (i=0; i<nr_lin; i++)
{
for (j=0; j<nr_col; j++)
cout<<A[i][j]<<'\t';
cout<<'\n'; // dup afiarea elementelor unei linii, se trece pe linia urmtoare
}
}
4.3.1 Iniializarea tablourilor bidimensionale
Forma general a iniializrii unui tablou multidimensional este similar cu aceea a
iniializrii altor variabile, dup cum se va vedea n continuare:
tip nume_tablou [dim_1]...[dim_N] = {lista_valori};
lista_valori este o list de constante separate prin virgul, al cror tip este compatibil cu
tip.
De exemplu, instruciunile care urmeaz iniializeaz tabloul patrate, cu numerele de la
1 la 5 i cu ptratele acestora:
int patrate[5][2]={1,1,2,4,3,9,4,16,5,25};
Ev entare: entual elementele de pe aceeai linie pot fi ncadrate ntre acolade suplim
int patrate[5][2]={{1,1},{2,4},{3,9},{4,16},{5,25}};
La declararea unei matrici i iniializarea elementelor sale, se poate omite numrul maxim
de linii, n schimb, datorit modului de memorare, trebuie specificat numrul maxim de
coloane:
TABLOURI

63
int mat[][3] = {{10, -5, 3},{32, 20, 1},{-1, 1, -2},{7, -8,
9} };
Construcia are acelai efect ca precedenta.
int mat[][3] = {{1, 1},{ -1},{3, 2, 1}};
mat reprezint o matrice 3 x 3, ale crei elemente se iniializeaz astfel:
mat[0][0]=1, mat[0][1]=1, mat[1][0]=-1, mat[2][0]=3, mat[2][1]=2, mat[2][2]=1
Elementele mat[0][2], mat[1][1], mat[1][2] nu sunt iniializate. Ele au valoarea zero dac
tabloul este global i valori iniiale nedefinite dac tabloul este automatic.
4.4 Tablouri multidimensionale
C accept tablouri cu mai mult de dou dimensiuni. Limita exact, dac exist, este
determinat de ctre compilatorul dvs. Forma general a unei declaraii de tablou
multidimensional este:
tip nume[dim_1][dim_2][dim_3]...[dim_N];
Tablourile de trei sau de mai multe dimensiuni nu sunt folosite prea des, datorit cantitii
de memorie necesar pentru stocarea acestora. De exemplu, un tablou de caractere
cvadridimensional, avnd dimensiunile 10, 6, 9, 4 necesit 10*6 *9 *4 sau 2160 de octei.
Dac tabloul ar fi fost compus din ntregi de 2 octei, ar fi fost necesari 4320 de octei.
Dac tabloul ar fi coninut variabile de tip double (alocnd 8 octei pentru fiecare
variabil), ar fi fost nevoie de 17280 octei. Practic, spaiul de memorie necesar se
mrete exponenial cu numrul de dimensiuni al tabloului. Pentru tablourile
multidimensionale de mari dimensiuni se aloc adesea n mod dinamic cte un spaiu de
memorie, folosind funciile de alocare dinamic a memoriei specifice limbajului C. Aceast
metod este cunoscut sub numele de tablou risipit (sparse array).
n cazul tablourilor multidimensionale, calculul fiecrui indice consum din timpul
calculatorului. Aceasta nseamn c durata de accesare a unui element dintr-un tablou
multidimensional poate fi mai mare dect n cazul unui element dintr-un tablou
unidimensional.
La transmiterea tablourilor multidimensionale ctre funcii, este necesar declararea
tuturor dimensiunilor, cu excepia primei din stnga. De exemplu, dac declarai tabloul m
sub forma int m[4][3][6][5]; funcia func1() care primete tabloul m, trebuie s
arate astfel:
void func1 (int d[ ] [3] [6] [5] )
{}
Desigur, putei introduce i prima dimensiune, dac dorii.
4.4.1 Iniializarea de tablouri nedimensionate
S presupunem c folosii iniializarea de tablouri pentru a crea un tabel de mesaje de
eroare, dup cum urmeaz:
char e1[18] = "Eroare de citire\n";
char e2[19] = "Eroare de scriere\n";
char e3[28] = "Nu poate deschide fisierul\n";
Dup cum v-ai dat seama probabil, este greoi s se numere manual caracterele din
fiecare mesaj, pentru a determina lungimea corect a tabloului. Putei cere C-ului s
calculeze aceste dimensiuni, folosind tablouri adimensionale. Dac n instruciunea de
iniializare a unui tablou, dimensiunea tabloului nu este specificat, compilatorul de C
creeaz automat un tablou suficient de mare pentru a memora toi iniializatorii. Acesta se
numete tablou nedimensionat (unsized array). Folosind aceast metod, tabelul de
mesaje devine
Capitolul 4
char el[] = "Eroare de citire\n";
char e2[] = "Eroare de scriere\n";
char e3[] = "Nu poate deschide fisierul\n";
Date fiind aceste iniializri, instruciunea
printf("%s are lungimea %d\n", e2, sizeof(e2));
va afia pe ecran urmtorul mesaj: Eroare de scriere are lungimea 19
n afar de faptul c este mai puin greoaie, iniializarea de tablouri nedimensionate
permite modificarea oricrui mesaj, fr teama c ar putea fi declarate tablouri de
dimensiuni insuficiente.
Iniializarea de tablouri nedimensionate nu se limiteaz numai la tablouri unidimensionale.
Pentru tablourile multidimensionale, trebuie precizate toate dimensiunile, n afar de cea
situat cel mai la stnga. (Celelalte dimensiuni sunt necesare compilatorului pentru a
aplica indecii n mod corespunztor.) Astfel, se pot crea tabele de diverse lungimi, pentru
care compilatorul va aloca n mod automat un spaiu de stocare suficient. De exemplu,
declaraia tabloului ptrate ca tablou nedimensionat poate fi scris dup cum urmeaz:
int patrate[][2] = {1,1, 2,4, 3,9, 4,16, 5,25};
Avantajul acestui tip de declaraie fa de cel clasic este c tabelul poate fi scurtat sau
lungit fr a se modifica dimensiunile tabloului.
4.5 Exemple
Exemplul 4.2 Interschimbarea elementelor unui vector
S se citeasc elementele unui vector cu maxim 100 de elemente reale i s se
interschimbe elementele vectorului n modul urmtor: primul cu ultimul, al doilea cu
penultimul, etc.


64
#define FALSE 0
#define TRUE 1
#include <iostream.h>
void main()
{ double vect[100], aux;
int n;//n-numarul real de elemente ale vectorului
cout<<"Nr. elemente"; cin>>n;
// de completat exemplul cu secvena de citire a elementelor vectorului
for (int i=0; i<n/2; i++){
aux=vect[i];
vect[i]=vect[n-1-i];
vect[n-1-i]=aux;
}
// de completat exemplul cu secvena de afiare a vectorului
}
Pentru schimbarea elementelor vectorului s-a folosit variabila auxiliar aux (vezi figura
alturat). Fr aceast variabil, la atribuirea vect[i]=vect[n-1-i], valoarea
elementului vect[i] s-ar fi pierdut. Trebuie observat, de asemenea, c variabila contor i
ia valori ntre 0 i n/2 (de exemplu, dac vectorul are 4 sau 5 elemente sunt necesare 2
interschimbri).

Exemplul 4.3 Citirea i afiarea elementelor unei matrici
S se citeasc de la tastatur elementele unei matrici de maxim 10 linii i 10 coloane. S
se afieze matricea citit.
aux
vect[i] vect[n-i-1]
1 3
2
TABLOURI

65
#include <iostream.h>
void main(void)
{int a[10][10]; int nr_lin, nr_col; cout<<"Nr. linii:";
cin>>nr_lin;
cout<<"Nr. coloane:"; cin>>nr_col;int i, j;
//citirea elementelor unei matrici
for (i=0; i<nr_lin; i++)
for (j=0; j<nr_col; j++) {
cout<<"A["<<i<<","<<j<<"]="; //afiarea unui mesaj prealabil citirii
cin>>A[i][j];
}
//afiarea elementelor matricii
for (i=0; i<nr_lin; i++) {
for (j=0; j<nr_col; j++)
cout<<A[i][j]<<'\t';
cout<<'\n'; // dup afiarea elementelor unei linii, se trece pe linia
urmtoare
}
}
Exemplul 4.4 Operaii cu matrici
S se citeasc elementele matricilor A(MXN), B(NXP) i C(MXN), unde M<=10, N<=10 i
P<=10. S se interschimbe liniile matricii A n modul urmtor: prima cu ultima, a doua cu
penultima, etc. S se calculeze i s se afieze matricile: AT = A
T
, SUM = A+C, PROD =
AXB. Implementarea citirilor i afirilor se va completa conform exemplului dat n
paragraful 4.3. Fiecare element din matricea produs PROD = AxB (A(MxN), B(NxP)),
PROD(MxP) este de forma:
prod
i,j
=
k=0
n-1
a
ik
*b
kj
, unde i = 0m-1 i j = 0n-1.
#include <iostream.h>
void main()
{
double a[10][10], b[10][10], c[10][10];
int m,n,p,j;
cout<<"m="; cin>>m; cout<<"n="; cin>>n; cout<<"p="; cin>>p;
// de completat secvena de citire a elementelor matricii a, cu m linii i n coloane
// de completat secvena de citire a elementelor matricii b, cu n linii i p coloane
// de completat secvena de afiare a matricii a
// interschimbarea liniilor matricii a:
for (i=0; i<m/2; i++)
for (j=0; j<n; j++){
double aux=a[i][j];a[i][j]=a[m-1-i][j];a[m-1-i][j]=aux;
}
cout<<"Matricea A cu liniile interschimbate:\n";
// de completat secvena de afiare a matricii a
// calculul matricii AT =AT
double at[10][10]; // at este matricea transpus
for (i=0; i<n; i++)
for (j=0; j<m; j++)
at[i][j]=a[j][i];
cout<<"A transpus=\n";
// de completat secvena de afiare a matricii at, cu n linii i m coloane
// de completat secvena de citire a elementelor matricii c, cu m linii i n coloane
Capitolul 4

66
// calculul matricii SUM=A+C, SUM(MxN):
double sum[10][10]; // sum este matricea suma dintre a si c
for (i=0; i<m; i++)
for (j=0; j<n; j++)
sum[i][j]=a[i][j]+ c[i][j];
cout<<"Matricea SUM=A+C este:\n";
// de completat secvena de afiare a matricii sum
double prod[10][10]; // prod este matricea produs dintre a i b
for (i=0; i<m; i++)
for (j=0; j<p; j++){
prod[i][j]=0;
for (k=0; k<n; k++)
prod[i][j]+=a[i][k]*b[k][j];
}
cout<<"Matricea produs dintre A si B este:\n";
// de completat secvena de afiare a matricii prod, cu m linii i p coloane
}


POINTERI
5. POINTERI
5.1 Variabile pointer
Pointerii sunt variabile care au ca valori adresele altor variabile (obiecte).
O variabil este un nume simbolic utilizat pentru un grup de locaii de memorie. Valoarea
memorat ntr-o variabil pointer este o adres.
Din punctul de vedere al coninutului zonei de memorie adresate, se disting urmtoarele
categorii de pointeri:
pointeri de date (obiecte) - conin adresa unei variabile din memorie;
pointeri generici (numii i pointeri void) - conin adresa unui obiect oarecare, de tip
neprecizat;
pointeri de funcii (prezentai n paragraful 6.12) - conin adresa codului executabil al
unei funcii.

Exemplu:
Tip variabil Nume Valoare Adres
propriu zis
x
5 1024
pointer
ptrx
1024 1028
n Tabelul de mai sus, variabila x are valoarea 5 i este memorat la adresa 1024.
Variabila ptrx are valoarea 1024 (adresa variabilei x) i este memorat la adresa de
memorie 1028. Vom spune c ptrx indic (engl. point) ctre x, deoarece valoarea
variabilei ptrx este chiar adresa de memorie a variabilei x.
5.1.1 Declararea variabilelor pointer
Sintaxa declaraiei unui pointer de date este:
tip *identificator_pointer;
Simbolul * precizeaz c identificator_pointer este numele unei variabile pointer
de date, iar tip este tipul obiectelor a cror adres o va conine.
Exemplu:
int u, v, *p, *q; // *p, *q sunt pointeri de ctre date de tip int
double a, b, *p1, *q1; // *p1, *q1 sunt pointeri ctre date de tip double
Pentru pointerii generici se folosete declaraia:
void *identificator_pointer;
Exemplu:
void *m;
Aceasta permite declararea unui pointer generic, care nu are asociat un tip de date precis.
Din acest motiv, n cazul unui pointer vid, dimensiunea zonei de memorie adresate i
interpretarea informaiei nu sunt definite, iar proprietile difer de ale pointerilor de date.
5.1.2 Operatorii pentru pointeri
Exist doi operatori unari care pot fi aplicai variabilelor pointer:
& - operatorul adres (de refereniere) - pentru aflarea adresei din memorie a unei
variabile;

67
Capitolul 5

68
* - operatorul de indirectare (de defereniere) - care furnizeaz valoarea din zona de
memorie spre care indic pointerul operand.
n exemplul prezentat anterior, pentru variabila ntreag x, expresia &x furnizeaz adresa
variabilei x. Pentru variabila pointer de obiecte int, numit ptr, expresia *ptr nseamn
coninutul locaiei de memorie a crei adres este memorat n variabila ptr. Expresia
*ptr poate fi folosit att pentru aflarea valorii obiectului spre care indic ptr, ct i
pentru modificarea acesteia (printr-o operaie de atribuire).
Exemplul 5.1
int x, y, *ptr; // pentru - variabila pointer ctre un int; x, y - variabile predefinite,
simple, de tip int
x=5; cout<<"Adresa variabilei x este:"<<&x<<\n;
cout<<"Valoarea lui x:"<<x<<\n;
ptr=&x; // atribuire: variabila ptr contine adresa variabilei x
cout<<"Variabila pointer ptr are valoarea:"<<ptr;
cout<<" si adreseaza obiectul:"<< *ptr<<\n;
y=*ptr; cout<<"y="<<y<<\n; // y=5
x=4; cout<<"x="<<x<<\n; cout<<"*ptr="<<*ptr<<\n; // x i *ptr
reprezint acelai obiect, un ntreg cu valoarea 4
x=70; // echivalenta cu *ptr=70;
y=x+10; // echivalenta cu y=*ptr+10
n exemplul anterior, atribuirea ptr=&x se execut astfel: operatorul & furnizeaz adresa
lui x, iar operatorul = atribuie valoarea (care este o adres) variabilei pointer ptr.
Atribuirea y=*ptr se realizeaz astfel: operatorul *acceseaz coninutul locaiei a crei
adres este coninut n variabila ptr, iar operatorul = atribuie valoarea variabilei y.
Declaraia int *ptr; poate fi, deci, interpretat n dou moduri, ambele corecte:
ptr este de tipul int * (ptr este de tip pointer spre int)
*ptr este de tipul int (coninutul locaiei spre care indic variabila ptr este de tipul
int)
Construcia tip * este de tipul pointer ctre int.
Atribuirea x=8;este echivalent cu ptr=&x; *ptr=x;
Variabilele pointer, alturi de operatorii de refereniere i de defereniere, pot apare n
expresii.
Exemplul 5.2
int x, y, *q; q=&x;
*q=8; // echivalent cu x=8;
q=&5; // invalid - constantele nu au adres
*x=9; // invalid - x nu este variabil pointer
x=&y; // invalid: x nu este variabil pointer, deci nu poate fi folosit cu operatorul
de indirectare
y=*q + 3; // echivalent cu y=x+3;
*q = 0; // seteaz x pe 0
*q += 1; // echivalent cu (*q)++ sau cu x++
int *r; r = q; /* copiaz coninutul lui q (adresa lui x) n r, deci r va
indica tot ctre x (va conine tot adresa lui x)*/
double w, *r = &w, *r1, *r2; r1= &w; r2=r1;
cout<<"r1="<<r1<<\n; //afieaz valoarea pointerului r1 (adresa lui w)
cout<<"&r1="<<&r1<<\n; // afieaz adresa variabilei r1
cout<<"*r1= "<<*r1<<\n;
double z=*r1; // echivalent cu z=w
POINTERI

69
cout<<"z="<<z<<\n;
5.1.3 Pointeri generici
La declararea pointerilor generici (void *nume;) nu se specific un tip, deci unui pointer
void i se pot atribui adrese de memorie care pot conine date de diferite tipuri: int,
float, char, etc. Aceti pointeri pot fi folosii cu mai multe tipuri de date, de aceea este
necesar folosirea conversiilor explicite prin expresii de tip cast, pentru a preciza tipul
datei spre care indic la un moment dat pointerul generic.

Exemplul 5.3
void *v1, *v2; int a, b, *q1, *q2;
q1 = &a; q2 = q1; v1 = q1;
q2 = v1; // eroare: unui pointer cu tip nu i se poate atribui un pointer generic
q2 = (int *) v1; double s, *ps = &s;
int c, *l; void *sv;
l = (int *) sv; ps = (double *) sv;
*(char *) sv = 'a'; /*Interpretare: adresa la care se gsete valoarea lui sv
este interpretat ca fiind adresa zonei de memorie care conine o data de tip char.
*/

Pe baza exemplului anterior, se pot face observaiile:
1. Conversia tipului pointer generic spre un tip concret nseamn, de fapt, precizarea
tipului de pointer pe care l are valoarea pointerului la care se aplic conversia
respectiv.
2. Conversia tipului pointer generic asigur o flexibilitate mai mare n utilizarea pointerilor.
3. Utilizarea n mod abuziv a pointerilor generici poate constitui o surs de erori.
5.2 Operaii cu pointeri
n afara operaiei de atribuire (prezentat n paragraful 5.1.2), asupra variabilelor pointer
se pot realiza operaii de adunare i scdere (inclusiv incrementare i decrementare)
precum i comparare.
5.2.1 Adunarea sau scderea
Sunt permise operaii de adunare sau scdere ntre un pointer de obiecte i un
ntreg:
Astfel, dac ptr este un pointer ctre tipul tip (tip *ptr;), iar n este un ntreg, expresiile
ptr + n i ptr - n au ca valoare, valoarea lui ptr la care se adaug, respectiv, se
scade n *sizeof(tip).
De exemplu, expresia p1 = p1+12; face ca p1 s conin adresa celui de-al
doisprezecelea element de tipul lui p1 situat dup acesta.

Un caz particular al adunrii sau scderii dintre un pointer de date i un ntreg (n=1) l
reprezint incrementarea i decrementarea unui pointer de date. n expresiile ptr++,
respectiv ptr--, valoarea variabilei ptr devine ptr+sizeof(tip), respectiv, ptr-
sizeof(tip).

Pentru a nelege mai bine aritmetica pointerilor, fie p1 un pointer ntreg cu o valoare
curent egal cu 2000. De asemenea, s presupunem c numerele ntregi ocup 2 octei
de memorie. Dup expresia p1++; valoarea curent a lui p1 va fi 2002, nu 2001,
Capitolul 5

70
deoarece, la fiecare incrementare a pointerului, acesta va conine adresa urmtorului
ntreg. De exemplu, presupunnd c p1 are valoarea 2000, expresia p--; determin o
valoare a lui p1 egal cu 1998.
n general, la fiecare incrementare a unui pointer, acesta va conine locaia de memorie a
urmtorului element de acelai tip cu tipul de baz al pointerului. n cazul pointerilor de tip
caracter, este o regul normal", fiindc ntotdeauna lungimea caracterelor este egal cu
un octet. Cu toate acestea, orice pointer de alt tip se va incrementa sau se va decrementa
cu o valoare egal cu lungimea tipului de date a crui adres o conine. De exemplu

dac
se folosesc caractere de 1 octet i ntregi de 2 octei, la incrementarea unui pointer de tip
caracter, valoarea sa va crete cu o unitate. La incrementarea unui pointer de tip ntreg,
valoarea sa va crete cu dou uniti, i aceasta datorit faptului c pointerii pot fi
incrementai sau decrementai numai n corelaie cu lungimea tipului lor de baz. Aceast
metod ofer sigurana faptului c pointerul va indica numai elementul corespunztor
tipului su de baz.
Este permis scderea a doi pointeri de obiecte de acelai tip, cu scopul de a
gsi numrul de obiecte de acelai tip care separ cei doi pointeri.
Toate celelalte operaii aritmetice sunt interzise. Mai concret, nu este permis nmulirea
sau mprirea pointerilor, aplicarea operatorilor bit cu bit, dup cum nu este permis
adunarea sau scderea variabilelor de tip float sau double la, sau din pointeri.
Exemplu:
int a, *pa, *pb;
cout<<"&a="<<&a<<\n; pa=&a; cout<<"pa="<<pa<<\n;
cout<<"pa+2"<<pa+2<<\n; pb=pa++; cout<<"pb="<<pb<<\n;
int i=pa-pb; cout<<"i="<<i<<\n;
5.2.2 Compararea valorilor variabilelor pointer
Valorile a doi pointeri pot fi comparate, folosind operatorii relaionali, ca n exemplul:
Exemplu:
int *p1, *p2;
if (p1<p2)
cout<<"p1="<<p1<<"<"<<"p2="<<p2<<\n;
else cout<<"p1="<<p1<<">="<<"p2="<<p2<<\n;
O operaie uzual este compararea unui pointer cu valoarea nul, pentru a verifica dac
acesta adreseaz un obiect. Compararea se face cu constanta simbolic NULL (definit n
header-ul stdio.h) sau cu valoarea 0.
Exemplu:
if (!p1) // sau if (p1 != NULL)
. . . . . ; // pointer nul
else . . . . ; // pointer nenul
5.3 Pointeri i tablouri
n limbajele C/C++ exist o strns legtur ntre pointeri i tablouri, deoarece numele
unui tablou este un pointer (constant!) care are ca valoare adresa primului element din
tablou. Diferena dintre numele unui tablou i o variabil pointer este aceea c unei
variabile de tip pointer i se pot atribui valori la execuie, lucru imposibil pentru numele unui
tablou. Acesta are tot timpul, ca valoare, adresa primului su element. De aceea, se spune
c numele unui tablou este un pointer constant (valoarea lui nu poate fi schimbat).
Numele unui tablou este considerat ca fiind o rvalue, deci nu poate apare dect n partea
dreapt a unei expresii de atribuire. Numele unui pointer (n exemplul urmtor, *ptr) este
POINTERI
considerat ca fiind un lvalue, deci poate fi folosit att pentru a obine valoarea obiectului,
ct i pentru a o modifica printr-o operaie de atribuire.
Exemplu:
int a[10], *ptr; // a este definit ca &a[0]; a este pointer constant
a = a + 1; // ilegal
ptr = a ; // legal: ptr are aceeai valoare ca i a, respectiv adresa elementului
a[0]; ptr este variabil pointer, a este constant pointer.
int x = a[0]; // echivalent cu x = *ptr; se atribuie lui x valoarea lui a[0]

Deoarece numele tabloului a este sinonim pentru adresa elementului de indice zero din
tablou, atribuirea ptr=&a[0] poate fi nlocuit, ca n exemplul anterior, cu ptr=a. Pentru
al patrulea element putem folosi a[4] sau *(ptr+4).

n C exist dou metode de a accesa elementele unui tablou, i anume: aplicarea de
indeci tablourilor i operaiile cu pointeri; acestea din urm fiind n general mai rapide,
sunt folosite mai des de ctre programatori.
5.3.1 Pointeri i iruri de caractere
Aa cum s-a artat ntr-un capitol anterior, un ir de caractere poate fi memorat ntr-un
vector de caractere. Spre deosebire de celelalte constante, constantele ir de caractere nu
au o lungime fix, deci numrul de octei alocai la compilare pentru memorarea irului,
variaz. Deoarece valoarea variabilelor pointer poate fi schimbat n orice moment, cu
mult uurin, este preferabil utilizarea acestora, n locul tablourilor de caractere (vezi
exemplul urmtor).
Exemplu:
char sir[10]; char *psir;
sir = "Salut"; // ilegal
psir = "Salut"; // legal
Operaia de indexare a elementelor unui tablou poate fi realizat cu ajutorul variabilelor
pointer.
Exemplu:
int a[10], *ptr; // a este pointer constant; ptr este variabil pointer
ptr = a; // ptr este adresa lui a[0]
ptr+i nseamn ptr+(i*sizeof(int)), deci: ptr + i & a[i]
Deoarece numele unui tablou este un pointer (constant), putem concluziona (Figura 5.1):
a+i &a[i] i a[i] *(a+i)
a[0] a[1] a[9]
a

a=&a[0] a+1=&a[1]

a+9=&a[9]

*a=a[0] *(a+1)=a[1]

*(a+9)=a[9]
ptr



Figura 5.1 Legtura dintre pointeri i tablouri
Exemplul 5.4 Legtura dintre pointeri i vectori
S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>

void main(void)
{int a[10] = {0,1,2,3,4,5,6,7,8,9}; int *pi1 = a ;
int *pi2 = &a[0]; int *pi3;

71
cout<<"a="<<a<<"&a="<<&a<<"*a="<<*a<<\n;
Capitolul 5

72
cout<<"a+1="<<(a+1)<< " &a[1]="<< &a[1]<<\n;
cout<<"a[1]="<<a[1]<< " *(a+1)="<< *(a+1)<<\n;
cout<<"pi1="<<pi1<<"pi2="<<pi2<<\n; int x=*pi1;
/* x primete valoarea locaiei a crei adres se afl n variabila pointer pi1, deci
valoarea lui a[0] */
cout<<"x="<<x<<\n; x=*pi1++; // echivalent cu *(pi1++)x=1
cout<<"x="<<x<<\n; x=(*pi1)++;
/* x=0: nti atribuirea, apoi incrementarea valorii spre care indic pi1. n urma
incrementrii, valoarea lui a[0] devine 1 */
cout<<"x="<<x<<\n; cout<<*pi1<<\n;x=*++pi1; //echivalent cu
*(++pi1)
cout<<"x="<<x<<\n; x=++(*pi1); cout<<"x="<<x<<\n; pi1=a;
pi3=pi1+3;
cout<<"pi1="<<pi1<<"*pi1="<<*pi1<<"&pi1="<<&pi1<<\n;
cout<<"pi3="<<pi3<<"*pi3="<<*pi3<<"&pi3="<<&pi3<<\n;
cout<<"pi3-pi1="<<(pi3-pi1)<<\n; //pi3-pi1=3
}
Exemplul 5.5 Legtura dintre pointeri i irurile de caractere
S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void main(void)
{int a=-5, b=12, *pi=&a; double u=7.13, v=-2.24, *pd=&v;
char sir1[]="sirul 1", sir2[]="sirul 2", *psir=sir1;
cout<<"a="<<a<<" &a="<<&a<<" b="<<b<<" &b="<<&b<<\n;
cout<<"*pi="<<*pi<<"pi="<<pi<<" &pi="<<&pi<<\n;
cout<<"*pd="<<*pd<<"pd="<<pd<<" &pd="<<&pd<<\n;
cout<<"*sir1="<<*sir1<<" sir1="<<sir1<<" &sir1="<<&sir1<<\n;
// *sir1=s sir1=sirul 1 &sir1=0xffd6
cout<<"*sir2="<<*sir2<<" sir2="<<sir2<<" &sir2="<<&sir2<<\n;
// *sir2=s sir2=sirul 2 &sir1=0xffce
cout<<"*psir="<<*psir<<" psir="<<psir<<" &psir="<<&psir<<\n;
// *psir=s psir=sirul 1 &sir1=0xffcc
cout<<"sir1+2="<<(sir1+2)<<" psir+2="<<(psir+2)<<\n;
// sir1+2=rul 1 psir+2=rul 1
cout<<"*(sir1+2)="<< *(sir1+2)<<\n;
// *(sir1+2)=r valoarea elementului de indice 2
void *pv1, *pv2;
pv1=psir; pv2=sir1;
cout<<"pv1="<<pv1<<"&pv1="<<&pv1<<\n;
cout<<"pv2="<<pv2<<"&pv2="<<&pv2<<\n;
pi=&b; pd=&v; psir=sir2;
cout<<"*pi="<<*pi<<"pi="<<pi<<" &pi="<<&pi<<\n;
cout<<"*pd="<<*pd<<"pd="<<pd<<" &pd="<<&pd<<\n;
cout<<"*psir="<<*psir<<"psir="<<psir<<" &psir="<<&psir<<\n;
}
Exemplul 5.6 Pointeri - vector
S se scrie un program care citete elementele unui vector de ntregi, cu maxim 20
elemente i nlocuiete elementul maxim din vector cu o valoare introdus de la tastatur.
Se va folosi aritmetica pointerilor.
#include <iostream.h>

void main()
POINTERI
{
int a[20]; int n, max, indice;
cout<<"Nr. elemente:"; cin>>n;
// citirea elementelor vectorului
for (i=0; i<n; i++)
{cout<<"a[<<i<<"]="; cin>>*(a+i);}
// aflarea valorii elementului maxim din vector i a poziiei acestuia
max=*a; indice=0;
for (i=0; i<n; i++)
if (max<=*(a+i))
{ max=*(a+i); indice=i;}
// citirea valorii cu care se va nlocui elementul maxim
int val;
cout<<"Valoare de inlocuire:"; cin >> val;
*(a+indice)=val;
// afisarea noului vector
for (i=0; i<n; i++)
cout<<*(a+i);<<'\t';
cout<<'\n';
/* dac n vector exist mai multe elemente a cror valoare este egal cu valoarea
elementului maxim, va fi nlocuit doar ultimul dintre acestea (cel de indice
maxim).*/
}
5.3.2 Pointeri i tablouri multidimensionale
Elementele unui tablou bidimensional sunt pstrate tot ntr-o zon continu de memorie,
dar inconvenientul const n faptul c ne gndim la aceste elemente n termeni de rnduri
(linii) i coloane (Error! Reference source not found.). Un tablou bidimensional este
tratat ca un tablou unidimensional ale crui elemente sunt tablouri unidimensionale.
int M[4][3]={{10,5,-3},{9,18,0},{32,20,1},{-1,0,8}};
Compilatorul trateaz att M, ct i M[0], ca tablouri de mrimi diferite. Astfel:
cout<<"Marime M:"<<sizeof(M)<<\n; // 24 = 2 octei * 12
elemente
cout<<"Marime M[0]"<<sizeof(M[0])<<\n; // 6 = 2 octei * 3
elemente
cout<<"Marime M[0][0]"<<sizeof(M[0][0])<<\n; // 2 octei
(sizeof(int))
Matricea M are 4 linii i 3 coloane. Numele tabloului bidimensional, M, refer ntregul
tablou; M[0] refer prima linie din tablou; M[0][0] refer
primul element al tabloului.

73

Aa cum compilatorul evalueaz referina ctre un tablou
unidimensional ca un pointer, un tablou bidimensional este
referit ntr-o manier similar. Numele tabloului bidimensional,
M, reprezint adresa (pointer) ctre primul element din tabloul
bidimensional, acesta fiind prima linie, M[0] (tablou unidimensional). M[0] este adresa
primului element (M[0][0]) din linie (tablou unidimensional), deci M[0] este un pointer ctre
int: M = M[0] = &M[0][0]. Astfel, M i M[linie] sunt pointeri constani.
Figura 5.2 Matricea M
M[0] 10 5 -3
M[1] 9 18 0
M[2] 32 20 1
M[3] -1 0 8

Putem concluziona:
M este un pointer ctre un tablou unidimensional (de ntregi - prima linie n exemplul
anterior).
Capitolul 5
*M este pointer ctre int (pentru c M[0] este pointer ctre int), i *M = *(M + 0)
M[0].
**M este ntreg; deoarece M[0][0] este int, **M=*(*M)
*(M[0])=*(M[0]+0) M[0][0].
Exemplul 5.7 S se testeze programul urmtor, urmrind cu atenie rezultatele obinute.
#include<iostream.h>
#include<conio.h>

74

void main()
{int a[3][3]={{5,6,7},
{55,66,77},
{555,666,777}};
clrscr();
cout<<"a="<<a<<" &a="<<&a<<"
&a[0]="<<&a[0]<<'\n';
cout<<"Pointeri catre vectorii
linii\n";
for (int i=0; i<3; i++){
cout<<" *(a+"<<i<<")="<<*(a+i);
cout<<" a["<<i<<"]="<<a[i]<<'\n';
}
// afiarea matricii
for (int i=0; i<3; i++){
for (int j=0; j<3; j++)
cout<<*(*(a+i)+j)<<'\t'; //sau: cout<<*(a[i]+j)<<'\t';
cout<<'\n';
}
}
5.4 Tablouri de pointeri
Un tablou de pointeri este un tablou ale crui elemente sunt pointeri. Modul general de
declarare a unui tablou de pointeri:
tip *nume_tablou[dim];
S considerm exemplul n care se declar i se iniializeaz tabloul de pointeri str_ptr
(Figura 5.3):
char *str_ptr[3] = {"Programarea", "este", "frumoas!"};
str_ptr
str_ptr[0] Programarea
str_ptr[1] este
str_ptr[2] frumoas!"
Rezultate
a=0x0012ff60
&a=0x0012ff60
&a[0]=0x0012ff60
Pointeri catre vectorii linii
*(a+0)=0x0012ff60 a[0]=0x0012ff60
*(a+1)=0x0012ff6c a[1]=0x0012ff6c
*(a+2)=0x0012ff78 a[2]=0x0012ff78
5 6 7
55 66 77
555 666 777
Figura 5.3 Tabloul de pointeri str_ptr
Deoarece operatorul de indexare [] are prioritate mai mare dect operatorul de
defereniere *, declaraia char*str_ptr[3] este echivalent cu char
*(str_ptr[3]), care precizeaz c str_ptr este un vector de trei elemente, fiecare
element este pointer ctre caracter.
n ceea ce privete declaraia: char *(str_ptr[3]), se poate observa:
1. str_ptr[3] este de tipul char * (fiecare dintre cele trei elemente ale vectorului
str_ptr[3] este de tipul pointer ctre char);
POINTERI

75
2. *(str_ptr[3]) este de tip char (coninutul locaiei adresate de un element din
str_ptr[3] este de tip char).
Fiecare element (pointer) din str_ptr este iniializat s indice ctre un ir de caractere
constant. Fiecare dintre aceste iruri de caractere se gsesc n memorie la adresele
memorate n elementele vectorului str_ptr: str_ptr[0], str_ptr[1], etc.

S ne amintim de la pointeri ctre iruri de caractere:
char *p="Hello";
*(p+1) = e p[1] = e;
n mod analog:
str_ptr[1] = "este";
*(str_ptr[1] + 1) = s; str_ptr[1][1] = s;
Putem conculziona:
str_ptr este un pointer ctre un pointer de caractere.
*str_ptr este pointer ctre char. Este evident, deoarece str_ptr[0] este pointer
ctre char, iar *str_ptr = *(str_ptr [0] + 0 ) str_ptr[0].
**str_ptr este un pointer de tip char. Este evident, deoarece str_ptr[0][0]
este de tip char, iar **str_ptr=*(*str_ptr) *(str_ptr[0])=
*(str_ptr[0]+0) str_ptr[0][0].
5.5 Pointeri la pointeri
S revedem exemplul cu tabloul de pointeri str_ptr. irurile spre care indic elementele
tabloului pot fi accesate prin str_ptr[index], ns deoarece str_ptr este un pointer
constant, acestuia nu i se pot aplica operatorii de incrementare i decrementare. Este
ilegal:
for (i=0;i<3;i++)
cout<<str_ptr++ ;
De aceea, putem declara o variabil pointer ptr_ptr, care s indice ctre primul element
din str_ptr. Variabila ptr_ptr este pointer ctre pointer i se declar astfel:
char **ptr_ptr;
n exemplul urmtor este prezentat modul de utilizare a pointerului la pointer ptr_ptr
(Figura 5.4).
Exemplu:
#include<iostream.h>
void main(void)
{
char *str_ptr[3] = {"Programarea ", "este ", "frumoasa! "};
char **ptr_ptr;
ptr_ptr = str_ptr;
for(int i=0;i<3;i++)
cout<<*(ptr_ptr+i);
}
Dup atribuire, i str_ptr i ptr_ptr pointeaz ctre aceeai locaie de memorie
(primul element al tabloului str_ptr). n timp ce fiecare element al lui str_ptr este un
pointer, ptr_ptr este un pointer ctre pointer. Deoarece ptr_ptr este un pointer
variabil, valoarea lui poate fi schimbat:
ptr_ptr str_ptr
Capitolul 5
Programarea
este
frumoas! "
Figura 5.4 Pointerul la pointer ptr_ptr
Referitor la declaraia char **ptr_ptr, putem concluziona:
ptr_ptr este de tipul char ** (ptr_ptr este pointer la pointer ctre char);
*ptr_ptr este de tipul char * (coninutul locaiei ptr_ptr este de tipul pointer ctre
char);
**ptr_ptr este de tipul char (**ptr_ptr *(*ptr_ptr); coninutul locaiei
*ptr_ptr este de tipul char).
5.6 Modificatorul const n declararea pointerilor
Modificatorul const se utilizeaz frecvent n declararea pointerilor, avnd urmtoarele
roluri:
Declararea unui pointer spre o dat constant
const *tip nume_pointer=dat_constant;
Exemplu:
const char *sirul="azi"; //variabila sirul este pointer spre un ir constant
de caractere
Atribuirile de forma:
*sirul="coco";
*(sirul+2)=A;
nu sunt acceptate, deoarece pointerul sirul pointeaz ctre o dat constant (ir
constant).
Declararea unui pointer constant ctre o dat care nu este constant
tip * const nume_pointer=dat_neconst;
Exemplu:
char * const psir="abcd"; const char *sir="un text";
sir="alt sir"; //incorect, sir indic ctre dat constant
psir=sir; //incorect, deoarece psir este pointer constant
Declararea unui pointer constant ctre o dat constant
const tip * const nume_pointer=dat_constant;
Exemplu:
const char * const psir1="mnP";
*(psir1+2)='Z'; // incorect, data spre care indic psir1 este constant
psir1++; // incorect, psir1 este pointer constant


76
FUNCII

77
6. FUNCII
6.1 Structura unei funcii
Un program scris n limbajul C/C++ este un ansamblu de funcii, fiecare dintre acestea
efectund o activitate bine definit.
Din punct de vedere conceptual, funcia reprezint o aplicaie definit pe o mulime
D (D = mulimea, domeniul de definiie), cu valori n mulimea C (C = mulimea de
valori, codomeniul), care ndeplinete condiia c oricrui element din D i
corespunde un unic element din C.
Funciile comunic prin argumente: ele primesc ca parametri (argumente) datele de
intrare, efectueaz prelucrrile descrise n corpul funciei asupra acestora i pot returna o
valoare (rezultatul, datele de ieire). Execuia programului ncepe cu funcia principal,
numit main. Funciile pot fi descrise n cadrul aceluiai fiier, sau n fiiere diferite, care
sunt testate i compilate separat, asamblarea lor realizndu-se cu ajutorul linkeditorului de
legturi.
O funcie este format din antet i corp, adic:
tip_val_return nume_func (lista_decl_param_formali) //Antet funcie
{
declaraii_variabile_locale
instruciuni //Corp funcie
return valoare
}
Prima linie reprezint antetul funciei, n care se indic: 1. tipul valorii returnate de
funcie, 2. numele acesteia i 3. lista declaraiilor parametrilor formali. La fel ca un operand
sau o expresie, o funcie are un tip, care este dat de tipul valorii returnate de funcie
ctre funcia apelant. Dac funcia nu ntoarce nici o valoare, n locul tip_val_return
se specific void. Dac tip_val_return lipsete, se consider, implicit, c acesta
este int. nume_func este un identificator.
Lista_decl_param_formali (ncadrat ntre paranteze rotunde) const ntr-o list
(enumerare) care conine perechi formate din tipul i identificatorul fiecrui parametru de
intrare, desprite prin virgul. Tipul unui parametru poate fi oricare, chiar i tipul pointer.
Dac lista parametrilor formali este vid, n antet, dup numele funciei, apar doar
parantezele ( ), sau (void).
Corpul funciei este un bloc, care implementeaz algoritmul de calcul folosit de ctre
funcie. n corpul funciei apar (n orice ordine) declaraii pentru variabilele locale i
instruciuni. Dac funcia ntoarce o valoare, se folosete instruciunea return
valoare;. La execuie, la ntlnirea acestei instruciuni, se revine n funcia apelant.
n limbajul C/C++ se utilizeaz declaraii i definiii de funcii.
Declaraia conine antetul funciei i informeaz compilatorul asupra tipului, numelui
funciei i a listei parametrilor formali (n care se poate indica doar tipul parametrilor
formali, nu i numele acestora). Declaraiile de funcii se numesc prototipuri, i sunt
constituite din antetul funciei, din care pot lipsi numele parametrilor formali.
Definiia conine antetul funciei i corpul acesteia. Nu este admis definirea unei funcii n
corpul altei funcii.
Capitolul 6

78
6.2 Apelul i prototipul funciilor
O funcie poate fi apelat printr-o construcie urmat de punct i virgul, numit
instruciune de apel, de forma:
nume_funcie(lista_parametrilor_efectivi);
Parametrii efectivi trebuie s corespund cu cei formali ca numr, ordine i tip. La apel, se
atribuie parametrilor formali valorile parametrilor efectivi, dup care se execut
instruciunile din corpul funciei. La revenirea din funcie, controlul este redat funciei
apelante, i execuia continu cu instruciunea urmtoare instruciunii de apel, din funcia
apelant. O alt posibilitate de a apela o funcie este aceea n care apelul funciei
constituie operandul unei expresii. Acest lucru este posibil doar n cazul n care funcia
returneaz o valoare, folosit n calculul expresiei.
Parametrii declarai n antetul unei funcii sunt numii formali, pentru a sublinia faptul c ei
nu reprezint valori concrete, ci numai in locul acestora pentru a putea exprima procesul
de calcul realizat prin funcie. Ei se concretizeaz la execuie prin apelurile funciei.
Parametrii folosii la apelul unei funcii sunt parametri efectivi (reali, concrei), iar valorile
lor vor fi atribuite la execuie parametrilor formali. Utilizarea parametrilor formali la
implementarea funciilor i atribuirea de valori concrete pentru ei la execuie, reprezint un
prim nivel de abstractizare n programare. Acest mod de programare se numete
programare procedural i realizeaz un proces de abstractizare prin parametri.
Variabilele declarate n interiorul unei funcii, ct i parametrii formali ai acesteia nu pot fi
accesai dect n interiorul acesteia. Aceste variabile sunt numite variabile locale i nu pot
fi accesate din alte funcii. Domeniul de vizibilitate a unei variabile locale este funcia n
care ea a fost definit. Dac n interiorul unei funcii exist instruciuni compuse (blocuri)
care conin declaraii de variabile, aceste variabile nu sunt vizibile n afara blocului.
Exemplul 6.1 Domeniul de vizibilitate a unei variabile
int f(void)
{ double x,z; int z;
. . .
return z; // x,y,z - variabile locale, vizibile doar n corpul funciei
}
void main()
{
int a=1, b=2; // variabile x i z nu sunt accesibile n main()
cout << "a=<<a<< b=<<b<< c=<<c\n; // a=1 b=2, c nedeclarat
. . . . . . . .
{ int a=5; b=6; int c=9;
cout << a=<<a<< b=<<b<<\n; // a=5 b=6 c=9
. . . . . . . .
}
cout << a=<<a<< b=<<b<< c=<<c\n; // a=1 b=6, c nedeclarat
. . . . . . . . . . . .
}
Exemplul 6.2: Apelul unei funcii
S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void f_afis(void)
{
cout<<Se execut instruciunile din corpul functiei\n;
double a=3, b=9.4; cout<<a<<*<<b<<=<<a*b<<\n;
cout<<Iesire din functie!\n;
}
FUNCII

79

void main()
{
cout<<Intrare n funcia principal\n;
f1( ); //apelul funciei f1, printr-o instruciune de apel
cout<<Terminat MAIN!\n;
}
nainte de a putea apela o funcie, aceasta trebuie definit (antet+corp), dar exist cazuri
n care definirea unei funcii nu poate fi fcut naintea apelului acesteia (cazul funciilor
care se apeleaz unele pe altele). n aceast situaie, la nceputul programului se face
doar declararea funciilor respective (se scriu prototipurile din care lipsesc numele
parametrilor formali), iar definirea lor se face dup funcia main.

Prototipurile funciilor din biblioteci (predefinite) se gsesc n headere. Utilizarea unei astfel
de funcii impune doar includerea n program a headerului asociat, cu ajutorul directivei
preprocesor #include.
Programatorul i poate crea propriile headere, care s conin declaraii de funcii, tipuri
globale, macrodefiniii, etc.
6.3 Regulile de competen ale unei funcii
Regulile de competen (scope rules) ale unui limbaj sunt acele reguli care
controleaz dac un fragment de program are cunotin sau acces la un alt
fragment de program sau de date.
n C, fiecare funcie reprezint un bloc de cod distinct. Codul unei funcii este propriu
acelei funcii i nu poate fi accesat de nici o alt instruciune coninut ntr-o alt funcie, cu
excepia cazului cnd este apelat funcia. (De exemplu, nu putei folosi goto pentru a
efectua un salt ntr-o alt funcie.) Codul care reprezint corpul unei funcii este ascuns
fa de restul programului i, cu excepia cazului n oare folosete date sau variabile
globale, nu poate afecta i nu poate fi afectat de ctre alte componente ale programului.
Altfel spus, codul i datele definite n cadrul unei funcii nu pot interaciona cu codul sau
datele definite n cadrul unei alte funcii, fiindc cele dou funcii au domenii de
competen diferite.
Variabilele definite n interiorul unei funcii se numesc variabile locale. O variabil local
devine activ la intrarea n aciune a funciei i se distruge la prsirea funciei, ceea ce
nseamn c variabilele locale nu-i pot pstra valoarea ntre dou apeluri ale funciei. n
C, toate funciile au acelai nivel al domeniului de aciune, adic nu se poate defini o
funcie n interiorul altei funcii. Iat de ce C nu este, din punct de vedere tehnic, un limbaj
structurat pe blocuri.
6.4 Transferul parametrilor unei funcii
Funciile comunic ntre ele prin argumente (parametrii). Exist urmtoarele moduri de
transfer (transmitere) a parametrilor ctre funciile apelate: prin valoare, prin pointeri, prin
referin.
6.4.1 Transferul parametrilor prin valoare
n exemplele anterioare, parametrii de la funcia apelant la funcia apelat au fost
transmii prin valoare. De la programul apelant ctre funcia apelat, prin apel, se
Capitolul 6

80
transmit valorile parametrilor efectivi, reali. Aceste valori vor fi atribuite, la apel,
parametrilor formali. Deci procedeul de transmitere a parametrilor prin valoare const n
ncrcarea valorii parametrilor efectivi n zona de memorie a parametrilor formali (n stiv).
La apelul unei funcii, parametrii reali trebuie s corespund - ca numr, ordine i tip - cu
cei formali.

Exemplul 6.3: Parametri formali i parametri efectivi.
S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
float suma(float a, float b)// a, b - parametri formali
{ return a+b; }

void main()
{
float x=2.0, y;
// apelul funciei suma; x, 3.0 sunt parametri efectivi
y = suma(x,3.0);// x=2.0 (nemodificat)
}
Fiecare argument efectiv utilizat la apelul funciei este evaluat, iar valoarea este atribuit
parametrului formal corespunztor. n interiorul funciei, o copie local a acestei valori va fi
memorat n parametrul formal. O modificare a valorii parametrului formal n interiorul
funciei (printr-o operaie din corpul funciei), nu va modifica valoarea parametrului efectiv,
ci doar valoarea parametrului formal, deci a copiei locale a parametrului efectiv. Faptul c
variabila din programul apelant (parametrul efectiv) i parametrul formal sunt obiecte
distincte, poate constitui un mijloc util de protecie. n cazul transmiterii parametrilor prin
valoare, parametrii efectivi pot fi chiar expresii. Acestea sunt evaluate, iar valoarea lor va
iniializa, la apel, parametrii formali.
Exemplul 6.4: Expresii ca parametri efectivi
double psi(int a, double b)
{
if(a>0) return a*b*2;
else return -a+3*b;
}

void main()
{
int x=4; double y=12.6, z;
z=psi(3*x+9, y-5) + 28;
cout<<z=<<z<<\n;
}
Transferul valorii este nsoit de eventuale conversii de tip. Aceste conversii sunt realizate
automat de compilator, n urma verificrii apelului de funcie, pe baza informaiilor despre
funcie, sau sunt conversii explicite, specificate de programator, prin operatorul cast.
Exemplu:
float f1(double, int);
void main()
{
int a, b;
float g=f1(a, b); // conversie automat: int a -> double a
float h=f1((double) a, b); // conversie explicit
}
FUNCII

81
Limbajul C este numit limbajul apelului prin valoare, deoarece, de fiecare dat cnd o
funcie transmite argumente unei funcii apelate, este transmis, de fapt, o copie a
parametrilor efectivi. n acest mod, dac valoarea parametrilor formali (iniializai cu
valorile parametrilor efectivi) se modific n interiorul funciei apelate, valorile parametrilor
efectivi din funcia apelant nu vor fi afectate.

Exemplul devenit clasic pentru explicarea diferenelor dintre cele trei tipuri transfer de
parametri este cel al funciei de permutare (interschimbare) a dou variabile. n cazul
transferului prin valoare parametrii funciei schimb_v sunt transmii astfel: parametrilor
formali x, y li se atribuie (la apel) valorile parametrilor efectivi a, b. Funcia schimb_v
permut valorile parametrilor formali x i y, dar permutarea nu are efect asupra
parametrilor efectivi a i b. Fie funcia schimb_v definit astfel:
void schimb_v (double x, double y)
{ double t=x; x=y; y=t; }

void main()
{ double a=4.7, b=9.7;
. . . . . . . . . . .
schimb_v(a, b); // apel funcie
. . . . . . . . . . . }
6.4.2 Transferul parametrilor prin pointeri
n unele cazuri, parametrii transmii unei funcii pot fi pointeri (variabile care conin
adrese). n aceste cazuri, parametrii formali ai funciei apelate vor fi iniializai cu valorile
parametrilor efectivi, deci cu valorile unor adrese. Astfel, funcia apelat poate modifica
coninutul locaiilor spre care indic argumentele (pointerii).

Pentru ca funcia de interschimbare (discutat i la apelul prin valoare) s poat permuta
valorile parametrilor efectivi, n limbajul C parametrii formali trebuie s fie pointeri ctre
valorile care trebuie interschimbate:
void schimb_p(double *x, double *y)
{ double t=*x; *x=*y; *y=t; }

void main()
{ double a=4.7, b=9.7;
. . . . . . . . . . .
schimb_p(&a, &b); // apel funcie
/* SAU:
double *pa, *pb;
pa=&a; pb=&b;
schimb_p(pa, pb);*/
. . . . . . . . . . . }
Se atribuie pointerilor x i y valorile pointerilor pa, pb, deci adresele variabilelor a i b.
Funcia schimb_p permut valorile spre care indic pointerii x i y, deci valorile lui a i b.
Dac parametrii funciei ar fi fost transmii prin valoare, aceast funcie ar fi interschimbat
copiile parametrilor formali, iar n funcia main modificrile asupra parametrilor transmii
nu s-ar fi pstrat.
Capitolul 6

82
6.4.3 Transferul parametrilor prin referin
n acest mod de transmitere a parametrilor, unui parametru formal i se poate asocia
(atribui) chiar obiectul parametrului efectiv. Astfel, parametrul efectiv poate fi modificat
direct prin operaiile din corpul funciei apelate.
n exemplul urmtor definim variabila br, variabil referin ctre variabila b. Variabilele b
i br se gsesc, n memorie, la aceeai adres i sunt variabile sinonime.
int b,c;
int &br=b; //br referin la alt variabil (b)
Instruciunea precedent se interpreteaz ca "la adresa lui br se gsete b".

Aceeai funcie de permutare (discutat la apelul prin valoare i cel prin pointeri) se poate
defini cu parametri formali de tip referin.
void schimb_r(double &x, double &y)
{ int t=x; x=y; y=t; }

void main()
{ double a=4.7, b=9.7;
. . . . . . . . . . . . . . .
schimb_r(a, b); // apel funcie
. . . . . . . . . . . . . . . }
n acest caz, x i y sunt sinonime cu a i b (nume diferite pentru aceleai grupuri de locaii
de memorie). Interschimbarea valorilor variabilelor de x i y nseamn interschimbarea
valorilor variabilelor a i b.

Comparnd funciile schimb_p i schimb_r, se observ c diferena dintre ele const n
modul de declarare a parametrilor formali. n cazul funciei schimb_p parametrii formali
sunt pointeri (de tip *double), iar n cazul funciei schimb_r, parametrii formali sunt
referine ctre date de tip double. n cazul transferului parametrilor prin referin,
parametrii formali ai funciei refer aceleai locaii de memorie ca parametrii efectivi (sunt
sinonime).

Comparnd cele trei moduri de transmitere a parametrilor ctre o funcie, se poate
observa:
1. La apelul prin valoare transferul datelor este unidirecional, adic valorile se transfer
numai de la funcia apelant ctre cea apelat. La apelul prin referin transferul datelor
este bidirecional, deoarece o modificare a parametrilor formali determin modificarea
parametrilor efectivi, care sunt sinonime (au nume diferite, dar refer aceleai locaii de
memorie).
2. La transmiterea parametrilor prin valoare, ca parametrii efectivi pot apare expresii sau
nume de variabile. La transmiterea parametrilor prin referin, ca parametri efectivi nu
pot apare expresii, ci doar nume de variabile. La transmiterea parametrilor prin pointeri,
ca parametri efectivi pot apare expresii de pointeri.
3. Transmiterea parametrilor unei funcii prin referin este specific limbajului C++.
4. Limbajul C este numit limbajul apelului prin valoare. Apelul poate deveni, ns, apel prin
referin n cazul variabilelor simple, folosind pointeri, sau aa cum vom vedea, n cazul
n care parametru efectiv este un tablou.
5. n limbajul C se poate alege, pentru fiecare parametru, tipul de apel: prin valoare sau
prin referin.

FUNCII
Valoarea returnat de o funcie poate s fie transmis i prin referin, cum ilustreaz
exemplul urmtor:
Exemplul 6.5: Valoare returnat prin referin

83
#include <iostream.h>
#include <stdio.h>

double &func(double &a, double b)
{ printf("In functie:\n");
printf("Val a=%f Adr
a=%x\n",a,&a);
cout<<"b="<<b<<'\n'; //b=2.2
a=2*b+1;
printf("Dup atrib: \n"
printf("Val a=%f Adr
a=%x\n",a,&a);
Rezultatul rulrii:

Val c=1.200000 Adr c=12ff84
Adr. d=12ff7c
In functie:
Val a=1.200000 Adr a=12ff84
b=2.2
Dupa atrib:
val a=5.400000 Adr a=12ff84
Val d=5.400000 Adr d=12ff7c
return a;
}
void main()
{double c=1.2,d;
printf("Val c=%f Adr c=%x\n",c, &c);
printf("Adr. d=%x\n", &d);
d=func(c,2.2);
printf("Val d=%f Adr d=%x\n", d, &d);
}

Aa cum s-a mai prezentat anterior, modificatorii sunt cuvinte cheie utilizai n declaraii
sau definiii de variabile sau funcii. Modificatorul de acces const poate apare n:
Declaraia unei variabile (precede tipul variabilei) restricionnd modificarea valorii
datei;
La declararea variabilelor pointeri definind pointeri constani ctre date neconstante,
pointeri neconstani ctre date constante i pointeri constani ctre date constante.
n lista declaraiilor parametrilor formali ai unei funcii, conducnd la imposibilitatea de a
modifica valoarea parametrului respectiv n corpul funciei, ca n exemplul urmtor:
Exemplul 6.6: Modificatorul de acces const n lista declaraiilor parametrilor formali ai
unei funcii
#include <iostream.h>
#include <stdio.h>

int func(const int &a)
//modificarea valorii parametrului a nu este permis
{printf("Adr a=%x Val a=%d\n",&a,a);int b=2*a+1;
cout<<"b="<<b<<'\n';return b;}

void main()
{const int c=33;int u;printf("Adr c=%x Val c=%d\n",&c,c);
u=func(c);cout<<"u="<<u<<'\n'; }
6.5 Apelul funciilor folosind tablouri
Transmiterea tablourilor ca argumente pentru funcii reprezint o excepie de la regula
uzual a transferului folosind apelul prin valoare.
Cnd un tablou este folosit ca argument al unei funcii, se transfer numai adresa
tabloului, i nu o copie a ntregului tablou. La apelul unei funcii cu numele unui tablou,
Capitolul 6

84
este transmis funciei un pointer al primului element din tablou. (Nu uitai, n C numele unui
tablou care nu este urmat de indice reprezint un pointer al primului element din tablou.)
Aceasta nseamn c declararea parametrului trebuie s fie compatibil cu tipul
pointerului. Exist trei modaliti de a declara un parametru care urmeaz s primeasc un
pointer de tablou. Prima ar fi declararea ca tablou, dup cum se va vedea n continuare:
/* Afieaz nite numere. */
#include <stdio.h>
void afieaz(int nume[10]);
void main(void)
{
int t[10], i;
for(i=0; i<10; ++i) t[i]=i; afieaz (t) ;
}
void afieaz(int num[10])
{
int i;
for(i=0; i<10; i++) printf("%d", num[i]);
}
Chiar dac parametrul num este declarat ca un tablou de zece ntregi, compilatorul de C l
convertete automat la un pointer de ntregi. Acest lucru este necesar fiindc nici un
parametru nu este capabil de a primi un tablou n totalitatea sa. Ca atare, din moment ce
este transmis numai un pointer de tablou, pentru a-l recepiona este necesar un parametru
pointer.
O a doua modalitate de a declara un parametru de tip tablou este de a-l declara drept
tablou nedimensionat, dup cum se va vedea n continuare:
void afieaz(int num[])
{
int i;
for(i=0; i<10; i++) printf("%d", num[i]);
}
n acest caz, parametrul num este declarat ca tablou de ntregi de dimensiune
necunoscut. Din moment ce limbajul C nu verific depirea limitelor unui tablou,
dimensiunea efectiv a tabloului este irelevant pentru parametru (dar nu i pentru
program, natural). Aceast metod de declarare definete num ca pointer ctre ntregi.
A treia modalitate de a declara num - cea mai des folosit n programele C profesionale -
este ca pointer, ca n exemplul urmtor:
void afieaz(int *num)
{
int i;
for(i=0;i<10;i++) printf("%d ",num[i]);
}
Aceast declaraie este permis deoarece orice pointer poate fi indexat folosind
parantezele drepte, asemntor unui tablou.

Exemplul 6.7: Tablouri ca parametri - elementul minim dintr-un vector
S se afle elementul minim dintr-un vector de maxim 10 elemente. Se vor scrie dou
funcii: de citire a elementelor vectorului i de aflare a elementului minim:
#include <iostream.h>
int min_tab(int a[], int nr_elem)
{int elm=a[0];
for (int ind=0; ind<nr_elem; ind++)
FUNCII

85
if (elm>=a[ind]) elm=a[ind];
return elm;
}
void citireVector(int b[], int nr_el)
{ for (int ind=0; ind<nr_el; ind++){
cout<<"Elem "<<ind+1<<"="; cin>>b[ind];}
}
void main()
{
int a[10]; int i,j,n; cout<<"n="; cin>>n;
citireVector(a,n);
int min=min_tab(a,n); cout<<"Elem. min:"<<min<<'\n';
}

Aceeai problem poate fi implementat folosind aritmetica pointerilor:
#include <iostream.h>
void citireVector(int *b, int nr_el)
{ for (int ind=0; ind<nr_el; ind++){
cout<<"Elem "<<ind+1<<"="; cin>>*b(ind+ind);}
}
int min_tab(int *a, int nr_elem)
{
int elm=*a;
for(int ind=0; ind<nr_elem; ind++)
if(elm>=*(a+ind)) elm=*(a+ind);
return elm;
}
void main()
{
int a[10]; int i,j,n;
cout<<"n="; cin>>n;
citireVector(a, n);
int min=min_tab(a,n);
cout<<"Elem. min:"<<min<<'\n';
}
Din exemplele anterioare se poate observa:
1. Prototipul funciei min_tab poate fi unul dintre:
int min_tab(int a[], int nr_elem);
int min_tab(int *a, int nr_elem);
2. Echivalene:
int *a int a[]
a[i] *(a+i)
3. Apelul funciilor:
citireVector(a,n);
int min=min_tab(a,n);
4. Pentru tablourile unidimensionale, la apel, nu trebuie specificat numrul de elemente.
Dimensiunea tabloului trebuie s fie cunoscut n funcia care l primete ca parametru. De
obicei, dimensiunea tabloului se transfer ca parametru separat (nr_elem).
5. Pentru tablourile multidimensionale, pentru ca elementele tabloului s poat fi referite
n funcie, compilatorul trebuie informat asupra modului de organizare a tabloului. Pentru
tablourile bidimensionale (vectori de vectori), poate fi omis doar precizarea numrului
Capitolul 6
de linii (valoarea din stnga), deoarece pentru a adresa elementul a[i][j], compilatorul
utilizeaz relaia:
&mat[i][j]=&mat+(i* N+j)*sizeof(tip)
n care N reprezint numrul de coloane, iar tip reprezint tipul tabloului.
6.5.1 Funcii care returneaz pointeri
Pointerii ctre variabile nu sunt nici ntregi, nici ntregi fr semn, ci adrese de memorie ale
unui anumit tip de date. Motivul acestei deosebiri rezid n aceea c operaiile cu pointeri
depind de tipul de baz. De exemplu, dac un pointer ntreg este incrementat, va conine o
valoare cu 2 uniti mai mare dect cea precedent (presupunnd ntregi de 2 octei). n
general, la fiecare incrementare sau decrementare a unui pointer, acesta va conine
adresa urmtorului (sau precedentului) segment de date de tipul su. Din moment ce
fiecare tip de date i poate avea lungimea sa diferit, compilatorul trebuie s tie care
este tipul de date a crui adres o conine pointerul. Din acest motiv, o funcie care
returneaz un pointer trebuie declarat ca atare. De exemplu, funcia urmtoare
returneaz pointerul primei apariii a caracterului c n irul s:
/* Returneaz pointerul primei aparitii a lui c in s. */
char *compara(char c, char *s)
{
while(c!=*s && *s) s++;
return(s); }
Dac nu este gsit nici o coinciden, va fi returnat un pointer ctre caracterul nul cu care
se ncheie irul. lat un scurt program care folosete funcia compara():
Exemplul 6.8: Funcii care returneaz pointeri
#include<stdio.h>
char *compara(char c, char *s); /* prototipul */
void main(void)
{
char s[80], *p, ch;
gets(s);
ch = getchar();
p = compara(ch, s);
if(*p) /* s-a gsit o coincidenta */
printf("%s ", p);
else printf("Nu s-a gsit nici o coincidenta.");
}
Acest program citete un ir i apoi un caracter. Dac irul conine caracterul, programul
scrie irul ncepnd cu caracterul respectiv. n caz contrar, afieaz mesajul Nu s-a gsit
nici o coincidenta.
Exemplul 6.9: Funcii care returneaz pointeri
#include <iostream.h>
double *f (double *w, int k)
{ // w contine adresa de nceput a vectorului a
cout<<"w= "<<w<<" *w= "<<*w<<'\n';
// w = adr. lui a ;*w = a[0]=10
return w+=k;
/*incrementeaz pointerului w cu 2 (val. lui k); deci w indic ctre elementul de indice 2
din vectorul a*/
}

Rezultatul rulrii:

Adr. lui a este: 0x0012ff3c
pa=0x0012ff3c
w= 0x0012ff3c *w= 10
pa=0x0012ff4c *pa=2

86
FUNCII

87
void main()
{double a[10]={10,1,2,3,4,5,6,7,8,9}; int i=2;
cout<<"Adr. lui a este: "<<a;
double *pa=a;
// pointerul pa conine adresa de nceput a tabloului a
cout<<"\npa="<<pa<<'\n';
// a[i] = * (a + i)
// &a[i] = a + i
pa=f(a,i); cout<<"pa="<<pa<<" *pa="<<*pa<<'\n';
// pa conine adr. lui a[2], adic adr. a + 2 * sizeof(double);
*pa=2;
}
6.6 Funcii de tip void
Una dintre utilizrile tipului void este de a declara n mod explicit funcii care nu
returneaz valori, ceea ce previne utilizarea acestora n expresii i o folosire incorect. De
exemplu, funcia afiseaza_vertical() i afieaz argumentul ir pe verticala
ecranului. Din moment ce nu returneaz nici o valoare, este declarat ca fiind de tip void.
void afiseaza_vertical(char *sir)
{ while(*sir) printf("%c\n", *str++); }
nainte de a utiliza o funcie de tip void este necesar declararea prototipului acesteia. n
caz contrar, C va presupune c funcia returneaz un ntreg i, atunci cnd compilatorul
ajunge la funcie, va semnala o neconcordan de tip. Programul care urmeaz prezint
un exemplu care afieaz o linie de comand vertical pe ecran:
#include <stdio.h>
void afiseaza_vertical(char *sir); /* prototipul */

void main(int argc, char *argv[])
{ if(argc) afiseaza_vertical(argv[1]); }

void afiseaza_vertical(char *sir)
{ while(*str) printf("%c\n", *str++) ; }
nainte ca standardul C s defineasc tipul void, funciile care nu returnau valori erau
trecute la tipul int.
6.7 Funcii cu parametri implicii
Spre deosebire de limbajul C, n limbajul C++ se pot face iniializri ale parametrilor
formali. Parametrii formali iniializai se numesc parametri implicii. De exemplu, antetul
funciei cmmdc (care calculeaz i returneaz cel mai mare divizor comun al numerelor
ntregi primite ca argumente) poate avea aceasta form:
int cmmdc(int x, int y=1);
Parametrul formal y este iniializat cu valoarea 1 i este parametru implicit. La apelul
funciilor cu parametri implicii, unui parametru implicit, poate s-i corespund sau nu, un
parametru efectiv. Dac la apel nu i corespunde un parametru efectiv, atunci parametrul
formal va primi valoarea prin care a fost iniializat (valoarea implicit). Dac la apel i
corespunde un parametru efectiv, parametrul formal va fi iniializat cu valoarea acestuia,
neglijndu-se astfel valoarea implicit a parametrului formal. n exemplul anterior, la
apelul: int div=cmmdc(9); x va lua valoarea 9, iar y va lua valoarea 1 (implicit).
Capitolul 6

88
Dac n lista de parametri formali ai unei funcii exist i parametri implicii i parametri
neiniializai, parametrii implicii trebuie s ocupe ultimele poziii n list, nefiind permis
intercalarea acestora printre parametrii neiniializai.
6.8 Funcii cu numr variabil de parametri
n limbajul C se pot defini funcii cu un numr variabil de parametri. Parametrii care trebuie
s fie prezeni la orice apel al funciei se numesc parametri fici, ceilali se numesc
parametri variabili. Parametrii fici preced parametrii variabili. Prezena parametrilor
variabili se indic n antetul funciei prin trei puncte care se scriu dup ultimul parametru fix
al funciei.

De exemplu, fie antetul funciei numite virf:
void virf (int n, double a, . . . )
Funcia virf are doi parametri fici (n i a ) i parametri variabili, pentru care nu se
precizeaz n prealabil numrul i tipul; numrul i tipul parametrilor variabili difer de la
un apel la altul.

Funciile cu un numr variabil de parametri sunt, de obicei, funcii de bibliotec (ex:
printf, scanf) i se definesc folosind nite macrouri speciale care permit accesul la
parametrii variabili i se gsesc n headerul stdarg.h.
6.9 Transferul parametrilor ctre funcia main
n situaiile n care se dorete transmiterea a unor informaii (opiuni, date iniiale, etc.)
ctre un program, la lansarea n execuie a acestuia, este necesar definirea unor
parametri ctre funcia main. Se utilizeaz trei parametrii speciali: argc, argv i env.
Trebuie inclus headerul stdarg.h.
Prototipul funciei main cu parametri n linia de comand este:
main(int argc, char *argv[ ], char *env[ ])
Dac nu se lucreaz cu un mediu de programare integrat, argumentele transmise ctre
funcia main trebuie editate (specificate) n linia de comand prin care se lanseaz n
execuie programul respectiv.
Un argument al liniei de comand este informaia care urmeaz dup numele
programului n linia de comand a sistemului de operare.
Linia de comand tastat la lansarea n execuie a programului este format din grupuri de
caractere delimitate de spaiu sau tab, fiecare grup fiind memorat ntr-un ir de caractere.
Virgulele, caracterele punct i virgul sau altele asemntoare nu sunt considerate drept
separatori. De exemplu fugi Grivei, fugi este alctuit din trei iruri, n timp ce
Dan,Sergiu,Andrei reprezint un singur ir, deoarece virgulele nu reprezint, n
general, separatori acceptai.
Unele medii accept includerea ntre ghilimele a unui ir coninnd spaii. Aceasta
determin tratarea ntregului ir drept un singur argument.

Dac se lucreaz cu un mediu integrat (de exemplu, Borland C), selecia comenzii
Arguments din meniul Run determin afiarea unei ferestre de dialog n care
utilizatorul poate introduce argumentele funciei main.

FUNCII

89
Adresele de nceput ale acestor iruri sunt memorate n tabloul de pointeri argv[], n
ordinea n care apar n linia de comand (argv[0] memoreaz adresa irului care
constituie numele programului, argv[1] - adresa primului argument, etc.).
Parametrul ntreg argc memoreaz numrul de elemente din tabloul argv (argc>=1).
Parametrul env[] este un tablou de pointeri ctre iruri de caractere care pot specifica
parametri ai sistemului de operare.

Funcia main poate returna o valoare ntreag. n acest caz n antetul funciei se specific
la tipul valorii returnate int, sau nu se specific nimic (implicit, tipul este int), iar n
corpul funciei apare instruciunea return valoare_intreag;. Numrul returnat este
transferat sistemului de operare (programul apelant) i poate fi tratat ca un cod de eroare
sau de succes al ncheierii execuiei programului.

Exemplul 6.10: Program Salut nume
De exemplu, programul care urmeaz scrie Salut, urmat de numele dvs., dac l tastai
direct dup numele programului.
#include <stdio.h>
#include <stdlib.h>
void main(int argc, char *argv[])
{
if (argc!=2) {
printf("Ati uitat sa va scriei numele.\n");
exit(1);
}
printf("Salut %s", argv[1]);
}
Dac ai fi denumit acest program nume i numele dvs. ar fi Dan, pentru a rula programul
ar fi suficient s tastai nume Dan. Rezultatul programului ar fi fost mesajul Salut Dan.

Exemplul 6.11: S se implementeze un program care afieaz argumentele transmise
ctre funcia main.
#include <iostream.h>
#include <stdarg.h>
void main(int argc, char *argv[], char *env[])
{cout<<"Nume program:"<<argv[0]<<'\n';//argv[0] contine numele
programului
if(argc==1)
cout<<"Lipsa argumente!\n";
else
for (int i=1; i<argc; i++){
cout<<"Argumentul "<<i<<":"<<argv[i]<<'\n';
}
6.10 Ce returneaz funcia main()?
Funcia main() returneaz un ntreg n urma procesului de apel, care n general este
sistemul de operare. Returnarea unei valori din main() este echivalentul apelrii funciei
exit() folosind aceeai valoare. Dac main() nu returneaz n mod explicit nici o
valoare, atunci valoarea transmis procesului de apel este nedefinit din punct de vedere
tehnic. n practic, majoritatea compilatoarelor de C returneaz automat valoarea 0, dar nu
contai prea mult pe aceasta n probleme de portabilitate.
Capitolul 6
Dac main() nu returneaz nici o valoare, poate fi declarat ca fiind de tip void. Unele
compilatoare afieaz un avertisment dac o funcie nu este declarat de tip void i nu
returneaz nici o valoare. Deci, dac optai ca main() s nu returneze nici o valoare,
atunci tipul valorii returnate trebuie declarat ca void.
6.11 Funcii recursive
O funcie este numit funcie recursiv dac ea se autoapeleaz, fie direct (n
definiia ei se face apel la ea nsi), fie indirect (prin apelul altor funcii).
Pentru fiecare apel al funciei, parametrii i variabilele automatice se memoreaz pe stiv,
avnd valori distincte. Variabilele statice ocup tot timpul aceeai zon de memorie
(figureaz ntr-un singur exemplar) i i pstreaz valoarea de la un apel la altul. Orice
apel al unei funcii conduce la o revenire n funcia respectiv, n punctul urmtor
instruciunii de apel. La revenirea dintr-o funcie, stiva este curat (stiva revine la starea
dinaintea apelului).
Un exemplu de funcie recursiv este funcia de calcul a factorialului, definit astfel:
fact(n)=1, dac n=0; altfel fact(n)=n*fact(n-1), dac n>0;
Alternativa: fact(n) = n*fact(n-1) definete funcia fact(n) prin ea nsi. Un proces recursiv
trebuie s conin ntotdeauna o parte care nu se definete prin ea nsui. n exemplul de
mai sus, partea care este definit direct este alternativa: fact(n) = 1 dac n=0.

Exemplul 6.12: S se implementeze recursiv funcia care calculeaz n!, unde n este
introdus de la tastatur:

90
#include <iostream.h>
int fact(int n)
{if(n<0)
{cout<<"Argument negativ!\n";
exit(2); }
else if(n==0) return 1;
else return n*fact(n-1);
}

void main()
{int nr, f; cout<<"nr="; cin>>nr;
f=fact(nr);
cout<<nr<<"!="<<f<<'\n';
Figura 6.1 Configuraia stivei
rev adr1 adr2 adr3 adr4
n 3 2 1 0
adr1 adr2 adr3
3 2 1
adr1 adr2
3 2
adr1

b
3
c d



a
}
Se observ c n corpul funciei fact se apeleaz nsi funcia fact.
Presupunem c nr=3 (iniial, funcia fact este apelat pentru a calcula 3!). S urmrim
Error! Reference source not found.. La apelul funciei fact, valoarea parametrului de
apel nr (nr=3) iniializeaz parametrul formal n. Pe stiv se memoreaz adresa de
revenire n funcia apelant (adr1) i valoarea lui n (n=3) (Error! Reference source not
found..a). Deoarece n>0, se execut instruciunea de pe ramura else (return
n*fact(n-1)). Funcia fact se autoapeleaz direct. Se memoreaz pe stiv noua
adres de revenire (adr2) i noua valoare a parametrului n (n=2) (Error! Reference
source not found.,b). La noul reapel al funciei fact, se execut din nou instruciunea de
pe ramura else (return n*fact(n-1)). Se memoreaz pe stiv adresa de revenire
(adr3) i noua valoare a parametrului n (n=1) (Error! Reference source not found..c). La
noul reapel al funciei fact, se execut din nou instruciunea de pe ramura else (return
FUNCII

91
n*fact(n-1)). Se memoreaz pe stiv adresa de revenire (adr4) i noua valoare a
parametrului n (n=0) (Error! Reference source not found..d).
n acest moment n=0 i se revine din funcie cu valoarea 1*fact(0)=1*1=1, se cur stiva
i se ajunge la configuraia din Error! Reference source not found..c). n acest moment
n=1 i se revine cu valoarea 2*fact(1)=2*1=2, se cur stiva i se ajunge la configuraia
stivei din figura Error! Reference source not found..b. n acest moment n=2 i se revine
cu valoarea 3*fact(2)=3*2=6, se cur stiva i se ajunge la configuraia stivei din Error!
Reference source not found..a.
O funcie recursiv poate fi realizat i iterativ. Modul de implementare trebuie ales n
funcie de problem. Dei implementarea recursiv a unui algoritm permite o descriere
clar i compact, recursivitatea nu conduce la economie de memorie i nici la execuia
mai rapid a programelor. n general, se recomand utilizarea funciilor recursive n
anumite tehnici de programare, cum ar fi unele metode de cutare (backtracking).

Exemplul 6.13: irul lui Fibonacci
Fie irul lui Fibonacci, definit astfel: f(0)=0, f(1)=1, f(n)=f(n-1)+f(n-2), dac n>1. S se scrie
un program care implementeaz algoritmul de calcul al irului Fibonacci att recursiv, ct
i iterativ. S se compare timpul de execuie n cele dou situaii.
#include <iostream.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#include <stdio.h>

long int iterativ_fib(long int n)
//varianta de implementare iterativ
{if(n==0) return 0; if (n==1) return 1;
int i; long int a, b, c; a=0; b=1;
for (i=2; i<=n; i++){
c=b; b+=a; a=c;}
return b;
}

long int recursiv_fib(long int n)
//varianta de implementare recursiv
{if (n==0) return 0; if (n==1) return 1;
long int i1=rfib(n-1);
long int i2=rfib(n-2);
return i1+i2;
}

void main()
{int n; clrscr();
cout<<MAXLONG<<'\n';
for (n=10; n<=40; n++) {
clock_t t1, t2, t3;
cout<<CLK_TCK<<'\n';
t1=clock(); long int f1=iterativ_fib(n);
t2=clock(); long f2=recursiv_fib(n); t3=clock();
double timp1=(double)(t2-t1)/CLK_TCK;
double timp2=(double)(t3-t2)/CLK_TCK;
printf("ITERATIV: %10ld t=%20.10lf\n",f1,timp1);
printf("RECURSIV: %10ld t=%20.10lf\n",f2,timp2);
Capitolul 6

92
cout<<"Apasa o tasta....\n"; getch();
} }
n exemplul anterior, pentru msurarea timpului de execuie s-a utilizat funcia clock, al
crei prototip se afl n header-ul time.h. Variabilele t1, t2 i t3 sunt de tipul
clock_t, tip definit n acelai header. Constanta simbolic CLK_TCK definete numrul
de bti ale ceasului, pe secund.
n general, orice algoritm care poate fi implementat iterativ, poate fi implementat i
recursiv. Timpul de execuie a unei recursii este semnificativ mai mare dect cel necesar
execuiei iteraiei echivalente.
6.12 Pointeri ctre funcii
O caracteristic puternic, dar derutant, a limbajului C o constituie pointerul ctre funcii
(function pointer). Chiar dac o funcie nu este o variabil, ea are totui o locaie fizic n
memorie, locaie care poate fi atribuit unui pointer. Din acest motiv, pentru apelarea unei
funcii se poate folosi un pointer ctre funcie.
Pentru a nelege modul de utilizare a pointerilor ctre funcii, trebuie s tii cte ceva
despre modul de compilare i apelare a unei funcii n C. Mai nti, pe msur ce funcia
este compilat, codul surs este transformat n cod obiect i este stabilit un punct de
intrare al funciei. Dac se apeleaz o funcie n timp ce ruleaz un program, este efectuat
un apel n limbaj main n punctul de intrare. Ca atare, dac un pointer conine adresa
punctului de intrare al unei funcii, acel pointer poate fi folosit pentru a apela funcia
respectiv.
Pointerii ctre funcii sunt variabile pointer care conin adresa de nceput (punctul
de intrare) a codului executabil al unei funcii.
Pointerii ctre funcii permit:
Transferul ca parametru al adresei unei funcii;
Apelul funciei cu ajutorul pointerului.

Declaraia unui pointer ctre funcie are urmtoarea form:
tip_val_intoarsa (*nume_point)(lista_declar_param_formali);
unde: nume_point este un pointer de tipul funcie cu rezultatul tipul_valorii_ntoarse. n
declaraia anterioar trebuie remarcat rolul parantezelor, pentru a putea face distincie
ntre declaraia unei funcii care ntoarce un pointer i declaraia unui pointer de funcie:
tip_val_intoarse * nume_point (lista_declar_param_formali);
tip_val_intoarse (* nume_point)(lista_declar_param_formali);
Exemplu:
int f(double u, int v); //prototipul funciei f
int (*pf)(double, int); //pointer ctre funcia f
int i, j; double d;
pf=f; //atribuie adresa codului executabil al funciei f pointerului
pf
j=*pf(d, i); //apelul funciei f, folosind pf

Exemplul 6.14 Calculul derivatei unei funcii ntr-un punct
Relaia de calcul a derivatei funciei f este f'(x) = lim
h0
f(x) - f(x-h)
h

FUNCII

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

double fd(double);//funcia a crei derivat se calculeaz
double deriv(double,double,double(*)(double)); //funcia de calcul a
derivatei

void main()
{
double d,x,h=1e-03;
printf("\nx= "); scanf("%lf",&x);
d=deriv(x,h,fd);
printf("\nx=%f; h= %f; d= %lf",x,h,d);
}

double deriv(double x,double h,double (*f)(double))
{
double it=((*f)(x)-(*f)(x-h))/h;
return it;
}

double fd(double x)
{ return cos(x);}

Adresa unei funcii se obine folosind numele funciei, fr paranteze sau argumente. (Este
similar cu obinerea adresei unui tablou folosind numai numele acestuia, fr a utiliza
indici.) Pentru a vedea o demonstraie practic, studiai programul care urmeaz,
acordnd o atenie special declaraiilor:
Exemplul 6.15 Pointeri ctre funcii
#include <stdio.h>
#include <string.h>

void verifica(char *a, char *b,int(*cmp) (const char *, const
char *));

void main(void)
{
char s1[80],s2[80];
int (*p)(); // declararea unui pointer de funcie fr parametri ce ntoarce un
ntreg
p = strcmp;
gets(s1); gets(s2);
verifica(s1,s2,p);
}

void verifica(char *a, char *b, int(*cmp) (const char *, const
char *))
{
printf ("verificarea egalitatii\n");
if(!(*cmp)(a, b)) printf("sunt egali");
else printf("nu sunt egali");
}
Capitolul 6

94
La apelarea funciei verifica(), parametrii transmii sunt doi pointeri de tip caracter i
un pointer funcie. n interiorul funciei verifica(), argumentele sunt declarate drept
pointeri de tip caracter i un pointer funcie. Remarcai modul de declarare a pointerului
funcie. Trebuie s folosii o metod similar pentru declararea altor pointeri funcie, dei
tipul returnat de funcie poate diferi. Parantezele din jurul *cmp au fost folosite pentru ca
compilatorul s poat interpreta corect instruciunea.
n interiorul funciei verifica(), expresia (*cmp)(a,b)apeleaz funcia strcmp(), a
crei adres se afl n cmp, cu argumentele a i b. Din nou apar necesare parantezele
din jurul expresiei *cmp. De asemenea, acest exemplu mai ilustreaz o metod general
de a utiliza pointerul funcie pentru apelarea funciei a crei adres o conine.
Observai c acum funcia verifica() poate fi apelat folosind direct funcia
strcmp(), dup cum se vede mai jos:
verifica(s1,s2,strcmp);
Aceasta elimin necesitatea de a folosi o variabil pointer adiional.
6.13 Probleme de implementare
Cnd creai funcii n C, sunt cteva lucruri important de reinut care le afecteaz eficiena
i utilitatea. Aceste subiecte vor fi tratate n paragraful care urmeaz.
6.13.1 Parametri i funcii de uz general
O funcie de uz general este o funcie care poate fi folosit ntr-o varietate de situaii, i
probabil de ctre mai muli programatori. De obicei, funciile de uz general nu trebuie s se
bazeze pe date globale. Toate informaiile de care are nevoie funcia trebuie transmise
acesteia prin intermediul parametrilor. Cnd aceasta nu este posibil, se vor folosi variabile
statice. Pe lng transformarea funciilor n funcii de uz general, parametrii ofer liniilor de
program lizibilitate i un risc mai redus de expunere la erori de program determinate de
erori marginale.
6.13.2 Eficien
Funciile reprezint elementele constructive ale limbajului i sunt de o importan crucial
pentru orice program, poate cu excepia celor mai simple. Cu toate acestea, n anumite
aplicaii specializate, poate fi necesar eliminarea unei funcii i nlocuirea acesteia cu
coduri in-line. Acestea efectueaz aceleai operaii ca o funcie, dar fr suprancrcarea
asociat unui apel de funcie. Din acest motiv, codul in-line este adesea folosit n loc de
apelurile la funcii, atunci cnd timpul de execuie a programului este critic.
Codul in-line este mai rapid dect apelul unei funciii, din dou motive. Mai nti, o
instruciune de apel (CALL) are nevoie de timp pentru a se executa. n al doilea rnd, dac
exist argumente de transmis, acestea trebuie aezate n memoria stiv, ceea ce iari
ocup timp. Pentru majoritatea aplicaiilor, aceast foarte uoar cretere a timpului de
execuie este complet nesemnificativ. Dar dac creterea conteaz, nu uitai c fiecare
apel al funciei folosete timp, care ar fi putut fi economisit dac codul funciei ar fi fost
plasat in-line. De exemplu, n continuare vom prezenta dou versiuni ale unui program
care afieaz ptratele numerelor de 1 la 10. Versiunea in-line ruleaz mai rapid dect
cealalt, fiindc apelul funciei necesit timp.




in line cu apelul funciei
FUNCII

95
#include<stdio.h>

void main(void)
{
int x;
for(x=1; x<11; ++x)
printf("%d", x*x)
}
#include<stdio.h>
int patrat(int a);
void main(void)
{
int x;
for(x=1; x<11; ++x)
printf("%d", patrat(x)
}
ptrat(int a)
{ return a*a; }
6.13.3 Biblioteci i fiiere
O dat ce ai scris o funcie, o putei utiliza n trei feluri: o putei lsa n acelai fiier cu
funcia main(), o putei introduce ntr-un fiier separat, la un loc cu alte funcii, sau o
putei insera ntr-o bibliotec. n acest paragraf vom discuta despre cteva probleme
legate de aceste opiuni.
6.13.3.1 Inserarea n fiiere separate
Cnd lucrai la un program de mari dimensiuni, una dintre cele mai frecvente i enervante
probleme este de a scotoci prin fiecare fiier n cutarea unei anumite funcii. Puin
organizare preliminar v va scuti de aceast problem.
Mai nti, grupai toate funciile avnd concepte similare sau apropiate ntr-un acelai
fiier. De exemplu, dac lucrai la un editor de texte, putei insera toate funciile pentru
tergere ntr-un singur fiier, cele de cutare a fragmentelor de text ntr-altul etc.
Dup aceea, adunai la un loc toate funciile de uz general. De exemplu, n cazul
programelor de baze de date, funciile de formatare pentru intrare/ieire sunt folosite de
diverse alte funcii i trebuie inserate ntr-un fiier separat.
n final, grupai funciile de mare importan ntr-un fiier separat, sau, dac este spaiu, n
fiierul main(). Aceste funcii iniiaz activitatea general a unui program, definindu-i n
esen modul de operare.
6.13.3.2 Biblioteci
Tehnic vorbind, o bibliotec de funcii este diferit de un fiier de funcii compilat separat.
Atunci cnd rutinele dintr-o bibliotec sunt legate de restul programului, numai acele funcii
pe care programul le folosete efectiv sunt ncrcate i legate cu programul. La un fiier
compilat separat, toate funciile sunt ncrcate i legate cu programul, indiferent dac sunt
folosite sau nu. n cazul majoritii funciilor pe care le creai, probabil c vei dori ca toate
funciile s fie plasate ntr-un fiier. n cazul bibliotecii standard C, probabil c nu vei dori
ca toate funciile s fie legate cu programul, fiindc astfel codul obiect ar deveni imens!
Uneori, vei dori s creai o bibliotec. De exemplu, s presupunem c ai conceput un set
special de funcii de uz statistic. Nu dorii s ncrcai toate aceste funcii dac programul
dvs. nu trebuie dect s calculeze media unui set de valori. n acest caz, este util o
bibliotec.

Fiecare bibliotec este format din dou pri: un fiier header i fiierul surs propriu zis.
n mod normal fiier header, caracterizat de extensia ".h", conine informaii despre
bibliotec care trebuie cunoscute de ctre programe. n general, fiierul header conine
declaraii de constante i tipuri, precum i antetele funciilor din bibliotec. Scriei urmtorul
fiier header i salvai-l cu numele bib.h.
/*Fis header: bib.h*/
extern int suma(int, int);
Capitolul 6

96
Aceast linie ne reamintete prototipul funciei. Cuvntul "extern" din C reprezint funcii
care vor fi legate ulterior.
Scriei urmtoarele instruciuni ntr-un fiier numit bib.c.
/*Fis biblioteca*/
#include"bib.h"
int suma(int a, int b)
{ return a+b;}
Observai c acest fiier include propriul su fiier header (bib.h) i c folosete ghilimele
n locul simbolurilor < i > , care sunt utilizate pentru bibliotecile sistem.
Scriei acum urmtoarele instruciuni ntr-un fiier numit main.c.
/*Fis princ: main.c*/
#include"bib.h"
#include<stdio.h>

void main(void)
{
int a=10,b=20,c;
c=suma(a,b);
printf("c=%d",c);
}
Acest program include biblioteca de funcii creat. Principalul avantaj al folosirii unei
biblioteci este acela c programul surs principal este mult mai scurt.
6.13.3.3 Ct de mare trebuie s fie un fiier program?
Fiindc C permite compilarea separat, apare n mod normal problema dimensiunii optime
a unui fiier. Aceasta este important, deoarece timpul de compilare este corelat n mod
direct cu dimensiunea fiierului compilat. n genere, procesul de legare dureaz mult mai
puin dect compilarea i elimin necesitatea unei recompilri sistematice a codului de
lucru. Pe de alt parte, meninerea evidenei mai multor fiiere poate genera probleme.
Dimensiunea unui fiier este o chestiune diferit pentru fiecare utilizator, compilator i
mediu de operare. Totui, ca regul de baz, un fiier surs nu trebuie s depeasc
1000015000 octei. De la acel punct ncolo, fiierul trebuie separat n dou sau mai
multe fiiere de dimensiuni mai mici.

Tipuri de date definite de utilizator

97
7. Tipuri de date definite de utilizator
Limbajele de programare de nivel nalt ofer utilizatorului faciliti de a prelucra att datele
simple (singulare, izolate), ct i pe cele compuse (structurate, grupate). Un exemplu de
grupare a datelor - de acelai tip - l constituie tablourile. Datele predefinite i tablourile
(prezentate n capitolele anterioare) nu sunt ns suficiente. Informaia prelucrat n
programe este organizat, n general n ansambluri de date, de diferite tipuri. Pentru a
putea descrie aceste ansambluri (structuri) de date, limbajele de programare de nivel nalt
permit programatorului s-i defineasc propriile tipuri de date.

Limbajul C ofer posibiliti de definire a unor tipurilor de date, prin:
structuri - permit gruparea unor obiecte (date) de tipuri diferite, referite printr-un nume
comun;
cmpuri de bii - membri ai unei structuri pentru care se aloc un grup de bii, n
interiorul unui cuvnt de memorie;
uniuni - permit utilizarea n comun a unei zone de memorie de ctre mai multe obiecte
de diferite tipuri;
enumerri - sunt liste de identificatori cu valori constante, ntregi.
declaraii typedef - asociaz nume noi tipurilor de date deja existente;
7.1 Structuri
Structura reprezint o grupare de date de tipuri diferite, identificate printr-un nume
comun.
Componentele unei structuri se numesc membrii (elementele sau cmpurile) structurii.
La declararea unei structuri se pot preciza tipurile, identificatorii elementelor componente
i numele structurii.
Forma general de declarare a unei structuri:
struct identificator_tip_structura {
lista_de_declaratii_membri;
} lista_identificatori_variabile;
n care: struct este un cuvnt cheie (obligatoriu); identificator_tip_structura
reprezint numele noului tip (poate lipsi); lista_de_declaratii_membri este o list n
care apar tipurile i identificatorii membrilor structurii;
lista_identificatori_variabile este o list cu identificatorii variabilelor de tipul
declarat.

Membrii unei structuri pot fi de orice tip, cu excepia tipului structur care se declar. Se
admit ns, pointeri ctre tipul structur. identificator_tip_structura poate lipsi din
declaraie, ns n acest caz, n lista_identificatori_variabile trebuie s fie
prezent cel puin un identificator_varabila.
Lista_identificatori_variabile poate lipsi, ns, n acest caz, este obligatorie
prezena unui identificator_tip_structura.
Exemplu: Se definete noul tip de date numit data, cu membrii zi, luna, an.
Identificatorii variabilelor de tipul data sunt data_naterii, data_angajarii.
struct data {
Capitolul 7

98
int zi;
char luna[11];
int an;
} data_nasterii, data_angajrii;
De poate apare sub forma: claraia de mai sus
struct data {
int zi;
char luna[11];
int an;
};
struct data data_nasterii, data_angajarii; /*Variabilele data_naterii i
data_angajrii sunt date de tipul data */
Se poate omite numele noului tip de date:
struct {
int zi;
char luna[11];
int an;
} data_nasterii, data_angajrii;
Iniializarea variabilelor de tip nou, definit prin structur, se poate realiza prin enumerarea
valorilor membrilor, n ordinea n care acetia apar n declaraia structurii. Referirea unui
membru al structurii se realizeaz cu ajutorul unui operator de baz, numit operator de
selecie, simbolizat prin punct ".", care are o prioritate maxim. Elementul din stnga
operatorului de selecie precizeaz numele variabilei de tipul introdus prin structur, iar
in dreapta - numele membrului structurii, ca n exemplul urmtor: elementul d
Exemplu:
struct angajat{
char nume[20], prenume[20];
int nr_copii;
double salariu;
char loc_nastere[20];
};
struct angajat a1= {"Popescu", "Vlad", 2, 2900200, "Galati"};
a1.nr_copii = 3;
strcpy(a1.nume, "Popesco");
Variabilele de acelai tip pot apare ca operanzi ai operatorului de atribuire. n acest caz
atribuirile se fac membru cu membru. n exemplul anterior am declarat i iniializat
variabila a1, de tip angajat. Declarm i variabila a2, de acelai tip. Dac dorim ca
membrii variabilei a2 s conin aceleai valori ca membrii variabilei a1 (a1 i a2 de tip
angajat), putem folosi operatorul de atribuire, ca n exemplul urmtor:
struct angajat a2;
a2=a1;
Aa cum s-a observat din exemplul anterior, structurile pot avea ca membri tablouri
(structura angajat are ca membrii tablourile de caractere loc_natere[20],
nume[20], prenume[20]). De asemenea, variabilele de tip definit prin structur pot fi
ablouri. grupate n t
Exemplu:
/* Se declar un tip nou numit persoana i variabila numit angajati, care este un
vector (cu maxim 100 de elemente), ale crui elemente sunt de tipul persoana */
struct persoana{
Tipuri de date definite de utilizator

99
char nume[20], prenume[20];
int nr_copii;
double salariu;
char loc_nastere[20];
} angajati[100];
//In ajai[100] iializarea elementelor vectorului ang
for (int i=0; i<100; i++){
cout<<"Introduceti datele pentru angajatul "<<i+1<<'\n';
cout<<"Numele :"; cin>>angajati[i].nume;
cout<<"Prenumele :"; cin>>angajati[i].prenume;
cout<<"Nr. copii:"; cin>> angajati[i].nr_copii;
cout<<"Locul nasterii:"; cin>> angajati[i].loc_natere;
}
Limbajul C
Ex
permite definirea de structuri ale cror membri sunt tot structuri:
emplu:
struct data{
int zi;
char luna[11];
int an;
};
struct persoana{
char nume[20], prenume[20];
int nr_copii;
double salariu;
char loc_nastere[20];
struct data data_nasterii;
};
struct persoana p1={"Popescu", "Vasile", 1, 600, "Galati", {22,
"Mai", 1978}};
//Modificarea membrului data_nasterii pentru variabila p1 de tip persoana:
p1.data_nasterii.zi=23;
strcpy(p1.data_nasterii.luna, "Februarie");
p1.data_nasterii.an=1980;
7.1.1 Transmiterea structurilor n funcii
Ca parametri ai unei funcii pot apare individual membrii unei structuri, sau structuri n
ntregime. Structurile pot fi transmise prin valoare sau prin intermediul pointerilor.
7.1.1.1 Transmiterea membrilor unei structuri
Cnd membrul unei structuri este transmis unei funcii, ceea ce se transmite funciei este
de fapt valoarea acelui membru. Ca atare, se transfer doar o variabil (n afar de cazul
n care, desigur, acel element are o natur mai complex, de exemplu un tablou de
caractere). De exemplu, fie structura p1 de tip persoana din exemplele precedente. lat
exemple de transfer ale fiecrui membru ctre o funcie:
func(p1.nr_copii); /* transmite valoarea ntreag a lui nr_copii */
func4(p1.nume); /* transmite adresa irului nume */
func(p1.nume[2]); nume[2] /* transmite valoarea tip caracter lui */
Dac dorii s transmitei adresa unui anumit membru al unei structuri, inserai operatorul
& naintea numelui structurii. De exemplu, pentru a transmite adresa membrilor structurii
p1, se scrie
Capitolul 7

100
func(&p1.nr_copii); /* transmite adresa variabilei nr_copii */
func4(p1.nume); nume /* transmite adresa irului */
func(&p1.nume[2]); nume[2] /* transmite adresa caracterului */
Nu uitai c operatorul & precede numele structurii, i nu pe acela al membrului n cauz.
Remarcai, de asemenea, c nume simbolizeaz deja o adres, deci nu este necesar
operatorul &.
7.1.1.2 Transmiterea de structuri
Cnd o structur este folosit ca argument al unei funcii, se va efectua transmiterea
ntregii structuri, folosind metoda standard a apelului prin valoare. Desigur, aceasta va
nsemna c, indiferent de schimbrile operate asupra coninutului structurii, odat aceasta
situat n interiorul funciei creia i este transferat, acestea nu vor afecta structura
folosit ca argument.
Cnd folosii o structur pe post de parametru, nu uitai c tipul argumentului trebuie s
coincid cu acela al parametrului. De exemplu, n programul urmtor att argumentul arg
c eclarate ca fiind de acelai tip de structur. t i parametrul parm sunt d
#include <stdio.h>
/* Definete un tip de structura. */
struct tip_struct {
int a, b;
char ch;
} ;

void f1(struct tip_struct parm);

void main(void)
{
struct tip_struct arg;
arg.a = 1000;
f1(arg) ;
}
void f1(struct tip_struct parm)
{ printf("%d", parm.a); }
Dup cum se vede n programul anterior, dac vei declara parametri de tip structur,
trebuie ca declaraia tipului structurii s aib caracter global, pentru a putea fi folosit de
ctre toate componentele structurii. De exemplu, dac tip_struct ar fi fost declarat n
interiorul funciei main() (de exemplu), atunci nu ar fi fost vizibil pentru funcia f1().
Structurile mai pot fi transmise ca parametri de funcii i prin intermediul pointerilor, aa
cum se arat n paragraful 7.1.2.2
7.1.2 Pointeri ctre structuri
C permite existena pointerilor ctre structuri, asemntori oricror ali pointeri de variabile.
Totui, exist anumite aspecte speciale ale pointerilor ctre structuri pe care este bine s
le cunoatei.
7.1.2.1 Declararea unui pointer structur
Ca i n cazul altor categorii de pointeri, pointerii ctre structuri se declar insernd un
asterisc (*) n faa numelui unei variabile tip structur. De exemplu, dac lum n
considerare structura persoana, definit anterior, instruciunea urmtoare definete
p_persoana ca pointer al unei date de tip structur:
Tipuri de date definite de utilizator

101
struct persoana *p_persoana
7.1.2.2 Utilizarea pointerilor structur
Exist dou utilizri principale pentru pointerii ctre structuri, i anume pentru a genera un
apel la o funcie prin referirea unui parametru i pentru a crea liste nlnuite i alte
structuri dinamice de date folosind sistemul de alocare al limbajului C. n paragraful de fa
vom discuta despre prima utilizare.
Exist un dezavantaj major al transferului ctre funcii a structurilor n ntregime, cu
excepia a celor mai simple, i anume acela al suprancrcrii necesare inserrii structurii
n stiv la executarea apelului la funcie. (Amintii-v c argumentele sunt transmise
funciilor pe stiv.) Pentru structuri simple, care conin numai civa membri, aceast
ncrctur nu este prea mare. Dac ns structura conine mai muli membri, sau dac o
parte din aceti membri sunt tablouri, viteza de rulare poate scdea la niveluri
inacceptabile. Soluia problemei o reprezint transmiterea doar a unui pointer ctre funcie.
Cnd un pointer ctre o structur este transferat unei funcii, numai adresa structurii este
inserat n memoria stiv, ceea ce permite o apelare foarte rapid a funciilor. Un al doilea
avantaj, n anumite cazuri, apare atunci cnd o funcie trebuie s refere structura efectiv
folosit ca argument, n loc de o copie a acesteia. Prin transmiterea unui pointer, funcia
poate modifica coninutul structurii folosite la apelare.
Pentru a gsi adresa unei variabile structur, operatorul & se plaseaz naintea numelui
structurii. De exemplu,
p_persoana = &p1;
amplaseaz adresa structurii p1 n pointerul p_persoana.
Pentru a accesa membrii unei structuri folosind un pointer ctre acea structur, trebuie s
folosii operatorul ->. De exemplu, instruciunile urmtoare refer cmpul nr_copii:
(*p_persoana).nr_copii sau p_persoana->nr_copii
operatorul -> este cunoscut sub numele de operator de selecie indirect (sgeat) i este
alctuit din semnul minus urmat de simbolul mai mare dect". Sgeata este folosit n
locul operatorului de selecie direct (punct) la accesarea membrului unei structuri folosind
un pointer al acelei structuri.

Dac este necesar ca variabila p1, de tip persoana, s fie prelucrat n funcia f, funcia
va primi ca parametru un pointer spre tipul persoana. Funcia va avea prototipul:
void f(struct persoana *p_persoana);
Apelul funciei se realizeaz astfel: f(&p1);
n corpul funciei f, accesul la membrii variabilei p_persoana, de tip *persoana, se
realizeaz astfel:
(*p_persoana).nume;
(*p_persoana).prenume;
(*p_persoana).data_nasterii.an;
sau
p_persoana->nume;
p_persoana->prenume;
p_persoana->data_nasterii.an;

Structurile sunt utilizate n mod frecvent la definirea unor tipuri de date recursive (n
implementarea listelor, arborilor, etc.).
Un tip de date este direct recursiv dac are cel puin un membru care este de tip
pointer spre el nsui.
Exemplu:
Capitolul 7

102
struct nod{
char nume[100];
int an;
struct nod *urmator;
};
7.2 Cmpuri de bii
De multe ori se utilizeaz date care pot avea doar 2 valori (0 sau 1), cum ar fi datele
pentru controlul unor dispozitive periferice, sau datele de valori mici. Declarnd aceste
date de tip int sau short int, n memorie se rezerv 16 bii. Alocarea unui numr att
de mare de locaii de memorie nu este justificat, de aceea, limbajul C ofer posibilitatea
declarrii unor date pentru care s se aloce un numr specificat de bii (alocare pe bii).
Un cmp de bii este un tip special de membru de structur pentru care se definete
lungimea acestui element al structurii.
C i structuri, astfel: mpurile de bii se pot declara ca membri ai une
struct identificator_tip_struct {
tip_elem_1 identificator_elem_1:lungime1;
tip_elem_2 identificator_elem_2:lungime2;
. . .
tip_elem_3 identificator_elem_3:lungime3;
} lista_identif_var_struct;
Lungime1, lungime2, etc. reprezint lungimea fiecrui cmp de bii, rezervat pentru
membrilor.. memorarea
Exemplu:
struc c t mis {
int a: 2;
unsi i b: 1; gned nt
int c: 3;
signed d: 2;
} x, y;
Nu este necesar s dai un nume fiecrui cmp de bii. De exemplu dac v intereseaz
nu ei declara structura misc dup cum urmeaz: mai biii b i c, put
struc c t mis {
int : 2;
unsi i b: 1; gned nt
int c: 3;
} x, y;
Remarcai, de asemenea, c biii de dup c nu trebuie neaprat specificai, dac nu sunt
losii. fo

e refer ca orice membru al unei structuri, prin nume calificate: Cmpurile s
Exemplu:
x.a = -1; x.b = 3; x.c = 4;
Este perfect posibil s se combine membrii normali ai unei structuri cu cmpurile de bii.
De exemplu,
struct persoana{
Tipuri de date definite de utilizator

103
char nume[20];
int varsta;
float plata;
unsigned activ: 1; /* pauza sau activ */
unsigned orar: 1; /* plata cu ora sau salariu */
unsigned impozite: 3; /* impozite fiscale */
};
definete nregistrarea unei persoane care folosete un singur octet pentru a memora trei
informaii: starea angajatului, dac angajatul primete salariu i numrul de impozite. n
bsena unui cmp de bii, aceast informaie ar fi necesitat 3 octei de memorie. a

i Ut lizarea cmpurilor de bii impune urmtoarele restricii:
Tipul membrilor poate fi signed, unsigned sau int. Elementele de de lungime 1
ate avea vreun semn.



trebuie declarate unsigned pentru c un singur bit nu po
Lungime este o constant ntreag din intervalul [0, 31];
Nu putei avea adresa unui cmp de bii (un cmp de bii nu poate fi operandul unui
operator de refereniere).
Variabilele de acest tip nu pot fi aranjate n tablouri.
Nu avei cum ti, de la un calculator la altul, dac ordonarea cmpurilor se face de la
dreapta la stnga sau invers.

Datorit restriciilor pe care le impune folosirea cmpurilor de bii, ct i datorit faptului c
aplicaiile care folosesc astfel de structuri de date au o portabilitate extrem de redus
(organizarea memoriei depinznd de sistemul de calcul), se recomand folosirea
cmpurilor de bii cu precauie, doar n situaiile n care se face o economie substanial
de memorie.
7.3 Uniuni
O uniune este o locaie de memorie care este folosit n comun de dou sau mai
multe variabile diferite, n general de tipuri diferite i la momente diferite.
Uniunile sunt similare cu structurile, singura diferen constnd n modul de memorare.
Declararea uniunilor:
union identificator_tip_uniune {
lista de declaratii_membri;
} lista_identificatori_variabile;
Spaiul de memorie alocat ntregii uniuni corespunde tipului membrului de dimensiune
maxim. Tipul uniune folosete n comun aceeai zon de memorie, care va conine
succesiv informaii organizate n mai multe moduri, corespunztor tipurilor membrilor.
Pentru a accesa un membru al unei uniuni se folosete aceeai sintax ca n cazul
structurilor.
union nu r me ic{
int i; //2 octei
float f; //4 octei
double d; //8 octei
} num;
num.i = 20;
num.f = 5.80;
Capitolul 7

104
cout<<sizeof(num)<<'\n'; //8

Exemplu:
Pentru variabile num se rezerv max(2,4,8) = 8 octei de memorie, dimensiunea maxim a
zonei de memorie alocate membrilor (pentru int s-ar fi rezervat 2 octei, pentru float 4,
iar pentru double 8). n exemplul anterior, n aceeai zon de memorie se pstreaz SAU
o valoare ntreag (num.i=20), SAU o valoare real, dubl precizie (num.f=5.80).
7.4 Enumerri
O enumerare este un set de constante ntregi cu nume, care specific toate valorile
legale pe care le poate lua o variabil de acest tip.
Tipul enumerare asociaz fiecrui identificator o constant ntreag. Sintaxa declaraiei:
enum identificator_tip_enumerare {
identif_elem1 = const1, . . .
} lista_identif_variabile;
Din declaraie pot lipsi fie identificator_tip_enumerare, fie
lista_identif_variabile. Pentru fiecare element al enumerrii, constanta ntreag
poate fi asociat n mod explicit (ca n declaraia anterioar), fie implicit. n modul implicit
nu se specific nici o constant, iar valoarea implicit este 0 pentru primul element, iar
pentru restul elementelor, valoarea precedent incrementat cu 1. Enumerrile se
folosesc n situaiile n care variabilele pot avea un numr mic de valori ntregi, asociind un
nume sugestiv pentru fiecare valoare.
Exemplu:
//1
enum boolean {FALSE, TRUE}; //definirea tipului boolean cu elementele
FALSE si TRUE
//declaratie echivalenta cu enum boolean {FALSE=0, TRUE=1};
cout<<"FALSE este "<<FALSE<<'\n'; //FALSE este 0
//2
enum temperatura {mica=-10, medie=10, mare=80};
//tipul enumerare temperatura, cu elementele mica (de valoare -10), medie
(valoare 10), mare (valoare 80)
enum temperatura t1, t2; //declararea variabilelor t1, t2 de tip enumerare
temperatura
t1=medie;
cout<<"t1="<<t1<<'\n'; //t1=10
Dac valoarea elementului mare nu ar fi fost precizat, ea ar fi fost considerat implicit 11
= 10+1.

Exemplul 7.1 Structuri - elevi
S se citeasc (cu ajutorul unei funcii de citire) urmtoarele informaii despre elevii
participani la un concurs de admitere: nume, numrul de nscriere i cele trei note
obinute. S se afieze, printr-o funcie, informaiile citite. S se afieze o list cu elevii
participani la concurs, ordonai alfabetic, notele i media obinut (funcie de ordonare,
funcie de calculare a mediei). S se afieze lista elevilor nscrii la concurs, n ordinea
descresctoare a mediilor.

Tipuri de date definite de utilizator

105
Sunt prezentate dou variante de implementare ale funciei cit_elev (de citire).
n Varianta 1 s-a definit tipul elev i se lucreaz cu vectori cu elemente de acest tip. n
funcia cit_elev se valideaz fiecare not. Se va observa modul de acces la membrii
structurii n funcia cit_elev. Dezavantajul principal al acestui mod de implementare l
constituie risipa de memorie, deoarece n funcia main, la declararea tabloului p cu
elemente de tip elev, se rezerv o zon de memorie continu, pentru 100 de elemente
de tip elev (100*sizeof(elev)).
#include <iostream.h>
#include <conio.h>
struct elev{
char nume[20];int nr_matr;int note[3];
}; //definirea tipului elev
void cit_elevi(elev a[], int n)
{
for (int i=0; i<n; i++){
cout<<"Nume elev:"; cin>>a[i].nume; // citirea numelui unui elev
cout<<"Nr. inscriere:"; cin>>a[i].nr_matr;
for (int j=0; j<3; j++){ // citirea notelor obinute
do{
cout<<"Nota :"<<j+1<<" ="; cin>>a[i].note[j];
if(a[i].note[j]<0 || a[i].note[j]>10) //validarea notei
cout<<"Nota incorecta!....Repeta!\n";
}while (a[i].note[j]<0 || a[i].note[j]>10);
}
}
}

void main()
{
int nr_elevi; clrscr();
cout<<"Nr. elevi:";cin>>nr_elevi;
elev p[100]; //declararea tabloului p, de tip elev
cit_elevi(p, nr_elevi); //apel funcie
}
n Varianta 2, inclus n programul principal, se lucreaz cu pointeri ctre tipul elev, iar
memoria este alocat dinamic.
#include <stdio.h>
#include <string.h>
#include <iostream.h>
#include <conio.h>

#define DIM_PAG 24 // dimensiunea paginii de afiare
#define FALSE 0
#define TRUE 1

struct elev{
char nume[20];int nr_matr;int note[3];
}; //definirea tipului elev

void cit_elevi(elev *a, int n)
{
for (int i=0; i<n; i++){
Capitolul 7

106
cout<<"Nume elev:"; cin>>(a+i)->nume; //sau
cin>>(*(a+i)).nume;
cout<<"Nr. inscriere:"; cin>>(a+i)->nr_matr;
for (int j=0; j<3; j++){
do{
cout<<"Nota :"<<(j+1)<<" =";
cin>>(a+i)->note[j];
if((a+i)->note[j]<0 || (a+i)->note[j]>10)
cout<<"Nota incorecta!....Repeta!\n";
}while ((a+i)->note[j]<0 || (a+i)->note[j]>10);
}
}
}

void ord_medii(elev *a, int n)
{
int gata =FALSE;int i;double med1, med2;elev aux;
while (!gata){
gata=TRUE;
for(i=0; i<=n-2; i++){
med1=0;med2=0;
for (int j=0; j<3; j++){
med1+=(a+i)->note[j]; med2+=(a+i+1)->note[j];// calculul mediilor
pentru elementele vecine
}
med1/=3; med2/=3;
if (med1<med2){
aux=*(a+i); *(a+i)=*(a+i+1);*(a+i+1)=aux; gata=FALSE;}
}
}
}

void ord_alf(elev *a, int n)
{
int gata=FALSE;int i; double med1, med2; elev aux;
while(!gata){
gata=TRUE;
for (i=0; i<=n-2; i++){
if(strcmp((a+i)->nume,(a+i+1)->nume)>0)
{aux=*(a+i); *(a+i)=*(a+i+1);*(a+i+1)=aux; gata=FALSE;}
}
}
}

void antet_afis(const char *s)
{printf("%s\n", s);}

void afis_elev(elev *a, int n, char c)
{clrscr();
if(c=='A')
antet_afis(" LISTA INSCRISILOR\n");
if(c=='O')
antet_afis(" LISTA ALFABETICA\n");
if(c=='R')
Tipuri de date definite de utilizator

107
antet_afis(" LISTA MEDII\n");
printf("Nr.crt.|Nr. Matricol| NUME
|Nota1|Nota2|Nota3| MEDIA\ |\n");
printf("------------------------------------------------------
\n");
int lin=3;
for(int i=0; i<n; i++){
printf("%7d|%12d|%-20s|",i+1,(a+i)->nr_matr,(a+i)->nume);
double med=0;
for (int j=0; j<3; j++){
printf("%-5d|", (a+i)->note[j]);
med+=(a+i)->note[j];
}
med/=3;printf("%-9.2f|\n", med);lin++;
if (lin==(DIM_PAG-1)){
printf(" Apasa o tasta...."); getch();
clrscr();
if(c=='A') antet_afis(" LISTA INSCRISILOR\n");
if(c=='O') antet_afis(" LISTA ALFABETICA\n");
if(c=='R') antet_afis(" LISTA MEDII\n");
printf("Nr.crt.| NUME |Nota1|Nota2|Nota3| MEDIA\
|\n");
printf("-----------------------------------------------------\
\n");
int lin=3;
}
}
printf(" Apasa o tasta...."); getch();
}
void main()
{ int nr_elevi; clrscr();
cout<<"Nr. elevi:";cin>>nr_elevi;
elev *p; // declararea pointerului p, ctre tipul elev
p=new elev[nr_elevi]; // alocarea dinamic a memoriei, pentru un tablou cu
nr_elevi elemente
cit_elevi(p, nr_elevi); // apel funcie
afis_elev(p, nr_elevi, 'A');// afisarea nscriilor
ord_medii(p, nr_elevi);
afis_elev(p, nr_elevi, 'R');// afiarea n ordinea descresctoare a mediilor
ord_alf(p, nr_elevi); // ordonare alfabetic
afis_elev(p, nr_elevi, 'O');// afiarea n ordinea descresctoare a mediilor
}
S-a im u plementat urmtoarele funcii:
cit_elevi - citete informaiile despre elevii nscrii.
afis_elevi - afieaz informaiile despre elevi. Aceast funcie este folosit
pentru cele trei afiri (lista nscriilor, lista alfabetic i clasamentul n ordinea
descresctoare a mediilor). Afiarea se realizeaz cu ajutorul funciei printf, care
permite formatarea datelor afiate. Afiarea se realizeaz ecran cu ecran (se
folosete variabila lin care contorizeaz numrul de linii afiate), cu pauz dup
fiecare ecran. La nceputul fiecrei pagini se afieaz titlul listei - corespunztor
caracterului transmis ca parametru funciei - i capul de tabel. De asemenea, pentru
fiecare elev nscris se calculeaz media obinut (variabila med).
Capitolul 7

108
ord_medii - ordoneaz vectorul de elevi (transmis ca parametru, pointer la tipul
elev), descresctor, dup medii. Se aplic metoda bulelor, comparndu-se mediile
elementelor vecine (med1 reprezint media elementului de indice i, iar med2 - a
celui de indice i+1) ale vectorului.
ord_alf - ordoneaz vectorul de elevi (transmis ca parametru, pointer la tipul
elev), cresctor, dup informaia coninut de membrul nume. Pentru compararea
numelor se folosete funcia strcmp.
Deoarece este foarte probabil ca vectorul nscriilor s aib multe elemente, pentru
ordonri, ar fi fost mai eficient metoda de sortare rapid; s-a folosit totui metoda bulelor
pentru a nu complica prea mult problema.
7.5 Declaraii de tip
Limbajul C permite atribuirea unui nume pentru un tip (predefinit sau utilizator) de date.
Pentru aceasta se folosesc declaraiile de tip. Forma general a acestora este:
typedef tip nume_nou;
nume_nou poate fi folosit la declararea datelor n mod similar cuvintelor cheie pentru
tipurile predefinite. Folosirea lui typedef poate simplifica declararea variabilelor de tip
structur, uniune sau enumerare.
Exemplu:
//1
typedef int INTREG;
INTREG x, y;
INTREG z=4;
//2
typedef struct{
double parte_real;
double parte_imaginar;
} COMPLEX;
COMPLEX x, y;

Preprocesorul

109
8. Preprocesorul
n codul surs al unui program n C se pot include diverse instruciuni destinate
compilatorului. Acestea se numesc directive de preprocesor (preprocessor directives) i,
dei nu fac parte efectiv din limbajul C, extind domeniul de aciune al mediului de
programare C. n acest capitol se va mai discuta i despre comentarii.
8.1 Preprocesorul C
Conform definiiei date de standardul ANSI C, preprocesorul C conine urmtoarele
directive:
#define #elif #else #endif
#error #if #ifdef #ifndef
#include #line #pragma #undef
Dup cum se poate vedea, toate directivele preprocesorului ncep cu simbolul # (diez).
Suplimentar, fiecare directiv de preprocesare trebuie s ocupe un singur rnd n
program. De exemplu,
I#include <stdio.h> #include <stdlib.h> este incorect.
8.2 Directiva #define
Aceast directiv definete un identificator i o secven de caractere (cu alte cuvinte, un
set de caractere) care vor nlocui identificatorul la fiecare apariie a acestuia n fiierul
surs. Standardul ANSI C numete identificatorul nume de macrocomand (macro name),
iar procesul de nlocuire, nlocuire a macrocomenzii (macro replacement). Forma general
a directivei este
#define nume_macro secventa_caract
Observai absena caracterului punct i virgul n aceast instruciune. ntre identificator i
secvena de caractere pot exista oricte spaii, dar, odat secvena de caractere nceput,
poate fi ncheiat numai printr-un caracter delimitator de rnd nou.
De exemplu, dac dorii s folosii cuvntul TRUE (adevrat) pentru valoarea i cuvntul
FALSE (fals) pentru valoarea zero, acestea pot fi definite ca macrocomenzi folosind
#define.
#define TRUE 1
#define FALSE 0
Aceasta va determina compilatorul s insereze 1 sau 0 n program la fiecare apariie a
cuvintelor TRUE, respectiv FALSE. De exemplu, urmtorul program afieaz pe ecran 0 1
2:
printf("%d %d %d", FALSE, TRUE, TRUE+1);
Odat definit numele unei macrocomenzi, acesta poate fi folosit n definirea numelor altor
macrocomenzi. De exemplu, urmtorul program definete valorile lui UNU, DOI i TREI:
#define UNU 1
#define DOI UNU+UNU
#define TREI UNU+DOI
Capitolul 8

110
nlocuirea unei macrocomenzi este pur i simplu nlocuirea unui identificator cu secvena
de caractere asociat acestuia. n consecin, dac dorii s definii un mesaj standard de
eroare, trebuie s scriei ceva de genul:
#define E_MS "eroare standard la intrare\n"
printf(E_MS);
Compilatorul va insera irul "eroare standard la intrare\n" cnd ntlnete identificatorul
E_MS. Pentru compilator, instruciunea printf() este interpretat ca:
printf("eroare standard la intrare\n");
Dac identificatorul se afl ncadrat ntre ghilimele, nu se produce nici un fel de nlocuire
de text. De exemplu,
#define XYZ acesta este un test
printf("XYZ");
nu va afia pe ecran "acesta este un test", ci XYZ.
Dac lungimea irului depete un rnd, acesta se poate continua pe rndul urmtor
insernd un backslash (\) la sfritul rndului, ca n exemplul urmtor:
#define SIR_LUNG "acesta este un sir foarte lung \
folosit pe post de exemplu"
Programatorii n C folosesc adesea majuscule pentru identificatorii definii. Aceast
convenie ajut pe oricine citete programul s-i dea seama c la un moment dat va avea
loc nlocuirea unui macro. De asemenea, cel mai indicat este s se insereze toate
declaraiile tip #define la nceputul fiierului sau ntr-un fiier antet separat, n loc ca
acestea s fie dispersate pe toat ntinderea programului.
Macrocomenzile sunt cel mai des folosite pentru atribuirea de nume numerelor magice"
care survin ntr-un program. De exemplu, avei un program care definete un tablou i are
mai multe rutine care acceseaz acel tablou. n loc de a codifica dimensiunea tabloului
folosind o constant, aceasta poate fi definit folosind o instruciune de tip #define, iar
apoi s folosii numele acelei macrocomenzi ori de cte ori este necesar. Astfel, dac
trebuie modificat dimensiunea tabloului, tot ce avei de fcut este s modificai
instruciunea #define i apoi s recompilai programul. De exemplu,
#define DIM_MAX 100;
/*...........*/
float bilant[DIM_MAX];
/*...........*/
for(i=0; i<DIM_MAX; i++) printf("%f", bilant[i]);
Deoarece DIM_MAX definete dimensiunea tabloului bilant, dac dimensiunea acestuia
trebuie modificat n viitor, nu trebuie dect s modificai, o singur dat, definiia lui
DIM_MAX. Toate referirile ulterioare la acesta vor fi actualizate automat la recompilarea
programului.
8.2.1 Definirea de macrocomenzi tip funcie
Directiva #define mai are o caracteristic puternic, i anume aceea c numele
macrocomenzii poate avea argumente. La fiecare apariie a numelui acesteia,
argumentele folosite n definiie pot fi nlocuite prin argumentele efective din program.
Aceast form de macrocomand se cunoate sub numele de macrocomand de tip
funcie (function-like macro). De exemplu:
#define variabila(a,b) (a##b)
Preprocesorul

111
n exemplul de mai sus macrocomanda alipete (concateneaz) dou simboluri (doi
tokeni). Astfel, apelul variabila(x,yz) se nlocuiete cu xyz, care poate fi o variabil,
numele unei funcii etc.
S analizm i un alt exemplu
#include <stdio.h>
#define ABS(a) (a)<0 ? -(a) : (a)

void main(void)
{
printf("abs de -1 si 1: %d %d", ABS(-1), ABS(1));
}
La compilarea acestui program, parametrul a din definiia macrocomenzii va fi nlocuit prin
valorile -1 i 1. Parantezele care ncadreaz pe a garanteaz o nlocuire corect n toate
cazurile. De exemplu, dac parantezele ar fi lipsit, expresia ABS(10-20) fi fost convertit n
10-20<0 ? -10-20 : 10:20 cea ce ar duce la un rezultat greit.
Utilizarea unui macro tip funcie n locul unor funcii propriu-zise are un avantaj major, prin
mrirea vitezei de execuie a codului, fiindc nu mai apare nici o ncrcare suplimentar
legat de apelarea funciei. Cu toate acestea, dac dimensiunea macrocomenzii tip funcie
este mare, acest supliment de vitez este "compensat" printr-o cretere a dimensiunii
programului, datorit codului care apare de dou ori.
Parametrii formali nu sunt nlocuii atunci cnd apar ntre ghilimele. Cu toate acestea, dac
numele unui parametru este precedat de un # n textul de nlocuit, combinaia va fi
dezvoltat ntr-un ir de caractere n care parametrul formal este nlocuit de parametrul
efectiv. Acest lucru, combinat de pild cu concatenarea irurilor, poate servi la crearea
unui macrou de tipul:
#define dprint(expr) printf(#expr " = %g\n", expr)
Atunci cnd este apelat sub forma dprint(x/y) macroul se dezvolt sub forma
printf("x/y" " = %g\n", x/y);
iar irurile sunt concatenate, astfel nct efectul este printf("x/y = %g\n", x/y);
n parametrul efectiv, pentru fiecare " trebuie folosit \" i pentru fiecare \ trebuie folosit \\,
astfel nct rezultatul s fie un ir de caractere legal.
8.3 Directiva #error
Directiva #error cere compilatorului s sisteze compilarea. Este folosita cu precdere la
depanarea programelor. Forma general a directivei #error este
#error mesaj_eroare
mesaj_eroare nu se introduce ntre ghilimele duble. La ntlnirea directivei #error,
afieaz mesajul de eroare, care poate fi urmat de alte mesaje, definite de creatorul
compilatorului.
8.4 Directiva #include
Aceast directiv cere compilatorului s mai citeasc i un alt fiier surs n afar de cel
care conine directiva. Numele fiierului surs adiional trebuie inclus ntre ghilimele duble
sau paranteze unghiulare (< i >). De exemplu, ambele instruciuni
#include "stdio.h"
#include <stdio.h>
Capitolul 8

112
cer compilatorului s citeasc i s compileze antetul pentru funciile cuprinse n biblioteca
sistemului de fiiere.
#include "c:\\bc\\test\\test.cpp"
Dup se vede n exemplul de mai sus, un fiier (test.cpp) ce se include poate fi dat
mpreun cu calea la care se afl el pe disc.
Fiierele dintr-o directiv #include pot conine, la rndul lor, alte directive #include.
Aceasta este cunoscut sub numele de directive #include imbricate (nested includes).
Numrul de niveluri de imbricare permis difer de la un compilator la altul. Totui,
standardul ANSI C prevede un numr minim egal cu opt.
Modul de ncadrare a numelui fiierului, ntre ghilimele sau ntre paranteze unghiulare,
controleaz modul de cutare a fiierului indicat:
Dac ncadrarea se efectueaz folosind paranteze unghiulare, cutarea fiierului se
execut ntr-un mod definit de ctre creatorul compilatorului. Adesea, aceasta
nseamn cutarea n directorul standard cu fiiere antet ale mediului de programare.
Numele acestui director este de obicei include i se afl n directorul n care este
instalat aplicaia C (n general avem calea: c:\bc\include). Calea spre directorul cu
includeri standard poate fi specificat n meniul OptionsDirectories, unde se
specific de altfel i calea spre bibliotecile standard.
Dac numele fiierului este ncadrat de ghilimele dar nu este precedat de o cale,
fiierul este cutat ntr-un alt mod care depinde de varianta de implementare. Pentru
multe compilatoare, aceasta nseamn cutarea n directorul curent de lucru. Dac
fiierul nu a fost gsit, cutarea este reluat, dar numele fiierului se consider
ncadrat ntre paranteze unghiulare.
Majoritatea programatorilor folosesc paranteze unghiulare pentru a include fiierele antet
standard. Utilizarea ghilimelelor este rezervat n general fiierelor care au o legtur cu
programul n cauz.
8.5 Directive de compilare condiional
Exist mai multe directive care permit compilarea selectiv a unor poriuni din codul surs
al programului. Acest proces se numete compilare condiional (conditional compilation)
i este folosit pe scar larg de firmele de comercializare a programelor, care ofer i
asigur ntreinerea mai multor versiuni personalizate ale aceluiai program.
8.5.1 Directivele #if, #else, #endif, #elif
Poate cele mai des folosite directive de compilare condiional le constituie #if, #else,
#elif i #endif. Aceste directive permit includerea condiionat a unor poriuni de cod,
n funcie de rezultatul unei expresii constante. Forma general a directivei #if este
#if expresie_constanta
secvena de instruciuni
#endif
Dac expresia constant care urmeaz instruciunii #if este adevrat, va fi compilat
codul existent ntre aceasta i instruciunea #endif. n caz contrar, codul respectiv este
ignorat. Directiva #endif marcheaz sfritul unui bloc #if. De exemplu,
/* Exemplu simplu de utilizare a directivei #if */
#include <stdio.h>
#define MAX 100

void main(void)
Preprocesorul

113
{
#if MAX>99;
printf("compilat pentru tablou cu peste 99 elemente\n");
#endif
}
Acest program va afia mesajul pe ecran, fiindc MAX este mai mare dect 99. Acest
exemplu ilustreaz un aspect important. Expresia care urmeaz directivei #if este
evaluat la compilare. Ca atare, trebuie s conin numai constante i identificatori definii
n prealabil; nu este permis folosirea variabilelor.
Directiva #else este oarecum asemntoare instruciunii else care constituie o parte a
limbajului C, n sensul c ofer o alternativ n cazul n care #if eueaz. Exemplul
anterior poate fi extins, dup cum urmeaz:
/* Exemplu simplu de utilizare a directivelor #if/#else. */
#include <stdio.h>
#define MAX 10
void main(void)
{
#if MAX>99
printf("compilat pentru tablou cu peste 99 elemente\n");
#else
printf("compilat pentru tablou de mici dimensiuni\n");
#endif
}
n acest caz, MAX a fost definit ca fiind mai mic dect 99, astfel c poriunea #if a codului
nu a fost compilat. Este compilat, n schimb, poriunea #else, i va afiat mesajul
compilat pentru tablou de mici dimensiuni. Remarcai c directiva #else este folosit
pentru a marca att sfritul blocului #if, ct i nceputul blocului #else, i aceasta
deoarece oricrui #if i poate fi asociat un singur #endif.
Directiva #elif are sensul de "else if" i determin un lan if-else-if (dac-altfel-
dac) pentru mai multe opiuni posibile de compilare. Directiva #elif este urmat de o
expresie constant. Dac expresia este adevrat, acel bloc de cod va fi supus compilrii,
fr a mai fi testat nici o alt expresie #elif. n caz contrar, este testat urmtorul bloc
din serie. Aspectul general al unei directive #elif este
#if expresie
secvena instruciuni
#elif expresie 1
secvena instruciuni
#elif expresie 2
secvena instruciuni
#elif expresie 3
secvena instruciuni
#elif expresie 4
secvena instruciuni

#elif expresie N
secvena instruciuni
#endif
De exemplu, urmtorul fragment de program utilizeaz valoarea TARA_ACTIVA pentru a
de valutare: fini simbolul unitii
#define SUA 0
Capitolul 8

114
#define ANGLIA 1
#define FRANA 2
#define TARA_ACTIVA SUA
#if TARA_ACTIVA == SUA
char currency[] = "dolar";
#elif TARA_ACTIVA == ANGLIA
char currency[] = "lira";
#else
char currency[] = "euro";
#endif
Standardul ANSI C precizeaz c directivele #if i #elif pot fi imbricate pe minimum
opt niveluri. (Probabil compilatorul dvs. accept mai multe.) Cnd este imbricat, fiecare
directiv de tip #endif, #else sau #elif se asociaz cu directiva #if sau #elif cea
ma xemplu, programul urmtor este absolut corect: i apropiat. De e
#if MAX>100
#if VERSIUNE_SERIALA
int port=198;
#elif
int port=200;
#endif
#else
char out_buffer[100];
#endif
8.5.2 Directivele #ifdef i #ifndef
O alt metod de compilare condiional folosete directivele #ifdef i #ifndef, ceea
ce nseamn if defined" (dac este definit), respectiv if not defined" (dac nu este definit).
Fo #ifdef este: rma general a directivei
#ifdef nume_macro
secvena instruciuni
#endif
Dac nume_macro a fost definit anterior ntr-o directiv de tip #define, blocul de cod va
fi c directivei #ifndef este ompilat. Forma general a
#ifndef nume_macro
secvena instruciuni
#endif
Dac nume_macro nu a fost definit printr-o directiv #define, blocul de cod este
compilat. Ambele directive pot folosi o directiv #else, dar nu una de tip #elif. De
exemplu,
#include <stdio.h>
#define DAN 10

void main(void) {
#ifdef DAN
printf("Buna Dan\n");
#else
printf("Buna, oricine ai fi\n");
#endif
#ifndef MIHAI
printf("MIHAI nu este definit\n");
Preprocesorul

115
#endif
}
va afia pe ecran mesajele "Buna Dan" i "MIHAI nu este definit". Dac DAN nu ar fi fost
definit, ar fi fost afiat mesajul "Buna, oricine ai fi", urmat de "MIHAI nu este definit". i
aceste dou directive accept imbricri.
8.5.3 Directiva #undef
Directiva #undef elimin o definiie enunat anterior a numelui macrocomenzii care o
urmeaz. Cu alte cuvinte, macrocomanda devine fr definiie". Forma general pentru
#undef este:
#undef nume_macro
De exemplu,
#define LUNG 100
#define LAT 100
char array[LUNG][LAT];
#undef LUNG
#undef LAT
/* n acest moment definiia pentru LUNG si LAT a fost eliminata */
Att LUNG, ct i LAT au fost definite pn la apariia instruciunilor #undef. Directiva
#undef este folosit pentru a permite localizarea numelor macrocomenzilor numai n
acele zone de cod care le necesit.
8.5.4 Utilizarea operatorului defined
n afar de #ifdef, mai exist o modalitate de a determina dac numele unei
macrocomenzi este definit, i anume utilizarea directivei #if n conjuncie cu operatorul
de compilare defined. Forma general a acestui operator este
defined nume_macro
Dac nume_macro este definit, atunci expresia este adevrat. n caz contrar este fals.
De exemplu, pentru a determina dac macrocomanda FIIER este definit, se poate folosi
oricare dintre urmtoarele comenzi de preprocesare:
#if defined FISIER sau #ifdef FISIER
De asemenea, defined poate fi precedat de ctre semnul "!" pentru a inversa condiia.
De exemplu, fragmentul urmtor este compilat numai dac DEPANA nu este definit.
#if !defined DEPANA;
printf("Versiune finala!\n");
#endif
Un alt motiv de a utiliza operatorul defined este acela c permite ca existena unui nume
de macrocomand s fie determinat printr-o instruciune #elif.
8.6 Directiva #line
Aceast directiv modific coninutul __LINE__ i __FILE__, care reprezint identificatori
predefinii ai compilatorului. Identificatorul __LINE__ conine numrul liniei de cod
compilate. Identificatorul __FILE__ este un ir care conine numele fiierului surs
compilat. Forma general a directivei #line este
#line numar "numefis"
Capitolul 8

116
unde numr este orice ntreg pozitiv care devine noua valoare a lui __LINE__, iar
opionalul numefis reprezint un identificator valid de fiier, care devine noua valoare a
lui __FILE__. Directiva este folosit mai ales la depanare i n aplicaii speciale.
De exemplu, fragmentul de cod urmtor indic faptul c numrtoarea liniilor va ncepe cu
100 i c instruciunea printf() va afia numrul 102, fiindc este a treia linie din
program de dup instruciunea #line 100.
#include <stdio.h>
#line 100 /* iniializeaz numrtorul de linii */
void main(void) /* linia 100 */
{ /* linia 101 */
printf("%d\n",__LINE__); /* linia 102 */
}
8.7 Directiva #pragma
Aceasta este o directiv definit prin varianta de implementare, care permite emiterea de
diverse instruciuni ctre compilator. De exemplu, un compilator poate avea o opiune care
s permit urmrirea execuiei programului. O asemenea opiune va fi specificat printr-o
instruciune #pragma. Pentru alte detalii i opiuni, urmrii manualul de utilizare al
compilatorului.
8.8 Operatorii de preprocesare # i ##
Exist doi operatori de preprocesare: diez (#) i diez dublu (##), care se folosesc cu
instruciunea #define
Operatorul #, n general numit de niruire (stringize), transform argumentul pe care l
precede ntr-un ir ncadrat ntre ghilimele. De exemplu, fie programul urmtor:
#include <stdio.h>
#define mkstr(s) # s

void main(void)
{ printf(mkstr(imi place C));}
Preprocesorul va transforma linia printf(mkstr(imi place C)); n printf("imi
place C");
Operatorul ##, denumit de lipire (pasting), concateneaz dou simboluri. De exemplu,
#include <stdio.h>
#define concat(a,b) a##b
void main(void)
{
int xy = 10; printf("%d", concat(x,y));
}
Preprocesorul transform linia printf("%d", concat(x,y)); n
printf("%d",xy);
Dac aceti operatori arat puin ciudat, gndii-v c nu sunt necesari i nici utilizai n
majoritatea programelor n C. Scopul lor principal este de a permite preprocesorului s
rezolve situaii speciale.
Preprocesorul

117
8.9 Nume predefinite de macrocomenzi
Standardul ANSI C definete cinci nume de macrocomenzi predefinite, ncorporate n
compilator. Acestea sunt
__LINE__, __FILE__, __DATE__, __TIME__, __STDC__
Fiecare cuvnt are nainte i dup liniu dubl de subliniere (underscore).
Dac dispunei de un compilator nestandard, acestuia i pot lipsi cteva sau toate aceste
macrocomenzi. De asemenea, compilatorul mai poate pune la dispoziie i alte
macrocomenzi predefinite. Macrocomenzile __LINE__ i __FILE__ au fost discutate n
paragraful referitor la directiva #line.
Macrocomanda __DATE__conine un ir de forma luna/zi/an. Acest ir reprezint data
conversiei fiierului surs n cod obiect.
Ora la care a fost executat aceast conversie este coninut sub form de ir __TIME__.
Forma irului este ora/minute/secunde.
Macrocomanda __STDC__ conine constanta 1 scris n baz 10. Aceasta semnific
faptul c implementarea este conform cu standardul ANSI C. Dac macrocomanda
conine un alt numr (sau nu este definit), implementarea nu este n variant standard.
8.10 Comentariile
n C, toate comentariile ncep cu perechea de caractere /* i se ncheie cu perechea */.
ntre asterisc i bara oblic nu trebuie s existe spaii. Compilatorul va ignora orice text
cuprins ntre simbolurile de nceput i de ncheiere ale unui comentariu. De exemplu, acest
program va afia pe ecran numai salut:
#include <stdio.h>
void main(void)
{
printf("salut");
/* printf("voios"); */
}
Comentariile pot fi plasate oriunde n program, dac nu intervin n mijlocul unui cuvnt-
cheie sau al unui identificator. Cu alte cuvinte, urmtorul comentariu este aezat corect:
x = 10+/*aduna numerele*/5;
n timp ce acesta
swi/*asta n-o sa mearg*/tch(c) { ...
este incorect, fiindc un cuvnt-cheie din C nu poate conine comentarii. n general ns,
nu este indicat s amplasai comentarii n mijlocul expresiilor, fiindc acestea i pierd din
claritate.
Comentariile nu pot fi imbricate. Adic un comentariu nu poate conine alt comentariu. De
exemplu, urmtorul fragment de cod determin o eroare la compilare:
/* Acesta este un comentariu exterior
x = y/a;
/* Acesta este un comentariu interior
care va determina o eroare */
*/
Comentariile pot fi incluse ori de cte ori este necesar explicarea operaiilor efectuate n
program. Orice funcie, n afar de cele evidente, trebuie s fie precedat de un
comentariu care s arate ce aciune efectueaz funcia, cum se numete i ce fel de
valoare returneaz.

Capitolul 8

118

Biblioteca standard

119
9. Biblioteca standard
Orice mediu de programare este prevzut cu una sau mai multe biblioteci de funcii
predefinite. Orice bibliotec este format din:
fiierele header (conine prototipurile funciilor, declaraiile de variabile);
biblioteca (arhiva) propriu-zis (conine definiii de funcii).

Funciile, tipurile de date i macrourile predefinite ale bibliotecii standard, sunt declarate n
fiiere header standard (orientate pe anumite numite tipuri de aplicaii):
<assert.h> <float.h> <math.h> <stdarg.h> <stdlib.h>
<ctype.h> <limits.h> <setjmp.h> <stddef.h> <string.h>
<errno.h> <locale.h> <signal.h> <stdio.h> <time.h>
Pentru ca funciile predefinite s poat fi utilizate, fiierele header n care se gsesc
prototipurile acestora trebuie incluse n funcia (programul) apelant printr-o directiv
preprocesor (exemplu #include <stdio.h>). De asemenea, utilizatorul i poate crea
propriile headere proprii. Pentru a putea utiliza funciile proprii, el trebuie s includ aceste
headere n programul apelant (exemplu #include "my_header.h").
9.1 Funcii de intrare/ieire: <stdio.h>
Limbajul C este practic unic n materie de abordare a operaiunilor de intrare/ieire
aceasta deoarece limbajul C nu definete cuvinte-cheie care efectueaz aceste operaii, ci
utilizeaz funcii din biblioteca standard. n continuare, pe parcursul crii, pentru expresia
intrare/ieire (In/Out) vom folosi prescurtarea uzual I/O.
n C, exist i operaii I/O pentru consol, i operaii I/O pentru fiier. Din punct de vedere
tehnic, C nu face prea mare deosebire ntre acestea. Totui, acestea sunt foarte diferite
conceptual i din acest motiv tratarea lor se va face n subcapitole separate. Funciile de
intrare/ieire au prototipurile n headerul <stdio.h>

n limbajul C, operaiile I/O se realizeaz cu ajutorul unor funcii din biblioteca standard
(stdio.h). Transferurile cu dispozitivele periferice (tastatur, monitor, disc, imprimant,
etc.) se fac prin intermediul unor dispozitive logice identice numite stream-uri (fluxuri) i
prin intermediul sistemului de operare. Un flux de date este un fiier sau un dispozitiv fizic
tratat printr-un pointer la o structur de tip FILE (din header-ul stdio.h). Cnd un
program este executat, n mod automat, se deschid urmtoarele fluxuri de date
predefinite, dispozitive logice (n stdio.h):
stdin (standard input device) - dispozitivul standard de intrare (tastatura) - ANSII C;
stdout (standard output device) - dispozitivul standard de ieire (monitorul) - ANSII C;
stderr (standard error output device) - dispozitivul standard de eroare (de obicei un
fiier care conine mesajele de eroare rezultate din execuia unor funcii) - ANSII C;
stdaux (standard auxiliary device) - dispozitivul standard auxiliar (de obicei interfaa
serial auxiliar) - specifice MS-DOS;
stdprn (standard printer) - dispozitivul de imprimare - specifice MS-DOS.

Fluxurile pot fi de tip text sau de tip binar. Fluxurile de tip text mpart fiierele n linii
separate prin caracterul \n (newline = linie nou), putnd fi citite ca orice fiier text.
Fluxurile de tip binar transfer blocuri de octei (fr nici o structur), neputnd fi citite
direct, ca fiierele text.

Capitolul 9

120
n abordarea limbajului C (impus de stdio.h), toate elementele care pot comunica
informaii cu un program sunt percepute - n mod unitar - ca fluxuri de date. Datele
introduse de la tastatur formeaz un fiier de intrare (fiierul standard de intrare).
Datele afiate pe monitor formeaz un fiier de ieire (fiierul standard de ieire).
Sfritul oricrui fiier este indicat printr-un marcaj de sfrit de fiier (end of file). n cazul
fiierului standard de intrare, sfritul de fiier se genereaz prin Ctrl+Z (^Z) (sub MS-
DOS) (sau Ctrl+D sub Linux). Acest caracter poate fi detectat prin folosirea constantei
simbolice EOF (definit n fiierul stdio.h), care are valoarea -1. Aceast valoare nu
rmne valabil pentru fiierele binare, care pot conine pe o poziie oarecare caracterul
\x1A.
De obicei, schimbul de informaii dintre programe i periferice se realizeaz folosind zone
tampon. O zon tampon pstreaz una sau mai multe nregistrri. Prin operaia de citire,
nregistrarea curent este transferat de pe suportul extern n zona tampon care i
corespunde, programul avnd apoi acces la elementele nregistrrii din zona tampon. n
cazul operaiei de scriere, nregistrarea se construiete n zona tampon, prin program,
fiind apoi transferat pe suportul extern al fiierului. n cazul monitoarelor, nregistrarea se
compune din caracterele unui rnd. De obicei, o zon tampon are lungimea multiplu de
512 octei. Orice fiier trebuie deschis nainte de a fi prelucrat, iar la terminarea prelucrrii
lui, trebuie nchis.
9.1.1 Operaii I/O pentru consol
9.1.1.1 Ieiri cu format
int printf(const char *sir_control, ... );
Funcia permite scrierea n fiierul standard de ieire (pe monitor) a datelor, ntr-un anumit
format. Funcia returneaz numrul de octei (caractere) afiai, sau -1 n cazul unei erori
i are dou tipuri de parametri:
1. Parametrul fix al funciei (const char *sir_control) conine:
Succesiuni de caractere afiate ca atare:
printf("\n Buna ziua!\n\n); // afiare: Buna ziua!
Specificatori de format care definesc conversiile care vor fi realizate asupra
datelor de ieire, din formatul intern, n cel extern (de afiare).
2. Parametrii variabili ai funciei (dac exist) sunt expresii. Valorile obinute n urma
evalurii acestora sunt afiate corespunztor specificatorilor de format care apar n
parametrul fix. De obicei, parametrul fix conine att specificatori de format, ct i alte
caractere. Numrul i tipul parametrilor variabili trebuie s corespund specificatorului
de format.
float x=1.2345;
printf("\n x= %7.3f,x);
// afiare numr real pe 7 poziii cu 3 zecimale: x= 1.235

Un specificator de format care apare n parametrul fix poate avea urmtoarea form:
% [-|0][spec_lat spec_prec] spec_form
Specificatorul de format (spec_form) este reprezentat de unul sau dou caractere care
definesc tipul conversiei aplicat datei afiate:
c - Afieaz un caracter
d sau i - Afieaz date ntregi; cele negative sunt precedate de semnul -.
e sau E - Afieaz date de tip float sau double n forma:
parte_ntreag.parte_fractionar exponent
Biblioteca standard

121
Exponentul ncepe cu e sau E i definete o putere a lui zece care nmulit cu
restul numrului d valoarea real a acestuia.
f - Afieaz date de tip float sau double n forma:
parte_ntreag.parte_fract
g sau G - Afieaz o dat real fie ca n cazul specificatorului terminat cu f, fie ca
n cazul specificatorului terminat cu e. Criteriul de afiare se alege automat, astfel
nct afiarea s ocupe un numr minim de poziii n cmpul de afiare.
h - Precede una din literele d, i, o, u, x, X. La afiare se fac conversii de tipul
short
l - Precede una din literele d, i, o, u, x, X. La afiare se fac conversii de tipul long.
L - Precede una din literele e, E, f, g, G. La afiare se fac conversii din tipul long
double.
n - Argumentul asociat este un pointer ntreg n care este plasat numrul de
caractere scrise pn n acel moment
o - Afieaz date de tip int sau unsigned int n octal.
p - Afieaz date de tip pointer
s - Afieaz un ir de caractere
u - Afieaz date ntregi fr semn
x sau X - Afieaz date de tip int sau unsigned int n hexazecimal.
% - Afieaz simbolul %
Specificatorul limii minime de cmp (spec_lat) este un numr prin care se insereaz
suficiente spaii n datele de ieire pentru a asigura o lungime de scriere minim. Dac
scrierea datei necesit un cmp de lungime mai mare, lungimea indicat n specificator
este ignorat. Dac scrierea datei necesit un cmp de lungime mai mic, data se va scrie
n cmp completndu-se restul cmpului cu caracterele nesemnificative implicite, adic
spaii; dac n loc de spaii dorim s folosim zerouri, atunci naintea specificatorului se
plaseaz cifra 0. Implicit, datele se aliniaz la dreapta cmpului n care se scriu. Prezena
caracterului "-" determin alinierea la stnga.
Specificatorul de precizie (spec_prec) urmeaz specificatorului limii minime de cmp
(dac acesta exist). Este alctuit dintr-un punct, urmat de un ntreg. Semnificaia sa
exact depinde de tipul de date cruia i se aplic.
Cnd specificatorul de precizie se aplic datelor n virgul mobil care folosesc
specificatorii %f, %e sau %E, atunci indic numrul de cifre care alctuiesc partea
zecimal. De exemplu, %10.4f afieaz un numr de cel puin 10 caractere, avnd patru
cifre dup virgul. Dac nu se indic precizia, se va folosi o valoare prestabilit egal cu 6.
Cnd specificatorul de precizie este aplicat formatelor %g sau %G, indic numrul de cifre
semnificative.
Dac se aplic la iruri, specificatorul de precizie indic dimensiunea maxim a cmpului.
De exemplu, %5.7s afieaz un ir care are cel puin 5 i cel mult 7 caractere lungime.
Dac irul este mai lung dect dimensiunea maxim, caracterele finale vor fi trunchiate.
Cnd se aplic ntregilor, specificatorul de precizie indic numrul minim de cifre care
apare pentru fiecare numr.

Funcia printf() accept doi modificatori suplimentari la civa dintre specificatorii si
de format, i anume * i #.
Dac # precede g, G, f, F, e sau E, se asigur existena unui punct zecimal, chiar dac nu
exist cifre dup virgul. Dac specificatorul de format x sau X este precedat de un #,
numrul hexazecimal va fi afiat cu un prefix 0x. Dac specificatorul o este precedat de un
#, numrul va fi afiat cu un 0 la nceput. Modificatorul # nu poate fi aplicat altor
specificatori de format.
Capitolul 9

122
n locul constantelor, specificatorii limii de cmp minime i de precizie pot fi indicai prin
argumente ale funciei printf(). Pentru a realiza acest lucru, folosii *. Cnd irul de
format este parcurs, printf() va identifica * cu un argument n ordinea n care survine.
Programul care urmeaz ofer un exemplu de utilizare pentru ambii modificatori: limea
minim de cmp este 10, precizia este 4 i valoarea de afiat este 123.34.
#include <stdio.h>
void main(void)
{
printf("%x %#x\n", 10, printf("%*.*f", 10, 4,10) ; 1234.34);
}
9.1.1.2 Intrri cu format
int scanf(const char *sir_control, ... );
Funcia citete din fiierul standard de intrare valorile unor variabile i le depune n
memorie, la adresele specificate. Funcia returneaz numrul cmpurilor citite corect, sau
EOF dac survine o eroare i are dou tipuri de parametri:
1. Parametrul fix al funciei conine:
Specificatorii de format care definesc conversiile aplicate datelor de intrare, din
formatul extern, n cel intern (n care sunt memorate). Specificatorii de format
sunt asemntori celor folosii de funcia printf: c, s, d, o, x sau X, u, f, l, L.
2. Parametrii variabili reprezint o list de adrese ale variabilelor care vor fi citite,
deci n aceast list, numele unei variabile simple va fi precedat de operatorul
adres &.
sir_control determin modul de citire a valorilor din variabilele ale cror pointeri se
afl n lista de argumente. irul de control const din trei categorii de caractere:
specificatori de format,
caractere spaiu,
caractere non-spaiu

Specificatorii de format de intrare sunt precedai de simbolul % i indic funciei
scanf() ce tip de date urmeaz a fi citit. Aceste coduri sunt asemntoare celor
folosite de funcia printf. Specificatorii de format corespund, de la stnga la
dreapta, cu argumentele din lista de argumente.

Funcia scanf() accept un specificator de format de uz general, denumit scanset. Un
scanset definete un set de caractere. Cnd scanf() proceseaz un scanset, va citi
caractere att timp ct acele caractere sunt parte ale setului definit de ctre scanset.
Caracterele citite vor fi atribuite tabloului de caractere indicat de argumentul corespunztor
al scansetului. Un scanset se definete introducnd caracterele respective ntre paranteze
ptrate precedate de simbolul %. De exemplu, scanset-ul %[XYZ]cere funciei scanf()
s citeasc numai caracterele X, Y i Z
La utilizarea unui scanset, scanf() va continua s citeasc caractere i s le insereze n
tabloul de caractere corespunztor, pn cnd ntlnete un caracter care nu se afl n
scanset. Dup executarea funciei scanf(), acest tablou va conine un ir ncheiat cu un
caracter nul, care const din caractere care au fost citite.

Se poate specifica un set inversat, dac primul caracter din set este un ^. Acesta cere
funciei scanf() s accepte orice caracter care nu este definit de scanset. Dac se
Biblioteca standard

123
folosete o cratim, se poate specifica un domeniu. De exemplu, instruciunea urmtoare
cere funciei scanf() s accepte toate caracterele de la A la Z: %[A-Z]
Este important de reinut c un scanset face diferena ntre litere mici i majuscule. Dac
dorii parcurgerea ambelor tipuri de litere, trebuie s le precizai individual.

Un caracter spaiu din irul de control determin funcia scanf() s omit alte
caractere asemntoare din fluxul de intrare. Un spaiu este fie un spaiu, un
tabulator, un tabulator vertical, un caracter de avans hrtie sau un delimitator de
linie nou. n esen, un caracter spaiu alb din irul de control determin scanf()
s citeasc, fr a stoca, orice numr (inclusiv zero) de caractere spaiu alb, pn
la ntlnirea unui caracter de alt tip.
Un caracter diferit de spaiu n irul de control determin scanf() s citeasc i s
omit caracterele corespunztoare din fluxul de intrare. De exemplu, "%d,%d"
determin scanf() s citeasc s citeasc un ntreg, s citeasc i s ignore o
virgul, i apoi s citeasc un alt ntreg. Dac respectivul caracter nu este gsit,
scanf() i nceteaz execuia. Dac dorii s fie citit i ignorat un simbol %, folosii
%% n tirul de control.
Se poate cere funciei scanf() s citeasc un cmp, dar s nu-i atribuie nici unei
variabile, insernd naintea codului de format un *. De exemplu, dac se d instruciunea
scanf("%d%*c%d", &x, &y);
se poate introduce perechea de coordonate 10, 10. Virgula va fi corect citit, dar nu va fi
atribuit nici unei variabile. Ignorarea unei atribuiri este adesea folosit cnd este
necesar prelucrarea doar a unei pri din datele de intrare.
int sprintf(char *sir_cu_format, const char *format, ... );
Funcia permite scrierea unor date n irul (tamponul) transmis ca prim argument, ntr-un
anumit format. Valoarea returnat reprezint numrul de octei (caractere) scrise n ir,
sau -1 n cazul unei erori.
Exemplu:
char sir[80]; int i;
sprintf(sir, "%s %d %c", "unu", 2, 3);// sir va conine unu 2 3
int sscanf(char *sir_cu_format, const char *format, ... );
Funcia citete valorile unor variabile din irul (tamponul) transmis ca prim argument i le
depune n memorie, la adresele specificate. Returneaz numrul cmpurilor citite corect.
Exemplu:
char sir[80]; int i;
sscanf("salut 1 2 3 4", "%s%d", sir, &i);
printf("%s %d", sir, i);// afieaz pe ecran salut 1
9.1.1.3 Funcii de intrare/ieire pentru caractere i iruri de caractere
int getchar(void);
Citete un caracter (cu ecou) din fiierul standard de intrare (tastatur). Dup cum i arat
i prototipul, funcia getchar() este declarat ca returnnd un ntreg. Totui, aceast
valoare se poate atribui unei variabile de tip char (dup cum, de altfel, se i procedeaz)
fiindc caracterul este coninut n octetul de ordin inferior. (De obicei, caracterul de ordin
superior este egal cu zero.) Dac survine o eroare, funcia getchar() returneaz EOF.
Capitolul 9

124
int putchar(int c);
Afieaz caracterul primit ca argument n fiierul standard de ieire (monitor). n cazul
funciei putchar(), chiar dac este declarat drept coninnd un parametru ntreg n
general se apeleaz folosind un argument de tip caracter. Numai octetul de ordin inferior
al parametrului este efectiv afiat pe ecran. Funcia putchar() returneaz caracterul
scris, sau EOF dac survine o eroare. (EOF este definit n fiierul stdio.h i este n
general egal cu -1.)
char *gets(char *sir);
Citete un ir de caractere din fiierul standard de intrare (pn la primul blank ntlnit sau
linie nou). Returneaz pointerul ctre irul citit.
int puts(const char *sir);
Afieaz irul argument n fiierul standard de ieire i adaug terminatorul de ir.
Returneaz codul ultimului caracter al irului (caracterul care precede NULL) sau -1 n caz
de eroare.
9.1.2 Operaii cu fiiere
9.1.2.1 Caracteristicile generale ale fiierelor
Noiunea de fiier desemneaz o colecie de informaii memorat pe un suport
permanent (de obicei discuri magnetice), perceput ca un ansamblu, creia i se
asociaz un nume (n vederea conservrii i regsirii ulterioare).

Caracteristicile unui fiier (sub sistem de operare MS-DOS) sunt:
Dispozitivul logic de memorare (discul);
Calea (n structura de directoare) unde este memorat fiierul;
Numele i extensia;
Atributele care determin operaiile care pot fi efectuate asupra fiierului (de exemplu:
R - read-only - citire; W - write-only scriere; RW - read-write citire/scriere; H - hidden -
nu se permite nici mcar vizualizarea; S - system - fiiere sistem asupra crora numai
sistemul de operare poate realiza operaii operaii, etc.).

Lucrul cu fiiere n programare ofer urmtoarele avantaje:
Prelucrarea de unei cantiti mari de informaie obinut din diverse surse cum ar fi
execuia prealabil a unui alt program;
Stocarea temporar pe suport permanent a informaiei n timpul execuiei unui program
pentru a evita suprancrcarea memoriei de lucru;
Prelucrarea aceleiai colecii de informaii prin mai multe programe.
Prelucrarea fiierelor se poate face la dou niveluri:
Nivelul superior de prelucrare a fiierelor n care se utilizeaz funciile specializate n
prelucrarea fiierelor.
Nivelul inferior de prelucrare a fiierelor n care se utilizeaz direct facilitile oferite de
sistemul de operare, deoarece, n final, sarcina manipulrii fiierelor revine sistemului
de operare. Pentru a avea acces la informaiile despre fiierele cu care lucreaz,
sistemul de operare folosete cte un descriptor (bloc de control) pentru fiecare fiier.
Ca urmare, exist dou abordri n privina lucrului cu fiiere:
abordarea implementat n stdio.h, asociaz referinei la un fiier un stream (flux de
Biblioteca standard

125
date), un pointer ctre o structur FILE.
abordarea definit n header-ul io.h (input/output header) asociaz referinei la un fiier
un aa-numit handle (indicator de fiier) care, din punct de vedere al tipului de date,
este in;

Scopul lucrului cu fiiere este acela de a prelucra informaia coninut. Pentru a putea
accesa un fiier va trebui s-l asociem cu unul din cele dou modaliti de manipulare.
Acest tip de operaie se mai numete deschidere de fiier. nainte de a citi sau scrie ntr-un
fiier (neconectat automat programului), fiierul trebuie deschis cu ajutorul funciei fopen
din biblioteca standard. Funcia primete ca argument numele extern al fiierului,
negociaz cu sistemul de operare i returneaz un nume (identificator) intern care va fi
utilizat ulterior la prelucrarea fiierului. Acest identificator intern este un pointer la o
structur care conine informaii despre fiier (poziia curent n buffer, dac se citete sau
se scrie n fiier, etc.). Utilizatorii nu trebuie s cunoasc detaliile, singura declaraie
necesar fiind cea pentru pointerul de fiier.
Exemplu: FILE *fp;

Operaiile care pot fi realizate asupra fiierelor sunt: deschiderea unui fiier, scrierea ntr-
un fiier, citirea dintr-un fiier, poziionarea ntr-un fiier i nchiderea unui fiier.
9.1.2.2 Deschiderea unui fiier
FILE *fopen(const char *nume_fiier, const char *mod);
Creeaz un flux de date ntre fiierul specificat prin numele extern (nume_fiier) i
programul C. Parametrul mod specific sensul fluxului de date i modul de interpretare a
acestora. Funcia returneaz un pointer spre tipul FILE, iar n caz de eroare - pointerul
NULL (prototip n stdio.h).
Parametrul mod este o constant ir de caractere, care poate conine caracterele cu
semnificaiile:
r: flux de date de intrare; deschidere pentru citire;
w: flux de date de ieire; deschidere pentru scriere (creeaz un fiier nou sau
suprascrie coninutul anterior al fiierului existent);
a: flux de date de ieire cu scriere la sfritul fiierului, adugare, sau crearea
fiierului n cazul n care acesta nu exist;
+: extinde un flux de intrare sau ieire la unul de intrare/ieire; operaii de scriere i
citire asupra unui fiier deschis n condiiile r, w sau a.
b: date binare;
t: date text (modul implicit).
Exemple:
"r+" - deschidere pentru modificare (citire i scriere);
"w+" - deschidere pentru modificare (citire i scriere);
"rb" - citire binar;
"wb" - scriere binar;
"r+b" - citire/scriere binar.
FILE *freopen(const char *nume_fi,const char*mod,FILE
*flux_date);
Asociaz un nou fiier unui flux de date deja existent, nchiznd legtura cu vechiul fiier i
ncercnd s deschid una nou, cu fiierul specificat. Funcia returneaz pointerul ctre
fluxul de date specificat, sau NULL n caz de eec (prototip n stdio.h).
Capitolul 9

126
int open(const char *nume_fiier, int acces [,int mod]);
Deschide fiierul specificat conform cu restriciile de acces precizate n apel. Returneaz
un ntreg care este un indicator de fiier sau -1 (n caz de eec) (prototip n io.h).
Restriciile de acces se precizeaz prin aplicarea operatorului | (disjuncie logic la nivel
de bit) ntre anumite constante simbolice, definite n fcntl.h, cum sunt:
O_RDONLY - citire O_WRONLY - scriere
O_RDWR - citire i scriere O_CREAT - creare
O_APPEND - adugare la sfritul fiierului
O_TEXT - interpretare CR-LF O_BINARY - nici o interpretare.,
Restriciile de mod de creare se realizeaz cu ajutorul constantelor:
S_IREAD - permisiune de citire din fiier
S_IWRITE - permisiune de scriere din fiier, eventual legate prin operatorul |.
int creat(const char *nume_fiier, int un_mod);
Creeaz un fiier nou sau l suprascrie n cazul n care deja exist. Returneaz indicatorul
de fiier sau -1 (n caz de eec). Parametrul un_mod este obinut n mod analog celui de la
funcia de deschidere (prototip n io.h).
int creatnew(const char *nume_fiier, int mod);
Creeaz un fiier nou, conform modului specificat. Returneaz indicatorul fiierului nou
creat sau rezultat de eroare (-1), dac fiierul deja exist (prototip n io.h).
Dup cum se observ, informaia furnizat pentru deschiderea unui fiier este aceeai n
ambele abordri, diferena constnd n tipul de date al entitii asociate fiierului.
Implementarea din io.h ofer un alt tip de control la nivelul comunicrii cu echipamentele
periferice (furnizat de funcia ioctrl), asupra cruia nu vom insista, deoarece
desfurarea acestui tip de control este mai greoaie, dar mai profund.
9.1.2.3 nchiderea unui fiier
int fclose(FILE *pf);
Funcia nchide un fiier deschis cu fopen i elibereaz memoria alocat (zona tampon i
structura FILE). Returneaz valoarea 0 la nchiderea cu succes a fiierului i -1 n caz de
eroare (prototip n stdio.h).
int fcloseall(void);
nchide toate fluxurile de date i returneaz numrul fluxurilor de date nchise (prototip n
stdio.h).
int close(int indicator);
nchide un indicator de fiier i returneaz 0 (n caz de succes) sau -1 n caz de eroare
(prototip n io.h).
9.1.2.4 Prelucrarea fiierelor text
Dup deschiderea unui fiier, toate operaiile asupra fiierului vor fi efectuate cu pointerul
su. Operaiile de citire i scriere ntr-un fiier text pot fi: la nivel de caracter (de octet), la
nivel de cuvnt (2 octei), la nivel de iruri de caractere, i cu formatare.

Comunicarea de informaie de la un fiier ctre un program este asigurat prin funcii de
citire care transfer o cantitate de octei (unitatea de msur n cazul nostru) din fiier
ntr-o variabil-program pe care o vom numi buffer, ea nsi avnd sensul unei niruiri
Biblioteca standard

127
de octei prin declaraia void *buf. Comunicarea de informaie de la un program ctre
un fiier este asigurat prin funcii de scriere care transfer o cantitate de octei dintr-o
variabil-program de tip buffer n fiier.

Fiierele sunt percepute n limbajul C ca fiind, implicit, secveniale (informaia este
parcurs succesiv, element cu element). Pentru aceasta, att fluxurile de date ct i
indicatorii de fiier au asociat un indicator de poziie curent n cadrul fiierului. Acesta
este iniializat la 0 n momentul deschiderii, iar operaiile de citire, respectiv scriere, se
refer la succesiunea de octei care ncepe cu poziia curent. Operarea asupra fiecrui
octet din succesiune determin incrementarea indicatorului de poziie curent.
9.1.2.4.1 Prelucrarea unui fiier la nivel de caracter
Fiierele pot fi scrise i citite caracter cu caracter folosind funciile putc (pentru scriere) i
getc (citire).
int putc(int c, FILE *pf);
c - este codul ASCII al caracterului care se scrie n fiier;
pf - este pointerul spre tipul FILE a crui valoare a fost returnat de funcia fopen.
Funcia putc returneaz valoarea lui c (valoarea scris n caz de succes), sau -1 (EOF) n
caz de eroare sau sfrit de fiier.
int getc(FILE *pf);
Funcia citete un caracter dintr-un fiier (pointerul spre tipul FILE transmis ca argument)
i returneaz caracterul citit sau EOF la sfrit de fiier sau eroare.

Exemplul 9.1: S se scrie un program care creeaz un fiier text n care se vor scrie
caracterele introduse de la tastatur (citite din fiierul standard de intrare), pn la
ntlnirea caracterului ^Z = Ctrl+Z.
#include <stdio.h>
#include <process.h>
void main()
{
int c, i=0; FILE *pfcar;
char mesaj[]="\nIntrodu caractere urmate de Ctrl+Z (Ctrl+D sub
Linux):\n";
char eroare[]="\n Eroare deschidere fiier \n";
while(mesaj[i]) putchar(mesaj[i++]);
pfcar=fopen("f_car1.txt","w"); // crearea fiierului cu numele extern
f_car1.txt
if(pfcar==NULL)
{
i=0;
while(eroare[i])putc(eroare[i++],stdout);
exit(1);
}while((c=getchar())!=EOF) // sau: while ((c=getc(stdin)) !=
EOF)
putc(c,pfcar); // scrierea caracterului n fiier
fclose(pfcar); // nchiderea fiierului
}
Exemplul 9.2: S se scrie un program care citete un fiier text, caracter cu caracter, i
afieaz coninutul acestuia.
Capitolul 9

128
#include <stdio.h>
#include <process.h>
void main()
{
int c, i=0;
FILE *pfcar;
char eroare[]="\n Eroare deschidere fiier \n";
pfcar=fopen("f_car1.txt","r"); //deschiderea fiierului numit f_car1.txt n
citire
if(pfcar==NULL)
{
i=0;
while(eroare[i]) putc(eroare[i++],stdout);
exit(1);
}
while((c=getc(pfcar))!=EOF) //citire din fiier, la nivel de
caracter
putc(c,stdout);
//scrierea caracterului citit n fisierul standard de ieire (afiare pe monitor)
fclose(pfcar);
}
9.1.2.4.2 Prelucrarea unui fiier la nivel de cuvnt
Funciile putw i getw (putword i getword) sunt echivalente cu funciile putc i getc,
cu diferena c unitatea transferat nu este un singur octet (caracter), ci un cuvnt (un int).
int getw(FILE *pf);
int putw(int w, FILE *pf);
Se recomand utilizarea funciei feof pentru a testa ntlnirea sfritului de fiier.
Exemplul 9.3
int tab[100];
FILE *pf;
// . . . deschidere fiier
while (!feof(pf)){
for (int i=0; i<100; i++){
if (feof(pf)) break;
tab[i]=getw(pf);
//citire din fiier la nivel de cuvnt i memorare n vectorul tab
// . . .
}
}
printf("Sfarit de fiier\n");
9.1.2.4.3 Prelucrarea unui fiier la nivel de ir de caractere
ntr-un fiier text, liniile sunt considerate ca linii de text separate de sfritul de linie
('\n'), iar n memorie, ele devin iruri de caractere terminate de caracterul nul ('\0').
Citirea unei linii de text dintr-un fiier se realizeaz cu ajutorul funciei fgets, iar scrierea
ntr-un fiier - cu ajutorul funciei fputs.
int fputs(const char *s, FILE *pf);
Biblioteca standard

129
Funcia scrie un ir de caractere ntr-un fiier i primete ca argumente pointerul spre zona
de memorie (buffer-ul) care conine irul de caractere (s) i pointerul spre structura FILE.
Funcia returneaz ultimul caracter scris, n caz de succes, sau -1 n caz de eroare.
char *fgets(char *s, int dim, FILE *pf);
Funcia citete maximum dim-1 octei (caractere) din fiier, sau pn la ntlnirea
sfaritului de linie. Pointerul spre zona n care se face citirea caracterelor este s.
Terminatorul null ('\0') este plasat automat la sfritul irului (buffer-lui de memorie).
Funcia returneaz un pointer ctre buffer-ul n care este memorat irul de caractere, n
caz de succes, sau pointerul NULL n cazul eecului.

Exemplul 9.4 S se scrie un program care creeaz un fiier text n care se vor scrie
irurile de caractere introduse de la tastatur.
#include <stdio.h>
void main()
{
int n=250; FILE *pfsir;
char mesaj[]="\nIntrodu siruri car.urmate de Ctrl+Z (Ctrl+D sub
Linux):\n";
char sir[250],*psir; fputs(mesaj,stdout);
pfsir=fopen("f_sir.txt","w"); //deschiderea fiierului f_ir.txt pentru scriere
psir=fgets(sir,n,stdin); // citirea irurilor din fiierul standard de intrare
while(psir!=NULL)
{
fputs(sir,pfsir); // scrierea n fiierul text
psir=fgets(sir,n,stdin);
}
fclose(pfsir);
}
Exemplul 9.5 S se scrie un program care citete un fiier text, linie cu linie, i afieaz
coninutul acestuia
#include <stdio.h>
void main()
{
int n=250; FILE *pfsir; char sir[250],*psir;
pfsir=fopen("f_sir.txt","r"); psir=fgets(sir,n,pfsir);
while(psir!=NULL)
{
fputs(sir,stdout); //sau: puts(sir);
//afiarea (scrierea n fiierul standard de ieire) irului (liniei) citit din fiierul text
psir=fgets(sir,n,pfsir); //citirea unei linii de text din fiier
}
fclose(pfsir);}
9.1.2.4.4 Intrri/ieiri formatate
Operaiile de intrare/ieire formatate permit citirea, respectiv scrierea ntr-un fiier text,
impunnd un anumit format. Se utilizeaz funciile fscanf i fprintf, similare funciilor
scanf i printf (care permit citirea/scrierea formatat de la tastatur/monitor).
int fscanf(FILE *pf, const char *format, . . .);
int fprintf(FILE *pf, const char *format, . . .);
Capitolul 9

130
Funciile primesc ca parametri fici pointerul (pf) spre tipul FILE (cu valoarea atribuit la
apelul funciei fopen), i specificatorul de format (cu structur identic celui prezentat
pentru funciile printf i scanf). Funciile returneaz numrul cmpurilor citite/scrise n
fiier, sau -1 (EOF) n cazul detectrii sfritului fiierului sau al unei erori.
9.1.2.5 Intrri/ieiri binare
Reamintim c fluxurile de tip binar transfer blocuri de octei (fr nici o structur),
neputnd fi citite direct, ca fiierele text. Comunicarea de informaie dintre un program i
un fiier este asigurat prin funcii de citire/scriere care transfer un numr de octei, prin
intermediul unui buffer.
9.1.2.5.1 Funciile de citire
size_t fread(void *buf, size_t dim, size_t n, FILE *flux_date);
Citete date dintr-un flux, sub forma a n blocuri (entiti), fiecare bloc avnd dimensiunea
dim, ntr-un buffer (buf). Returneaz numrul de blocuri citite efectiv, sau -1 n caz de
eroare (prototip n stdio.h).
int read(int indicator, void *buf, unsigned n);
Citete dintr-un fiier (precizat prin indicatorul su, indicator) un numr de n octei i i
memoreaz n bufferul buf. Funcia returneaz numrul de octei citii efectiv (pentru
fiierele deschise n mod text nu se numr simbolurile de sfirit de linie), sau -1 n caz de
eroare (prototip n io.h).
9.1.2.5.2 Funciile de scriere
Fiierele organizate ca date binare pot fi prelucrate cu ajutorul funciilor fread i fwrite.
n acest caz, se consider c nregistrarea este o colecie de date structurate numite
articole. La o citire se transfer ntr-o zon special, numit zona tampon, un numr de
articole care se presupune c au o lungime fix.
size_t fwrite(const void *buf, size_t dim, size_t n, FILE
*flx_date);
Scrie informaia (preluat din buffer, buf este pointerul spre zona tampon care conine
articolele citite) ntr-un flux de date, sub forma a n entiti de dimensiune dim. Returneaz
numrul de entiti scrise efectiv, sau -1 n caz de eroare (prototip n stdio.h).
int write(int indicator, void *buf, unsigned n);
Scrie ntr-un fiier (desemnat prin indicatorul su, indicator) un numr de n octei
preluai dintr-un buffer (buf este pointerul spre acesta). Returneaz numrul de octei
scrii efectiv sau -1 n caz de eroare (prototip n io.h).

Exemplul 9.6 S se scrie un program care creeaz un fiier binar n care se vor introduce
numere reale, nenule.
#include <iostream.h>
#include <stdio.h>
int main()
{ FILE *f; double nr; int x;
if((f=fopen("test_nrb.dat", "wb")) == NULL) //deschidere flux binar,
scriere
{cout<<"\nNu se poate deschide fiierul test_nrb.dat"<<'\n';
Biblioteca standard

131
return 1;
}
cout<<"\nIntroducei numere(diferite de 0) terminate cu un
0:"<<'\n';
cin>>nr;
while(nr!=0)
{x=fwrite(&nr, sizeof(nr), 1, f); //scriere n fiier
cin>>nr; }
fclose(f);
return 0;
}
Ex ram ce citete dintr-un fiier binar numere reale, nenule. emplul 9.7 S se scrie un prog
#include <iostream.h>
#include <stdio.h>
int main()
{ FILE *f; double buf;
if ((f= fopen("test_nrb.dat", "rb")) == NULL)
{
cout<<"\nNu se poate deschide fiierul test_nrb.dat"<<'\n';
return 1;
}
cout<<"\nNumerele nenule citite din fiier sunt:"<<'\n';
while((fread(&buf, sizeof(buf), 1, f))==1)
// funcia sizeof(buf) care returneaza numarul de octei necesari variabilei buf.
cout<<buf<<" ";
fclose(f);
cout<<'\n';
return 0;
}
9.1.2.6 Poziionarea ntr-un fiier
Pe lng mecanismul de poziionare implicit (asigurat prin operaiile de citire i scriere) se
pot folosi i operaiile de poziionare explicit.
int fseek(FILE *pf, long deplasament, int referina);
Funcia deplaseaz capul de citire/scriere al discului, n vederea prelucrrii nregistrrilor
fiierului ntr-o ordine oarecare. Funcia seteaz poziia curent n fluxul de date la n octei
fa de referin): deplasament - definete numrul de octei peste care se va
avea una din valorile: deplasa capul discului; referina - poate
0 - nceputul fiierului (SEEK_SET);
_CUR); 1 - poziia curent a capului (SEEK
2 - sfritul fiierului (SEEK_END).
Funcia returneaz valoarea zero la poziionarea corect i o valoare diferit de zero n
caz de eroare (prototip n stdio.h).
int lseek(int indicator, long n, int referinta);
Seteaza poziia curent de citire/scriere n fiier la n octei fa de referin.
Returneaz valoarea 0 n caz de succes i diferit de zero n caz de eroare (prototip n
io.h).
int fgetpos(FILE *flux_date, fpos_t *poziie);
Capitolul 9

132
Determin poziia curent (pointer ctre o structur, fpos_t, care descrie aceast poziie
n fluxul de date). nscrie valoarea indicatorului n variabila indicat de poziie.
Returneaz 0 la determinarea cu succes a acestei poziii sau valoare diferit de zero n
caz de eec. Structura care descrie poziia poate fi transmis ca argument funciei
fsetpos (prototip n stdio.h).
int fsetpos(FILE *flux_date, const fpos_t *poziie);
Seteaz poziia curent n fluxul de date (atribuie indicatorului valoarea variabilei indicate
poziie), la o valoare obinut printr apelul funciei fgetpos. Returneaz valoarea 0 n
caz de succes, sau diferit de 0 n caz de eec (prototip n stdio.h).

Exist funcii pentru modificarea valorii indicatorului de poziie i de determinare a poziiei
curente a acestuia:
long ftell(FILE *pf);
Indic poziia curent a capului de citire n fiier. Funcia returneaz o valoare de tip long
int care reprezint poziia curent n fluxul de date (deplasamentul n octei a poziiei
capului fa de nceputul fiierului) sau -1L n caz de eroare (prototip n stdio.h).
long tell(int indicator);
Returneaz poziia curent a capului de citire/scriere n fiier (exprimat n numr de octei
fa de nceputul fiierului), sau -1 n caz de eroare (prototip n io.h).
void rewind(FILE *flux_date);
Poziioneaz indicatorul la nceputul fluxului de date specificat ca argument (prototip n
stdio.h).
9.1.2.7 Funcii utilitare pentru lucrul cu fiiere
Funcii de eroare
void clearerr(FILE *flux_date);
Funcia clearerr terge indicatorii de sfrit de fiier i eroare ai fluxului.
int ferror(FILE *flux_date);
Funcia ferror testeaz indicatorul de eroare al fluxului, i returneaz non-zero dac
este setat. Acesta este setat dac o operaie de citire sau scriere a detectat o eroare
(datorat de exemplu hardware-ului). Funciile de citire (cu sau fr format) nu fac
distincie ntre sfrit de fiier i eroare, astfel c trebuie apelate funciile feof i ferror
pentru a determina cauza.
void perror(const char *sir)
Funcia perror() mapeaz valoarea variabilei globale errno ntr-un fiier i scrie acel
ir n stderr. Dac valoarea lui ir nu este nul, irul respectiv este scris primul, urmat de
punct i virgul i de mesajul de eroare definit prin varianta de implementare.
Funcii de testare a sfritului de fiier
int feof(FILE *flux_date);
Returneaz o valoare diferit de zero n cazul ntlnirii sfritului de fiier sau 0 n celelalte
cazuri (prototip n stdio.h).
Biblioteca standard

133
int eof(int indicator);
Returneaz valoarea 1 dac poziia curent este sfritul de fiier, 0 dac indicatorul este
poziionat n alt parte, sau -1 n caz de eroare (prototip n io.h).

Funcii de golire a fluxurilor de date
int fflush(FILE *flux_date);
Golete un fluxul de date specificat ca argument. Returneaz 0 n caz de succes i -1
(EOF) n caz de eroare (prototip n stdio.h).
int flushall(void);
Golete toate fluxurile de date existente, pentru cele de scriere efectund i scrierea n
fiiere. Returneaz numrul de fluxuri asupra crora s-a efectuat operaia (prototip n
stdio.h).
9.1.2.8 Alte operaii cu fiiere
9.1.2.8.1 Funcii care permit operaii ale sistemului de operare asupra fiierelor
int remove(const char *nume_fiier);
terge un fiier. Returneaz valoarea 0 pentru operaie reuit i -1 pentru operaie euat
(prototip n stdio.h).
int rename(const char *nume_vechi, const char *nume_nou);
Redenumete un fiier. Returneaz 0 pentru operaie reuita i -1 n cazul eecului
(prototip n stdio.h).
int unlink(const char *nume_fiier);
terge un fiier. Returneaz 0 la operaie reuit i -1 la eec; dac fiierul are permisiune
read-only, funcia nu va reui operaia (prototip n io.h, stdio.h).
9.1.2.8.2 Funcii care permit manipularea aceluiai fiier prin dou indicatoare de fiier
independente
int dup(int indicator);
Duplic un indicator de fiier. Returneaz noul indicator de fiier pentru operaie reuit
sau -1 n cazul eecului (prototip n io.h).
int dup2(int indicator_vechi, int indicator_nou);
Duplic un indicator de fiier la valoarea unui indicator de fiier deja existent. Returneaz
0 n caz de succes i -1 n caz de eec (prototip n io.h).
9.1.2.8.3 Funcii pentru aflarea sau modificarea dimensiunii n octei a fiierelor
int chsize(int indicator, long lungime);
Modific dimensiunea unui fiier, conform argumentului lungime. Returneaz 0 pentru
operaie reuit sau -1 n caz de eec (prototip n stdio.h).
long filelength(int indicator);
Returneaz lungimea unui fiier (n octei) sau -1 n caz de eroare (prototip n io.h).
Capitolul 9

134
9.1.2.8.4 Funcii de lucru cu fiiere temporare
Acestea ofer faciliti de lucru cu fiiere temporare prin generarea de nume unice de fiier
n zona de lucru.
FILE *tmpfile(void);
Deschide un fiier temporar, ca flux de date, n mod binar (w+b). Returneaz pointerul
ctre fiierul deschis n cazul operaiei reuite, sau NULL n caz de eec (prototip n
stdio.h).
char *tmpnam(char *sptr);
Creeaz un nume unic pentru fiierul temporar (prototip n stdio.h).
int creattemp(char *cale, int attrib);
Creeaz un fiier unic ca nume, cu atributele specificate n argumentul attrib (prin
_fmode,O_TEXT sau O_BINARY), n directorul dat n argumentul cale. Returneaz
indicatorul (handler-ul) ctre fiierul creat sau -1 (i setarea errno) n cazul eecului
(prototip n io.h).

9.2 Funcii pentru caractere i iruri de caractere
9.2.1 Funcii de testare i conversie a caracterelor: <ctype.h>
Au prototipul n headerul <ctype.h>. Toate aceste funcii primesc ca argument un
caracter i returneaz un numr ntreg care este pozitiv dac argumentul ndeplinete o
anumit condiie, sau valoarea zero dac argumentul nu ndeplinete condiia.
int isalnum(int c);
Returneaz valoare ntreag pozitiv dac argumentul este liter sau cifr. Echivalent cu:
isalpha(c)||isdigit(c)
int isalpha(int c);
Testeaz dac argumentul este liter mare sau mic. Echivalent cu isupper(c)||
islower(c).
int iscntrl(int c);
Testeaz dac argumentul este caracter de control (neimprimabil).
int isdigit(int c);
Testeaz dac argumentul este cifr.
int isgraph(int c);
Testeaz dac argumentul este caracter imprimabil, cu excepia spaiului.
int islower(int c);
Testeaz dac argumentul este liter mic.
int isprint(int c);
Testeaz dac argumentul este caracter imprimabil, inclusiv blancul.
Biblioteca standard

135
int ispunct(int c);
Testeaz dac argumentul este caracter de punctuaie (caracter imprimabil, dar nu liter
sau spaiu).
int isspace(int c);
Testeaz dac argumentul este spaiu alb (' ', '\n', '\t', '\v', '\r')
int isupper(int c);
Testeaz dac argumentul este liter mare.
int isxdigit(int c);
Testeaz dac argumentul este cifr hexazecimal (0-9, a-f, A-F).
int tolower(int c);
Funcia schimb caracterul primit ca argument din liter mare, n liter mic i returneaz
codul ASCII al literei mici. Dac argumentul nu este liter mare, codul returnat este chiar
codul argumentului.
int toupper(int c);
Funcia schimb caracterul primit ca argument din liter mic, n liter mare i returneaz
codul acesteia. Dac argumentul nu este liter mic, codul returnat este chiar codul
argumentului.
9.2.2 Funcii pentru iruri de caractere: <string.h>
Funciile pentru operaii cu iruri se gsesc n header-ul <string.h>. n acesta este
definit tipul size_t care reprezint o varietate de ntreg fr semn.
char *strcpy(ir_destinaie, ir_surs)
Funcia copie irul surs n irul destinaie. Pentru a fi posibil copierea, lungimea irului
destinaie trebuie s fie mai mare sau egal cu cea a irului surs, altfel pot apare erori
grave.
char *strcat(ir_destinaie, const ir_surs)
Funcia concateneaz cele dou iruri: irul surs este adugat la sfritul irului
destinaie. Tabloul care conine irul destinaie trebuie s aib suficiente elemente.
int strcmp(const ir_1, const ir_2);
Funcia compar cele dou iruri date ca argument i returneaz o valoare ntreag egal
diferena dintre codurile ASCII ale primelor caractere care nu coincid.
char *strstr(const ir_1, const ir_2)Funcia returneaz un pointer al
primei apariii a lui ir_2 n ir_1. Dac nu este gsit nici o coinciden, se returneaz
un pointer nul.
size_t strlen(const nume_ir)
Returneaz un numr ntreg ce reprezint lungimea unui ir de caractere, fr a numra
terminatorul de ir.
Capitolul 9

136
9.3 Funcii matematice: <math.h>
Standardul ANSI C definete 22 de funcii matematice printre care:
9.3.1 Funcii aritmetice
9.3.1.1 Valori absolute
int abs(int x);
Returneaz un ntreg care reprezint valoarea absolut a argumentului.
long int labs(long int x);
Analog cu funcia abs, cu deosebirea c argumentul i valoarea returnat sunt de tip long
int.
double fabs(double x);
Returneaz un real care reprezint valoarea absolut a argumentului real.
9.3.1.2 Funcii de rotunjire
double floor(double x);
Returneaz un real care reprezint cel mai apropiat numr, fr zecimale, mai mic sau
egal cu x (rotunjire prin lips).
double ceil(double x);
Returneaz un real care reprezint cel mai apropiat numr, fr zecimale, mai mare sau
egal cu x (rotunjire prin adaos).
9.3.2 Funcii trigonometrice directe i inverse
double sin(double x);
Returneaz valoarea lui sin(x), unde x este dat n radiani. Numrul real returnat se afl n
intervalul [-1, 1].
double cos(double x);
Returneaz valoarea lui cos(x), unde x este dat n radiani. Numrul real returnat se afl n
intervalul [-1, 1].
double tan(double x);
Returneaz valoarea lui tg(x), unde x este dat n radiani.
double asin(double x);
Returneaz valoarea lui arcsin(x), unde x se afl n intervalul [-1, 1]. Numrul real returnat
(n radiani) se afl n intervalul [-/2, /2].
double acos(double x);
Returneaz valoarea lui arccos(x), unde x se afl n intervalul [-1, 1]. Numrul real returnat
se afl n intervalul [0, ].
double atan(double x);
Biblioteca standard

137
Returneaz valoarea lui arctg(x), unde x este dat n radiani. Numrul real returnat se afl
n intervalul [0, ].
double atan2(double y, double x);
Returneaz valoarea lui tg(y/x), cu excepia faptului ca semnele argumentelor x i y permit
stabilirea cadranului i x poate fi zero. Valoarea returnat se afl n intervalul [-,]. Dac x
i y sunt coordonatele unui punct n plan, funcia returneaz valoarea unghiului format de
dreapta care unete originea axelor carteziene cu punctul, fa de axa absciselor. Funcia
folosete, de asemenea, la transformarea coordonatelor carteziene n coordonate polare.
9.3.3 Funcii exponeniale i logaritmice
double exp(double x);
Returneaz valoarea e
x
.
double log(double x);
Returneaz logaritmul natural al argumentului ( ln(x) ).
double log10(double x);
Returneaz logaritmul zecimal al argumentului (lg (x) ).
double pow(double baza, double exponent);
Returneaz un real care reprezint rezultatul ridicrii bazei la exponent (baza
exponent
).
double sqrt(double x);
Returneaz rdcina ptrat a argumentului

x .
double hypot(double x, double y);
Funcia distanei euclidiene - returneaz x
2
+ y
2
, deci lungimea ipotenuzei unui triunghi
dreptunghic, sau distana punctului P(x, y) fa de origine.
9.4 Funcii utilitare: <stdlib.h>
Header-ul <stdlib.h> definete funcii pentru conversia numerelor, alocarea memoriei i
alte sarcini similare.
double atof (const char *s);
int atoi(const char *s);
long atol(const char *s)
Transform irul s n double, int respectiv long.
int rand(void);
Genereaz un numr aleator n intervalul [0, RAND_MAX].
void exit(int status);
Termin execuia unui program. Codul returnat de terminarea corect este memorat n
constanta simbolic EXIT_SUCCES, iar codul de eroare - n EXIT_FAILURE.
void abort();
Capitolul 9

138
Termin forat execuia unui program.
int system(const char *comanda);
Permite execuia unei comenzi DOS, specificate prin irul de caractere transmis ca
parametru.
9.5 Operaii cu directoare
Funciile de parcurgere a cataloagelor de fiiere descrise n aceast seciune (opendir,
readdir, closedir) sunt definite de mai multe medii de programare C (Borland,
Watcom, Visual C, GNU Linux), precum i de standardul POSIX. Aceste funcii sunt
descrise n <dirent.h>.
DIR *opendir(const char *nume);
Funcia opendir deschide un flux pentru directorul cu numele nume, i returneaz un
pointer la fluxul deschis. Fluxul este poziionat pe prima intrare din director. Funcia
returneaz un pointer la flux n caz de succes, sau NULL n caz de eroare i variabila
global errno indic codul erorii. Cteva erori posibile
EACCES Acces interzis
ENOTDIR nume nu este un director
struct dirent *readdir(DIR *dir);
Funcia readdir returneaz un pointer la o structur de tip dirent care reprezint
urmtoarea intrare din directorul indicat de fluxul dir. Returneaz NULL dac s-a depistat
sfritul de director sau dac a aprut o eroare. Structura de tip dirent conine un cmp
char d_name[]. Utilizarea altor cmpuri din structur reduce portabilitatea programelor.
Funcia returneaz un pointer la o structur de tip dirent, sau NULL dac s-a depistat
sfritul de director sau dac a aprut o eroare.
int closedir(DIR *dir);
Funcia closedir nchide fluxul dir. Funcia returneaz 0 n caz de succes sau EOF n
caz de eroare.
9.6 Funcii pentru dat i or: <time.h>
Headerul <time.h> declar tipuri i funcii pentru manipularea datei i timpului. Anumite
funcii prelucreaz timpul local, care poate diferi fa de timpul calendaristic, de exemplu
datorit of fusului orar. clock_t i time_t sunt tipuri aritmetice care reprezint timpi, iar
struct tm memoreaz data i ora descompuse n elementele lor constitutive. Structura
tm este definit dup cum urmeaz:
struct tm {
int tm_sec; /*secunde de la nceputul unui minut
(0,59)*/
int tm_min; /*minute de la nceputul unei ore (0,59) */
int tm_hour; /*ore de la miezul nopii (0,23) */
int tm_mday; /*ziua din lun (1,31) */
int tm_mon; /*luna ncepnd cu Ianuarie (0,11) */
int tm_year; /*anul dup 1900*/
int tm_wday; /*zile ncepnd de Duminic (0,6) */
int tm_yday; /*zile dup 1 Ianuarie (0,365) */
Biblioteca standard

139
int tm_isdst; /*cod ce indic ora de var*/
}
tm_isdst este pozitiv dac ora de var este n vigoare, zero dac nu este, i negativ
dac informaia nu este disponibil.
clock_t clock(void)
clock ntoarce timpul procesorului folosit de ctre program de la nceputul execuiei, sau -
1 dac nu este disponibil. clock()/clk_per_sec reprezint un timp n secunde.
time_t time(time_t *tp)
time ntoarce timpul calendaristic curent sau -1 dac timpul nu este disponibil. Dac tp
nu este null, valoarea returnat este atribuit de asemenea lui *tp.
double difftime(time_t time2, time_t time1)
difftime ntoarce time2 - time1 exprimat n secunde.
time_t mktime(struct tm *tp)
mktime transform timpul local din structura *tp ntr-un timp calendaristic n aceeai
reprezentare folosit de timp. Componentele vor avea valori n domeniul prezentat.
mktime ntoarce timpul calendaristic sau -1 dac timpul nu poate fi reprezentat.
Urmtoarele patru funcii ntorc pointeri ctre obiecte statice care pot fi suprascrise de
ctre alte apeluri.
char *asctime(const struct tm *tp)
asctime transform timpul din structura *tp ntr-un ir de forma
Sun Jan 3 15:14:13 1988\n\0
char *ctime(const time_t *tp)
ctime transform timpul calendaristic *tp n timp local; este echivalent cu
asctime(localtime(tp))
struct tm *gmtime(const time_t *tp)
gmtime transform timpul calendaristic *tp n Timp Universal (TU). ntoarce NULL dac
TU nu este disponibil.
struct tm *localtime(const time_t *tp)
localtime transform timpul calendaristic *tp n timp local.
size_t strftime(char *s, size_t smax, const char *fmt, const
struct tm *tp)
strftime formateaz informaia de dat i timp din *tp n s n conformitate cu fmt, care
este analog cu un specificator de format de la printf. Caracterele obinuite (inclusiv '\0'
final) sunt copiate n s. Fiecare %c este nlocuit dup regulile de mai jos, folosind valorile
corespunztoare mediului local. n s sunt plasate maxim smax caractere. strftime
ntoarce numrul de caractere, exclusiv '\0', sau zero dac s-au produs mai mult de smax
caractere.
. %a numele prescurtat al zilei din sptmn
sptmn. %a numele complet al zilei din
i. %b numele prescurtat al luni
Capitolul 9

140
datei i timpului.
).
1-12).
66).
tru AM sau PM.
ima zi a sptmnii) (00-53).
Luni e prima zi a sptmnii) (00-53).
mpului.
(00-99).
zonei de timp, dac exist.
%% %
9.7 Valori limit dependente de implementare: i
%b numele complet al lunii.
%c reprezentarea local a
%d ziua din lun (01-31).
%h ora (ceas cu 24 de ore) (00-23
%I ora (ceas cu 12 ore) (0
%j ziua din an (001-3
%m luna (01-12).
%m minutul (00-59).
%p echivalentul local pen
%S secunda (00-61).
%U numrul din an al sptmnii (Duminica e pr
%w ziua din sptmn (0-6, Duminica este 0).
%W numrul din an al sptmnii (
%x reprezentarea local a datei.
%X reprezentarea local a ti
%y anul fr secol
%y anul cu secol.
%Z numele
<limits.h> <float.h>
le. Valorile
de mai jos sunt magnitudinile minime acceptabile; pot fi folosite valori mai mari.
or
AR_MIN
83647
char
7
X r
295
USHRT_MAX 65535 valoarea maxim a unui unsigned short
im pentru cantitatea corespondent. Fiecare implementare i definete
alorile potrivite.


Headerul <limits.h> definete constante pentru dimensiunile tipurilor integra
CHAR_BIT 8
UCHAR_MAX
bii ntr-un char
CHAR_MAX
SCHAR_MAX
valoarea maxim a unui char
CHAR_MIN 0 or SCH valoarea minim a unui char
INT_MAX 32767 valoarea maxim a unui int
INT_MIN -32767 valoarea minim a unui int
LONG_MAX 2147483647 valoarea maxim a unui long
LONG_MIN -21474 valoarea minim a unui long
SCHAR_MAX +127 valoarea maxim a unui signed char
SCHAR_MIN -127 valoarea minim a unui signed
SHRT_MAX +32767 valoarea maxim a unui short
SHRT_MIN -3276 valoarea minim a unui short
UCHAR_MA 255 valoarea maxim a unui unsigned cha
UINT_MAX 65535 valoarea maxim a unui unsigned int
ULONG_MAX 4294967 valoarea maxim a unui unsigned long

Numele din Tabelul de mai jos, un subset al lui <float.h>, sunt constante legate de
aritmetica numerelor n virgul mobil. Atunci cnd este dat o valoare, ea reprezint
magnitudinea min
v
FLT_RADIX 2 baza de reprezentare, de ex. 2, 16
FLT_ROUNDS mobil pentru adunare modul de rotunjire n virgul
FLT_DIG 6 cifre zecimale de precizie
FLT_EPSILON .0+x != 1.0 1E-5 cel mai mic numr x astfel nct 1
Biblioteca standard

141
E+37 FLT_MAX 1 numrul maxim n virgul mobil
FLT_MAX_EXP
ezentabil n maxim astfel nct FLT_RADIX

este repr
n-1
FLT_MIN 1E-37 numrul normalizat minim n virgul mobil
FLT_MIN_EXP este un numr normalizat minimum n astfel nct 10
n
DBL_DIG 10 cifre zecimale de precizie
DBL_EPSILON 1.0+x != 1.0 1E-9 cel mai mic numr x astfel nct
DBL_MAX 1E+37 numrul maxim de tip double
DBL_MAX_EXP
prezentabil n maxim astfel nct FLT_RADIX

este re
n-1
DBL_MIN 1E-37 numrul normalizat minim de tip double
DBL_MIN_EXP minimum n astfel nct10
n
este un numr normalizat
9.8 Moduri de alocare a memoriei
-zise i pentru variabilele
explicit static.
mod explicit, cu ajutorul funciilor de alocare dinamic, aflate n
l <alloc.h>.
Exemp
Alocarea memoriei se poate realiza n urmtoarele moduri:
alocare static - pentru instruciunile de control propriu
globale i variabilele locale declarate n mod
alocare pe stiv - pentru variabilele locale.
alocare dinamic - n
headeru
lu:
int a,b; double x,w;
double f1(int c, double v)
{ int b; stati

c double z; }


emorie ct este necesar n momentul respectiv, se va aloca memorie n mod dinamic.
care/dezalocare a memoriei au prototipurile n header-ele
<s
int f1(int w)
{double a; }

void main()
{ double b, c; int k; b=f1(k,c); }
9.8.1 Alocarea memoriei n mod dinamic
Pentru toate tipurile de date (simple sau structurate), la declararea acestora, compilatorul
aloc automat un numr de locaii de memorie (corespunztor tipului datei). Dimensiunea
zonei de memorie necesar pentru pstrarea valorilor datelor este fixat naintea lansrii
n execuie a programului. n cazul declarrii unui tablou de ntregi cu maximum 100 de
elemente vor fi alocai 100*sizeof(int) locaii de memorie succesive. n situaia n
care la un moment dat tabloul are doar 20 de elemente, pentru a aloca doar atta
m

Este de dorit ca n cazul datelor a cror dimensiune nu este cunoscut a priori sau variaz
n limite largi, s se utilizeze o alt abordare: alocarea memoriei n mod dinamic. n mod
dinamic, memoria nu mai este alocat n momentul compilrii, ci n momentul execuiei.
Alocarea dinamic elimin necesitatea definirii complete a tuturor cerinelor de memorie n
momentul compilrii. n limbajul C, alocarea memoriei n mod dinamic se face cu ajutorul
funciilor malloc, calloc, realloc; eliberarea zonei de memorie se face cu ajutorul
funciei free. Funciile de alo
tdlib.h> i <alloc.h>:
void *malloc(size_t nr_octei_de_alocat);
Capitolul 9

142
Fu
re
ncia malloc necesit un singur argument (numrul de octei care vor fi alocai) i
turneaz un pointer generic ctre zona de memorie alocat (pointerul conine adresa
primului octet al zonei de memorie rezervate).
void *calloc(size_t nr_elemente, size_t mrimea_n_octei_
a_unui_elem);
Fu memorie pentru un tablou de ncia calloc lucreaz n mod similar cu malloc; aloc
_elemente, numrul de octei pe care este nr memorat un element este
mrimea_n_octei_a_unui_elem i returneaz un pointer ctre zona de memorie alocat.
void *realloc(void *ptr, size_t mrime);
Funcia realloc permite modificarea zonei de memorie alocat dinamic cu ajutorul
funciilor malloc sau calloc.
Observaie:
n cazul n care nu se reuete alocarea dinamic a memoriei (memorie insuficient),
funciile malloc, calloc i realloc returneaz un pointer null. Deoarece funciile
alloc, calloc, realloc returneaz un pointer generic, rezultatul poate fi atribuit m
oricrui tip de pointer. La atribuire, este indicat s se utilizeze operatorul de conversie
explicit (vezi exemplu).

El inamic cu una dintre funciile malloc, calloc sau
realloc) se realizeaz cu ajutorul funciei free.
iberarea memoriei (alocate d
void free(void *ptr);
Pentru a putea afla memoria RAM disponibil la un moment dat, se poate utiliza funcia
coreleft:
unsigned coreleft(void);

Exemplu: S se aloce dinamic memorie pentru 20 de valori ntregi.
int *p;
p=(int*)malloc(20*sizeof(int));
//p=(int*)calloc(20, sizeof(int));

Exerciiu: S se scrie un program enteaz func
Func
care implem ia numit introd_val.
i ucerea unui numr de valori reale, pentru care se aloc
memorie dinamic. Valorile citite cu ajutorul funciei introd_val sunt prelucrate n funcia
main, .
n, funcia introd_val
e dinamic */
("%d", nr);
izeof(float))) )
("%lf", p+i); return p;}

oat *pt; pt=introd_val();
a trebuie s permit introd
apoi memoria este eliberat
#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
float *introd_val()
/* pentru a putea realiza eliberarea memoriei n funcia mai
trebuie s returneze adresa de nceput a zonei de memorie alocat
ouble *p; int nr;printf("Numr valori:"); scanf {d
if (!(p=(float*)malloc(nr*s
{
rintf("Memorie insuficient!\n");return NULL; p
}
for (int i=0; i<nr; i++){
printf("Val %d=", i+1); scanf
}
void main()
{fl
Biblioteca standard

143
// prelucrare tablou
free(pt);
}



Capitolul 10

144
10. GESTIUNEA ECRANULUI N MOD TEXT
Biblioteca standard a limbajului C i C++ conine funcii pentru gestiunea ecranului. Acesta
poate fi gestionat n dou moduri: mod text sau mod grafic.
n capitolul de fa prezentm funciile standard mai importante utilizate la gestiunea
ecranului n mod text, iar n capitolul urmtor se trateaz gestiunea ecranului n mod
grafic.

Toate funciile standard de gestiune a ecranului n mod text au prototipurile n fiierul
conio.h.
Modul text presupune c ecranul este format dintr-un numr de linii i un numr de
coloane. n mod curent se utilizeaz 25 de linii a 80 sau 40 de coloane fiecare. Aceasta
nseamn c ecranul are o capacitate de 25*80=2000 sau 25*40= 1000 caractere.
Poziia pe ecran a unui caracter se definete printr-un sistem de dou coordonate ntregi:
(x,y) unde x este numrul coloanei, iar y este numrul liniei pe care este situat caracterul.
Colul din stnga sus al ecranului are coordonatele (1,1). Colul din dreapta jos al ecranului
are coordonatele (80,25) sau (40,25).
n mod implicit, funciile de gestiune a ecranului n mod text au acces la tot ecranul.
Accesul poate fi limitat la o parte din ecran utiliznd aa numitele ferestre.
Fereastra este o parte dreptunghiular a ecranului care poate fi gestionat
independent de restul acestuia.
Un caracter de pe ecran, pe lng coordonate, mai are i urmtoarele atribute:
o culoarea caracterului afiat;
o culoarea fondului;
o clipirea caracterului.
Aceste atribute sunt dependente de adaptorul grafic utilizat. Cele mai utilizate adaptoare
sunt:
placa MDA, care este un adaptor monocrom;
placa Hercules, care este un adaptor monocrom;
placa CGA, care este un adaptor color;
placa EGA, care este un adaptor color;
placa VGA, care este un adaptor color de mare performan.
Pentru adaptoarele color de mai sus, se pot utiliza 8 culori de fond i 16 pentru afiarea
caracterelor.
Atributul unui caracter se definete cu ajutorul formulei:
atribut = 16 * culoare_fond +culoare_caracter + clipire (2.1)
unde:
culoare fond (background) - Este o cifr din intervalul [0,7] i are semnificaia din Tabelul
10.1.
culoare_caracter (foreground) - Este un ntreg din intervalul [0,15] i are semnificaia din
Tabelul 10.1.
clipire - Are valoarea 128 (clipirea caracterului) sau 0 (fr clipire).
n tabelul de mai jos se indic corespondena dintre valorile numerice i culorile definite de
ele cu ajutorul relaiei (1).
Tabelul 10.1 Corespondena dintre valorile numerice i culori
Culoare Constant
simbolic
Valoare Culoare Constant
simbolic
Valoare
negru BLACK 0 albastru deschis LIGHTBLUE 9
GESTIUNEA ECRANULUI N MOD TEXT

145
Culoare Constant
simbolic
Valoare Culoare Constant
simbolic
Valoare
albastru BLUE 1 verde deschis LIGHTGREEN 10
verde GREEN 2 turcoaz deschis L1GHTCYAN 11
turcoaz CYAN 3 rou deschis LIGHTRED 12
rou RED 4 purpuriu deschis LIGHTMAGENTA 13
purpuriu MAGENTA 5 galben YELLOW 14
maro BROWN 6 alb WHITE 15
gri deschis LIGHTGRAY 7 clipire BLINK 128
gri nchis DARKGRAY 8
n paragrafele urmtoare se vor enumera funciile standard mai importante pentru
gestiunea ecranului n mod text.
10.1 Setarea ecranului n mod text
Se realizeaz cu ajutorul funciei textmode. Aceasta are prototipul:
void textmode(int modtext);
unde: modtext - Poate fi exprimat numeric sau simbolic n felul urmtor:
Tabelul 10.2 Constante i caracteristici pentru diferite moduri text
Modul text activat Constant simbolic Valoare
Caractere albe pe fond negru; 40 de coloane BW40 0
Color 40 de coloane C40 1
Caractere albe pe fond negru; 80 de coloane BW80 2
Color 80 de coloane C80 3
Monocrom 80 de coloane MONO 7
Color cu 43 linii pentru placa EGA i 50 de linii pentru placa
VGA
C4350 64
Modul precedent LASTMODE -1
Modul MONO se poate seta pe un adaptor monocolor. Celelalte moduri se pot seta pe
adaptoare color.
10.2 Definirea unei ferestre
Dup setarea ecranului n mod text, acesta are caracteristicile indicate n paragraful
precedent.
Adesea dorim s partajm ecranul n zone care s poat fi gestionate independent,
aciune care se realizeaz cu ajutorul ferestrelor. O fereastr se poate defini cu ajutorul
funciei window. Prototipul ei este:
void window(int stnga int sus, int dreapta,int jos);
unde:
(stnga, sus) - Reprezint coordonatele colului din sting sus al ferestrei.
(dreapta, jos) - Reprezint coordonatele colului dreapta jos al ferestrei.
La un moment dat este activ o singur fereastr i anume aceea definit de ultimul apel
al funciei window. Funciile de gestiune a ecranului n mod text acioneaz totdeauna
asupra ferestrei active. Dup setarea modului text cu ajutorul funciei textmode, este
activ tot ecranul. Menionm c funcia window nu are nici un efect dac parametri de la
apel sunt eronai.
10.3 tergerea unei ferestre
Fereastra activ se terge cu ajutorul funciei clrscr. Ea are prototipul:
Capitolul 10

146
void clrscr(void);
Dup apelul funciei clrscr, fereastra activ (sau tot ecranul, dac nu s-a definit n
prealabil o fereastr prin apelul funciei window) devine vid. Fondul ei are culoarea
definit prin culoarea de fond (background) curent.
Funcia clrscr poziioneaz cursorul pe caracterul din stnga sus al ferestrei active,
adic n poziia de coordonate (1,1) a ferestrei active.
10.4 Gestiunea cursorului
Utilizatorul poate plasa cursorul pe un caracter al ferestrei folosind funcia gotoxy. Ea are
prototipul:
void gotoxy(int coloana,int linie);
unde: (coloana, linie) - Reprezint coordonatele caracterului pe care se plaseaz cursorul;
aceste coordonate sunt relative la fereastra activ.
Dac coordonatele de la apel sunt n afara ferestrei active, atunci apelul funciei este
ignorat. Poziia cursorului din fereastra activ se poate determina cu ajutorul a dou
funcii, care au prototipurile:
int wherex(void);
returneaz numrul coloanei n care se afl cursorul;
int wherey(void);
returneaz numrul liniei n care se afl cursorul.
Exist cazuri cnd se dorete ascunderea cursorului. Acest lucru se poate realiza printr-o
secven special n care se utilizeaz funcia geninterrupt. O secven de acest fel
este urmtoarea:
void ascundecursor () /* face invizibil cursorul */
{ _AH = 1; _CH = 0x20; geninterrupt(0x10); }
Cursorul poate fi reafiat apelnd funcia de mai jos:
void af iscursor () /* face vizibil cursorul */
{ _AH = 1; _CH = 6; _CL = 7; geninterrupt(0x10); }
Amintim c _AH, _CH i _CL sunt nume utilizate pentru regitrii calculatorului.
10.5 Determinarea parametrilor ecranului
Utilizatorul are posibilitatea s obin parametri cureni ai ecranului prin apelarea funciei
gettextinfo. Ea are prototipul:
void gettextinfo(struct text_info *p);
unde structura textinfo este definit n fiierul conio.h astfel:
struct text_info {
unsigned char winleft;
unsigned char wintop;
unsigned char winright;
unsigned char winbottom;
unsigned char attribute;
unsigned char normattr;
unsigned char currmode;
unsigned char screenheight;
unsigned char screenwidth;
GESTIUNEA ECRANULUI N MOD TEXT

147
unsigned char currx;
unsigned char curry;
};
Dup apelul funciei gettextinfo structura de tip textinfo, spre care pointeaz p,
este completat cu urmtoarele informaii:
o amplasarea colurilor ferestrei;
o culoarea fondului, a caracterelor i clipirea acestora;
o modul curent;
o dimensiunea ecranului;
o poziia cursorului.
10.6 Modurile video alb/negru
Exist dou modurile video alb/negru: intens i normal.
Modul intens se obine apelnd funcia highvideo de prototip:
void highvideo(void);
Modul normal se obine cu ajutorul funciei lowvideo de prototip:
void lowvideo(void);
Intensitatea iniial este de obicei cea normal. Se poate reveni la intensitatea normal
dac se apeleaz funcia normvideo de prototip:
void normvideo(void);
10.7 Setarea culorilor
Culoarea fondului se seteaz cu ajutorul funciei textbackground de prototip:
void textbackground(int culoare);
unde: culoare - Este un ntreg n intervalul [0,7] i are semnificaia definit n tabelul de la
nceputul acestui capitol.
Culoarea caracterelor se seteaz cu ajutorul funciei textcolor de prototip:
void textcolor(int culoare);
unde: culoare - Este un ntreg din intervalul [0,15] i are semnificaia definit n tabelul de
la nceputul acestui capitol.
Se pot seta ambele culori, precum i clipirea caracterului folosind funcia textattr de
prototip:
void textattr(int atribut);
unde: atribut se definete cu ajutorul relaiei (1).

Exemplul 10.1 S se scrie o funcie care afieaz parametrii ecranului.
void pecr() /* afieaz parametrii ecranului */
{ struct text_info par_ecr;
clrscr();
gettextinfo(&par_ecr);
printf("sting:%u sus:%u dreapta:%u jos:%u\n", par_ecr.winleft,
par_ecr.wintop, par_ecr.winright, par_ecr.winbottom);
printf("atribut:%u mod curent:%u\n", par_ecr.attribute,
par_ecr.currmode);
Capitolul 10

148
printf("inaltimea ecranului:%u latimea ecranului: %u\n",
par_ecr.screenheight, par_ecr.screenwidth);
printf("coloana cursorului:%u linia cursorului: %u\n",
par_ecr.curx, par_ecr.cury);
}
Exemplul 10.2 S se scrie un program care seteaz pe rnd modurile text, definite cu
ajutorul constantelor simbolice: BW40, C40, BW80, C80 i C4350 i afieaz parametrii
ecranului pentru fiecare din modurile respective.

#include <stdio.h>
#include <conio.h>
#include "BXVIII1.cpp"

void main() /* seteaz modurile definite cu ajutorul
constantelor simbolice BW40, C40, BW80, C80 si C4350 si
afiseaz parametrii ecranului in fiecare caz */
{
int i;
int tab[]={BW40,C40,BW80,C80,C4350};
char *text[]={"BW40","C40","BW80","C80","C4350"};
for(i=0;i<5;i++){
textmode(tab[i]);
pecr();
printf("\n\t\t\t%s\n\n",text[i]);
printf ("Acionati o tasta pentru a continua\n");
getch();
}
}
Observaie:
Programul de fa presupune prezena la calculator a unui adaptor color de tip EGA sau
VGA.
10.8 Gestiunea textelor
Pentru afiarea caracterelor colorate n conformitate cu atributele definite prin relaia:
atribut = 16*culoare_fond + culoare_caracter + clipire (2.2)
se pot folosi funciile:
putch - Afieaz un caracter.
cputs - Afieaz un ir de caractere (este analog cu funcia puts).
cprintf - Afieaz date sub controlul formatelor de conversie (este analog cu funcia
printf).
Toate aceste funcii au prototipul n fiierul conio.h. Atributul de culoare i clipire se
seteaz cu ajutorul funciilor indicate n paragraful (10.7).
Biblioteca standard a limbajului C conine i alte funcii utile n gestiunea textelor. Dintre
acestea le amintim pe cele mai importante.
Operaiile de tergere i inserare de linie se pot realiza prin funciile de mai jos:
void insline(void);
insereaz o linie cu spaii n fereastr; liniile de sub poziia curent a cursorului se
deplaseaz n jos cu o poziie;
void clreol(void);
GESTIUNEA ECRANULUI N MOD TEXT

149
terge sfritul liniei ncepnd cu poziia cursorului;
void delline(void); terge toat linia pe care este poziionat
cursorul.
Un text poate fi copiat dintr-o zon dreptunghiular a ecranului n alta, folosind funcia
movetext. Ea are prototipul:
int movetext(int stnga, int sus, int dreapta, int jos, int
stnga_dest, int sus_dest);
unde: stnga, sus - definesc nceputul textului care se copiaz; dreapta, jos - definesc
sfritul textului care se copiaz, iar stnga_dest - definesc poziia primului caracter al
textului dup sus_dest copiere. Celelalte poziii rezult automat din structura textului.
Funcia returneaz valoarea 1 dac textul s-a copiat corect sau 0 la eroare.
Textele dintr-o zon dreptunghiular pot fi salvate ntr-o zon de memorie sau citite dintr-o
astfel de zon folosind funciile gettext i puttext. Ele au prototipurile de mai jos:
int gettext(int stnga, int sus, int dreapta, int jos, void
*destinatie);
unde: stnga, sus, dreapta, jos - definesc o zon dreptunghiular din ecran care conine
textul de salvat, iar destinaie - Este pointerul spre zona de memorie n care se salveaz
textul.
Funcia returneaz 1 la copiere cu succes i 0 la eroare.
int puttext(int stnga, int sus, int dreapta, int jos, void
*sursa);
unde: stnga, sus dreapta, jos - definesc o zon dreptunghiular din ecran n care se va
afia textul citit din memorie, iar sursa - Este pointerul spre zona de memorie din care se
transfer textul pe ecran.
Funcia returneaz 1 la copiere cu succes i 0 la eroare. Menionm c fiecare caracter de
pe ecran se pstreaz pe doi octei: pe un octet caracterul; pe octetul urmtor atributul
caracterului.
Exemplul 10.3 S se scrie un program care afieaz texte n modurile video intens i
video normal.

#include <conio.h>
main () /* afieaz texte in modurile video intens si normal */
{
textmode(BW80);
window(10,4,60,4);
clrscr();
lowvideo();
cputs("lowvideo");
highvideo();
cputs("highvideo");
normvideo();
cputs("normvideo");
textmode(LASTMODE);
cprintf("\n\rActionati o tasta pentru a continua");
getch();
}
Exemplul 10.4 S se scrie un program care afieaz toate combinaiile de culori posibile
pentru fond i caractere. Se consider c se dispune de un adaptor color EGA/VGA.

Capitolul 10

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

main () /* - afiseaza toate combinatiile de culori posibile
pentru fond si caractere; - se dispune de un adaptor
EGA/VGA. */
{
static char *tculoare[] = {
"0 BLACK negru", "1 blue albastru", "2 GREEN verde",
"3 CYAN turcoaz", "4 RED rosu", "5 MAGENTA purpuriu",
"6 BROWN maro", "7 LIGHTGRAY gri deschis", "8 DARKGRAY gri
inchis",
"9 LIGHTBLUE albastru deschis", "10 LIGHTGREEN verde deschis",
"11 LIGHTCYAN turcoaz deschis", "12 LIGHTRED rosu deschis",
"13 LIGHTMAGENTA purpuriu deschis", "14 YELLOW galben", "15
WHITE alb"
};
int i,j,k;
struct text_info atr;
gettextinfo(&atr);
for(i=0; i <8; i++){
/* i alege culoarea fondului */
window(3,2,60,20); k=2;
textbackground(i);
clrscr();
for(j=0; j < 16; j++, k++) {
textcolor(j);
gotoxy(2,k);
/* j alege culoarea caracterului */
if(i == j)
continue;
cputs(tculoare[j]);
}
gotoxy(1,18);
printf("actionati o tasta pentru a continua\n");
getch();
}
window(atr.winleft,atr.wintop, atr.winright, atr.winbottom);
textattr(atr.attribute);
clrscr();
}
Exemplul 10.6 S se scrie o funcie care afieaz o fereastr limitat de un chenar i pe
fondul creia se afieaz un ntreg. Cursorul devine invizibil la afiarea ferestrei. Funcia
are prototipul:
void fereastra (int st, int sus, int dr, int jos, int fond, int
culoare, int chenar, int n);
unde: (st, sus) - Coordonatele colului din stnga sus. (dr, jos) - Coordonatele colului din
dreapta jos. fond - ntreg din intervalul [0,7] care definete culoarea de fond a ferestrei.
culoare - ntreg din intervalul [0,15] care definete culoarea pentru afiarea caracterelor.
chenar - definete tipul chenarului: 0 - fr bordur; 1 - linie simpl; 2 - linie dubl; n -
numrul ntreg care se afieaz n fereastr ncepnd cu punctul de coordonate relative
(3,3).
GESTIUNEA ECRANULUI N MOD TEXT

151
Zona de ecran n care se afieaz fereastra se pstreaz n memoria heap nainte de a se
afia fereastra. Adresa acestei zone de memorie se pune pe o stiv definit cu ajutorul
unui tablou de pointeri spre tipul void. Acest tablou este global i are 100 de elemente. El
se definete astfel:
void far *stiva[100];
Locul liber n tablou se definete cu ajutorul variabilei globale istiva:
int istiva;
void orizontal(int,int);
void vertical(int,int,int,int);
void fereastra(int st, int sus, int dr, int jos, int fond, int
culoare, int chenar, int n)
/* afieaz o fereastra limitata de un chenar si pe fondul
creia se afieaz numrul ferestrei */
{
extern ELEM far *stiva[];
extern int istiva;
/* memoreaz partea din ecran pe care se va afia fereastra */
if(istiva==MAX){
printf("\nprea multe ferestre\n"); exit(1);
}
if((stiva[istiva]= (ELEM *)farmalloc(sizeof(ELEM)))==0){
printf("memorie insuficienta\n");
exit(1);
}
if((stiva[istiva]->zonfer= farmalloc(2*(dr-st+1)*(jos-
sus+1)))==0){
printf("\nmemorie insuficienta\n");
exit(1);
}
stiva[istiva]->x=st; stiva[istiva]->y=sus;
stiva[istiva]->u=dr; stiva[istiva]->v=jos;
if((gettext(st,sus,dr,jos,stiva[istiva]-> zonfer))==0){
printf("\neroare la memorarea ecranului\n");
exit(1);
}
istiva++;
/* activeaz fereastra si o afieaz pe ecran */
window(st,sus,dr,jos); textattr(16*fond+culoare); clrscr();
/* trasare chenar */
if(chenar){
textcolor(WHITE); highvideo();
/* coltul sting sus */
switch(chenar){
case SIMPLU: putch(218); break;
case DUBLU: putch(201); break; }
/* chenar orizontal sus */
orizontal(dr-st-2,chenar);
/* coltul dreapta sus */
switch(chenar){
case SIMPLU: putch(191); break;
case DUBLU: putch(187); break; }
/* chenar vertical sting */
vertical(jos-sus,1,2,chenar);
/* coltul sting jos */
Capitolul 10

152
gotoxy(1,jos-sus+1);
switch(chenar){
case SIMPLU: putch(192); break;
case DUBLU: putch(200); break; }
/* chenar orizontal jos */
orizontal(dr-st-2,chenar);
/* chenar vertical dreapta */
vertical(jos-sus-1,dr-st,2,chenar);
/* coltul dreapta jos */
gotoxy(dr-st,jos-sus+1);
switch(chenar){
case SIMPLU: putch(217); break;
case DUBLU: putch(188); break;}
normvideo();
textattr(16*fond+culoare); }
/* sfirsit afiare chenar */
/* scrie pe n in fereastra */
gotoxy(3,3); cprintf("%d",n);
/* ascunde cursor */
_AH=1;
_CH=0x20;
geninterrupt(0x10);
} /* sfirsit fereastra */

void orizontal(int a,int chenar) /* traseaz un chenar orizontal
*/
{ while(a--)
switch(chenar){
case SIMPLU: putch(196); break;
case DUBLU: putch(2 05); break; }
}

void vertical(int a,int col,int lin,int chenar)
{ while(a--) {
gotoxy(col,lin++);
switch(chenar){
case SIMPLU: putch(179); break;
case DUBLU: putch(186); break; }
}
}
Exemplul 10.7 S se scrie un program care afieaz ferestre pe ecran n mod aleator.
Ferestrele sunt de dimensiune fix, dar au poziii aleatoare pe ecran. De asemenea, ele
pot avea chenar format dintr-o linie simpl sau dubl sau s nu aib chenar. Culorile de
fond i de afiare a caracterelor sunt aleatoare. Ferestrele se numeroteaz i numrul
ferestrei se afieaz n fereastr. Prima fereastr afiat se numeroteaz cu 1.
Dup afiarea unei ferestre se va aciona o tast oarecare, corespunztoare codului
ASCII, pentru a afia fereastra urmtoare. Se revine la fereastra precedent dac se
acioneaz tasta ESC.
Execuia programului se termin n cazul n care se acioneaz tasta ESC n momentul n
care nu este afiat nici o fereastr. Se presupune c se dispune de un adaptor color
EGA/VGA.
#include<stdio.h>
#include<conio.h>
GESTIUNEA ECRANULUI N MOD TEXT

153
#include<stdlib.h>
#include<alloc.h>
#include<dos.h>
#define MAX 100
#define ESC 0x1b
#define SIMPLU 1
#define DUBLU 2

typedef struct{
int x,y,u,v;
void far *zonfer; } ELEM;
ELEM far *stiva[MAX];
int istiva;

#include "bviii2.cpp" /* pcit_int */
#include "bviii3.cpp" /* pcit_int_lim */
#include "bxviii6.cpp" /* fereastra */

void main () /* afiseaza ferestre pe ecran in mod aleator */
{
int c,culoare,fond,i,inalt,j,lung,s,stanga,sus; struct text_info
info, crt;
struct time ora_crt;
istiva=0; clrscr();
/* pastreaza tot ecranul */
if((stiva[istiva]=(ELEM *)farmalloc(sizeof(ELEM)))==0)
{printf("memorie insuficienta\n"); exit(1);}
if((stiva[istiva]->zonfer=farmalloc(2*80*25))==0)
{printf("memorie insuficienta\n"); exit(1);}
if(gettext(1,1,80,25,stiva[istiva]->zonfer)==0)
{printf("nu se poate salva ecranul\n"); exit(1);}
istiva++;
/* salveaza parametrii ecranului */
gettextinfo(&info);
/* citeste dimensiunile ferestrelor: lungimea si inaltimea */
if(pcit_int_lim("lungime:",8,70,&lung)==0)
{printf("s-a tastat EOF\n"); exit(1);}
if(pcit_int_lim("inaltime:",5,15,&inalt)==0)
{printf("s-a tastat EOF\n"); exit(1);}
/* coordonatele maxime pentru coltul din stinga sus a
ferestrelor */
i=79-lung; j=25-inalt;
/* seteaza saminta pentru sirul de numere pseudo-aleatoare care
definesc parametrii ferestrelor:
- coltul din stinga sus;
- atributul de culoare. */
gettime(&ora_crt);
s=(3600L*ora_crt.ti_hour+60*ora_crt.ti_min+ora_crt.ti_sec)%65535
;
srand(s);
printf("Actionati o tasta pentru a continua\n");
printf("cu ESC se revine la ecranul precedent\n");
for(;;){
c=getch();
Capitolul 10

154
if(c!=ESC)
{
/* s-a tastat un caracter diferit de ESC */
/* se genereaza parametrii ferestrei */
stanga=random(i)+1;
sus=random(j) + 1;
fond=random(8);
while((culoare=random(15)+1)!=fond)
fereastra(stanga,sus,stanga+lung,sus+inalt,
fond,culoare,istiva%3,istiva); continue;
}
/* s-a tastat ESC */
if(--istiva>0){
/* se reface zona din ecran eliminind fereastra activa */
puttext(stiva[istiva]->x,stiva[istiva]->y,
stiva[istiva]->u, stiva[istiva]->v, stiva[istiva]-
>zonfer);
farfree(stiva[istiva]);}
else
/* se ntrerupe executia programului */
break; }
puttext(info.winleft,info.wintop,info.winright,
info.winbottom,stiva[0]); window(1,1,80,25);
farfree(stiva[0]); textattr(info.attribute);
/* afi?eaz? cursorul */
_AH=1; _CH=6; _CL=7;
geninterrupt(0x10);
clrscr();
}
GESTIUNEA ECRANULUI N MOD GRAFIC

155
11. GESTIUNEA ECRANULUI N MOD GRAFIC
Modul grafic presupune c ecranul este format din "puncte luminoase" (pixeli). Numrul
acestora depinde de adaptorul grafic i se numete rezoluie. O rezoluie este cu att mai
bun cu ct este mai mare.
Adaptorul CGA are o rezoluie de 200 de rnduri a 640 de coloane, iar adaptorul EGA
ofer o rezoluie de tot attea coloane, dar de 350 de rnduri.
Adaptorul VGA ofer o rezoluie de 480 de rnduri a 640 de coloane sau chiar mai mare,
de pn la 768 de rnduri, a 1024 de coloane.
Pentru gestiunea ecranului n mod grafic se pot utiliza peste 60 de funcii standard aflate
n biblioteca sistemului. Aceste funcii au prototipul n fiierul graphics.h. n acest capitol
indicm funciile mai importante care permit gestiunea ecranului n mod grafic, funcii care
folosesc pointeri de tip far (32 de bii).
11.1 Setarea modului grafic
Modul grafic se seteaz cu ajutorul funciei initgraph. Aceast funcie poate fi folosit
singur sau mpreun cu o alt funcie numit detectgraph care determin parametrii
adaptorului grafic. Prototipul ei este:
void far detectgraph(int far *gd, int far *gm);
unde:
n zona spre care pointeaz gd se pstreaz una din valorile din Tabelul 10.2:
Tabelul 11.1 Valorile constantelor pentru adaptorul grafic
Constanta
simbolic
Valoare Constanta
simbolic
Valoare
CGA 1 IBM8514 6
MCGA 2 HERCMONO 7
EGA 3 ATT400 8
EGA64 4 VGA 9
EGAMONO 5 PC3270 10
n zona spre care pointeaz gm se memoreaz una din valorile:
Tabelul 11.2 Valorile constantelor pentru modul grafic
Adaptor Constant simbolic Valoare Rezoluie/culori
CGA CGAC0 0 320*200 puncte i maximum 4 culori.
CGAC1 1
CGAC2 2
CGAC3 3
CGAHI 4 640*200 puncte i 2 culori: alb/negru.
EGA EGALO 0 640*200 puncte i maximum 16 culori.
EGAHI 1 640*350 puncte.
VGA VGALO 0 640*200 puncte.
VGAMED 1 640*350 puncte.
VGAHI 2 640*480 puncte.

Valorile spre care pointeaz gd definesc nite funcii standard corespunztoare
adaptorului grafic. Aceste funcii se numesc drivere. Ele se afl n subdirectorul BGI.
Capitolul 11

156
Funcia detectgraph detecteaz adaptorul grafic prezent la calculator i pstreaz
valoarea corespunztoare acestuia n zona spre care pointeaz gd.
Modul grafic se definete n aa fel nct el s fie cel mai performant pentru adaptorul
grafic curent.
Cele mai utilizate adaptoare sunt cele de tip EGA i VGA. De aceea, n cele ce urmeaz,
vom presupune c adaptorul curent este de tip EGA. n felul acesta, toate exerciiile din
acest capitol pot fi rulate la un calculator echipat cu un adaptor EGA sau VGA.
Apelul funciei detectgraph trebuie s fie urmat de apelul funciei initgraph. Aceasta
seteaz modul grafic n conformitate cu parametri stabilii de apelul prealabil al funciei
detectgraph.
Funcia initgraph are prototipul:
void far initgraph(int far *gd, int far *gm, int far *cale);
unde: gd i gm sunt pointeri care au aceeai semnificaie ca n cazul funciei
detectgraph. cale - Este pointer spre irul de caractere care definete calea
subdirectorului BGI care conine driverele. De exemplu, dac BGI este subdirector al
directorului BORLANDC, atunci vom folosi irul de caractere: "C:\\BORLANDC\\BGI". Se
mai poate folosi i o variabil suplimentar de tip ir de caractere declarat i iniializat
astfel:
char path[]="C:\\BORLANDC\\BGI";
Exemplu:
Pentru setarea n mod implicit a modului grafic, putem utiliza secvena de mai jos:
int driver, mod_grafic;

detectgraph(&driver,&mod_grafic);
initgraph(&driver,&mod_grafic, "c:\\BORLANDC\\BGI");
Dup apelul funciei initgraph se pot utiliza celelalte funcii standard de gestiune grafic
a ecranului. Din modul grafic se poate iei apelnd funcia closegraph de prototip:
void far closegraph(void);
Funcia initgraph poate fi apelat folosind secvena de mai jos:
int driver, mod_grafic;
driver = DETECT;
initgraph(&driver,&mod_grafic, "C:\\BORLANDC\\BGI");
Constanta simbolic DETECT este definit n fiierul graphics.h alturi de celelalte
constante simbolice care definesc driverul. Aceasta are valoarea zero.
Prin apelul de mai sus, funcia initgraph apeleaz funcia detectgraph pentru a defini
parametrii implicii ai adaptorului grafic.
Utilizatorul poate defini el nsui parametri pentru iniializarea modului grafic. De exemplu,
secvena:
int driver = 1; /* CGA */
int mod_graf = 0; /* CGACO */
initgraph(sdriver,&mod_graf, "C:\\BORLANDC\\BGI");
seteaz modul grafic corespunztor unui adaptor grafic CGA cu rezoluia 320*200 puncte.
n afara acestor funcii, utilizatorul mai poate utiliza i funcia setgraphmode care
selecteaz un mod grafic diferit de cel activat implicit prin initgraph. Aceast funcie are
prototipul:
void far setgraphmode(int moife);
unde: mode - are valorile 0-4 pentru CGA, 0 -1 pentru EGA, 0 - 2 pentru VGA.
GESTIUNEA ECRANULUI N MOD GRAFIC

157
Ea poate fi utilizat mpreun cu funcia restorecrtmode de prototip:
void far restorecrtmode(void);
Aceast funcie permite revenirea la modul precedent, iar setgraphmode realizeaz
trecerea invers.
Alte funcii din aceast categorie sunt:
void far graphdefaults(void);
repune parametri grafici la valorile implicite;
int far getgraphmode(void);
returneaz codul modului grafic;
char *far getmodename(int mod);
returneaz pointerul spre numele modului grafic definit de codul numeric mod;
char *far getdrivername(void);
returneaz pointerul spre numele driverului corespunztor adaptorului curent;
void far getmoderange(int grafdriv, int far *min, int far *max);
definete valorile minimale i maximale ale modului grafic utilizat; grafdriv are. ca valoare
una din valorile 1-10 indicate mai sus la funcia detectgraph.
Valoarea minim a modului grafic este pstrat n zona spre care pointeaz min, iar cea
maxim n zona spre care pointeaz max.

Exemplul 11.1 S se scrie un program care seteaz modul grafic n dou feluri:
cu ajutorul funciei detectgraph;
fr aceast funcie.
Programul afieaz rezultatele setrii.
#include<conio.h>
#include<stdio.h>
#include<graphics.h>

main () /*seteaza modul grafic si afiseaz parametrii setrii */
{
int gdriv,gmod;
int mod,min,max;
/* setare prin apelul functiei detectgraph */
detectgraph(&gdriv,&gmod);
printf("valori dup apelul functiei\ detectgraph\n");
printf("driver=%d\tmod grafic=%d\n",gdriv,gmod);
printf("Acionai o tasta pentu a continua\n");
getch();
initgraph(&gdriv, &gmod,"c:\\borlandc\\bgi");
printf("valori dup initgraph\n");
printf("driver=%d\tmod grafic=%d\n",gdriv,gmod);
printf("Acionai o tasta pentru a continua\n");
getch();
closegraph();

/* setare fara apelul lui detectgraph */
gdriv=DETECT;
initgraph(&gdriv, fcgmod, "c:\\borlandc\\bgi");
printf("iniializare fara detectgraph\n");
printf("driver=%d\tmod grafic=%d\n",gdriv,gmod);
Capitolul 11

158
printf("Acionai o tasta pentru a continua\n");
getch();

/* afieaz numele adaptorului grafic curent */
printf("adaptor grafic: %s\n",getdrivername());
mod=getgraphmode();
printf("cod mod=%d\tmod grafic:%s\n",mod,getmodename(mod));
getmoderange(gdriv,&min,&max);
printf("domeniul pentru adaptorul grafic=[%d,%d]\n",min,max);
printf ("Acionai o tasta pentru a continuaW);
getch();
closegraph();
}
11.2 Gestiunea culorilor
Adaptoarele grafice sunt prevzute cu o zon de memorie n care se pstreaz dale
specifice gestiunii ecranului. Aceast zon de memorie poart denumirea de memorie
video.
n mod grafic, ecranul se consider format din puncte luminoase numite pixeli. Poziia pe
ecran a unui pixel se definete printr-un sistem binar: (x,y), unde: x - definete coloana n
care este afiat pixelul, iar y - definete linia n care este afiat pixelul. n cazul
adaptoarelor color, unui pixel i corespunde o culoare. Culoarea pixelilor se pstreaz pe
bii n memoria video. Memoria video necesar pentru a pstra starea ecranului setat n
mod grafic, se numete pagin video. Adaptoarele pot conine mai multe pagini video.
Gestiunea culorilor este dependent de tipul de adaptor grafic existent la microprocesor. n
cele ce urmeaz vom avea n vedere adaptoarele grafice de tip EGA/VGA. n mod
concret, ne vom referi la facilitile oferite de adaptorul EGA, deoarece adaptorul VGA,
avnd performane superioare, permite utilizarea acestor faciliti. Numrul maxim al
culorilor care pot fi afiate cu ajutorul unui adaptor EGA este de 64.
Culorile se codific prin numere ntregi din intervalul [0,63]. Cele 64 de culori nu pot fi
afiate simultan pe ecran. n cazul adaptorului EGA se pot afia simultan pe ecran cel mult
16 culori. Mulimea culorilor care pot fi afiate simultan pe ecran se numete palet.
Culorile din componena unei palete pot fi modificate de utilizator prin intermediul funciilor
standard. La iniializarea modului grafic se seteaz o palet implicit.
Paleta se definete cu ajutorul unui tablou de 16 clemente pentru adaptorul EGA.
Elementele acestui tablou au valori din intervalul [0,63|. Fiecare element din acest tablou
reprezint codul unei culori.
Codurile culorilor din paleta implicit au denumiri simbolice definite n fiierul graphics.h.
Ele au prefixul EGA_.
n tabela de mai jos se indic codurile culorilor pentru paleta implicit.

Funciile de gestiune a culorilor pot avea ca parametri nu numai codurile culorilor, ci i
indeci n tabloul care definete culorile unei palete. De aceea, indicii din intervalul [0,15]
pot fi referii prin constante simbolice definite n fiierul graphics.h. Aceste denumiri
sugereaz culoarea din compunerea paletei.
void far setallpalette(struct palettetype far *paleta);
unde: palettetype - Este un tip definit n fiierul graphics.h ca mai jos:
struct palettetype {
unsigned char size;
signed char colors[MAXCOLORS +1 ];};
GESTIUNEA ECRANULUI N MOD GRAFIC

159
unde: size - Este dimensiunea paletei; colors - Este un tablou ale crui elemente au
ca valori codurile culorilor componente ale paletei care se definete.
Modificarea paletei curente cu ajutorul funciei setpalette sau setallpalette
conduce la schimbarea corespunztoare a culorilor afiate pe ecran n momentul apelului
funciilor respective.
Pentru a determina codurile culorilor componente ale paletei curente vom folosi funcia
getpalette de prototip:
void far getpalette(struct palettetype far *paleta);
Exemplu:
struct palettetype pal;

getpalette(&pal);

Dup apelul funciei getpalette se atribuie componentelor structurii datele
corespunztoare din paleta curent. Paleta implicit poate fi determinat folosind funcia
getdefaultpalette de prototip:
struct palettetype *far getdefaultpalette(void);
Numrul culorilor dintr-o palet poate fi obinut apelnd funcia getmaxcolor de prototip:
int far getmaxcolor (void);
Funcia returneaz numrul maxim de culori diminuat cu 1. Deci, n cazul adaptorului EGA
funcia returneaz valoarea 15.
O alt funcie care determin dimensiunea paletei este funcia getpalettesize. Ea are
prototipul:
int far getpalettesize(void);
Funcia returneaz numrul culorilor componente ale paletei. n cazul adaptorului EGA
funcia returneaz valoarea 16.

Exemplul 11.2 S se scrie un program care afieaz codurile culorilor pentru paleta
implicit.
#include<graphics.h>
#include<stdlib.h>
#include<stdio.h>
#include<conio.h>

main () /* afieaz codurile culorilor pentru paleta implicita
*/
{
int gd=DETECT,gm,i;
struct palettetype far *pal=(void *)0;
initgraph(&gd,&gm,"c:\\borlandc\\bgi");
pal=getdefaultpalette(); for(i=0;i<16;i++){
printf("colors[%d]=%d\n",i,pal->colors[i]);
getch();
}
closegraph();
}
Capitolul 11

160
11.3 Starea ecranului
n mod grafic, ecranul se compune din n*m puncte luminoase (pixeli). Aceasta nseamn
c pe ecran se pot afia m linii a n pixeli fiecare. Poziia unui pixel se definete printr-un
sistem binar de ntregi: (x,y) numite coordonatele pixelului. Coordonata x definete
coloana pixelului, iar y definete linia acestuia. Pixelul aflat n colul din stnga sus are
coordonatele (0,0). Coloanele se numeroteaz de la stnga spre dreapta, iar liniile de sus
n jos.
Biblioteca grafic a sistemului conine 4 funcii care permit utilizatorului s obin
urmtoarele informaii relativ la ecran:
o coordonata maxim pe orizontal;
o coordonata maxim pe vertical;
o poziia curent (pixel curent).
Prototipurile acestor funcii sunt:
int far getmaxx(void);
funcia returneaz coordonata maxim pe orizontal (abscisa maxim);
int far getmaxy(void);
funcia returneaz coordonata maxim pe vertical (ordonata maxim);
int far getx(void);
funcia returneaz poziia pe orizontal (abscisa) a pixelului curent;
int far gety(void);
funcia returneaz poziia pe vertical (ordonata) a pixelului curent.
Exemplul 11.3 S se scrie un program care afieaz urmtoarele informaii:
culoarea fondului;
culoarea pentru desenare;
coordonatele maxime;
coordonatele pixelului curent.
#include<graphics.h>
#include<stdlib.h>
#include<stdio.h>
#include<conio.h>

main() /* afieaz:
- culoarea fondului;
- culoarea pentru desenare;
- coordonatele maxime;
- coordonatele pixelului curent. */
{
int gd=DETECT,gm,cul_fond,cul_desen,crt_x,crt_y,maxx,maxy;
initgraph(&gd,&gm,"c:\\borlandc\\bgi");
cul_fond=getbkcolor(); cul_desen=getcolor();
maxx=getmaxx(); maxy=getmaxy();
crt_x=getx(); crt_y=gety();
closegraph();
printf("culoarea fondului=%d\n", cul_fond);
printf("culoarea pentru desenare=%d\n",cul_desen);
printf("abscisa maxima=%d\n",maxx);
printf("ordonata maxima=%d\n",maxy);
printf("abscisa curenta=%d\n",crt_x);
printf("ordonata curenta=%d\n",crt_y);
GESTIUNEA ECRANULUI N MOD GRAFIC

161
printf("Acionai o tasta pentru a continua\n");
getch();
closegraph();
}
11.4 Gestiunea textelor
Afiarea textelor presupune definirea unor parametri care pot fi gestionai prin funciile
descrise mai jos. n mod grafic dispunem de mai multe seturi de caractere. Setul de
caractere se alege prin intermediul parametrului numit font. Pentru acest parametru se pot
utiliza urmtoarele valori:
Tabelul 11.3 Valorile constantelor pentru setul de caractere
Constant simbolic Valoare
DEFAULT FONT 0
TRIPLEX FONT 1
SMALL FONT 2
SANS SERIF FONT 3
GOTHIC FONT 4
Ali parametri utilizai n definirea caracterelor sunt:
nlimea i limea caracterelor;
direcia de scriere a caracterelor:
o de la stng la dreapta: HORIZ_DIR;
o de jos n sus: VERT_DIR;
cadrajul caracterelor fa de poziia curent:
o pe orizontal; poziia curent se afl:
n stnga: LEFT_TEXT;
n centru: CENTER_TEXT;
n dreapta: RIGHT_TEXT.
o pe vertical; poziia curent se afl n:
marginea inferioar: BOTTOM_TEXT;
centru: CENTER_TEXT;
marginea superioar: TOP_TEXT.
Aceti parametri se seteaz cu ajutorul a dou funcii settextstyle i
settextjustify. Prima are prototipul:
void far settextstyle(int font, int direction, int charsize);
unde: font - definete setul de caractere; direction - definete direcia de scriere a textului;
charsize - definete dimensiunea caracterului n pixeli.
Dimensiunea se definete astfel:
Tabelul 11.4 Valorile constantelor pentru stilul textului
Valoarea parametrului Matricea folosit pentru afiarea
caracterului (n pixeli)
1 8*8
2 16*16
3 24*24

10 80*80
Dimensiunea poate fi stabilit de utilizator folosind funcia setusercharsize. n acest
caz, parametrul charsize are valoarea zero.
Cea de-a doua funcie definete cadrajul textului. Ea are prototipul:
Capitolul 11

162
void far settextjustify(int oriz, int vert);
unde: oriz - definete cadrajul pe orizontal; vert - definete cadrajul pe vertical.
Valorile acestor parametri pot fi determinate cu ajutorul funciei gettextsettings de
prototip:
void far gettextsettings(struct textsettingstype far *textinfo);
Tipul textsettingstype este definit n fiierul graphics.h astfel:
struct textsettingstype {
int font;
int direction;
int charsize;
int horiz;
int vert;
};
Funcia gettextsettings atribuie componentelor structurii de tip textsettingstype
valorile curente. Amintim valorile numerice ale constantelor simbolice indicate mai sus.
Tabelul 11.5 Valorile constantelor pentru aliniarea textului
Constant
simbolic
Valoare
LEFT_TEXT 0
CENTER_TEXT 1
RIGHT_TEXT 2
BOTTOM_TEXT 0
TOP_TEXT 2
HORIZ_DIR 0
VERT_DIR 1
Dup setarea parametrilor de mai sus se pot afia texte folosind funciile outtext i
outtextxy. Prima afieaz textul ncepnd cu poziia curent de pe ecran. Cea de a doua
funcie permite afiarea textului ncepnd cu un punct al crui coordonate sunt definite prin
primii doi parametri efectivi ai funciei. Funciile afieaz caractere colorate folosind
culoarea de desenare curent.
Funcia outtext are prototipul:
void far outtext(char far *sir);
unde:sir - Este pointer spre o zon de memorie n care se pstreaz caracterele de afiat.
Tabelul 11.6
Valoarea
parametrului
Matricea folosit pentru
afiarea caracterului (n pixeli)
1 8*8
2 16*16
3 24*24
10 80*80
Se afieaz caracterele respective pn la ntlnirea caracterului NUL. Funcia outtextxy
are prototipul:
void far outtextxy (int x, inty, char far *sir);
unde: (x,y) - definete poziia punctului de pe ecran ncepnd cu care se afieaz textul; sir
- Are aceeai semnificaie ca n cazul funciei outtext.
Dimensiunile n pixeli a unui ir de caractere se pot determina folosind funciile
textheight i textwidth. Acestea au prototipurile:
GESTIUNEA ECRANULUI N MOD GRAFIC

163
int far textheight(char far *sir);
funcia returneaz nlimea n pixeli a irului pstrat n zona spre care pointeaz sir,
int far textwidth(char far *sir);
funcia returneaz limea n pixeli a irului aflat n zona spre care pointeaz sir.
Utilizatorul poate defini dimensiunea caracterelor apelnd funcia setusercharsize. Ea
are prototipul:
void far setusercharsize(int multx, int divx, int multy, int
divy);
Dimensiunea caracterelor se definete prin nmulirea limii lor cu multx/divx i a
nlimii cu multy/divy. Modificarea dimensiunii caracterelor n acest mod este posibil
pentru fonturile diferite de fontul DEFAULT_FONT.
Observaie: Funcia printf poate fi folosit pentru a afia caractere n mod obinuit. Ea
ignor parametrii indicai mai sus.

Exemplul 11.4 S se scrie un program care afieaz texte folosind toate cele 5 fonturi,
caracterele avnd pe rnd dimensiunile 1, 2, 3 i 4. n cazul fonturilor diferite de
DEFAULT_FONT, se vor afia texte ale cror caractere se vor afla n rapoartele: 4/3 n
lime i 2/1 n nlime.
#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#include <string.h>

void main() /* afiseaza texte cu diferite fonturi si dimensiuni */
{
int gdriver=DETECT,gmod;
char *denfont[]={ "Val=0 DEFAULT_FONT", "Val=1 TRIPLEX_FONT",
"Val=2 SMALL_FONT", "Val=3 SANS_SERIF_FONT", "Val=4 GOTHIC_FONT"
};
int stil,x=0,y=0; int dim;
char dimensiune[30];
for(dim=1;dim<5;dim++)
{
y=0;
initgraph(&gdriver,&gmod, "c:\\borlandc\\bgi");
for(stil=DEFAULT_FONT;stil<=GOTHIC_FONT;stil++)
{
settextstyle(stil,HORIZ_DIR,dim);
sprintf(dimensiune,"dim=%d font:",dim);
outtextxy(x,y,dimensiune);
x+=textwidth (dimensiune);
/* avans la coloana libera de pe aceeasi linie */
outtextxy(x,y,denfont[stil]);
y+=textheight (denfont[ stil]);
/* avans la inceputul liniei urmatoare */
x=0;
/* se defineste dimensiunea de catre utilizator raport:
4/3 in latime; 2/1 in lungime. */
if(stil!=DEFAULT_FONT)
{
setusercharsize (4,3,2,1);
Capitolul 11

164
/* definesc raporturile pentru dimensiunile caracterelor */
strcpy(dimensiune,"dim utilizator:4/3,2/1");
outtextxy(x,y,dimensiune);
y+=textheight(dimensiune);
x=0;
}
getch();
}
closegraph();
printf("Actionati o tasta pentru a continua\n");
getch();
}
}
Exemplul 11.5 S se scrie un program care afieaz texte cadrate n toate variantele
definite de funcia settextjustify.
#include <graphics.h>
#include <conio.h>
#include <stdio.h>

main ()
/* afieaz texte cadrate in toate variantele definite de
funcia settextjustify */
{
int gdriver=DETECT,gmod;
char *hjust[]={"LEFT_TEXT", "CENTER_TEXT", "RIGHT_TEXT"};
char *vjust[]={"BOTTOM_TEXT", "CENTER_TEXT", "TOP_TEXT"};
int x=200,y=100,hj,vj;
for(hj=LEFT_TEXT;hj<=RIGHT_TEXT;hj++) {
initgraph(&gdriver,&gmod,"c:\\borlandc\\bgi");
outtextxy(x,y,hjust[hj]);
y+=textheight(hjust[hj])+8;
for(vj=BOTTOM_TEXT;vj<=TOP_TEXT;vj++)
{
settextjustify(hj,vj);
outtextxy(x,y,"N");
x+=textwidth("N");
outtextxy(x+100*vj+100,y,vjust[vj]);
getch();
}
closegraph();
}
}
11.5 Gestiunea imaginilor
n paragrafele precedente s-a artat c ecranul n mod grafic se compune din n*m puncte
luminoase numite pixeli. Un pixel are o poziie definit prin coordonatele sale i este
colorat n cazul adaptoarelor color. La adaptoarele monocrom pixelul are o nuan de gri.
Utilizatorul poate afia pe ecran un pixel cu ajutorul funciei putpixel. Aceasta are
prototipul:
void far putpixel(int x, inty, int culoare);
GESTIUNEA ECRANULUI N MOD GRAFIC

165
unde: (x,y) - definete poziia punctului; culoare - definete culoarea punctului i este un
ntreg din intervalul [0,15] i reprezint indicele culorii n tabela care definete paleta
curent.
Funcia getpixel permite stabilirea culorii unui pixel afiat pe ecran. Ea are prototipul:
unsigned far getpixel (int x, int y);
unde: (x,y) - definete poziia punctului.
Funcia returneaz un ntreg din intervalul [0,15]. Acesta definete culoarea pixelului de
coordonate (x,y), fiind index n tabloul care definete paleta curent.
Ecranul poate fi partajat n mai multe pri care pot fi gestionate independent. Aceste pri
le vom numi ferestre grafice. n continuare, prin ferestr vom nelege o fereastr grafic.
O fereastr se definete cu ajutorul funciei setviewport de prototip:
void far setviewport(int st, int sus, int dr, int jos, int d);
unde: (st, sus) sunt coordonatele colului stnga sus al ferestrei; (dr, jos) sunt coordonatele
colului dreapta jos al ferestrei; d - Indicator cu privire la decuparea desenului (vezi mai
jos).
Fereastra definit n urma apelului funciei setviewport devine fereastra activ. Iniial
(imediat dup setarea modului grafic), fereastra activ este tot ecranul.
O fereastr activ se poate terge cu ajutorul funciei clearviewport. Ea are prototipul:
void far clearviewport(void);
Dup apelul funciei clearviewport, toi pixelii ferestrei active au aceeai culoare i
anume culoarea de fond curent.
Poziia curent dup apelul funciei clearviewport este pixelul de coordonate relative
(0,0), adic chiar colul din stnga sus al ferestrei.
O alt funcie utilizat pentru a terge tot ecranul este funcia cleardevice. Ea are
prototipul:
void far cleardevice(void);
Dup apelul funciei cleardevice se terge tot ecranul i pixelul curent devine cel din
colul stnga sus al ecranului.
Parametri ferestrei active se pot determina apelnd funcia getviewsettings. Aceasta
are prototipul:
void far getviewsettings(struct viewporttype far *fereastra)
unde: viewporttype - Este un tip definit n fiierul graphics.h astfel:
struct viewporttype {
int left; int top; int right; int bottom; int clip;
};
Dup apelul funciei getviewsettings, la componentele structurii de tip viewporttype de
la apel li se atribuie valorile corespunztoare ale ferestrei active.
Parametrul clip are dou valori: CLIP_ON (valoarea 1) sau CLIP_OFF (valoarea zero).
Dac clip are valoarea 1, atunci funciile de afiare a textelor i de desenare nu pot scrie
sau desena n afara limitelor ferestrei active. n caz contrar, se pot depi limitele ferestrei
active. Deci textele i figurile care nu ncap n fereastra activ se trunchiaz dac: clip =
CLIP_ON.
Imaginea ecranului se pstreaz n memoria video a adaptorului grafic i formeaz o
pagin. n cazul adaptoarelor de tip EGA/VGA, adaptorul dispune de o memorie video
capabil s memoreze 8 pagini. Acestea se numeroteaz de la 0 la 7.
Capitolul 11

166
Funciile de desenare i scriere de texte acioneaz asupra unei singure pagini. Aceasta
se numete pagina activ. Utilizatorul poate activa o pagin folosind funcia
setactivepage de prototip:
void far setactivepage(int nrpag);
unde: nrpag - Este numrul paginii care se activeaz.
De obicei, pagina activ este vizualizat pe ecran. Cu toate acestea, programatorul are
posibilitatea s vizualizeze o alt pagin dect cea activ. Aceasta se realizeaz utiliznd
funcia setvisualpage de prototip:
void far setvisualpage(intr/?g);
unde: nrpag - Este numrul paginii care se vizualizeaz.
Aceast funcie poate fi util pentru animaie.
Imaginea unei zone dreptunghiulare de pe ecran poate fi salvat n memorie folosind
funcia getimage. Ea are prototipul:
void far getimage(int st, int sus, int dr, int jos, void far
*zt);
unde: (st, sus) - definete coordonatele colului stnga sus a zonei de pe ecran care se
salveaz; (dr, jos) - definete coordonatele colului dreapta jos a zonei de pe ecran care se
salveaz; zt - Pointer spre zona de memorie n care se salveaz imaginea de pe ecran.
Dimensiunea zonei de memorie spre care pointeaz zt trebuie s fie suficient de mare
pentru a putea salva datele care definesc imaginea de pe ecran, care se salveaz.
Aceast dimensiune se poate determina folosind funcia imagesize de prototip:
unsigned far imagesize(int st, int sus, int dr, int jos);
unde: (st,sus) - definete coordonatele colului din stnga sus a zonei dreptunghiulare de
pe ecran; (dr,jos) - definete coordonatele colului din dreapta jos a zonei dreptunghiulare
de pe ecran.
Funcia imagesize se apeleaz nainte de a apela funcia getimage pentru a stabili
dimensiunea zonei de memorie necesar pentru a salva o imagine dreptunghiular de pe
ecran. Zona de memorie respectiv se poate rezerva n memoria heap innd seama de
valoarea returnat de funcia imagesize.
Imaginea de pe ecran salvat cu ajutorul funciei getimage, poate fi afiat pe ecran n
orice parte a acestuia, cu ajutorul funciei putimage. Cu aceast ocazie se pot face
anumite operaii asupra datelor care definesc imaginea. Funcia are prototipul:
void far putimage(int st, int sus, void far *zt, int op);
unde: (st,sus) - definete coordonatele colului stnga sus a zonei de pe ecran n care se
afieaz imaginea. zt - Pointer spre zona n care se pstreaz datele care formeaz
imaginea de afiat. Aceste date au fost pstrate n zona respectiv prin intermediul funciei
getimage.
op - definete operaia ntre datele aflate n zona spre care pointeaz zt i cele existente
pe ecran n zona dreptunghiular definit de parametri st, sus (colul din stnga sus; colul
din dreapta jos rezult din datele existente n zona spre care pointeaz zt).
Parametrul op se definete ca mai jos:
Tabelul 11.7 Valorile constantelor pentru modul de copiere
Constant
simbolic
Valoare Aciune
COPY_PUT 0 copiaz imaginea din memorie pe ecran
XOR_PUT 1 "sau exclusiv" ntre datele de pe ecran i cele aflate n
memorie
GESTIUNEA ECRANULUI N MOD GRAFIC

167
OR_PUT 2 "sau" intre datele de pe ecran i cele din memorie
AND_PUT 3 "i" ntre datele de pe ecran i cele din memorie
NOT_PUT 4 copiaz imaginea din memorie pe ecran completnd
datele aflate n memorie.
Pentru a defini pixelul curent se utilizeaz funcia moveto. Aceasta are prototipul:
void far moveto(intx, inty);
Dup apelul funciei moveto, pixelul curent devine cel de coordonate (x,y). O funcie
nrudit cu aceasta este funcia moverel. Aceasta are prototipul:
void far moverel(int dx, int dy);
Dac notm cu (x,y) coordonatele pixelului curent, atunci dup apelul funciei moverel,
pixelul curent are coordonatele: (x+dx,y+dy).
Observaie:
Majoritatea funciilor care au ca parametri coordonate de pixel, interpreteaz aceste
coordonate ca fiind relative fa de fereastra activ al crei col stnga sus are
coordonatele (0,0). Aa de exemplu, funciile: outtextxy, putpixel, getpixel,
moveto au ca parametri coordonate relative la pixelul din colul stnga sus al ferestrei
active.
Funciile getx i gety returneaz abscisa, respectiv ordonata, relative la pixelul din colul
stnga sus al ferestrei active.
n schimb funciile getmaxx i getmaxy returneaz totdeauna abscisa, respectiv
ordonata, maxim pentru tot ecranul n conformitate cu modul grafic.
De asemenea, funciile setviewport i getviewsettings gestioneaz coordonate
care sunt relative fa de colul stnga sus al ecranului i nu fa de fereastra activ. Astfel
de coordonate le vom numi n continuare absolute.
Exerciii:
Exemplul 11.6 S se scrie un program care realizeaz urmtoarele:
a. Afieaz, ntr-o zon de dimensiune 50*50, pixeli colorai folosind toate culorile din
palet. Zona se afl n colul din stnga sus al ecranului.
b. Definete fereastra de coordonate: (60,0) - colul stnga sus; (120,60) - colul dreapta
jos. Afieaz n fereastra activ pixeli colorai folosind toate culorile din palet.
c. Definete fereastra de coordonate: (20,100) - colul stnga sus; (100,180) - colul
dreapta jos. Afieaz n fereastra activ pixeli colorai folosind toate culorile din palet.
Afieaz n fereastra activ textul "abcdefg" ncepnd cu poziia de coordonate(1,1). Se
utilizeaz culoarea de index 6.
d. Se terge fereastra activ. Se afieaz textul "abcdefg" ncepnd cu poziia curent din
fereastr i folosind culoarea de index 14.
e. Se terge tot ecranul.
f. Se revine din modul grafic.
Dup realizarea fiecrui punct de mai sus se vizualizeaz ecranul apelnd funcia getch.
Pentru a continua, se acioneaz o tast oarecare.
#include <graphics.h>
#include <conio.h>
main () /* - afieaz in trei zone ale ecranului pixeli colorai
folosind toate culorile paletei;
- in una din zone se afieaz si textul "abcdefg";
- in final se terg zonele afiate. */
{
int gd=DETECT,gm; int i,j,c;
initgraph(&gd,&gm,"c:\\borlandc\\bgi");
/* zona din coltul stinga sus al ecranului */
Capitolul 11

168
for(i=0;i<50;i++){
c=i;
for(j=0;j<50;j++,c++) {
c=c%16;
putpixel(i,j,c); }
}
getch();
/* definete o fereastra si afieaz in ea pixeli colorai */
setviewport(60,0,120,60,1);
for(i=0;i<50;i++){
c=0;
for(j=0;j<50;j++,c++){
c=c%16;
putpixel(i,j,c); }
}
getch();
/* definete ultima zona si afieaz in ea pixeli colorai */
setviewport(20,100,100,180,1);
for(i=0;i<40;i++){
c=10;
for(j=0;j<250;j++,c++){
c=c%16;
putpixel(i,j,c); }
}
/* afieaz textul "abcdefg" */
setcolor(6);
outtextxy(1,1,"abcdefg"); getch();
/* terge ultima zona si apoi afieaz acelai text folosind
culoarea de index 14 */
clearviewport(); setcolor(14); outtext("abcdefg"); getch();
/* terge tot ecranul */
cleardevice(); getch();
/* ieire din modul grafic */
closegraph();
getch(); }
Exemplul 11.7 S se scrie un program care realizeaz urmtoarele:
a. Afieaz un pixel n punctul de coordonate absolute (20,30), apoi textul: (x,y), unde: x i
y sunt coordonatele returnate de funciile getx i respectiv gety.
b. Se deplaseaz poziia curent cu valoarea relativ 30, att pe abscis, ct i pe
ordonat, apoi se afieaz pixelul curent i textul: (x,y), unde: x i y sunt valorile returnate
de funciile getx i respectiv gety
c. Se definete fereastra de coordonate: (200,0,420,70); apoi se repet secvenele a-b de
mai sus.
d. Se terge fereastra activ.
e. Se terge ecranul i se iese din modul grafic.
Culoarea pentru afiare este culoarea de index maxim.
#include <graphics.h>
#include <conio.h>
#include <stdio.h>

main() /*-afieaz:
GESTIUNEA ECRANULUI N MOD GRAFIC

169
a- un pixel in punctul de coordonate absolute (20,30), apoi
textul (x-y) unde x si y sunt coordonatele returnate de
getx si respectiv gety;
b- se deplaseaz poziia curenta cu valoarea relativa 30 atit pe
abscisa cit si pe ordonata, apoi se afieaz pixelul
curent si textul (x,y) unde x si y se definesc ca mai
sus; c- se definete fereastra 200,0,420,70 si se
repeta secvenele a-b de mai sus; se terg afirile si
apoi se iese din modul grafic. */
{
int gd=DETECT,gm; int x,y,i; char msg[80];
initgraph(&gd, &gm, "c:\\borlandc\\bgi");
for(i=0;i<2;i++){
moveto(20,30);
putpixel(getx(),gety(),getmaxcolor());
sprintf(msg,"(%d %d)",getx(),gety());
outtext(msg);
/* deplasare relativa fata de poziia curenta */
moverel(30,30);
putpixel(getx(),gety(),getmaxcolor());
sprintf(msg,"(%d %d)",getx(),gety());
outtext(msg); getch();
setviewport(200,0,420,70,1);
}
clearviewport();
getch(); cleardevice();
getch(); closegraph();
}
Exemplul 11.8 S se scrie un program care realizeaz urmtoarele:
a. Afieaz pixeli colorai ntr-o zon dreptunghiular n colul din stnga sus al ecranului,
apoi o afieaz pe ecran n zone ce au poziii definite aleator.
b. La afiarea imaginii se folosesc toate operaiile dintre imagini oferite de funcia
putimage.
c. Culoarea de fond se schimb folosind toate culorile din palet.
Dup afirile indicate mai sus execuia se poate termina acionnd tasta zero; orice alt
tast acionat permite continuarea programului cu un nou set de imagini afiate aleator.
Se tre imagini cnd acestea se suprapun. observ efectul operaiilor din
#include <graphics.h>
#include <conio.h>
#include <alloc.h>
#include <stdlib.h>
#include <dos.h>
#include <stdio.h>

main () /* - afieaz pixeli colorai intr-o zona
dreptunghiulara in coltul din sting sus al ecranului,
apoi afieaz imaginea respectiva pe ecran in zone ce
au poziii definite aleator;
- la afiarea imaginii se folosesc toate operaiile oferite de
funcia putimage;
- de asemenea, se schimba culoarea de fond folosind toate
culorile din paleta. */
{
Capitolul 11

170
int gd=DETECT,gm; int i,j,c,k; unsigned dim;
void far *buf;
struct time t;
int rx,ry,x,y;

initgraph(&gd, &gm, "c:\\borlandc\\bgi");
/* afieaz pixeli colorai */
for(i=0;i<50;i++){
c=i;
for(j=0;j<50;j++,c++) {
c=c%16;
putpixel(i,j,c); }
}
getch();
/* salveaz zona afiat pe ecran */
dim=imagesize(0,0,50,50);
if((buf=farmalloc(dim))==0){
closegraph();
printf("Memorie insuficienta\n");
exit(1); }
getimage(0,0,50,50,buf);
/* seteaz saminta */
gettime(&t); srand(t.ti_hour*3600L +t.ti_min*60+t.ti_sec);
/* se determina valorile maxime pentru abscisa si ordonata
coltului sting al imaginilor */
x=getmaxx()-50; y=getmaxy()-50;
/* afiarea aleatoare a imaginilor */
do{
for(k=0;k<16;k++) {
setbkcolor(k);
for(i=COPY_PUT;i<=NOT_PUT;i++){
rx=random(x); ry=random(y);
setviewport(0,0,getmaxx(),getmaxy(), 1);
putimage(rx,ry,buf,i); getch(); } }
setcolor (1);
/* culoarea pentru afiarea textului in partea de jos a
ecranului */
setviewport(1,340,639,349,1);
/* fereastra pentru
text */
outtextxy(0,0,"Pentru a termina tastati zero; se continua cu
orice alta tasta");
if(getch()=='0')
break;
clearviewport ();
/* terge textul afiat */ }
while(1);
closegraph();
}
GESTIUNEA ECRANULUI N MOD GRAFIC

171
11.6 Tratarea erorilor
Erorile survenite n gestiunea n mod grafic a ecranului pot fi puse n evidenj cu ajutorul
funciei graphresult. Ea are prototipul:
int far graphresult(void);
Funcia ret rut naintea ape urneaz codul ultimei erori care a ap lului funciei
graphresult s ri. Constanta au valoarea constantei simbolice grOk dac nu au fost ero
grOk este definit n fiierul graphics.h.
Mesajul de eroare poate fi decodificat cu ajutorul funciei grapherrormsg. Aceasta are
prototipul:
char far *far grapherrormsg(int coderoare);
unde: coderoare - Este valoarea returnat de funcia graphresult.
Funcia grapherrormsg returneaz un pointer spre textul de eroare. Constanta grOk are
valoar z valori negat ea ero, iar codurile de eroare a ive. u
Exerciii:
Exemplul 11.9 S se s z parametri imp crie un program care afiea licii ai modului grafic
setat prin apelul funciei initgraph:
numele adaptorului numele modului g grafic; rafic;
rezoluia; fereastra curent;
decupajul; poziia curent;
numrul culorilor disponibile; culoarea curent;
setul de caractere; direcia textului;
dimensiunea caracterelor; cadrajul textelor.
#include <conio.h>
#include <graphics.h>
#include <stdio.h>
#include <stdlib.h>
int grafdriver, grafmod; struct palettetype paleta;
int maxculori; int xmax, ymax; int posx,posy;
char *Fonts[] = {"DefaultFont", "TriplexFont" , "SmallFont",
"SansSerifFont", "GothicFont"};
char *TextDirect[]={"HorizDir","VertDir"};
char *HorizJust[]={"LeftText","CenterText","RightText"};
char *VertJust[]={"BottomText","CenterText","TopText"};

void inimodgrafic() /* iniializeaz modul grafic */
{
int eroare;
grafdriver=DETECT;
initgraph(&grafdriver, &grafmod,"c:\\borlandc\\bgi");
eroare=graphresult();
if(eroare!= grOk){
printf ("eroare la initializarea modului\
grafic: %s\n", grapherrormsg(eroare));
exit(1);
}
getpalette(&paleta); maxculori=getmaxcolor() + 1;
xmax=getmaxx(); ymax=getmaxy();
posx=getx(); posy=gety();}

void fereastra_principala(char *antet)/*
afieaz antetul in fereastra principala */
Capitolul 11

172
{ int inalt;
/* sterge ecranul */
cleardevice();
/* seteaz fereastra principala pe tot ecranul */
setviewport (0,0,xmax,ymax,1);
/* determina inaltimea textului */
inalt=textheight("H");
/* afiarea textului */
outtextxy(xmax/2, 2, antet);
/* seteaz o fereastra pentru a continua afisarea */
setviewport(1, inalt+5, xmax-1,
ymax-(inalt+ 5),1);
}

void afisinit()
/* afiseaz datele de la initializarea modului grafic */
{
struct viewporttype infview; struct textsettingstype inftext;
char *driver,*mod; int x,y; char sir[130];

getviewsettings(&infview);
gettextsettings(&inftext); driver=getdrivername();
mod=getmodename(grafmod);
x=10; y=4;
/* se scrie textul:rezultatele initializrii */
fereastra_principala("Rezultatele initializrii");
/* cadrajul textului */
settextjustify(LEFT_TEXT,TOP_TEXT);
/* afieaz adaptorul grafic */
sprintf(sir,"adaptorul grafic: %-20s(%d)", driver, grafdriver);
outtextxy(x,y,sir); y+=8;
/* afieaz modul grafic */
sprintf(sir, "modul grafic: %-20s (%d)", mod, grafmod);
outtextxy(x,y,sir); y+=8;
/* afieaz rezoluia */
sprintf(sir,"rezolutia: (0,0,%d,%d)", xmax, ymax);
outtextxy(x,y,sir); y+=8;
/* fereastra grafica curenta */
sprintf(sir,"fereastra curenta:(%d, %d, %d, %d)", infview.left,
infview.top, infview.right, infview.bottom);
outtextxy(x,y,sir); y+=8;
sprintf(sir,"decupaj: %s",infview.clip ? "ON" : "OFF");
outtextxy(x,y, sir); y+=8;
/* poziia curenta */
sprintf(sir, "pozitia curenta:(%d, %d)",posx, posy);
outtextxy(x, y, sir); y+=8;
/* numr culori disponibile */
sprintf(sir, "numr culori: %d", maxculori);
outtextxy(x,y,sir); y+=8;
/* culoarea curenta */
sprintf(sir, "culoarea curenta: %d",getcolor());
outtextxy(x, y, sir); y+=8;
/* setul de caractere */
sprintf(sir, "setul de caractere: %s", Fonts[inftext.font]);
GESTIUNEA ECRANULUI N MOD GRAFIC

173
outtextxy(x,y,sir); y+=8;
/* direcia textului */
sprintf (sir,"directia textului:
%s",TextDirect[inftext.direction]);
outtextxy(x,y,sir); y+=8;
/* dimensiunea caracterului */
sprintf (sir,"dimensiunea caracterului: %d",inftext.charsize);
outtextxy(x,y,sir); y+=8;
/* cadraj orizontal */
sprintf(sir, "cadraj orizontal: %s",
HorizJust[inftext.horiz]); outtextxy(x,y,sir); y+=8;
/* cadraj vertical */
sprintf(sir,"cadraj vertical: %s", VertJust[inftext.vert]);
outtextxy(x,y,sir);
}

void main () /* afiseaza starea curenta a unor parametri ai
modului grafic */
{
inimodgrafic();
afisinit();
outtextxy(8,ymax-50,"Acionati o tasta pentru a termina");
getch ();
closegraph();
}
11.7 Desenare i colorare
Biblioteca standard a sistemului pune la dispoziia utilizatorului o serie de funcii care
permit desenarea i colorarea unor figuri geometrice.
Amintim c un de prototip punct colorat (pixel) se afieaz cu ajutorul funciei putpixel
(vezi paragraful 10.5):
void far putpixel(int x, int y, int culoare);
unde: (x,y) sunt coordonatele punctului care se afieaz i ele sunt relative la fereastra
activ; culoare este index n tabloul care definete paleta curent.
Indexul respectiv definete codul culorii pentru afiarea pixelului pe ecran.
Menionm c n acest paragraf prin parametrul culoare vom nelege un index n tabloul
care definete paleta curent. Acest index definete codul culorii pentru desenarea i
colorarea figurilor.
Pentru ne trasarea liniilor se pot folosi trei funcii: line, lineto i linerel. Funcia li
are prototipul:
void far line(int xstart, int ystart, int xfin, int yfin);
Funcia traseaz un segment de dreapt ale crui capete sunt punctele de coordonate:
(xstart, ystart) (xfin, yfin).
Funcia lineto are prototipul:
void far lineto(int i, int y);
Ea traseaz un segment de dreapt care are ca origine poziia curent, iar ca punct final
cel de coordonate (x,y). Punctul final devine poziia curent.
Amintim c funcia movet agraful 10.5). o permite definirea poziiei curente (vezi par
Cea de a treia funcie utilizat la trasarea dreptelor are prototipul:
Capitolul 11

174
void far linerel(int x, int y);
Dac notm cu xcrt i ycrt coordonatele poziiei curente, atunci funcia lincrel traseaz
un segment de dreapt ale crui capete sunt punctele de coordonate: (xcrt, ycrt) i (xcrt+x,
ycrt+y).
Alte funcii care permit trasri de figuri geometrice utilizate frecvent sunt:
void far arc(int xcentru, int ycentru, int unghistart, int
unghifin, int raza);
traseaz un arc de cerc; unghiurile sunt exprimate n grade sexagesimale.
void far circle(int xcentru, int ycentru, int raza);
traseaz un cerc; (xcentru, ycentru) sunt coordonatele centrului arcului de cerc i respectiv
cercului trasat de aceste funcii; parametrul raza definete mrimea razei curbelor
respective.
void far ellipse(int xcentru, int ycentru, int unghistart, int
unghifin, int semiaxamare, int semiaxamica);
traseaz un arc de elips cu centrul n punctul de coordonate (xcentru, ycentru) avnd
semiaxa marc definit de parametrul semiaxamare, iar semiaxa mic de parametrul
semiaxamica.
void far rectangle(int st, int sus, int dr, int jos);
traseaz un dreptunghi definit de colurile sale opuse: (st, sus) - Colul din stnga sus; (dr,
jos) - Colul din dreapta jos.
void far drawpoly(int nr, int far *tabpct);
traseaz o linie poligonal: nr - Numrul laturilor; tabpct - Este un pointer spre ntregi care
definesc coordonatele vrfurilor liniei poligonale. Acestea sunt pstrate sub forma:
abscisa_i, ordonata_i, unde i are valorile 1, 2,..., nr+1. Linia poligonal este nchis dac
primul punct coincide cu ultimul (au aceleai coordonate). Coordonatele utilizate ca
parametri la apelul acestor funcii sint relative la fereastra activ. Culoarea de trasare este
cea curent. La trasarea liniilor cu ajutorul funciilor: line, lineto i linerel se poate
i un stil de trasare folosind funcia setlinestyle. Aceast funcie are prototipul:

defin
void far setlinestyle(int stil, unsigned ablon, int grosime);
unde:stil - Este un ntreg din intervalul [0,4] care definete stilul liniei conform tabelului de
mai jos:
belul 11 onstantelor pentru stilul liniei
aloare Stil
Ta

.8 Valorile c
Constant
simbolic
V
SOLID_LINE 0 linie continu
DOTTED_LINE 1 linie punctat
CENTER_LINE 2 linie ntrerupt format din liniue de
dou dimensiuni
DASHED_LINE 3 linie ntrerupt format din liniue de
aceeai dimensiune
USERBIT_LINE 4 stil definit de utilizator prin ablon
ablon - definete stilul liniei. Are sens numai cnd primul parametru (stil) are valoarea 4;
n rest este neglijat i de aceea poate avea valoarea zero. grosime - definete ljimea liniei
n pixeli; pot fi dou limi: NORM_WIDTH (valoarea 1 pixel) i THICK_WIDTH (valoarea 3
pixeli).
Stilul curent poate fi determinat apelnd funcia getlinesettings de prototip:
GESTIUNEA ECRANULUI N MOD GRAFIC

175
void far getlinesettings(struct linesettingstype far
*linieinfo);
unde: linesettingstype - Este definit n fiierul graphics.h astfel:
struct linesettingstype {
int linestyle;
unsigned upattern;
int thickness;};
Dup apelul funciei getlinesettings, componentelor structurii de tip
linesettingstype de la apel li se atribuie valorile curente ale stilului de trasare dup
cum urmeaz:
linestyle - Are ca valoare stilul definit mai sus; upattem - Are ca valoare ablonul definit de
utilizator. Aceast valoare are semnificaie numai dac linestyle are valoarea 4. thickness -
Are valoarea 1 sau 3 i reprezint grosimea de trasare a dreptelor prin funciile line,
lineto sau tinerel.
Din cele de mai sus rezult c pentru trasarea liniilor se pot folosi 4 stiluri standard
(definite de valorile SOLID_LINE, DOTTED_LINE, CENTER_LINE i DASHED_LINE),
precum i unul nestandard, definit de utilizator (valoarea USERBIT_LINE).
Stilul nestandard se precizeaz cu ajutorul parametrului ablon. Acesta este o dat de tip
int (16 bii). Fiecare bit din ablon reprezint un pixel al liniei. Fiecare bit din ablon setat
reprezint un pixel colorat cu culoarea curent, biii din ablon de valoarea zero reprezint
pixeli colorai cu culoarea de fond.
Alte funcii din biblioteca standard a sistemului permit trasarea de figuri geometrice
mpreun cu colorarea interiorului acestora. Indicm mai jos prototipurile funciilor mai
importante din aceast clas:
void far bar(int st, int sus, int dr, int jos);
unde: st, sus, dr, jos - Au aceleai semnificaii ca n cazul funciei rectangle.
Funcia deseneaz un domeniu dreptunghiular colorat (fr a avea o frontier scoas n
eviden).
void far bar3d(int st, int sus, int dr, int jos, int profunzime,
int ind);
Funcia deseneaz o prism dreptunghiular colorat pentru ind diferit de zero. Pentru
ind=0, nu se traseaz partea de sus a prismei.
void far pieslice(int xcentru, int ycentru, int unghistart, int
unghi in, int raza);
Funcia deseneaz un sector de cerc colorat.
void far fillpoly(int nr, int far *tabpct);
unde: nr i tabpct - Au aceleai semnificaii ca n cazul funciei drawpoly.
Funcia deseneaz un poligon colorat.
void far fillellipse(int xcentru, int ycentru,int semiaxamare,
int semiaxamica);
Funcia deseneaz o elips colorat.
Menionm c figurile desenate cu funciile indicate mai sus se coloreaz folosind o
culoare definit n prealabil cu ajutorul funciei setfillstyle. De asemenea, o figur
poa : te fi colorat n mai multe feluri
folosind culoarea de fond;
Capitolul 11

176
colorare uniform (toi pixelii din interiorul figurii au aceeai culoare) folosind
culoarea definit prin funcia setfillstyle;
colorare prin haur. Haura poate fi standard sau definit de utilizator.
Modul de lo e. Ea are co rare al unei figuri se definete tot cu ajutorul funciei setfillstyl
prototipul:
void far setfillstyle(int haura, int culoarea);
unde: haura - definete modul de colorare conform tabelului de mai jos; culoarea -
definete culoarea pentru colorarea figurilor.
Parametr
abelul 11.9 rile pen ura
ul haura are urmtoarele valori:
T Valo tru parametrul ha
Constant simbolic Valoare Constant simbolic Valoare
EMPTY_FILL 0 HATCH_FILL 7
SOLID_FILL 1 XHATCH_FILL 8
LINE_FILL 2 INTERLEAVE_FILL 9
LTSLASH_FILL 3 WIDE_DOT_FILL 10
SLASH_FILL 4 CLOSE_DO _FILL T 11
BKSLASH_FILL 5 USER_FILL 12
LTBKSLASH_FILL 6
Valoarea EMPTY_FILL coloreaz figura folosind culoarea de fond. Valoarea SOLID_FILL
realizeaz colorarea uniform a figurii (toi pixelii din interiorul figurii au aceeai culoare).
Valorile de la LINE_FILL (2), pn la CLOSE_DOT_FILL (11) definesc diferite hauri
standard. V te de c aloarea USER_FILL se utilizeaz cnd haura se define tre utilizator.
Pentr u a defini o haur nestandard se utilizeaz funcia setfillpattern. Aceasta are
proto tipul:
void far setfillpattern(char far *h_utilizator, int culoare);
unde: h_utilizator - Este un pointer spre o zon de memorie n care se definete, pe 8
octei, haura; culoare - definete culoarea de haurare.
ablonul se definete printr-un ir de 8 octei. Fiecare octet definete 8 pixeli, deci un
ablon definete 64 pixeli.
Modul curent utilizat la colorare se poate determina cu ajutorul funciei
getfillsetlings. Aceasta are prototipul:
void far getfillsettings(struct fillsettingstype far
*stilcolorare);
un ierul graphics.h astfel: de: fillsettingstype - Este definit n fi
struct fillsettingstype {
int pattern;
int color;};
unde: pattern - Este componenta care defines a modul de colorare utilizat la colorare
(ntreg din intervalul [0,12]); color - definete culoarea utilizat la colorare.
Funcia getfill torul funciei pattern determin ablonul definit de utilizator cu aju
setfillpattern . Ea are prototipul:
void far getfillpattern(char far *sablon);
La apelul funciei getfillpattern se atribuie, la 8 octei din zona spre care pointeaz
pointerul ablon, valorile care stabilesc haura definit de utilizator prin apelul prealabil al
funciei setfillpattern.
Utilizatorul poate trasa i alte figuri dect cele pentru care au fost prevzute funcii
standard de fel l celor ind ate u ic mai sus. n acest scop se pot folosi funciile putpixel,
GESTIUNEA ECRANULUI N MOD GRAFIC

177
line, lineto, linerel, arc etc., pentru a trasa elemente componente ale figurii de
trasat.
Pentru a ll. colora un domeniu nchis obinut n acest fel, se folosete funcia floodfi
Aceasta a re prototipul:
void far floodfill(intx, inty, int culoare frontiera);
unde: (x,y) sunt coordonatele unui punct interior figurii care se coloreaz; culoare frontiera
- definete culoarea utilizat la trasarea conturului figurii.
Interiorul figurii se coloreaz n conformitate cu parametrii curent setai prin apelul funciei
setfillstyle.
La trasarea figurilor trebuie s se in seama de faptul c pixelii nu sunt puncte ideale. Ei
au forme dreptunghiulare. Din aceast cauz, figurile afiate pe ecran vor avea un aspect
deformat fa de forma lor ideal. Pentru a evita acest lucru se utilizeaz nite factori de
corecie n i unul umii coeficieni de aspect. Acetia sunt doi: unul realativ la abscis
relativ la or tio de donat. Valorile lor se pot seta cu ajutorul funciei setaspectra
prototip:
void far setaspectratio(int xaspect, int yaspect);
Valorile acestor coeficieni depind de adaptorul grafic. Raportul (double)xaspect/yaspect
se folosete adesea la trasarea curbelor definite analitic.
Valori e le curente ale acestor coeficieni pot fi gsite apelnd funcia getaspectratio d
protot ip:
void far getaspectratio(int far *xaspect, int far *yaspect);
Dup apel, cei doi coeficieni de aspect cureni se afl memorai n zonele spre care
pointeaz parametrii xaspect i yaspect.
Exerciii:
Ex rogram care traseaz linii orizontale folosind cele 4 stiluri emplul 11.10 S se scrie un p
standard i ambele grosimi.
#include <graphics.h>
#include <conio.h>

main ()
/* traseaz linii orizontale folosind cele 4 stiluri standard si
ambele grosimi */
{
char *stil[]={"SOLID_LINE = 0", "DOTTED_LINE =1", "CENTER_LINE
=2", "DASHED_LINE =3"};
char *grosime[]={"NORM_WIDTH =1", "THICK_WIDTH =3"};
int gd=DETECT,gm; int i,j; int x,y;
initgraph(&gd,&gm,"c:\\borlandc\\bgi");
x=getmaxx()/4; y=getmaxy()/8;
settextstyle(DEFAULT_FONT,HORIZ_DIR, 1);
settextjustify(LEFT_TEXT,CENTER_TEXT);
for(i=SOLID_LINE;i<=DASHED_LINE;i++)
for(j=0;j<2;j++){
outtextxy(x,y,stil[i]);
outtextxy(x+textwidth(stil[i])+4, y, grosime[j]);
y +=textheight(grosime[j])+4;
if(j)
setlinestyle(i,0,3);
else
setlinestyle(i,0,1);
line(x,y,3*x,y); y+=20;
Capitolul 11

178
}
getch();
closegraph();
}
Exemp se scrie un program care traseaz urmtoarele figuri: lul 11.11 S
cerc;
elips;
dreptunghi;
patrulater.
Tipul figurii se stabilete aleator. Figurile sunt trasate folosind n mod aleator culoarea de
desenare.
#include <graphics.h>
#include <conio.h>
#include <stdlib.h>

main () /* traseaz figuri geometrice in mod aleator */
{
int gd=DETECT,gm;
int i;
int xmax,ymax,x,y;
int poligon[10];
initgraph(&gd, &gm, "c:\\borlandc\\bgi");
outtextxy(0,0,"Pentru a termina acionai tasta zero");
setviewport(0,8,getmaxx(),getmaxy(),1);
srand (1993);/* seteaz saminta irului de numere pscudo-
aleatoare */
xmax=getmaxx();
ymax=getmaxy();
for (;;){
setcolor(random(15)+1);
switch(random(4)){
case 0: /* cerc */
x=random(xmax/2)+xmax/4;
y=random(ymax/2)+ymax/4;
circle(x,y,random(80)+1); break;
case 1: /* elipsa */
x=random(xmax/2)+xmax/8;
y=random(ymax/2)+ymax/8;
ellipse(x,y,0,359,random(80)+1, random(60)+1); break;
case 2 : /* dreptunghi */
x=random(xmax/2)+xmax/10;
y=random(ymax/2)+ymax/10;
rectangle(x,y,x+random(xmax/4)+1,y+random(ymax/4)+1);
break;
case 3: /* patrulater */
for(i=0;i<8; i+=2){
poligon[i]=random(xmax);
poligon[i+1]=random(ymax);}
poligon[8]=poligon[0];
poligon[9]=poligon[1];
drawpoly(5,poligon);break;
} /* sfirsit switch */
if(getch()=='0') break;
}
GESTIUNEA ECRANULUI N MOD GRAFIC

179
closegraph();
}
Exemplul 11.12 S se scrie un program care coloreaz figurile geometrice trasate n
programul precedent.
#include <graphics.h>
#include <conio.h>
#include <stdlib.h>
main() /* traseaz si coloreaz figuri geometrice in mod aleator
*/
{
int gd=DETECT,gm; int i;
int xmax,ymax,x,y; int poligon[8];
initgraph(&gd,&gm,"c:\\borlandc\\bgi");
outtextxy(0,0,"Pentru a termina acionai tasta zero");
setviewport(0,8,getmaxx(),getmaxy(), 1);
srand (1993); /* seteaz saminta irului de numere pseudo-
aleatoare */
xmax=getmaxx(); ymax=getmaxy(); setcolor(getmaxcolor());
for (;;){
setfillstyle(SOLID_FILL,random(15)+1);
switch(random(4)){
case 0: /* cerc */
x=random(xmax/2)+xmax/4; y=random(ymax/2)+ymax/4;
pieslice(x,y,0,360,random(80)+1); break;
case 1: /* elipsa */
x=random(xmax/2)+xmax/8; y=random(ymax/2)+ymax/8;
fillellipse(x,y,random(80)+1, random(60)+1); break;
case 2: /* dreptunghi */
x=random(xmax/2)+xmax/10; y=random(ymax/2)+ymax/10;
bar(x, y, x+random(xmax/4) +1,
y+random(ymax/4)+1);break;
case 3: /* patrulater */
for(i=0;i<8; i+=2){
poligon[i]=random(xmax);
poligon[i+1]=random(ymax);
}
fillpoly(4,poligon);break;
} /* sfirsit switch */
if(getch()=='0') break;
}
closegraph();
}
Exemplul 11.13 S se scrie un program care afieaz 15 dreptunghiuri colorate, pe trei
rnduri, folosind toate cele 15 culori ale paletei diferite de culoarea de fond. Sub fiecare
dreptunghi se listeaz indicele culorii dreptunghiului, n tabloul care definete paleta
curent de culori. Dup afiarea celor 15 dreptunghiuri se poate regla monitorul aa nct
fiecare dreptunghi s fie vizibil.
Acest program poate fi utilizat ori de cte ori se constat c monitorul este dereglat.
#include <stdio.h>
#include <graphics.h>
#include <stdlib.h>
#include <conio.h>

Capitolul 11

180
main () /* afieaz 15 dreptunghiuri colorate */
{
int gd,gm; int lat,inalt,x,y,i,j,culoare;
char asculoare[5]; gd = DETECT;

initgraph(&gd,&gm,"c:\\borlandc\\bgi");
culoare = 1; lat = 78; inalt = 64;
x = lat/2; y = inalt/2;
for(j = 0; j <3; j++){
for(i = 0; i < 5; i++){
setfillstyle(SOLID_FILL,culoare);
setcolor(culoare); bar(x,y,x+lat,y+inalt);
itoa(culoare,asculoare,10);
outtextxy(x+lat/2,y+inalt+4,asculoare);
++culoare; x += (lat/2)*3; }
y += (inalt/2)*3; x = lat/2; }
getch(); closegraph();
}
Exemplul 11.14 S se scrie un program care afieaz dreptunghiuri utiliznd toate
haurile standard.
#include <stdio.h>
#include <graphics.h>
#include <stdlib.h>
#include <conio.h>

void main () /* afieaz dreptunghiuri cu toate hasurile
standard */
{
int gd,gm;
int lat,inalt,x,y,i,j,hasura;
char ashas[5];
gd = DETECT;
initgraph(&gd,&gm,"c:\\borlandc\\bgi");
lat =78; inalt = 64; x = lat/2;
y = inalt/2;
for(j = 0,hasura=EMPTY_FILL; j <3; j++)
{
for(i = 0; i < 5; i++){
if(hasura >=12) break; /* nu mai sunt hasuri */
setfillstyle(hasura,WHITE);
bar(x,y,x+lat,y+inalt);
rectangle(x,y,x+lat,y+inalt);
itoa(hasura,ashas,10);
outtextxy(x+lat/2,y+inalt+4,ashas);
++hasura;
x += (lat/2)*3;
}
if(hasura >= 12) break;
y += (inalt/2)*3; x = lat/2;
}
getch();
closegraph();
}
GESTIUNEA ECRANULUI N MOD GRAFIC

181
Exemplul 11.15 S se scrie un program care traseaz un cerc folosind ecuaiile
parametrice ale cercului:
x = r*cos(g) + xcentru; y = r*sin(g) + ycentru; (2.3)
unde: (xcentru,ycentru) sunt coordonatele centrului cercului. r - Este raza cercului. g - Este
unghiul n radiani dintre axa Ox i razaOM, O fiind originea axelor de coordonate, iar M
este punctul de pe cerc de coordonate (x,y).
Cnd unghiul g variaz de la 0 la 2*PI, punctul M(x,y) descrie cercul de raz r i cu centru
n punctul de coordonate (xcentru.ycentru).
Programul afieaz dou curbe pentru a pune n eviden importana coeficienilor de
aspect. Prima curb se afieaz folosind ecuaiile (1), iar cea de a doua curb se traseaz
corectnd ordonata conform relaiilor de mai jos:
x = r*cos(g) + xcentru; (2.4)
y = r*(xaspect/yaspect)*sin(g) + ycentru; (2.5)
unde: xaspect i yaspect sunt coficienii de aspect obinui prin apelul funciei
getaspectratio.
#include <stdio.h>
#include <graphics.h>
#include <stdlib.h>
#include <conio.h>
#include <math.h>
#define PI 3.14159265

main()
{
int gd=DETECT,gm;
int xaspect,yaspect; double FactorAspect,draza,rad;
int x,y,g;
int xcentru,ycentru;

initgraph(&gd,&gm,"c:\\borlandc\\bgi");
getaspectratio(&xaspect,&yaspect);
FactorAspect=(double)xaspect/yaspect; draza=150;
FactorAspect *=draza;
xcentru=getmaxx()/2; ycentru=getmaxy()/2;
/* traseaz un cerc fara a tine seama de coeficienii de aspect
*/
for(g=0;g<360;g++){
rad=g*PI/180.0;
x=draza*cos(rad)+xcentru; y=draza*sin(rad)+ycentru;
putpixel(x,y,WHITE);
}
getch();
/* traseaz un cerc tinind seama de coeficienii de aspect */
for(g=0;g<360;g++){
rad=g*PI/180.0;
x=draza*cos(rad)+xcentru; y=FactorAspect*sin(rad)+ycentru;
putpixel(x,y,LIGHTBLUE);
}
getch(); closegraph();
}
Exemplul 11.16 S se scrie un program care deplaseaz o imagine pe ecran.
#include<graphics.h>
#include<conio.h>
Capitolul 11

182
#include<alloc.h>
#include<dos.h>

main () /* deplaseaz un vapor pe ecran */
{
void desen_vapor();
int grmode,grdrive;
void *ptr; void *vapor1,*vapor2;
int linia,coloana;
grdrive=DETECT;
initgraph(&grdrive,&grmode,"c:\\borlandc\\bgi");
grmode=EGAHI;
setgraphmode(grmode);
setbkcolor(BLACK);
cleardevice();
desen_vapor();
setfillstyle(SOLID_FILL,LIGHTRED);
bar(10,0,25,10);
vapor1 = malloc(imagesize(0,0,50,50));
getimage(0,0,50,50,vapor1);
cleardevice();
desen_vapor();
setfillstyle(SOLID_FILL,YELLOW);
bar(25,0,40,10);
vapor2 = malloc(imagesize(0,0,50, 50));
getimage(0,0,50,50,vapor2);
setbkcolor(LIGHTBLUE);
cleardevice();
linia=coloana=0;
for(;;){
putimage(coloana,linia,vapor1,XOR_PUT); delay(100);
putimage(coloana,linia,vapor1,XOR_PUT);
coloana+=25;
if(coloana<570){
putimage(coloana,linia,vapor2,XOR_PUT); delay(100);
putimage(coloana,linia,vapor2,XOR_PUT);
coloana +=25; if(coloana>570) coloana=0;
}
else{
linia+=60;
coloana=0;
if(linia>300) linia=0;
}
if(kbhit()) break;
}
getch(); closegraph();
free(vapor1); free(vapor2);
}

void desen_vapor () /* deseneaz un vapor */
{
int puncte[]={ 25,10, 10,30, 0,30, 10,50, 40,50, 50,30, 40,30,
25,10};
setcolor(CYAN); drawpoly(8,puncte);
GESTIUNEA ECRANULUI N MOD GRAFIC

183
line(10,30,40,30);
setfillstyle(SOLID_FILL,LIGHTMAGENTA);
floodfill(25,45,CYAN);
setfillstyle(SOLID_FILL,WHITE);
floodfill(25,20,CYAN);
setcolor(BROWN); line(25,10,25,30);
}

Capitolul 12

184
12. Sortare i cutare
n universul calculatoarelor, algoritmii de cutare i sortare se afl probabil printre cele mai
importante i mai amnunit analizate obiecte de programare. Aceste rutine sunt utilizate
de aproape toate programele de baze de date, ca i de compilatoare, interpretoare i
sisteme de operare. n capitolul de fa se prezint principiile de baz ale cutrii i
sortrii.
12.1 Sortarea
Sortarea reprezint procesul de aranjare a unui set de informaii similare ntr-o ordine
cresctoare sau descresctoare.
ntr-un proces de sortare, de cele mai multe ori, doar o parte a informaiei este
reprezentativ pentru stabilirea relaiei de ordine. Aceast parte, denumit criteriul (cheia)
sortrii, stabilete efectiv aezarea unui element naintea altuia. De aceea, cheia este
folosit n comparaii, dar fiecare modificare se aplic asupra ntregii structuri de date. De
exemplu, ntr-o list de expediie potal, criteriul de sortare l-ar putea constitui codul
potal, dar operaia de sortare opereaz asupra adresei complete.
12.1.1 Clase de algoritmi de sortare
pentru sortarea tablourilor de date se folosesc urmtoarele trei metode generale:
permutare
selecie
inserare
Pentru a nelege principiile acestor metode, imaginai-v cazul unui pachet de cri de joc.
Ordonarea crilor de joc prin metoda permutrii nseamn a le etala pe mas i apoi a
schimba ntre ele crile care nu sunt n ordinea dorit pn la epuizarea acestora. Prin
metoda seleciei, ordonarea se realizeaz prin extragerea succesiv a crii celei mai mici.
Crile vor fi reinute n mn, fiecare carte plasnd-o n spatele celei anterior extrase.
Operaiunea continu pn cnd ntregul pachet a ajuns n mna dvs. Pentru a sorta
crile prin metoda inserrii, va trebui s inei tot pachetul n mn i s aezai una dup
alta crile pe mas, fiecare carte ocupnd poziia corect. Pachetul va fi ordonat n
momentul n care ai terminat crile din mn.
12.1.2 Aprecierea algoritmilor de sortare
Pentru fiecare metod de sortare s-au dezvoltat mai multe tipuri de algoritmi. Exist
avantaje specifice fiecruia, dar criteriile generale de apreciere a unui algoritm de sortare
sunt:
Viteza medie de sortare a informaiilor
Viteza de lucru n cazurile extreme: cel mai favorabil i cel mai defavorabil
Comportarea natural sau nenatural a algoritmului
Capacitatea de a rearanja elemente avnd aceeai cheie de sortare (elemente
egale)
S analizm cu atenie aceste criterii. n mod evident, rapiditatea cu care un anumit
algoritm sorteaz este un element foarte important. Viteza cu care un ir poate fi sortat
Sortare i cutare

185
este direct proporional cu numrul de comparaii i cu numrul de substituiri care se
efectueaz, substituirile necesitnd mai mult timp de lucru. O comparaie nseamn
confruntarea unui element al irului cu un alt element; o permutare se produce atunci
cnd dou elemente i schimb poziia ntre ele. Aa cum se va vedea n continuare,
pentru unele subrutine timpul de sortare crete exponenial n funcie de numrul de
elemente pe care se aplic sortarea, n timp ce pentru altele creterea este logaritmic.
Timpii de operare n cazul cel mai favorabil i cel mai defavorabil sunt importani dac se
estimeaz c aceste situaii pot aprea frecvent. Adesea sortarea opereaz eficient pentru
cazuri de complexitate medie dar extrem de ineficient pentru cazurile defavorabile.
Se spune c un algoritm de sortare are o comportare natural dac efortul minim de lucru
este cel depus pentru o list deja n ordinea dorit, efortul crescnd pe msur ce lista
iniial este mai puin ordonat, i atingnd un maximum pentru cazul unei liste n ordine
invers. Efortul depus de un algoritm este estimat de numrul de comparaii i substituiri
pe care-l efectueaz.
n fine, pentru a nelege de ce poate fi important rearanjarea elementelor avnd chei de
sortare identice, s ne imaginm cazul unei baze de date de tipul list de expediie
potal, ordonat dup un criteriu principal i alte criterii secundare. Criteriul principal este
codul potal, iar ntre adresele cu acelai cod subcriteriul de sortare este reprezentat de
numele de familie. Cnd pe list se adaug un nume nou i lista este reordonat, nu se
dorete modificarea ordinii controlate de subcriteriu (adic de numele de familie). Pentru a
se satisface aceast opiune, un algoritm de sortare va trebui s nu modifice elemente
avnd aceleai valori ale criteriului de sortare.
12.1.3 Sortare prin metoda bulelor
S considerm c avem de sortat n ordine cresctoare valorile elementelor unui tablou.
Sortarea prin metoda bulelor (bubble sort) const n urmtoarele: se compar primele
dou elemente ale tabloului de sortat i dac nu sunt n ordinea cerut, se permut ntre
ele. Apoi se compar elementul al doilea cu al treilea i se procedeaz ca mai sus. n
general, se compar dou elemente nvecinate, s zicem al i-lea cu al i+1-lea i dac nu
sunt n ordinea cerut, atunci ele se permut. Se procedeaz n acest fel cu toate
perechile de elemente nvecinate ale tabloului de sortat. Apoi procesul respectiv se reia de
la nceput. El se ntrerupe cnd se constat c toate elementele nvecinate ale irului sunt
n ordinea cerut (n cazul de fa, cresctoare).
O proprietate a acestei metode este aceea c la fiecare parcurgere a irului de numere,
cel puin un element ajunge s-i ocupe poziia sa final n conformitate cu ordonarea
avut n vedere. Astfel, dup prima parcurgere a irului, elementul ajuns pe ultimul loc nu
va mai fi permutat, ocupndu-i locul final. Dac se ordoneaz cresctor un tablou de
numere, atunci dup prima parcurgere a elementelor lui, elementul maxim va avea
indicele cel mai mare. Dup cea de-a doua parcurgere, maximul dintre clementele rmase
(fr a considera ultimul element) va ocupa penultima poziie n tablou, etc. Algoritmul
metodei e descris n continuare iar utilizarea metodei ntr-un program este prezentat n
Exemplul 12.1.
ALGORITM Sort_Bule
NCEPUT
REPET
NCEPUT
gata Adev
PENTRU i=0 LA n-2 REPET
NCEPUT
DAC vect[i] > vect[i+1] ATUNCI
NCEPUT
aux=vect[i]
Capitolul 12

186
vect[i]=vect[i+1]
vect[i+1]=aux
gata=Fals
SFRIT DAC
SFRIT PENTRU
SFRIT REPET
CT TIMP not gata
SFRIT ALGORITM
Metodei bulelor i se pot aduce uoare ameliorri n ceea ce privete accelerarea. De
exemplu, metoda prezint o particularitate interesant: un element aparinnd nceputului
listei este poziionat corect de la primul pas, n timp ce un element de la sfritul listei se
ndreapt mult mai lent spre poziia final. Pornind de aici se poate aduce o mbuntire
algoritmului bulelor. n loc s se citeasc permanent lista n aceeai direcie, ntre dou
parcurgeri succesive se poate inversa sensul (n algoritm acest lucru se traduce prin
prezena a nc unui ciclu PENTRU i= n-2 LA 0 REPET ... cu acelai corp, dup
cel deja existent). n acest fel un mare numr de elemente se vor deplasa mai rapid spre
poziia corect. Aceast variant a algoritmului este cunoscut sub numele de metoda
basculrii, deoarece introduce efectul propagrii unei micri de basculare ntre
elementele tabloului.
Dei principiul basculrii mbuntete metoda bulelor i el opereaz ca algoritm de
ordinul n
2
. Aceasta pentru c numrul de comparaii nu s-a modificat, iar numrul de
substituiri s-a redus doar cu o valoare relativ mic.
12.1.4 Sortarea prin selecie
O sortare prin selecie este aceea care determin elementul de rang minim i l substituie
primului element al listei. Apoi, din restul de n-1 elemente rmase este determinat din nou
elementul de rang minim i trimis pe cea de-a doua poziie i aa mai departe.
Algoritmul metodei e descris n continuare iar utilizarea metodei ntr-un program este
prezentat n Exemplul 12.1.
ALGORITM Sort_Select
NCEPUT
PENTRU ind_el_ref=0 LA n-2 REPET
NCEPUT
gata Adev
ind_el_min=ind_el_ref ;
el_min=v[ind_el_ref];
PENTRU i=ind_el_ref+1 LA n-1 REPET
NCEPUT
DAC vect[i]<el_min vect[i+1] ATUNCI
NCEPUT
ind_el_min=i; //Indicele elem minim
el_min=v[i]; //Valoarea elem minim
gata=Fals
SFRIT DAC
SFRIT REPET
DAC not gata //Se face schimb
NCEPUT
v[ind_el_min]=v[ind_el_ref];
v[ind_el_ref]=el_min;
SFRIT DAC
SFRIT REPET
SFRIT ALGORITM
Sortare i cutare

187
12.1.5 Sortarea prin inserare
Metoda de sortare prin inserare este a treia i ultima din categoria metodelor simple de
sortare. Principiul de lucru este urmtorul: n prima faz sunt ordonate primele dou
elemente ale setului de date; dup aceea se introduce elementul care urmeaz n poziia
corect n raport cu primele dou. Cel de-al patrulea element va fi poziionat n lista de trei
elemente ordonate n prealabil. Procedeul continu pn cnd ntreaga list a fost
ordonat.
Algoritmul metodei e descris n continuare iar utilizarea metodei ntr-un program este
prezentat n Exemplul 12.1.
ALGORITM Sort_Insert
NCEPUT
PENTRU ind_el_ref=1 LA n-1 REPET
NCEPUT
el_min=v[ind_el_ref];
PENTRU i=ind_el_ref-1 LA 0, PAS -1 REPET
NCEPUT
DAC el_min<v[i] ATUNCI
NCEPUT
v[i+1]=v[i];
SFRIT DAC
SFRIT REPET
v[i+1]=el_min
SFRIT REPET
SFRIT ALGORITM

Spre deosebire de metoda bulelor sau de cea a seleciei, aici numrul de comparaii ce
intervin depinde de gradul iniial de ordonare al listei. Metoda inserrii prezint dou
avantaje suplimentare fa de celelalte metode prezentate pn acum. Mai nti, ea are o
comportare natural, adic volumul de calcul este cel mai mic pentru o list deja ordonat
i cel mai mare pentru o list aflat iniial n ordine inversat. Din aceast cauz algoritmul
este excelent de aplicat unor seturi de date aproape n ordine. Al doilea avantaj este
conservarea ordinii elementelor avnd criteriul de sortare identic. Aceasta nseamn c
dac o list este sortat dup dou criterii diferite, ea va rmne ordonat n raport cu
ambele criterii i dup aplicarea algoritmului de sortare cu inserare. Putem s mai
observm c dei numrul comparaiilor introduse poate fi considerabil redus pentru
anumite mulimi de date, la fiecare inserare are loc o repoziionare a ntregului ir de
elemente. Prin urmare, este posibil ca numrul de substituiri s devin substanial.
12.1.6 Algoritmi de sortare superiori
Toi algoritmii discutai n seciunea precedent prezint dezavantajul esenial c timpul de
lucru este proporional cu ptratul numrului de elemente sortate. Din aceast cauz
sortarea unor cantiti mari de date este fcut extrem de lent. Practic, de la un moment
dat, algoritmul devine prea lent pentru a fi utilizat. Dac un proces de sortare dureaz prea
mult, de cele mai multe ori vina o poart algoritmul su de baz. n aceast situaie, o
sugestie des ntlnit este transcrierea programului n cod de asamblare. n unele condiii,
utilizarea codului de asamblare accelereaz de un anumit numr de ori o subrutin, dar
dac algoritmul de baz este ineficient, procesul va rmne foarte lent indiferent de gradul
de optimizare al programrii lui. Reinei c pentru o subrutin de ordinul n
2
creterea
vitezei de lucru a programului propriu-zis sau chiar a calculatorului realizeaz progrese
neeseniale deoarece creterea duratei de execuie n funcie de numrul de elemente
este mai rapid. Regula de subliniat este c, dac subrutina de sortare scris n C nu este
destul de rapid, atunci ea nu va fi suficient de rapid nici transcris n limbaj de
Capitolul 12

188
asamblare. Singura soluie o reprezint introducerea unui algoritm de sortare mai
performant.
12.1.7 Sortarea prin metoda Shell
Metoda Shell a fost descoperit de ctre Donald L. Shell. Metoda pornete de la analiza
critic a metodei bulelor. n metoda bulelor, se compar elementele vecine, i, dac nu
sunt n ordinea cerut, atunci ele se permut. De aceea, elementele care nu sunt n ordine
corect se deplaseaz cu o singur poziie. Pentru a mbunti acest procedeu, ar trebui
s realizm deplasri cu mai multe locuri ale elementelor, la o permutare a lor. Acest lucru
se poate realiza dac n loc de a compara elemente nvecinate, comparm elemente
aflate la o anumit distan ntre ele. n cazul n care ele nu sunt n ordinea cerut, ele se
vor permuta. n felul acesta elementele se deplaseaz fcnd salturi mai mari dect o
poziie. Distana dintre elementele comparate se numete increment.
La fiecare permutare a dou valori, algoritmul compar valoarea mai mic permutat cu
cea precedent (poziia precedent se stabilete folosind incrementul) i realizeaz o
nou permutare dac este nevoie.
Aceast comparaie se continu, propagndu-se spre nceputul irului, pn cnd:
a. nu se mai fac permutri; sau
b. nu mai exist elemente n ir (se ajunge la un element care nu mai are precedent n ir).
Incrementul se micoreaz dup o parcurgere a irului de clemente care se sorteaz i se
reia parcurgerea de la nceputul irului. De aici rezult denumirea de sortare cu
micorarea incrementului.

Eficiena metodei Shell este mult mai mare n comparaie cu metoda bulelor n cazul n
care se sorteaz un numr mai mare de date (de ordinul sutelor sau miilor).
O influen asupra eficienei metodei o are i modul n care se alege incrementul. S-a
artat c valorile incrementului la diferite parcurgeri ale irului de sortat este bine s fie
numere prime ntre ele. n capitolul de fa ne mrginim Ia alegerea incrementului iniial
egal cu n/2, unde n este numrul elementelor irului de sortat. De asemenea, dup fiecare
parcurgere a irului, acesta se va njumti. Cazul cel mai nefavorabil al acestei metode
se obine cnd n este o putere a lui doi. Acest caz se poate evita dac la fiecare
parcurgere a irului incrementul se determin prin relaia:
increment = increment/2 + 1, dac increment > 2.
Metoda de sortare Shell poate fi definit astfel:
1. inc = n/2, unde prin n am notat numrul elementelor care se sorteaz.
2. Se realizeaz o parcurgere a irului de elemente care se sorteaz. Aceasta implic
urmtorii pai:
2.1. i = inc.
2.2. j = i-inc+1.
2.3. Dac j>0 i elementele de ordine j i j+inc nu satisfac criteriul de ordonare,
atunci elementele respective se permut. Altfel se continu cu pasul 2.6.
2.4. j = j-inc.
2.5. Se reia de la pasul 2.3.
2.6. i = i+1.
2.7. Dac i > n, se termin parcurgerea curent a irului. Altfel se reia de la pasul 2.
3. inc = inc/2.
4. Dac inc > 0, atunci se reia de la pasul 2. Altfel irul este sortat.

Paii 2.4 i 2.5 se realizeaz n cazul n care s-a efectuat permutarea elementelor de
ordinul j i j+inc. n acest caz se permut, dac este necesar, elementele precedente
elementului deplasat n poziia j. Elementele precedente sunt: j-inc, j-2*inc,.... Aceasta se
realizeaz repetnd pasul 2.3 att timp ct j > 0 i se fac permutri.
Sortare i cutare
n continuare este prezentat un mic exemplu, iar n Exemplul 12.1 un program complet de
sortare folosind i metoda Shell.
Exemplu
Nr componente vector:7. nainte de ordonare: v = 46 30 32 40 6 17 45
****** SORT SHELL ******
Interschimbare element 0 cu 3, increment 3: 40 30 32 46 6 17 45
Interschimbare element 1 cu 4, increment 3: 40 6 32 46 30 17 45
Interschimbare element 2 cu 5, increment 3: 40 6 17 46 30 32 45
Interschimbare element 3 cu 6, increment 3: 40 6 17 45 30 32 46
Interschimbare element 0 cu 1, increment 1: 6 40 17 45 30 32 46
Interschimbare element 1 cu 2, increment 1: 6 17 40 45 30 32 46
Interschimbare element 3 cu 4, increment 1: 6 17 40 30 45 32 46
Interschimbare element 2 cu 3, increment 1: 6 17 30 40 45 32 46
Interschimbare element 4 cu 5, increment 1: 6 17 30 40 32 45 46
Interschimbare element 3 cu 4, increment 1: 6 17 30 32 40 45 46
Dup ordonare SHELL: v= 6 17 30 32 40 45 46
12.1.8 Sortarea prin metoda rapid (QuickSort)
Aceasta reprezint o alt metod de sortare a elementelor unui vector. Algoritmul este
recursiv: se mparte vectorul n dou partiii, fa de un element pivot (de obicei, elementul
din "mijlocul vectorului"). Partiia stng ncepe de la indexul i (la primul apel i=0), iar
partiia dreapt se termin cu indexul j (la primul apel j=n -1) (vezi Figura 12.1).


n-1
pivot i

0
j

n-1


0
j i
Figura 12.1 Sortarea prin metoda QuickSort
Partiia stng este extins la dreapta (i incrementat) pn cnd se gsete un element
mai mare dect pivotul; partiia dreapt este extins la stnga (j decrementat) pn cnd
se gsete un element mai mic dect pivotul. Cele dou elemente gsite, vect[i] i
vect[j], sunt interschimbate.
Se reia ciclic extinderea partiiilor pn cnd i i j se "ncrucieaz" (i devine mai mare ca
j). n final, partiia stng va conine elementele mai mici dect pivotul, iar partiia dreapt -
elementele mai mari dect pivotul, dar nesortate.
Algoritmul este reluat prin recursie pentru partiia stng (cu limitele ntre 0 i j ), apoi
pentru partiia dreapt (cu limitele ntre i i n-1 ). Recursia pentru partea stng se oprete
atunci cnd j atinge limita stng (devine 0), iar recursia pentru partiia dreapt se oprete
cnd i atinge limita dreapt (devine n-1). Algoritmul metodei e descris n continuare iar
utilizarea metodei ntr-un program este prezentat n Exemplul 12.1.
ALGORITM Sort_Rapida(vect[], stg, drt) //la primul apel stg=0 si drt=n-1
NCEPUT SUBALGORITM
istg; jdrt
DAC i<j ATUNCI
NCEPUT
pivot=vect[(stg+drt)/2]
CT TIMP i<=j REPET //extinderea partiiilor stnga i dreapta pn cnd i se
ncrucieaz cu j
NCEPUT
CT TIMP i<drt si vect[i]<pivot REPET
i = i + 1

189
Capitolul 12

190
CT TIMP j<stg si vect[j] >pivot REPET
j = j - 1
DAC i<=j ATUNCI
NCEPUT //interschimb elementele vect[i] i vect[j]
auxvect[i]; vect[i]vect[j]; vect[j]aux
ii+1; jj-1
SFRIT DAC
SFRIT REPET
DAC j>stg ATUNCI //partiia stng s-a extins la maxim, apel quickSort ptr ea
CHEAM QuickSort(vect, stg, j)
DAC i<drt ATUNCI //partiia dreapt s-a extins la maxim, apel quickSort ptr ea
CHEAM QuickSort(vect, i, drt)
SFRIT DAC
SFRIT SUBALGORITM

Exemplul 12.1 Program de sortare cu utilizarea diverselor metode prezentate
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <conio.h>

#define TRUE 1
#define FALSE 0

void gener(double v[], int n)
//functia de generare aleatoare a elementelor vectorului v, cu n
elemente
{for (int i=0; i<n; i++)
v[i]=rand()%50; //Generare de numere aleatoare de la 0 la 49
}
void afis(double v[], int n)
//functia de afisare a vectorului
{for (int i=0; i<n; i++)
printf("%3.0f",v[i]);
printf("\n");
}

void copie_vect(double v1[], double v[], int n)
//functie de "duplicare "a unui vector; copie vectorul v in
vectorul v1
{for (int i=0; i<n; i++)
v1[i]=v[i];
}

/* Sortare prin met bulelor*/
void Sortare_bule(double v[], int n)
{
int i,gata;
do
{
gata=TRUE;
for(i=0; i<n-1; i++)
if (v[i]>=v[i+1])
{
Sortare i cutare

191
double aux=v[i]; v[i]=v[i+1]; v[i+1]=aux;
printf("Interschimbare element %2d cu %2d: ",i,i+1);
afis(v,n);
gata=FALSE;
}
}
while(!gata);
}

/* Sortare prin selectie */
void Sortare_select(double v[], int n)
{
register int i, ind_el_ref, ind_el_min, gata;
double el_min;
for(ind_el_ref=0; ind_el_ref<n-1; ++ind_el_ref)
{
gata=1; ind_el_min=ind_el_ref ;
el_min=v[ind_el_ref]; //Elementul de referinta curent cu care
se compara elem urmatoare
for(i=ind_el_ref+1; i<n; ++i)
if(v[i]<el_min) // Sortare crescatoare
{
ind_el_min=i; //Indicele elementului minim
el_min=v[i]; //Valoarea elementului minim
gata=0; //Se va face un schimb
}
if(!gata)
{//Schimbarea elementului minim cu cel de de referinta
v[ind_el_min]=v[ind_el_ref]; v[ind_el_ref]=el_min;}
}
}

/* Sortarea prin inserare*/
void Sortare_insert(double v[], int n)
{
register int ind, i; double el_min;
for(ind=1; ind<n; ++ind)
{
el_min=v[ind];
for(i=ind-1; i>=0 && el_min<v[i]; i--)
v[i+1]=v[i];
v[i+1]=el_min;
}
}

/* Sortarea prin metoda Shell */
void Sortare_Shell (double v[],int n)
{
int inc,i,j; double aux;
for(inc=n/2;inc>0;inc/=2)
/* se realizeaza o parcurgere a sirului */
for(i=inc;i<n;i++)
/* se compara doua elemente aflate la distanta inc unul de
altul
si daca este cazul se permuta;
Capitolul 12

192
- daca s-a realizat o permutare, atunci elementul deplasat in
fata
se compara cu precedentele lui si se permuta daca este cazul.
*/
for(j=i-inc; j>=0 && v[j]>v[j+inc]; j-=inc)
{ aux=v[j]; v[j]=v[j+inc]; v[j+inc]=aux;
printf("Interschimbare element %2d cu %2d, increment %2d:
",j,j+inc,inc);afis(v,n);
}
}

void Sortare_rapida(double v[], int stg, int drt)
{
int i,j; i=stg; j=drt; double pivot, aux;
if (i<j){
pivot=v[(stg+drt)/2];
while (i<=j)
{ //extindere partitie st si dr pana i se incrucis cu j
while (i<drt && v[i]<pivot) i++;
while (j>stg && v[j]>pivot) j--;
if (i<=j)//interschimbare elemente
{ aux=v[i];v[i]=v[j];v[j]=aux; i++; j--; }
}
if (j>stg) Sortare_rapida(v,stg,j);
if (i<drt) Sortare_rapida(v,i,drt);
}
}

void main()
{
clock_t ti,tf; int n; //n = nr elemente vector

printf("Nr componente vector:"); scanf("%d", &n);
double v[200], v1[200];
gener(v, n);
printf("\nInainte de ordonare: v="); afis(v, n);

printf("\n****** SORT BULE ******\n");
copie_vect(v1,v,n);
ti=clock();
Sortare_bule(v1,n); tf=clock(); double dif_b=tf-ti;
printf("Dupa ordonare BULE: v1="); afis(v1, n);
printf("Durata: %lf", dif_b);

printf("\n****** SORT SELECT ******\n");
copie_vect(v1, v, n);
Sortare_select(v1, n);
printf("Dupa ordonare SELECT: v1="); afis(v1, n);

printf("\n****** SORT INSERT ******\n");
copie_vect(v1, v, n);
Sortare_insert(v1, n);
printf("Dupa ordonare INSERT: v1="); afis(v1, n);

printf("\n****** SORT SHELL ******\n");
Sortare i cutare

193
copie_vect(v1, v, n);
Sortare_Shell(v1, n);
printf("Dupa ordonare SHELL: v1="); afis(v1, n);

printf("\n****** SORT QUICK ******\n");
int st=0; int dr=n-1; copie_vect(v1, v, n);
Sortare_rapida(v1, st, dr);
printf("Dupa ordonare QUICK: v1="); afis(v1, n);

getch();
}
12.2 Cutarea
Organizarea informaiei n baze de date este fcut n aa fel nct s permit unui
utilizator s localizeze un articol dorit prin simpla introducere a unui cuvnt-cheie.
Exist o metod unic de cutare n liste nesortate i o alta pentru liste sortate.
Majoritatea compilatoarelor ofer funcii de cutare ca parte a bibliotecii lor standard. Ca i
n cazul sortrii, se poate ns ntmpl ca subrutinele de uz general s devin
inacceptabile pentru unele aplicaii particulare din cauza unor dezavantaje suplimentare
legate de gradul prea mare de generalitate.
12.2.1 Metode de cutare
Localizarea informaiei ntr-o list neordonat necesit folosirea unei cercetri secveniale
ncepnd cu primul element i sfrindu-se fie la gsirea obiectului cutat, fie la epuizarea
listei. Metoda este specific listelor nesortate, dar se poate aplica n aceleai condiii i
seturilor de date ordonate. ns, pentru liste sortate, este mai indicat metoda de cutare
binar, care v ajut s localizai mult mai repede informaia n cauz.
12.2.1.1 Cutarea secvenial
Cutarea secvenial este simplu de programat. Funcia prezentat n exemplul urmtor
caut o valoare ntr-o list de lungime cunoscut pn la prima apariie a acesteia.
Cautare_secventiala(double v[], int n, double val)
{
register int t;
for(t=0; t<n; ++t )
if (val==v[t]) return t; //Indice elem cautat
return -1; //Nu s-a gasit elem cautat
}
Aceast funcie returneaz indicele primului element identic cu caracterul cutat, n caz c
acesta exist. n caz contrar ea returneaz -1.
Este uor de observat c o cutare secvenial direct va testa n medie 1/2 n elemente.
n cazul cel mai favorabil, ea va testa un singur element, iar n cazul cel mai nefavorabil, n
elemente. Pentru informaii stocate pe disc, timpul de cutare poate crete. Dac lista de
date nu este sortat, cutarea nu se poate face dect secvenial.
Capitolul 12

194
12.2.1.2 Cutarea binar
Pentru seturi de date sortate, vei putea folosi pentru cutare o metod cu mult superioar
celei secveniale. Aceasta este cutarea binar, care folosete o abordare gen dezbin i
cucerete.

Cheia de identificat este comparat cu cheia elementului din mijlocul tabelei: dac sunt
identice atunci cutarea se termin; dac nu metoda se aplic recursiv fie primei jumti
a tabelei fie celeilalte, n funcie de rezultatul testului. Aceast descriere recursiv poate fi
scris mai formal (n pseudocod) astfel:

Cutare Binar(Elemente, Prim, Ultim, Cheie)
SETEAZ Mjloc LA (Prim + Ultim) div 2 /*div-operatorul de mprire ntreaga*/
DAC Prim < Ultim ATUNCI
DAC Cheie < Elementul din Mijloc ATUNCI
Cutare Binar(Elemente, Prim, Mijloc - 1, Cheie)
ALTFEL
DAC Cheie > Elementul din Mijloc ATUNCI
Cutare Binar(Elemente, Mijloc + 1, Ultim, Cheie)
ALTFEL
Elementul din Mijloc este cel cutat
SFRIT DAC
SFRIT DAC
SFRIT DAC
SFRIT Cutare Binar

De exemplu, pentru a localiza numrul 4 n urmtorul ir 1 2 3 4 5 6 7 8 9, o cutare binar
va cuta nti la mijlocul irului, unde se afl 5. Deoarece acest element e mai mare dect
cel cutat, cercetarea va continua n prima jumtate adic n: 1 2 3 4 5. Elementul de
mijloc este acum 3. Acesta este mai mic dect 4, deci va fi abandonat prima jumtate.
Cercetare se va continua cu 4 5. n aceast etap, este gsit elementul cutat.
V prezentm mai jos o funcie de cutare pentru valori. Funcia returneaz indicele
elementului a crui valoare se caut, sau -1 dac elementul nu a fost gsit. Putei adapta
aceast funcie pentru o structur oarecare de date, prin modificarea prii de comparaii
din program.
/* Cautare binara*/
Cautare_binara(double v[], int n, double val)
{
int med, min, max;
min = 0; max =n-1;
while (min<=max)
{
med=(min+max)/2;
if(val<v[med]) max=med-1;
else
if(val>v[med])
min = med+1;
else
return med; /* localizare */
}
return -1; //Nu s-a gasit elem cautat
}

Liste, cozi, stive i arbori

195
13. Liste, cozi, stive i arbori
Un program const din dou componente: algoritmi i structuri de date. Un program de
calitate este o combinaie reuit a ambelor componente. Alegerea i modul de
implementare ale unei structuri de date are o importan egal cu aceea a rutinelor
necesare la manevrarea acesteia. Modul de organizare i de accesare a informaiei este
de obicei determinat de natura problemei de programare. Din acest motiv, este important
s dispunei n orice moment de metoda corespunztoare de stocare i gsire a datelor.
Modul de legare a unui tip de date de reprezentarea sa n calculator este invers corelat
cu gradul su de abstractizare. Cu alte cuvinte, pe msur ce tipurile de date sunt mai
abstracte, modul n care le concepe mental programatorul are o legtur din ce n ce mai
redus cu modul n care sunt acestea reprezentate n memorie. Tipurile simple de date,
cum ar fi char i int, sunt strns legate de modul de reprezentare. Tablourile simple,
care constituie ansambluri organizate de tipuri de date de baz, nu sunt att de legate ca
tipurile elementare, dar modul de existen al acestora n memorie este asemntor cu
modul de vizualizare.
Pe msur ce complexitatea unui tip de date crete, acestea devin conceptual mai puin
similare cu echivalentele lor din memorie. De exemplu, valorile n virgul mobil sunt mai
abstracte dect ntregii. Structura, care reprezint un conglomerat de tipuri de date, este
nc i mai complex. Nivelul final de abstractizare transcende simplul aspect fizic al
datelor, prin adugarea mecanismului de accesare a datelor, adic de stocare i
recuperare a acestora. n esen, datele fizice sunt legate cu un motor de date (data
engine), care controleaz modul de accesare a acestora de ctre un program. Exist patru
mari categorii de motoare de date:
Lista nlnuit Coada Stiva Arborele binar
Fiecare dintre aceste metode asigur o soluie pentru o anumit clas de probleme. n
esen, metodele de mai sus reprezint dispozitive care efectueaz o anumit operaie de
stocare i recuperare asupra informaiilor i cererilor primite. Toate aceste metode
stocheaz un articol i recupereaz un articol, unde prin articol se nelege o unitate
informaional.
13.1 Liste
Lista este o mulime dinamic cu un numr variabil de elemente.
La nceput lista este o mulime vid. n procesul execuiei programului se pot aduga
elemente noi listei i totodat pot fi eliminate diferite elemente din list de care nu mai este
nevoie. Deci, elementele unei liste sunt structuri de acelai tip. Se obinuiete s se
ordoneze elementele unei liste folosind pointeri care intr n compunerea elementelor
listei. Datorit acestor pointeri, elementele listei devin structuri recursive. Listele organizate
n acest fel se numesc liste nlnuite.
List nlnuit este o mulime dinamic de structuri recursive de acelai tip, pentru
care sunt definite una sau mai multe relaii de ordine cu ajutorul unor pointeri din
compunerea structurilor respective. Elementele unei liste, de obicei, se numesc
noduri.
Capitolul 13
Dac ntre nodurile unei liste exist o singur relaie de ordine, atunci lista se numete
simplu nlnuit. n mod analog, lista este dublu nlnuit dac ntre nodurile ei sunt
definite dou relaii de ordine.
n general, vom spune c o list este n-nlnuit dac ntre nodurile ei sunt definite n
relaii de ordine.
n legtur cu listele nlnuite se au n vedere unele operaii de interes general:
a. crearea unei liste nlnuite;
b. accesul la un nod oarecare al unei liste nlnuite;
c. inserarea unui nod ntr-o list nlnuit;
d. tergerea unui nod dintr-o list nlnuit;
e. tergerea unei liste nlnuite.
13.1.1 Liste simplu nlnuite
Aa cum s-a artat mai sus, ntre nodurile unei liste simplu nlnuite (simple-linked) este
definit o singur relaie de ordonare. De obicei aceast relaie este cea de succesor,
adic fiecare nod conine un pointer a crui valoare reprezint adresa nodului urmtor din
list. n mod analog se poate defini relaia de precedent. n cele ce urmeaz ne vom
mrgini numai la liste simplu nlnuite pentru care nodurile satisfac relaia de succesor.
ntr-o astfel de list exist totdeauna un nod i numai unul care nu mai are urmtor
(succesor), precum i un nod care nu este urmtorul (succesorul) nici unui alt nod. Aceste
noduri formeaz capetele listei simplu nlnuite.

O list nlnuit (linked list) poate fi accesat ntr-o manier aleatorie, deoarece fiecare
entitate informaional este dotat cu o legtur cu urmtorul articol de date din list, i din
acest motiv lista nlnuit necesit o structur de date complex; n plus, o operaie de
recuperare asupra unei liste nlnuite nu
elimin i nu distruge un articol din list. Pentru
a realiza aceasta, este nevoie de o operaie
specific de tergere.

196

Fiecare articol de date const dintr-o structur
care conine cmpul informaional i un pointer
de legtur. Conceptual, o list simplu nlnuit are aspectul prezentat n Fig 13.1.
Date

Date

Date
0
Figura 13.1 List simplu nlnuit
n esen, exist dou moduri de a alctui o list nlnuit simpl. Primul rezid n
inserarea fiecrui articol nou la sfritul listei. Cellalt const n adugarea articolelor noi
n locuri bine determinate, de exemplu n ordine cresctoare. Modul de alctuire a listei va
determina codarea funciei de stocare. S ncepem cu situaia mai simpl a crerii unei
liste nlnuite folosind adugarea articolelor la sfritul listei.
n general, articolele stocate ntr-o list nlnuit constau din structuri, deoarece fiecare
articol trebuie s conin att legtura cu articolul urmtor de pe list, ct i datele n sine.
Ca atare, va fi necesar definirea unei structuri care va fi folosit n exemplele urmtoare.
Deoarece listele de adrese sunt adesea stocate ntr-o list nlnuit, o structur tip adres
este oportun. Structura de date pentru fiecare element din lista de adrese este definit
mai jos:
struct adresa {
char nume[40];
char strada[40];
char oras[20] ;
char stat[3];
char cod_postal [11];
struct adresa *urm; } info;
Liste, cozi, stive i arbori

197
Funcia store_ls(), prezentat n cele ce urmeaz, construiete o list simplu nlnuit
prin adugarea fiecrui element nou la sfritul listei. Este necesar transferul unui pointer
ctre o structur de tip adresa, precum i al unui pointer ctre ultimul element din list.
Dac lista este goal, atunci pointerul ultimului element din list trebuie s fie nul.
void store_ls(struct adresa *i, struct adresa **ultim)
{
if(!*ultim) *ultim = i; /* primul articol din lista */
else (*ultim)->urm = i;
i->urm = NULL;
*ultim = i;
}
Dei lista creat prin intermediul funciei store_ls() poate fi sortat printr-o operaie
separat, este mai simpl sortarea listei n timpul construirii acesteia, prin inserarea
fiecrui element nou n secvena corespunztoare a lanului. De asemenea, dac lista este
deja sortat, este avantajoas meninerea sortrii prin inserarea articolelor noi n locaia
corespunztoare fiecruia. Aceast operaie se realizeaz printr-o parcurgere secvenial
a listei pn la gsirea locaiei corespunztoare, inserarea noii adrese n acel loc i
rearanjarea legturilor.
La inserarea unui articol ntr-o list simplu nlnuit pot surveni trei situaii posibile:
articolul poate deveni primul pe list, poate fi plasat ntre alte dou articole sau poate
deveni ultimul articol. Diagramele din Error! Reference source not found. indic
modificarea legturilor pentru fiecare caz n parte.
Capitolul 13
Figura 13.2 Inserarea unui nou element ntr-o list simplu nlnuit
Date

Date

Date
0
Nou

Lista iniial
Date

Date

Date
0
Nou

Inserarea unui nou element la nceput
Date

Date

Date
0
Nou

Inserarea unui nou element la interior
Date

Date

Date

Nou
0
Inserarea unui nou element la sfrit
Reinei c dac schimbai primul articol dintr-o list, trebuie s actualizai punctul de
intrare n list peste tot n program. Pentru a evita aceast sarcin, putei folosi ca prim
articol o santinel (sentinel). n acest caz, selectai o valoare de intrare. Aceast metod
are dezavantajul unei locaii suplimentare pentru memorarea valorii-santinel, dar acesta
nu este un factor de prea mare importan.
Funcia prezentat n cele ce urmeaz, store_ls_sort(), va insera structuri de tip
adresa n lista de adrese ntr-o ordine ascendent bazat pe cmpul nume. Este necesar
transferul unui pointer ctre pointerul primului i ultimului element din list, o dat cu un
pointer ctre informaia care va fi stocat. Deoarece primul sau ultimul element din list se
poate modifica, funcia store_ls_sort() actualizeaz automat pointerii ctre nceputul,
respectiv sfritul listei, dac acetia se modific. La primul apel din program ctre funcia
store_ls_sort(), prim i ultim trebuie s fie

pointeri nuli.
/* Stocare in ordine ascendenta */
void store_ls_sort (struct adresa *i, /*noul element de stocat */
struct adresa **prim, /* inceputul listei */
struct adresa **ultim) /* sfarsitul listei */
{
struct adresa *vechi, *p;
p = *prim;
if(!*ultim) { /* primul element din lista */
i->urm = NULL;
*ultim = i;

198
*prim = i;
Liste, cozi, stive i arbori

199
return;
}
vechi = NULL;
while(p) {
if(strcmp(p->nume, i->nume) <0) { vechi = p; p = p->urm; }
else {
if(vechi) { /* intra la mijloc */
vechi->urm = i; i->urm = p; return;
}
i->urm = p; /* noul prim element */
*prim = i; return;}
}
(*ultim)->urm = i; /*introduce la sfrit */
i->urm = NULL; *ultim = i; }
O list nlnuit dispune rareori de o anumit funcie dedicat procesului de citire a
datelor, adic de returnare a unui articol dup altul n ordinea din list. De obicei, aceast
funcie este att de scurt, nct este pur i simplu plasat n interiorul unei alte rutine,
cum ar fi o funcie de cutare, tergere sau afiare. De exemplu, rutina de mai jos afieaz
toate numele dintr-o list de adrese:
void display(struct adresa *prim)
{
while(prim) {printf("%s\n", prim->nume); prim = prim->urm; }
}
La apelarea funciei display(), prim trebuie s fie un pointer ctre prima structur din
list.
Citirea articolelor dintr-o list se rezum la urmrirea lanului. O rutin de cutare bazat
pe cmpul nume ar putea fi scris dup cum urmeaz:
struct adresa *search(struct adresa *prim, char *n)
{
while(prim) {
if(!strcmp(n, prim->nume)) return prim;
prim = prim->urm; }
return NULL; /* nici o coincidenta */
}
Deoarece funcia search() returneaz un pointer ctre articolul din list care corespunde
numelui cutat, trebuie declarat ca returnnd un pointer de structur de tip adresa. Dac
nu exist nici o coinciden, se va returna un pointer nul.
tergerea unui articol dintr-o list nlnuit simpl este o operaie direct. Ca i n cazul
inserrii unui articol, exist trei situaii: tergerea primului articol, tergerea unui articol din
interiorul listei i tergerea ultimului articol. n Fig 13.3 sunt prezentate toate aceste
operaii.
Capitolul 13
Figura 13.3 tergerea unui element dintr-o list simplu nlnuit
Date

Date

Date
0
Lista iniial
ters
0
Date

Date
0
tergerea primului element
Date

ters
0
Date
0
tergerea unui element din interior
Date

Date
0
ters
0
tergerea ultimului element
Funcia urmtoare terge un articol dat dintr-o list de structuri de tip adresa:
void sterg_ls (
struct adresa *p, /* articolul precedent */
struct adresa *a, /* articolul care trebuie ters */
struct adresa **prim, /* inceputul listei */
struct adresa **ultim, /* sfritul listei */
{
if(p) p->urm = a->urm;
else *prim = a->urm;
if(i==*ultim &&p) *ultim = p;
}
Funcia sterg_ls() trebuie s primeasc pointerii articolului ters, al articolului
precedent din lan, precum i ai primului i ultimului articol din list. Funcia actualizeaz
automat pointerii prim i ultim, n cazul n care articolul indicat de vreunul dintre acetia
este ters.
Listele simplu nlnuite au o deficien major care le interzice utilizarea pe scar larg,
i anume imposibilitatea de a fi citite n ordine invers. Din acest motiv, cele mai des
folosite sunt listele dublu nlnuite.
13.1.2 Liste dublu nlnuite
Listele dublu nlnuite sunt alctuite din date la care se adaug att legturi cu urmtorul
articol, ct i cu precedentul. Fig 13.4 indic modul de dispunere al acestor legturi.
Existena a dou legturi n locul uneia singure
prezint mai multe avantaje, din care poate cel mai
important rezid n faptul c lista poate fi citit n
ambele direcii. Aceasta simplific gestiunea datelor
din list i faciliteaz introducerea i tergerea
acestora, permind utilizatorului o parcurgere a
listei n orice direcie. Un alt avantaj se manifest
numai ntr-un anumit caz de eroare. Din moment ce ntreaga list poate fi consultat
folosind fie legturile dintr-un sens, fie dintr-altul, dac una dintre legturi sufer un defect,
lista poate fi reconstruit folosind cealalt legtur.
Date
0
Date

Date
0
Figura 13.4 List dublu nlnuit
Exist trei modaliti de inserare a unui nou element ntr-o list dublu nlnuit: inserarea
unui nou prim element, introducerea unui element ntre alte dou existente sau inserarea
unui nou element ultim. Aceste operaii sunt ilustrate n Fug 13.5.

200
Liste, cozi, stive i arbori
Figura 13.5 Inserarea unui nou element ntr-o list dublu nlnuit
Date
0
Date

Date
0
Nou

Lista iniial
Date

Date

Date
0
Nou
0
Inserarea unui nou element la nceput
Date
0
Date

Date
0
Nou

Inserarea unui nou element la interior Inserarea unui nou element la sfrit
Date
0
Date

Date

Nou
0
Construirea unei liste dublu nlnuite este un proces asemntor celui de alctuire a unei
liste simplu nlnuite, cu deosebirea c sunt necesare dou legturi. Ca atare, structura
trebuie s asigure spaiu pentru ambele. Utiliznd din nou exemplul cu lista de adrese,
structura adres poate fi modificat dup cum urmeaz, pentru a asigura ambele legturi:
struct adresa {
char nume[40];
char strada[40];
char oras[20];
char stat[3] ;
char cod_postal[11];
struct adresa *urm;
struct adresa *preced;
} info;
Utiliznd adresa ca articol de date fundamental, funcia store_ld() alctuiete o list
dublu nlnuit:
void store_ld(struct adresa *i, struct adresa **ultim)
{
if(!*ultim) *ultim=i; /* Primul articol din lista*/
else (*ultim)->urm = i;
i->urm = NULL;
i->preced = *ultim;
*ultim = i;
}

201
Capitolul 13

202
Funcia store_ld() insereaz fiecare nou intrare la sfritul listei. Funcia trebuie
apelat cu un pointer ctre datele care trebuie stocate, precum i cu un pointer ctre
sfritul listei, care trebuie s fie nul la prima apelare.
Asemntor listelor simplu nlnuite, o list dublu nlnuit poate fi construit prin
intermediul unei funcii care stocheaz fiecare element ntr-o anumit locaie din list, n
loc de a plasa fiecare element la sfritul listei. Funcia prezentat n continuare,
store_ld_sort(), creeaz o list sortat n ordine cresctoare:
/* Creeaz o lista ordonata dublu inlantuita. */
void store_ld_sort(
struct adresa *i, /* elementul nou */
struct adresa **prim, /* primul element pe lista */
struct adresa **ultim /* ultimul element pe lista */
)
{
struct adresa *vechi, *p;
if(*ultim==NULL) { /* primul element pe lista */
i->urm = NULL;
i->preced = NULL;
*ultim = i;
*prim = i;
return;
}
p = *prim; /* incepe in varful listei */
vechi = NULL; while(p) {
if(strcmp(p->nume, i->nume)<0) {
vechi = p;
p = p->urm;
}
else {
if(p->preced) {
p->preced->urm = i;
i->urm = p;
i->preced = p->preced;
p->preced = i;
return;
}
i->urm = p; /* noul prim element */
i->preced = NULL;
p->preced = i;
*prim = i;
return;
}
}
vechi->urm = i; /* insereaz la sfrit */
i->urm = NULL;
i->preced =* vechi;
*ultim = i;
}
Deoarece primul sau ultimul element din list se poate modifica, funcia
store_ld_sort() actualizeaz n mod automat pointerii ctre elementele de nceput i
de sfrit ale listei prin intermediul parametrilor prim i ultim. Funcia trebuie apelat printr-
un pointer ctre datele care urmeaz a fi stocate i doi pointeri ctre primul, respectiv
ultimul element din list. Cnd funcia este apelat pentru prima dat, obiectele indicate de
prim i ultim trebuie s fie nule.
Liste, cozi, stive i arbori
Ca i n cazul listelor simplu nlnuite, recuperarea unui anumit articol de date dintr-o list
dublu nlnuit se rezum la urmrirea legturilor pn la localizarea elementului
corespunztor.
Exist trei cazuri care trebuie luate n considerare la tergerea unui element dintr-o list
dublu nlnuit: tergerea primului articol, tergerea unui articol dintre dou articole i
tergerea ultimului articol. Fig 13.6 prezint modul de rearanjare a legturilor.
Figura 13.6 tergerea dintr-o list dublu nlnuit
Date
0
Date

Date
0
Lista iniial
ters
0 0
Date
0
Date
0
tergerea primului articol
Date
0
ters
0 0
Date
0
tergerea unui element din interior
Date
0
Date
0
ters
0 0
tergerea ultimului articol
Funcia sterg_ld(), prezentat mai jos, terge un articol dintr-o list dublu nlnuit.
void sterg_ld (
struct adresa *a, /* articolul care va fi ters */
struct adresa **prim, /* primul articol */
struct adresa **ultim) /* ultimul articol */
{
if(a->preced) a->preced->urm = i->urm;
else { /* noul prim element */
*prim = a->urm;
if(prim) prim->preced = NULL;
}
if(a->urm) a->urm->preced = a->preced;
else /* terge ultimul element */
*ultim = a->preced;
}
Deoarece pot fi terse i primul sau ultimul element din list, funcia sterg_ld()
actualizeaz n mod automat pointerii ctre primul i ultimul element din list, prin
intermediul parametrilor prim i ultim. Funcia trebuie apelat printr-un pointer ctre datele
care trebuie terse, precum i un pointer ctre pointerii primului i ultimului articol din list.
13.2 Cozi
O coad (queue) este o list simplu nlnuit care este accesat n ordinea first in,
first out - FIFO (primul care intr, primul care iese).
Cu alte cuvinte, primul articol din coad este primul recuperat, al doilea de pe list este al
doilea recuperat etc. Acesta este singurul mod de stocare i recuperare a datelor dintr-o
coad, nefiind permis accesul aleator al unui anumit articol.

203
Capitolul 13

204
Pentru a vizualiza modul de funcionare al unei cozi, s considerm dou funcii,
stochez() i recuperez(). Funcia stochez() aeaz un articol la sfritul unei cozi,
iar recuperez() elimin primul element din coad i returneaz valoarea acestuia.
Tabelul 13.1 ilustreaz o serie de asemenea operaii.
Tabelul 13.1 Operaii cu cozi
Aciunea Coninutul
cozii
stochez(A)
A
stochez(B)
A B
stochez(C)
A B C
recuperez() returneaz A B C
stochez(D)
B C D
recuperez() returneaz B C D
recuperez() returneaz C D
Nu uitai c o operaie de recuperare elimin un articol din coad i l distruge, dac
acesta nu este stocat n alt parte. Ca atare, este posibil ca o coad s fie goal,
deoarece toate componentele sale au fost nlturate.
Pentru a vedea un exemplu de coad n aciune, vom folosi un program simplu de
planificare a ntlnirilor.
Exemplul 13.1 Program simplu de planificare a ntlnirilor
Acest program permite introducerea unui numr de ntlniri, apoi, pe msur ce ntlnirile
au avut loc, acestea sunt terse de pe list. Din raiuni de simplitate, fiecare descriere a
unei ntlniri va fi limitat la 255 caractere, iar numrul acestora a fost arbitrar limitat la
100.
/* Mini-planificator de intalniri */
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#define MAX 100

char *p[MAX], *recuperez(void);
int poz_stoc = 0; int poz_rec = 0;
void introduc(void), stochez(char *q), listez(void),
sterg(void);

void main(void)
{
char s[80]; register int t;
for(t=0; t<MAX; ++t) p[t] = NULL; /*init. tablou la 0 */
for(;;) {
printf("Introduc, Listez, Sterg, Terminare: ");
gets(s);
*s = toupper(*s);
switch(*s) {
case 'I': introduc(); break;
case 'L': listez(); break;
case 'S': sterg(); break;
case 'T': exit(0);
}
}
}
Liste, cozi, stive i arbori

205
/* introducerea intalnirilor n coada */
void introduc(void)
{
char s[256], *p;
do{
printf("Introduceti intalnirea %d: ", poz_stoc+1);
gets(s) ;
if(*s==0) break; /* nu mai sunt locuri libere */
p=(char *)malloc(strlen(s)+1);
if(!p) {
printf("Memorie epuizata.\n"); return; }
strcpy(p,s);
if(*s) stochez(p);
}
while (*s);
}
/* Consulta coada. */
void listez(void)
{
register int t;
for(t = poz_rec; t<poz_stoc; ++t)
printf("%d. %s\n", t+1, p[t]);
}
/* Sterge o intalnire din coada. */
void sterg(void)
{
char *p;
if((p=recuperez())==NULL) return; printf("%s\n", p);
}
/* Stocheaza o intalnire. */
void stochez(char *q)
{
if(poz_stoc==MAX) {
printf("Lista completa\n" ) ;
return;
}
p[poz_stoc] = q; poz_stoc++;
}
/* Recupereaza o intalnire. */
char *recuperez(void)
{
if(poz_rec==poz_stoc) {
printf("Nu mai sunt intalniri.\n"); return NULL; }
poz_rec++;
return p[poz_rec-1];
}

Funciile stochez() i recuperez() din program vor stoca pointeri ctre irurile care
descriu ntlnirile.
Observai c aceste funcii necesit dou variabile globale: poz_stoc (care memoreaz
indicele urmtoarei locaii libere de memorare) i poz_rec (care stocheaz indicele
urmtorului articol care va fi recuperat). Aceste funcii pot fi folosite pentru a menine o
coad de alte tipuri de date prin simpla modificare a tipului de baz al tabloului cu care
opereaz acestea.
Capitolul 13
Funcia stochez() amplaseaz pointerii noilor ntlniri ctre sfritul listei i verific dac
lista este complet. Funcia recuperez() preia ntlnirile din coad n timpul desfurrii
unor evenimente. La fiecare nou ntlnire programat, poz_stoc este incrementat i, la
fiecare ntlnire desfurat, poz_rec este incrementat. n esen, poz_rec este mereu
pe urmele lui poz_stoc pe toat lungimea cozii. Dac poz_rec i poz_stoc sunt egale,
nu mai exist evenimente de programat. Chiar dac informaia stocat ntr-o coad nu
este practic distrus de recuperez(), este totui distrus fiindc nu mai poate fi
accesat niciodat.
13.2.1 Cozi circulare
E posibil ca, n timpul studiului programului precedent, s v fi gndit deja la o
mbuntire. De exemplu, n loc de a cere programului s se opreasc la limita tabloului
folosit pentru stocarea cozii, putei cere indicelui de stocare (poz_stoc) i a celui de
recuperare (poz_rec) s salte napoi la nceputul tabloului. Astfel, n coad se pot plasa
oricte articole, atta timp ct de asemenea se extrag articole din tablou. Aceast
implementare a unei cozi se numete implementare circular, deoarece i folosete
tabloul de stocare ca i cum acesta ar fi un cerc, i nu o list liniar.
Pentru a crea o coad circular n programul de planificare, este necesar s modificai
funciile stochez() i recuperez() dup cum urmeaz:
void stochez(char *q) {
/* Coada e plina daca poz_stoc este cu o unitate mai mic dect poz_rec sau daca
poz_stoc este la sfarsitul tabloului care stocheaz coada si poz_rec este la
inceputul acestuia. */
if(poz_stoc+1==poz_rec || (poz_stoc+1)==MAX && !poz_rec)) {
printf("Lista completa\n"); return;
p[poz_stoc] = q;
poz_stoc++;
if(poz_stoc==MAX) poz_stoc = 0; /* salt inapoi */
}

char *recuperez(void)
{
if(poz_rec==MAX) poz_rec = 0; /* salt inapoi */
if(poz_rec==poz_stoc) {
printf("Nu sunt evenimente in lista.\n");
return NULL;
}
poz_rec++;
return p[poz_rec-1];
}
n esen, coada este complet cnd indicele de stocare este cu o unitate mai mic dect
indicele de recuperare; n caz contrar, n coad exist spaiu pentru un alt eveniment.
Conceptual, tabloul folosit pentru programul de planificare se prezint ca n Fig 13.7.

206
Poate cea mai comun utilizare a unei
cozi circulare se regsete n sistemele de
operare, acolo unde o coad circular
memoreaz informaia citit din i scris
pe fiiere, pe disc sau n consol. Cozile
circulare sunt de asemenea folosite n
programe de aplicaie n timp real, care
trebuie s continue s proceseze
informaia n timpul memorrii temporare a
Date

Date

Date

Figura 13.7 Coad circular
Liste, cozi, stive i arbori

207
cererilor de I/O. Multe procesoare de texte procedeaz astfel cnd reformateaz un
paragraf sau aliniaz o linie. Informaia tastat nu este afiat pn la ncheierea operaiei.
Pentru a realiza aceasta, programul de aplicaie trebuie s controleze intrrile de la
tastatur n timpul execuiei celuilalt proces. Dac se apas vreo tast, aceasta este rapid
introdus n coad i execuia celuilalt proces continu. Dup ncheierea procesului,
caracterele sunt reproduse din coad.
13.3 Stive
O stiv (stack) este o list simplu nlnuit care este accesat n ordinea last in, first
out - LIFO (ultimul care intr, primul care iese).
Pentru a v imagina o stiv, gndii-v la un vraf de farfurii. Prima farfurie de pe mas este
ultima care va fi folosit, iar ultima farfurie aezat n stiv este i prima care va fi folosit.
Stivele sunt foarte des folosite n programele de sistem, inclusiv n compilatoare i
interpretoare. De fapt, compilatoarele de C folosesc stivele pentru a transfera argumente
ctre funcii. Cnd se lucreaz cu stive, cele dou operaii de baz - anume memorarea i
citirea - sunt numite n mod tradiional push (a mpinge) i pop (a scoate). Ca atare, pentru
a implementa o stiv este nevoie de dou funcii, i anume push(), care amplaseaz o
valoare n stiv, i pop(), care citete o valoare din stiv. De asemenea, este necesar
utilizarea unei regiuni de memorie drept stiv. n acest scop se poate folosi un tablou sau
se poate aloca o regiune de memorie folosind funciile de alocare dinamic ale limbajului
C. Ca i n cazul cozilor, funcia de citire preia o valoare din list i o distruge, dac
aceasta nu este stocat n alt parte. n continuare sunt prezentate formele generale ale
unor funcii push() i pop() care folosesc un tablou de ntregi. Se pot pstra stivele de alte
tipuri de date modificnd tipul de baz al tabloului cu care opereaz funciile push() i
pop().
int stack[MAX];
int vfs = 0; /* vrful stivei */
/* Introducerea unui element in stiva. */
void push(int i)
{
if(vfs>=MAX) {
printf ( "Stiva plina"); return; }
stack[vfs] = i; vf s++;
}

/* Citete elementul din vrful stivei. */
pop(void)
{
vfs--;
if(vfs<0) {
printf("Depire a stivei in sens negativ\n"); return 0;}
return stack[vfs];
}
Variabila vfs este indicele vrfului stivei. La implementarea acestor funcii, nu trebuie s
uitai de prevenirea depirilor n sens pozitiv sau negativ ale stivei. n aceste rutine, o
stiv goal este semnalat printr-un vfs egal cu zero, iar o stiv plin este indicat printr-
un vfs superior ultimei locaii de stocare. Pentru a vedea cum funcioneaz o stiv, vezi
Tabelul 13.2.
Capitolul 13

208
Tabelul 13.2 Operaii cu stive
Aciune Coninutul stivei
push(A)
A
push(B)
B A
push(C)
C B A
pop() citete C B A
push(F)
F B A
pop() citete F B A
pop() citete B A
pop() citete A stiv goal
Un excelent exemplu de utilizare a unei stive o reprezint un calculator cu patru funcii.
Majoritatea calculatoarelor accept n prezent o form standard a unei expresii denumite
notaie infix, care ia forma general operand-operator-operad. De exemplu, pentru a
aduna 100 cu 200, mai nti se introduce 100, apoi se apas tasta PLUS (+), apoi se
introduce 200, i n fine se apas tasta EGAL (=). Spre deosebire de acestea, multe
calculatoare mai vechi (din care unele se mai produc i n prezent), folosesc notaia
postfix, n cadrul creia se introduc mai nti operanzii i apoi operatorul. De exemplu,
pentru a aduna 100 cu 200 folosind notaia postfix, mai nti se introduce 100, apoi 200,
iar apoi se apas tasta PLUS. Pe msur ce operanzii sunt introdui, acetia sunt aezai
ntr-o stiv. De fiecare dat cnd este introdus un operator, cei doi operanzi sunt eliminai
din stiv, iar rezultatul este introdus n stiv. Un avantaj al notaiei postfix este acela c
utilizatorul poate introduce expresii lungi, complexe.
Exemplul 13.2 Calculator postfix pentru expresii ntregi
Exemplul urmtor demonstreaz modul de utilizare al unei stive prin implementarea unui
calculator postfix pentru expresii ntregi.
/* Un calculator simplu cu patru functii. */
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
int *p; /* pointer ctre o regiune de memorie libera */
int *vfs; /* pointer ctre vrful stivei */
int *bzs; /* pointer ctre baza stivei */

void push(int i); int pop(void); void main(void)
{
int a, b; char s[80];
p = (int *) malloc(MAX*sizeof(int)); /* memorie stiva */
if(!p) {
printf("Eroare de alocare\n"); exit(1); )
vfs = p; bzs = p+MAX-1;
printf("Calculator cu patru functii\n");
printf("Tastai 'q' pentru a renunta\n");
do {
printf(": "); gets (s) ;
switch(*s) {
case '+':
a = pop(); b = pop();
printf("%d\n", a+b); push(a+b); break;
case '-':
a = pop(); b = pop();
printf('"td\n", b-a); push(b-a); break;
case '*':
Liste, cozi, stive i arbori

209
a = pop(); b = pop();
printf("*d\n", b*a); push(b*a) ; break;
case '/':
a = pop(); b = pop();
if(a==0) { printf("impartire cu zero\n"); break;}
printf("%d\n", b/a); push(b/a); break;
case '.': /* arata vrful stivei */
a = pop(); push(a);
printf("valoarea in varf: %d\n", a); break;
default: push(atoi(s));
}
} while(*s!='q');
}
/* introduce un element in stiva */
void push(int i)
{
if(p>bzs) {
printf("Stiva plina\n"); return;}
*p = i; p++;
}
/* Citete elementul din vrful stivei. */
pop(void)
{
p--;
if(p<vfs) { printf("Depire in sens negativ\n"); return 0; }
return *p;
}
Aa cum se observ, a fost necesar modificarea funciilor push() i pop(), funcii care au
fost folosite pentru memorarea stivei ntr-o zon de memorie alocat dinamic, n loc de un
tablou de dimensiune fix. Dei utilizarea memoriei dinamic alocate nu era necesar
pentru acest exemplu simplu, este prezentat modul de utilizare a memoriei dinamic
alocate n lucrul cu stive. nainte de a putea folosi aceste funcii, a fost necesar alocarea
unei zone libere de memorie folosind malloc(), adresa nceputului acelei regiuni
trebuind alocat variabilei vfs, iar adresa sfritului regiunii trebuind alocat regiunii bzs.
13.4 Arbori binari
Ultima structur de date examinat o constituie arborele binar (binary tree). Dei exist
mai multe categorii de arbori, cei binari sunt o categorie special deoarece, atunci cnd
sunt sortai, se preteaz la cutri, inserii i tergeri rapide. Fiecare articol dintr-un arbore
este alctuit din informaii i legturi cu membrul din stnga i cu cel din dreapta. Error!
Reference source not found. prezint un arbore de mici dimensiuni.
Pentru discuiile referitoare la arbori este necesar o terminologie special. Specialitii n
calculatoare nu sunt vestii pentru gramatica lor, ca atare terminologia aferent arborilor
reprezint o veritabil metafor a confuziei. Primul articol al unui arbore l constituie
rdcina (root). Fiecare articol de date este denumit nod (node), iar orice component a
arborelui este cunoscut sub numele de subarbore (subtree). Un nod fr subarbori este
denumit nod terminal (terminal node) sau frunz (leaf). nlimea unui arbore este egal cu
numrul de nivele pe care se extinde rdcina acestora. Cnd lucrai cu arbori, v putei
imagina dispunerea lor n memorie exact ca i pe hrtie. Nu uitai ns c un arbore
reprezint numai o modalitate de organizare logic a datelor n memorie, iar memoria este
liniar.
Capitolul 13
ntr-un fel, arborele binar este o form special de list nlnuit. Articolele pot fi
accesate, inserate sau terse n orice ordine. De asemenea, operaia de recuperare nu
este distructiv. Dei arborii sunt uor de vizualizat, prezint totui probleme de
programare foarte dificile. Aceast discuie nu reprezint dect un timid nceput.
Majoritatea funciilor care folosesc arbori sunt recursive, deoarece arborele nsui este o
structur de date recursiv. Cu alte cuvinte, fiecare subarbore este el nsui un arbore. Ca
atare, rutinele despre care vom discuta aici vor fi tot recursive. Nu uitai c exist i
versiuni nerecursive ale acestor funcii, dar sunt mult mai dificil de neles.
Modul de organizare a unui arbore depinde de modul n care va fi referit acesta. Procesul
de accesare a fiecrui nod dintr-un arbore se numete traversarea arborelui (tree
traversal). Fie arborele din figura Figura 13.8.
Exist trei modaliti de traversare a unui arbore: inordine, preordine i postordine. Dac
se folosete inordinea, se parcurge subarborele stng, apoi rdcina i apoi subarborele
drept. Modul preordine implic succesiunea rdcin,
subarbore stng, subarbore drept, iar n modul
postordine se pleac din subarborele stng, subarborele
drept i se ajunge n rdcin. Ordinea de acces n cele
trei metode este

210
inordine a b c d e f g
preordine d b a c f e g
postordine a c b e g f d
Dei un arbore nu trebuie sortat, n majoritatea cazurilor
aceast operaie este necesar. Desigur, ceea ce
alctuiete un arbore sortat depinde de modul n care va
fi traversat arborele. n continuare, vom presupune
folosit modul inordine. n consecin, un arbore binar sortat este acela n care subarborele
stng conine noduri mai puine sau egale cu rdcina, iar nodurile de pe dreapta sunt mai
mari dect rdcina.
d
b f
a c e g
Figura 13.8 Arbore simplu
Exemplul 13.3 Creare i afiare arbore
S lum n considerare un program mic, dar interesant, care alctuiete un arbore binar
sortat, iar apoi afieaz arborele n mod inordine, pe marginile ecranului.
n continuare prezentm integral programul de afiare a arborelui. ncercai diferii arbori
pentru a testa modul de alctuire al fiecruia.
#include <stdlib.h>
#include <stdio.h>

struct arbore {
char info;
struct arbore *stang;
struct arbore *drept;
};

struct arbore *radacina; /* primul nod din arbore */
struct arbore *sort_arb(struct arbore *radacina, struct arbore
*r, char info);
void print_arbore(struct arbore *radacina, int l) ;

void main(void)
{
char s[80];
radacina = NULL; /* initializarea radacinii */
do{
Liste, cozi, stive i arbori

211
printf("introduceti o litera: ");
gets(s);
if(!radacina) radacina=sort_arb(radacina, radacina, *s);
else sort_arb(radacina,radacina,*s); }
while(*s);
print_arbore(radacina, NULL);
}

struct arbore *sort_arb(struct arbore *radacina, struct arbore
*r, char info)
{
if(!r) {
r = (struct arbore *) malloc(sizeof(struct arbore));
if(!r) {printf("Memorie epuizata\n"); exit(0);}
r->stang = NULL;
r->drept = NULL;
r->info = info;
if(!radacina) return r; /* prima intrare */
if(info<radacina->info) radacina->stang = r;
else radacina->drept = r;
return r;
}
if(info<r->info) sort_arb(r, r->stang, info);
else sort_arb(r, r->drept, info);
}

void print_arbore(struct arbore *r, int l)
{
int i;
if(r==NULL) return;
print_arbore(r->drept, l+1);
for(i=0; i<l; ++i)
printf(" ");
printf("%c\n", r->info);
print_arbore(r->stang, l+1);
}
Funcia sort_arb() construiete un arbore binar sortat. Algoritmul funciei nu face dect
s urmeze legturile spre stnga sau spre dreapta n funcie de cmpul info. Pentru a
utiliza aceast funcie, este necesar o variabil global care indic spre rdcina
arborelui. Aceast global trebuie iniial setat la NULL. Valoarea returnat a primului apel
la sort_arb() trebuie atribuit acestui pointer. La urmtoarele apeluri nu mai este
necesar reatribuirea rdcinii. Presupunnd c numele globalei este rad, pentru
apelarea funciei sort_arb() se folosete secvena:
/* apelarea funciei sort_arb() */
if(!rad) rad = sort_arb(rad, rad, info);
else sort_arb(rad, rad, info);
Astfel, att primul element, ct i cele ulterioare acestuia, pot fi inserate corect.
Funcia sort_arb() este un algoritm recursiv, ca majoritatea rutinelor care opereaz cu
arbori. Dac se folosesc metodele iterative, aceeai rutin devine de cteva ori mai lung.
Funcia trebuie apelat folosind urmtoarele argumente (de la stnga la dreapta): un
pointer ctre rdcina ntregului arbore, un pointer ctre rdcina urmtorului arbore n
care se va cuta i informaia care va fi memorat. La prima apelare a funciei, primii doi
parametri reprezint, ambii, pointeri ctre rdcina ntregului arbore. Din motive de
Capitolul 13
claritate, ca informaie stocat n arbore se va considera un singur caracter. Totui,
programatorul poate utiliza orice tip de date.
Pentru a traversa n ordine arborele alctuit folosind funcia sort_arb() i pentru a afia
cmpul info al fiecrui nod, se poate folosi funcia in_ordine(), prezentat n
continuare:
void in_ordine(struct arbore *radacina)
{
if(!radacina) return;
in_ordine(radacina->stanga);
if(radacina->info) printf("%c ", radacina->info);
in_ordine(radacina->dreapta);
}
Aceast funcie recursiv returneaz n momentul ntlnirii unui nod terminal (adic un
pointer nul).
Funciile pentru traversarea arborelui n modurile preordine i postordine sunt prezentate
n continuare.
void pre_ordine(struct arbore *radacina)
{
if(!radacina) return;
if(radacina->info) printf("%c ", radacina->info);
pre_ordine(radacina->left);
pre_ordine(radacina->right);
}

void post_ordine(struct arbore *radacina)
{
if(!radacina) return;
post_ordine(radacina->left) ; post_ordine(radacina->right);
if(radacina->info) printf("%c ", radacina->info);
}
Pentru a afia arborele, programul necesit o versiune uor modificat a funciei
in_ordine(). Deoarece arborele este afiat pe marginile ecranului, subarborele drept
trebuie afiat naintea celui stng, pentru ca arborele s arate corect. (Aceasta reprezint,
din punct de vedere tehnic, opusul unei traversri n mod inordine.) Aceast funcie nou
este funcia print_arbore() din program.

Programul sorteaz efectiv informaia furnizat i reprezint n esen, o variaie a sortrii
pe care ai urmrit-o n capitolul precedent. n caz general, performanele acestui program
sunt bune, dar sortarea rapid rmne o metod superioar de sortare de uz general,
deoarece necesit mai puin memorie i mai puine operaii de procesare. Totui, dac
trebuie s alctuii un arbore pornind de la zero sau dac trebuie s ntreinei un arbore
deja sortat, trebuie s introducei noile intrri n ordinea de sortare,
folosind funcia sort_arb().

212
Dac ai rulat programul de afiare a arborelui, ai constatat probabil
c unii arbori sunt n echilibru - altfel spus, fiecare subarbore are
aproximativ aceeai nlime cu a celorlali, iar restul sunt foarte
neechilibrai. De fapt, dac ai inserat arborele abcd, acesta va arta
ca n figura alturat, deci nu mai exist subarbori. Acesta se
numete arbore degenerat, deoarece s-a transformat ntr-o list
liniar. n general, dac datele de intrare folosite la alctuirea unui
arbore binar au o distribuie oarecum aleatoare, arborele generat va
aproxima un arbore echilibrat. (Este posibil reajustarea arborelui la
a
b
d
c
Liste, cozi, stive i arbori

213
fiecare inserie de date pentru meninerea arborelui n echilibru, dar este un proces
complex care depete cadrul acestui capitol.)
Funciile de cutare sunt uor de implementat pentru arborii binari. Urmtoarea funcie
returneaz un pointer ctre nodul care este identic cu cheia; n caz contrar, returneaz
zero.
struct arbore *search_arbore(struct arbore, *radacina, char
cheia)
{
if(!radacina) return radacina; /* arbore gol */
while(radacina->info!=cheia) {
if(cheia<radacina->info) radacina = radacina->stang;
else radacina = radacina->drept;
if(radacina==NULL) break;
}
return radacina;
}
Din pcate, tergerea unui nod dintr-un arbore nu este att de simpl ca o operaie de
cutare. Nodul ters poate fi rdcina, un nod din stnga sau un nod din dreapta. De
asemenea, este posibil ca nodul s aib ntre zero i doi subarbori ataai acestuia.
Procesul de rearanjare a pointerilor se preteaz la un algoritm recursiv, care este
prezentat n cele ce urmeaz:
struct arbore *sterg_arb(struct arbore *radacina, char cheia)
{
struct arbore *p, *p2;
if(!radacina) return radacina; /* nu a fost gsit */
if(radacina->info==cheia) { /* sterge rdcina */
/* adic arborele este gol */
if(radacina->stang==radacina->drept)
{ free(radacina); return NULL;}
/* sau daca un subarbore este nul */
else if(radacina->stang ==NULL) {
p = radacina->drept;
free(radacina);
return p;
}
else if(radacina->drept==NULL) {
p = radacina->stang;
free(radacina);
return p;
}
/* sau ambii subarbori exista */
else {
p2 = radacina->drept;
p = radacina->drept;
while(p->stang) p = p->stang;
p->stang = radacina->stang;
free(radacina);
return p2;
}
}
if(radacina->info->cheia) radacina->drept ==
sterg_arb(radacina->drept,cheia);
else radacina->stang = sterg_arb(radacina->stang, cheia);
Capitolul 13

214
return radacina;
}
Nu uitai s actualizai pointerul rdcinii n restul programului, fiindc nodul ters ar putea
fi rdcina arborelui. Cel mai simplu mod de a realiza aceasta este de a atribui valoarea
returnat de sterg_arb() variabilei din programul dvs. care indic spre rdcin,
utiliznd o apelare similar celei ce urmeaz:
radacina = sterg_arb(radacina,cheia);
Arborii binari ofer o deosebit putere, flexibilitate i eficien cnd sunt folosii cu
programe de administrare a bazelor de date, deoarece informaiile aferente acestor baze
de date trebuie s se afle pe disc, iar timpii de acces sunt importani. Deoarece un arbore
binar n echilibru are, n cel mai ru caz, de efectuat log
2
n comparaii, este mult mai
convenabil de utilizat dect o list nlnuit, care implic o cutare secvenial.

Liste, cozi, stive i arbori

215

Manuale electronice

1. http://www.programmingtutorials.com/c.aspx
2. Marshall Brain - Introduction to C Programming: http://devcentral.iftech.com/
articles/ C++/ default.php
3. Steve Summit - Introductory C Programming Class Notes: http://
www.eskimo.com/ ~scs/ cclass/ cclass.html
4. Steve Summit - Intermediate C Programming Class Notes:
http://www.eskimo.com/ ~scs/ cclass/ cclass.html
5. Brian Brown - C Programming:
http://www.xploiter.com/mirrors/cprogram/default.htm

Bibliografie




[1] Vlad, S., Ursu, M.F. - Informatica tehnic, Univ. Tehnic Cluj-Napoca, Cluj-Napoca, 1996
[2] tefnescu, D., Segal, C. - Iniiere n limbajele C/C++, Ed. Fundaiei Univ., Galai, 2000, ISBN
973-8139-38-4, pg. 11
[3] Schildt, H. - C - Manual complet. Ed. Teora, Bucureti, 1998, ISBN 973-601-760-5, pg. 4
[4] Kernigham Brian W i Ritchie Dennis M. - The ANSI C programming language 2
nd
Ed.-
Prentice Hall
[5] Deaconu, A. - Programare avansat n C i C++, Univ. "Transilvania" Braov, 2003
[6] Negrescu, L. - Limbajele C i C++ pentru nceptori. Vol. 1: Limbajul C, Ed. Microinformatica
SRL, Cluj-Napoca, 1994
[7] Stoilescu, D. - Culegere de C/C++, Ed. Radial, Galai, 1998.
[8] Prisecaru, T., Ene, A.S. - Limbajul de programare C++ - Noiuni de baz, Ed. Matrix Rom B,
Ed. Bucureti, 2000, ISBN 973-685-093-5
[9] Ptru, B. - Aplicaii n C i C++. Ed. Teora, Bucureti, 1998, ISBN 973-601-471-1
[10] Novac, C. - Limbajul Turbo C++, Universitatea "Dunrea de Jos", Galai, 1993