Sunteți pe pagina 1din 158

Universitatea Transilvania

Facultatea de Matematic i Informatic


Catedra de Informatic

Note de curs despre

Programarea obiect orientat n


C++
(incluznd i bazele programrii
n C)

Dorin BoKu
2001-2002
n loc de introducere
Dup iniierea n programare, cu sprijinul altor cursuri,
paralele cu programarea sau complementare n cel mai bun
neles al cuvntului, iat-ne btnd, cu nelepciune
sporit, la poarta unei lumi n care vom vedea aceleai
concepte ntr-o micare care respect rigorile unui joc nou,
mult mai interesant din punct de vedere al mptimiilor n
ale programrii. Avem de lmurit i adncit dou teme de
meditaie mari i importante pentru formarea oricrui
informatician :

Paradigma programrii obiect orientate


Universul C++ ale crui origini vin dinspre C i
dinspre nceputurile dintotdeauna ale programrii.

Dup experienele cursurilor introductive n programare, n


prezentul curs voi deplasa accentul de la ct mai mult
despre la esenialul despre, ceea ce va aduce
beneficii tuturor, sper.
Pentru titularul de curs este un prilej (nu tocmai comod) de
a scoate n eviden cunotinele i abilitile
indispensabile unei cltorii la captul creia, cei care nu
au abandonat, primesc certificatul simbolic de Oameni
care au ncercat limitele unui limbaj de cotitur pentru orice
programator. Care este rezultatul unei astfel de ncercri?
Depinde, ca ntotdeauna, de curiozitatea i complexul de
motive care i nsoesc pe participanii la cltorie.
Multe dintre tainele programrii n C/C++ vor trebui aflate n
momentul n care, optnd pentru meseria de specialist n
ingineria softului, vei avea motive, timp i condiii s o
facei.
Studentul care citete acest suport de curs trebuie s
neleag un lucru elementar: fr determinare clar nu se
poate face nimic cu temeinicie; dincolo de determinare se
afl foarte mult munc, nelept drmuit ntre
numeroasele borne care ateapt s fie trecute, cu o not
care s certifice un anumit coeficient de inteligen.

Autorul

2
I BAZELE C++. LIMBAJUL C

3
1 Privire de ansamblu asupra limbajului C
1.1 Despre originile limbajului C
Legenda spune c C a fost inventat i implementat de Dennis Ritchie pe un
calculator DEC PDP-11, care utiliza sistemul de operare UNIX. Virtual, C este
rezultatul unui proces de dezvoltare complex, la care putem spune c a participat
ntreaga comunitate preocupat de ridicarea performanelor n munca de
programare. De fapt, strmoi direci ai limbajului C pot fi considerate limbajele
BCPL (creat de Martin Richards) i limbajul B (inventat de Ken Thompson). n
anii 70, limbajul B a influenat n cel mai nalt grad specificarea limbajului C. Mult
timp, standardul de facto pentru C a fost versiunea ce nsoea sistemul de
operare UNIX. Acest standard a fost descris pentru prima dat n cartea The C
Programming Language, scris de Brian Kernigan i Dennis Ritchie, aprut n
1978 la editura Prentice Hall. Odat cu creterea popularitii calculatoarelor
personale, au fost create numeroase implementri de C, ceea ce a generat o
problem nou: compatibilitatea implementrilor. Pentru rezolvarea acestei
probleme, n vara anului 1983, a fost nfiinat un comitet pentru crearea unui
standard ANSI (American National Standard Institute) care avea ca sarcin
specificarea definitiv a limbajului C. Standardul ANSI C a fost adoptat n
decembrie 1989, primele copii devenind disponibile la nceputul lui 1990. La ora
actual, toate compilatoarele C/C++ se aliniaz la standardul ANSI C. Totodat
standardul ANSI C este o baz pentru propunerea de standard ANSI C++(Bazat
pe limbajul C, C++ adaug extinderi care permit programarea obiect orientat).
Evident, vom reveni asupra topicii C++.

1.2 Locul limbajului C n lumea limbajelor de programare


Specialitii consider C un limbaj de nivel mediu. Aceast apreciere nu
presupune neaprat c C este mai puin performant dect limbajele de nivel
nalt, precum BASIC sau PASCAL. De asemenea, nu trebuie s concluzionm
c C are dificultile unui limbaj de asamblare. C este considerat un limbaj de
nivel mediu deoarece combin cele mai bune faciliti ale unui limbaj de
nivel nalt cu posibilitile de control i flexibilitatea unui limbaj de
asamblare.
Astfel, ca limbaj de nivel mediu C permite lucrul cu bii, octei i adrese
elemente de baz pentru funcionarea calculatorului. Cu toate acestea, codul C
rmne n foarte mare msur portabil.

 Despre un sistem soft spunem c este portabil dac n momentul n


care este scris pe o anumit main, sub un anumit mediu de operare,
poate fi uor adaptat pe alt main, eventual cu alt sistem de operare.

Tot ca nite trsturi specifice limbajului C semnalm urmtoarele:


Chiar dac C are cinci tipuri de date de baz, nu este un limbaj centrat
pe tipuri de date aa cum este, de exemplu, Pascal. Prin aceast afirmaie
sugerm faptul c n C lucrul cu diferite instane ale tipurilor de date de baz

4
beneficiaz de un cadru mult mai liberal (controalele compilatorului nu mai sunt
att de severe ca n Pascal).
Spre deosebire de un limbaj de nivel nalt, C nu face aproape nici un
control n timpul executrii unui program. Responsabilitatea de a evita
producerea erorilor i de a le dibui i corecta, dac le-a ocazionat, este a
programatorului.
C permite lucrul direct cu bii, octei cuvinte i pointeri ceea ce l face
potrivit pentru programare la nivel de sistem.

 Numim programare la nivel de sistem activitatea de scriere a codului


pentru anumite componente ale sistemului de operare sau care sunt
accesorii ale sistemelor de operare.

C are doar 32 cuvinte-cheie (27 din standardul Kernigan & Ritchie i


cinci adugate de comitetul de standardizare ANSI C). Limbajele de nivel nalt
depesc cu mult oferta limbajului C. Faptul c are att de puine cuvinte cheie
ar trebui s fie benefic pentru procesul de nvare a limbajului. Ceea ce se
nva greu n C este democraia prea mare n comparaie, de exemplu, cu
stilul autoritar n care compilatorul Pascal asist scrierea de programe
corecte.

1.3 C este limbaj structurat


Deoarece nu ofer suport pentru implementarea autentic a conceptului de
structur n blocuri, C este numit, simplu, limbaj structurat. C nu este limbaj
<structurat n blocuri> deoarece nu permite definirea de funcii n interiorul altor
funcii, situaie absolut normal i cu efecte interesante asupra modularizrii
codului Pascal, de exemplu.
Caracteristica esenial a limbajelor structurate este compartimentarea
codului i a datelor, prin care se nelege capacitatea unui limbaj de a separa i
ascunde de restul programului toate informaiile i instruciunile necesare
efecturii unei sarcini.
O modalitate de realizare a compartimentrii este utilizarea de subrutine care
folosesc variabile locale. Utiliznd variabile locale putem scrie modulele astfel
nct ceea ce se ntmpl n interiorul lor s nu aib efecte n alte seciuni ale
programului. C permite compartimentarea n acest spirit, utiliznd potenialul
noiunii de funcie.

 Utilizarea excesiv a variabilelor globale, n orice limbaj de programare


structurat, permite greelilor s se strecoare n program, sub forma
efectelor secundare neprevzute.

Evident, un limbaj de programare structurat descurajeaz sau interzice utilizarea


instruciunii goto.
Un alt mod de a structura i de a compartimenta codul, n C, este utilizarea
blocurilor de cod. Un bloc de cod este un grup de instruciuni alturate logic,
tratate ca un singur element. Blocurile de cod permit reprezentarea multor

5
algoritmi cu limpezime, elegan i eficien. n C un bloc de cod poate fi creat
incluznd ntre acolade un grup de instruciuni.

Dac n Pascal am avea:


.
if I<10
then
begin
gotoxy(12,I);
write(Valoarea curent a lui I:,I);
end;
.
atunci n mod echivalent, n C avem:
.
if (I<10)
{
gotoxy(12,I);
cout<<Valoarea curent a lui I:<<I;
}
.
Blocul de cod este delimitat de acolade.
L-am evideniat folosind efectul de umbrire (shading) a textului.

1.4 Relaia limbajului C cu programatorul


Specialitii n limbaje de programare afirm ceea ce, de fapt, s-a avut n vedere
la specificarea unor limbaje: acestea nu sunt pentru programatori. Limbaje
precum COBOL sau BASIC au fost specificate nu pentru a ndulci soarta
programatorilor sau pentru a mri sigurana n exploatare a codului creat, ci
pentru a lrgi accesul celor muli la nelegerea programelor sau chiar la scrierea
de programe pentru a rezolva probleme simple.
Din contr C (ca i C++) a fost creat, influenat i testat de ctre adevraii
programatori. Rezultatul final este c C ofer programatorului exact ceea ce i
dorete: restricii puine, structurare, blocuri de cod, funcii de sine stttoare i
un set compact de cuvinte cheie. De asemenea faptul c poate fi utilizat n locul
limbajelor de asamblare i sporete limbajului C popularitatea printre
programatori.

1.5 Componentele de baz ale unui program C


n Tabelul 1 prezentm cuvintele-cheie, care, utilizate conform regulilor sintactice
specifice, permit scrierea de programe n C. Obinuina de a scrie programe n
alte limbaje de programare poate fi de un real folos n C. Astfel, multe din
abilitile cultivate ca autori de programe Pascal sunt transpuse, cu unele
modificri de sintax sau semantic i n C. Diferite compilatoare de C pot
beneficia de extinderi sintactice care permit programelor s beneficieze de
avantajele unor medii de operare particulare.

6
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
Tabelul 1 Cele 32 cuvinte-cheie definite de standardul ANSI C

Din cele 32 cuvinte-cheie prezentate n Tabelul 1, cele prezentate cu caractere


bold au fost adugate de comitetul ANSI C, celelalte corespunznd standardului
C original.

 Toate cuvintele-cheie n C se scriu cu litere mici . De asemenea, este


important s tim c n C literele mari difer de cele mici. Astfel c, n timp
ce for este cuvnt-cheie, FOR nu este cuvnt-cheie.

Toate programele C constau din una sau mai multe funcii a cror
sintax i semantic o vom prezenta n seciunile urmtoare.

n sfrit, componentele unui program C simplu se grupeaz n urmtoarele


seciuni:

Directive preprocesor n aceast seciune se includ


bibliotecile de care are nevoie
programul

Seciunea de definire a tipurilor i n aceast seciune sunt definite


constantelor globale constante sau tipuri de date necesare
n program

Antet program principal

Seciunea declarativ n aceast seciune se fac toate


declaraiile de variabile ale programului

Seciunea executabil n aceast seciune se amplaseaz


versiunea cod C a algoritmului care
rezolv problema

Un programator Pascal recunoate n acest ablon de organizare a codului unui


program C o parte din filozofia scrierii codului Pascal dar i o serie de elemente
inedite care l atenioneaz asupra faptului c limbajul C este o lume care
propune o nou abordare a unei probleme mai vechi :nvarea calculatoarelor

7
s rezolve anumite probleme. Aceast nou abordare o vom dezbate treptat n
seciunile care vor urma.

8
2 Expresii n C
n aceast seciune vom trece n revist propunerile limbajului C n ceea ce
provete posibilitatea de a utiliza expresii. Toate limbajele de programare
acord o atenie special noiunii de expresie deoarece, n ultim analiz, orice
transformare a datelor de intrare ale unui program este realizat prin intermediul
uneia sau a mai multor expresii. Aa cum vom descoperi pe parcurs, C este un
limbaj mult mai flexibil dect alte limbaje n materie de definire i utilizare a
expresiilor. Ceea ce este foarte limpede n acest moment este faptul c
expresiile sunt realizate cu ajutorul elementelor atomice numite date i
operatori. Datele pot fi reprezentate cu ajutorul constantelor sau prin intermediul
variabilelor. Ajungem, evident, la problema tipurilor de date suportate de C.

2.1 Cinci tipuri de date de baz n C


n C exist cinci tipuri de date de baz: caracter (char), ntreg (int), virgul
mobil (float), virgul mobil dubl precizie (double) i fr nici o valoare (void).
Toate celelalte tipuri de date din C se bazeaz pe cele cinci tipuri de baz.
Dimensiunea reprezentrii i domeniul valoric corespunztor pentru tipurile de
date de baz pot s difere, n funcie de tipul procesorului i de modul de
implementare a limbajului C. n toate cazurile, ns, un caracter se reprezint
pe un octet. Chiar dac de multe ori un ntreg se reprezint pe doi octei, nu se
poate conta pe aceast observaie dac dorim ca programele scrise s fie
portabile. De fapt, nsui standardul ANSI C, stipuleaz doar domeniul de
cuprindere minimal al fiecrui tip de date, nu i mrimea sa n octei.
Formatul exact al valorilor n virgul mobil depinde de modul lor de introducere.
ntregii corespund, n general, mrimii normale a unui cuvnt pe calculatorul
respectiv.
Valorile de tip char sunt, n general, utilizate pentru a memora valori definite de
setul de caractere ASCII. Valorile care ies din acest domeniu sunt tratate n mod
diferit de compilatoare.
Domeniul valoric pentru float i double va depinde de metoda folosit pentru a
reprezenta numere n virgul mobil. Standardul ANSI C indic domeniul valoric
pentru virgul mobil de la 1E-37 pna la 1E+37. Evident, vor exista deosebiri
att n ceea ce privete ordinul de mrime ct i n ceea ce privete precizia ntre
cele dou specii de virgul mobil. Numrul minim de cifre din punct de vedere al
preciziei este precizat n Tabelul 2.

Tipul void declar explicit c o funcie nu returneaz nici o valoare sau


creaz pointeri generici.

9
Tip de dat Dimensiune reprezenatre Domeniul valoric minimal
n bii
char 8 -127..127
unsigned char 8 0..255
signed char 8 -127..127
int 16 -32767..32767
unsigned int 16 0..65535
signed int 16 Similar cu int
short int 16 Similar int
unsigned short int 16 0..65535
signed short int 16 Similar cu short int
long int 32 -2.147.483.647..2.147.483.647
signed long int 32 Similar cu long int
unsigned long int 32 0..4.294.967.295
float 32 6 zecimale exacte
double 64 10 zecimale exacte
long double 80 10 zecimale exacte

Tabelul 2 Tipurile de date definite prin standardul ANSI C

2.2 Modificarea tipurilor de baz


Exceptnd tipul void, tipurile de baz pot fi precedate de diveri specificatori de
conversie. Un specificator de conversie se utilizeaz pentru a modifica tipul de
baz n ideea de adaptare mai precis la diferite situaii. Dup cum rezult i din
Tabelul 2, lista specificatorilor de conversie este:
signed
unsigned
long
short
n mod evident, diferena ntre ntregii cu semn i ntregii fr semn const n
modul n care se interpreteaz bitul de pe poziia cea mai semnificativ. Dac, de
exemplu, indicai un ntreg cu semn, compilatorul genereaz cod care presupune
c bitul cel mai semnificativ va fi utilizat ca bit de semn (0 dac numrul este
pozitiv, 1 dac numrul este negativ). S mai menionm faptul c, n general,
pentru reprezentarea ntregilor negativi se folosete codul complementar
(complementul fa de 2).
Detalii referitoare la caracteristicile codului complementar se pot obine
consultnd lucrri de specialitate n care se dezbate problema codificrii datelor
numerice n sistemele de calcul. n acest sens se poate consulta lucrarea [4]
care face o introducere accesibil n problematica mai sus menionat.

2.3 Nume de identificatori n C


n C/C++ numele variabilelor, funciilor, etichetelor i ale altor diverse obiecte
definite de ctre utilizator sunt numite identificatori. Aceti identificatori pot s
aib unul sau mai multe caractere. Primul caracter trebuie s fie obligatoriu o

10
liter sau o liniu de subliniere; urmtoarele pot fi litere, cifre sau liniua de
subliniere.
Exemple de identificatori:

Coreci Incoreci
numr_de pagini 1_valoare_returnat
_limita1 ok!
ok_ switch..conversie

Standardul ANSI C stipuleaz c identificatorii pot avea orice lungime. Totui,


nu toate caracterele sunt obligatoriu semnificative. Dac identificatorul este
implicat ntr-un proces de editare de legturi externe, vor conta cel mult ase
caractere. Aceti identificatori, denumii nume externe, includ numele funciilor i
ale variabilelor globale care aparin mai multor fiiere. Dac fiierul nu este
utilizat ntr-un proces de editare de legaturi externe, atunci vor fi semnificative cel
mult 31 de caractere. Acest tip de identificator este denumit nume intern i
include, de exemplu, nume de variabile locale. De remarcat faptul ca n C++ nu
exist limite ale lungimii unui identificator i toate caracterele sunt semnificative.
Aceast diferen ncepe s conteze n momentul n care dorii s convertii un
program din C n C++.
Pare evident, dar facem precizarea c un identificator C nu poate fi identic cu
un cuvnt-cheie i nu trebuie s aib acelai nume ca o funcie din
biblioteca C sau C++.

2.4 Variabile C
Aa cum s-a aflat i n alte mprejurri, o variabil este numele unei locaii de
memorie utilizat pentru a pstra o valoare care poate fi modificat de
program.
nainte de a fi utilizate n program, variabilele trebuie declarate. Declararea unei
variabile n C are forma:

<Tip> <List_de_variabile>;

<Tip> trebuie s fie un tip de dat valid (predefinit sau definit de utilizator)
precedat, eventual, de un specificator de conversie.
<List_de_variabile> poate consta dintr-un nume de identificator sau mai multe
nume de identificatori separate prin virgul.
Exemple de declaraii de variabile:

int nr_pag;
char opt,ch;
unsigned i, j;

Variabilele se pot declara n trei moduri: n interiorul funciilor, n cadrul definiiei


parametrilor funciei i n afara oricrei funcii. Prin urmare, este vorba despre
variabile locale, parametri formali i variabile globale.

11
2.5 Variabile locale n C
Variabilele declarate n interiorul unei funcii sunt numite variabile locale. O
parte din literatura C/C++ numete aceste variabile automatice. innd cont de
asemnarea evident cu variabilele locale din Pascal, de exemplu, vom folosi
termenul de variabil local.
Afirmaia cea mai important referitor la variabilele locale este urmtoarea:

Variabilele locale sunt accesibile doar instruciunilor care sunt n interiorul


blocului n care sunt declarate variabilele.

Alt amnunt important i specific limbajului C este faptul c:

Variabilele locale exist ct timp se execut blocul de cod n care sunt


declarate.

Altfel spus, o variabil local este creat la nceperea execuiei blocului su i


este distrus la ncheierea execuiei acestui bloc.
Blocul de cod cel mai uzual n care se declar variabile este funcia.
Deoarece noiunea de funcie este central pentru fizionomia unui program C,
prezentm, n continuare, o viziune asupra unui program C care include i
noiunea de funcie.

Directive preprocesor
Declaraii globale
Declaraie funcie_1
:
Declaraie funcie_n
int main()
{
Declaraii de date ale programului principal
Instruciuni program principal
Orice program C conine obligatoriu o funcie al crei nume este main
}
Implementare funcie_1
:
Implementare funcie_n

Totodat s precizm faptul c sintaxa de declarare a unei funcii (prototip n


C++), conform standardului ANSI C este :

<Tip returnat> <Nume funcie> (<Lista de parametri formali>)


Toat aceast construcie sintactic se mai numete i <Antet funcie>.
n C clasic declararea unei funcii permitea doar specificarea tipului returnat,
problema eventualilor parametri ateptai de funcie avnd o rezolvare aparte, pe

12
care nu mai insistm deoarece standardul ANSI C ca i standardul ANSI C++
descurajeaz, respectiv interzice utilizarea cii clasice.
n C++ declararea unei funcii se face apelnd la prototipuri.
n sfrit, implementarea unei funcii nseamn o construcie sintactic de tipul:

<Antet funcie>
{
<Declaratii de date>
<Instructiuni executabile>
}

Referindu-ne la standardul ANSI C/ANSI C++ putem spune c:


<Nume funcie> este un identificator valid.
<Tip returnat> specific tipul de dat asociat cu numele funciei.
<Lista de parametri formali> const din o serie de perechi de denumiri, separate
ntre ele prin virgul, unde prima denumire specific un tip de dat iar cea de-a
doua este numele parametrului formal.
Parametrii formali care apar n antetul unei funcii, n principiu, trebuie s
corespund ca tip cu parametrii actuali care apar la apelul unei funcii.Cnd un
parametru actual trimis unei funcii nu se potrivete exact, ca tip, cu parametrul
formal corespunztor, compilatorul ncearc o conversie convenabil. De
exemplu, o dat de tip int trimis unei funcii care ateapt o dat de tip float
este convertit la tipul float. Prezentm, n continuare, cteva exemple.

void f1(void)
{
int x;
x=12;
}
void f2(void)
{
int x;
x=-128;
}

Variabila x este declarat att n f1 ct i n f2. Variabila x din f1 nu are nici o


influen asupra variabilei x din f2 deoarece fiecare variabil este cunoscut
doar n blocul de cod gazd. Din obinuin i din respect fa de tradiie,
majoritatea programatorilor declar variabilele folosite de o funcie imediat dup
acolada deschis a funciei i nainte de orice instruciune executabil. De fapt,
se pot declara variabile n orice bloc de cod, obinndu-se chiar efecte benefice
pentru calitatea codului rezultat. Astfel putem avea:

void fexemplu(void)
{
int i;
printf(Introduceti un numar:);

13
scanf(%d,&i);
if (i>0)
{
char nume [40];
printf(Numele Dvs.:);
gets(nume);
}
}

Din exemplul de mai sus reinem doar faptul c, n situaia n care numrul
preluat de la tastatur (cu ajutorul rutinei de uz general scanf ) este mai mare
dect zero, atunci devine activ blocul de cod n care se declar variabila nume.
Aceast variabil este distrus la ieirea din acest bloc de cod.
Prin urmare, un avantaj potenial: variabilei nume i se aloc memorie numai
dac se activeaz blocul de cod, ceea ce nseamn economie de memorie.
Este absolut evident faptul c se declar ntr-un bloc de cod una sau mai multe
variabile strict necesare n acest bloc de cod; n acest mod prevenim, ntr-o
oarecare msur, apariia unor efecte secundare. Mai semnalm o diferen
important ntre modul de declarare a variabilelor locale n C fa de C++.
n C trebuie declarate toate variabilele locale la nceputul blocului n care
intenionm s le definim, nainte de orice instruciune executabil. n C++ nu
mai exist aceast restricie. Astfel c secvena de cod C:

void f(void)
{
int i;
i=10;
int j;
j=20;
}

este considerat greit de un compilator C i perfect acceptabil de ctre un


compilator C++.
Deoarece variabilele locale sunt create i distruse la fiecare intrare, respectiv
ieire din blocul n care au fost declarate, coninutul lor se pierde odat cu
prsirea blocului. Acest lucru este important s se tie cnd apelm o funcie.
La apelarea ei sunt create variabilele locale iar la ncheierea ei acestea sunt
distruse, deci variabilele locale nu pstreaz valorile lor ntre apelri. Putem
determina compilatorul s pstreze aceste valori utiliznd specificatorul de
stocare static asupra cruia vom reveni.

2.6 Parametrii formali


Dac o funcie urmeaz s foloseasc argumente, ea trebuie s declare
variabilele pe care le accept ca valori ale argumentelor. Aceste variabile sunt
denumite parametri formali ai funciei. Variabilele n cauz se comport ca
oricare alt variabil local din acea funcie.

14
2.7 Variabile globale
Variabilele globale, spre deosebire de cele locale, sunt cunoscute n tot
programul i pot fi utilizate de ctre orice zon a codului. Totodat, ele i
pstraz valoarea tot timpul execuiei programului. Variabilele globale se
creaz prin declarare n afara oricrei funcii. Orice expresie are acces la ele,
indiferent de tipul blocului de cod n care se afl expresia. De semnalat faptul c
o variabil global este vizibil n orice bloc de cod al programului ct timp n
respectivul bloc de cod nu a fost declarat o variabil cu acelai nume, de
acelai tip. n caz afirmativ, n blocul de cod este prioritar referirea la variabila
local.
Stocarea variabilelor globale este fcut de compilator ntr-o zon de memorie,
special alocat. Variabilele globale sunt utile atunci cnd mai multe funcii ale
aceluiai program folosesc aceleai date. Utilizarea excesiv a variabilelor
globale ar trebui evitat deoarece:
Ocup memoria pe tot timpul execuiei programului, nu doar cnd sunt
necesare;
Dac o funcie utilizeaz o variabil global n locul uneia locale, atunci
funcia i pierde din generalitate, bazndu-se pe ceva exterior logicii ei;
Variabile globale multe nseamn efecte secundare necunoscute i
nedorite.

2.8 Modelatori de acces


n C exist doi modelatori de acces (const i volatile) care introduc restricii
suplimentare asupra modului de apelare sau modificare a variabilelor. Aceti
modelatori trebuie s precead specificatorul de tip i numele tipului de dat la
care se refer.
Variabilele de tip const nu pot fi modificate de programele n care sunt
declarate. Acestor variabile li se permite, totui, s primeasc o valoare iniial.
Compilatorul poate s plaseze variabilele de acest tip n ROM (Read Only
Memory). Evident, aceste variabilele de tip const pot fi utilizate n construcia
unor expresii. Tehnic vorbind, modelatorul const poate fi utilizat i pentru a
proteja obiectele trimise ca argumente unei funcii, de modificri n interiorul
acelei funcii. Multe funcii din biblioteca standard a limbajului utilizeaz const n
declaraiile lor de parametri. Ca un exemplu, funcia strlen() are urmtorul
prototip:

size_t strlen( const char * s);

Modelatorul volatile informeaz compilatorul c valoarea unei variabile


poate fi modificat pe ci nedeclarate explicit de program. Aceasta nseamn c
este posibil urmtorul scenariu: Adresa unei variabile este transmis unei rutine
rezidente n memoria sistemului, aceast rutin fiind abilitat s modifice
valoarea variabilei. Evident, pentru programatori acesta este un mecanism
extrem de practic i interesant. Modelatorul volatile poate fi combinat cu
modelatorul const fcndu-se plauzibil scenariul: Valoarea unei variabile poate

15
fi modificat de condiii externe, fiind protejat de modificri accidentale n
programul n care este declarat.

2.9 Specificatori de clase de stocare


Limbajul C admite patru specificatori de clase de stocare:
extern
static
register
auto
Aceti specificatori indic compilatorului modul n care trebuie s stocheze
variabilele la care se refer. Cadrul sintactic general de utilizare a specificatorilor
de clase de stocare este:

<Specificator_de_stocare> <Tip> <Nume_variabil>;

extern
Deoarece C/C++ permit seciunilor separate ale unui program s fie compilate
independent i s li se editeze legturile mpreun, trebuie s existe o modalitate
de a comunica tuturor fiierelor variabilele globale necesare programului.
Scenariul cruia trebuie s i facem fa este urmtorul: Cum putem informa
toate fiierele care compun un program C despre variabilele globale utilizate?.
Soluia este urmtoarea : Se declar variabilele globale ntr-un fiier, care este
de preferat s conin i funcia principal a programului, aceleai variabile
declarndu-se i n toate fiierele care folosesc variabilele globale, nsoite de
specificatorul extern.

static
Variabilele de tip static sunt variabile permanente n interiorul funciei sau
fiierului n care se gsesc. Spre deosebire de variabilele globale, ele nu sunt
cunoscute n afara funciei sau fiierului, dar i pstreaz valoarea ntre dou
apelri. Aceast caracteristic este folositoare la scrierea de funcii generice i
de bibliotec , utilizabile de alte programe. Specificatorul static are efecte diferite
asupra variabilelor locale i globale.

Variabile locale statice


Aplicat unei variabile locale, specificatorul static informeaz compilatorul de
dorina de a i se asocia variabilei un loc de stocare permanent, similar celui
asociat unei variabile globale. Diferena esenial ntre variabilele locale statice
i o variabil global se refer la faptul c variabila local static rmne
cunoscut doar blocului n care a fost declarat. Altfel spus, o variabil
local static este o variabil care i pstreaz valoarea ntre apelurile funciei n
care a fost declarat.

Variabile globale statice

16
Aplicnd specificatorul static unei variabile globale, cerem compilatorului s
creeze o variabil global care este cunoscut doar n fiierul n care a fost
declarat. Aceasta nseamn c, dei variabila este global, rutine din alte
fiiere nu au acces la ea i nu i pot modifica coninutul.

register
Specificatorul de stocare register se aplic, prin tradiie, doar variabilelor de tip
int i char. Totui standardul ANSI C i d definiia astfel nct poate fi folosit
pentru orice tip de variabil. Iniial, register cerea compilatorului s pstreze
valoarea unei variabile ntr-un registru din CPU, nu n memoria RAM, unde
variabilele sunt stocate, de regul. Scopul unei astfel de cereri: spor de vitez n
timpul operaiilor asupra variabilei. Actualmente, definiia specificatorului register
a fost mult extins, acesta putnd fi aplicat oricrui tip de variabil. Standardul
ANSI C stipuleaz, simplu, c register este o indicaie dat compilatorului c
obiectul vizat va fi utilizat preferenial din punct de vedere al vitezei.
Specificatorul se poate aplica doar variabilelor locale i parametrilor formali. Prin
urmare, nu sunt permise variabile globale de tip register.

auto
Specificatorul auto este, practic, nefolosit, fiind reclamat doar de motive de
compatibilitate ntre codul C i codul C++.

2.10 Iniializarea variabilelor


Forma general a iniializrii unei variabile respect sintaxa:

<Tip> <Nume_variabil> = <Constanta>;

Exemple:

char ch=A;
int media=0;
float bilant=0;

Variabilele globale i cele statice locale sunt iniializate doar la nceputul


execuiei programului. Variabilele locale (cu excepia celor de tip static, sunt
iniializate de fiecare dat cnd este ntlnit blocul n care sunt declarate.

Variabilele locale care nu sunt iniializate au valori necunoscute nainte de


prima atribuire. Variabilele globale i locale de tip static neiniializate sunt
iniializate din oficiu cu zero.

Evident, trebuie s discutm n continuare despre problema reprezentrii


constantelor n programele C.

Constante C

17
Constantele se refer la valori fixe pe care programul nu poate s le modifice.
Constantele pot fi de oricare din tipurile fundamentale de date. Modul n care se
reprezint n program fiecare constant depinde de tipul su.
Constantele de tip caracter sunt incluse ntre ghilimele simple. A i % sunt
exemple de constante de tip caracter. C definete i caractere multioctet, n
mediile care nu utilizeaz limba englez. O situaie asemntoare se ntlnete
i n Delphi.
Constantele de tip ntreg sunt specificate ca numere fr parte fracionar. De
exemplu, 3 i -15 sunt exemple de constante ntregi.
Constantele n virgul mobil cer punctul zecimal urmat de partea zecimal a
numrului. 0.75 este un exemplu de constant care apeleaz la virgula mobil.
Limbajul C permite i notaia tiinific, cunoscut i n alte limbaje.
De asemenea, C stabilete pentru o constant numeric cel mai scurt tip de date
compatibil care o poate pstra. Astfel c, -10 este implicit un int, 60.000 este
unsigned int iar 120.000 este un long int. Tipul constantei numerice poate fi
specificat i explicit ca n exemplele din Tabelul 3.

Tip de data Exemplu de constant


int 1, 234, 2000, -243
long int 100000, 23000L, -45L
short int 9, -2000
unsigned int 10000U, 900U, 45000
float 120.15F, 3.75e-5F
double 120.15, 22122122, -0.9876432
long double 1000.25L
Tabelul 3 Exemple de constante numerice

Dup cum se vede, constantele n virgul mobil sunt asimilate implicit tipului
double.

Constante hexazecimale i octale


Deoarece exist numeroase situaii n care avem nevoie de referiri la sistemele
de numeraie octal i hexazecimal, C permite utilizarea constantelor octale i
hexazecimale astfel:

O constant octal ncepe cu 0 (zero).


Exemplu:

int octala=017; /*In zecimal 15 */

O constant hexazecimal ncepe cu 0x.


Exemplu:

int hexa =0x100; /*In zecimal 256*/

18
Constante de tip ir
C admite, cum era i firesc i constanta de tip ir de caractere. O constant ir
este o succesiune de caractere delimitat de ghilimele. A nu se confunda irurile
de caractere cu caracterele. a i a sunt constante de tipuri diferite( disticie
care, n Pascal, nu este operat sintactic, vorbind.

Constante de tip backslash caracter


ncadrarea constantelor de tip caracter ntre apostrofuri funcioneaz pentru
majoritatea caracterelor afiabile. ns, altele, puine la numr, sunt imposibil de
introdus de la tastatur (constanta BEL, de exemplu). n acest scop C introduce
constante speciale, de tip backslash caracter. C admite mai multe coduri
backslash, cum rezult i din Tabelul 4. Pentru a se asigura portabilitatea
programelor sunt indicate codurile backslash n locul codurilor lor ASCII.

Codul Semnificaia
\b Backspace
\f form feed (=Salt la pagin nou)
\n CR+LF
\r CR
\t tab orizontal
\ Ghilimele
\ Apostrof
\0 Null
\\ Backslash
\v tabulare vertical
\a Alert
\N constant n octal; N este constanta
\xN constant n hexazecimal; N este constanta
Tabelul 4 Coduri backslash n C
2.11 Operatori n C
C dispune de foarte muli operatori. De fapt, C acord acestora o importan mult
mai mare n comparaie cu alte limbaje. C definete, n esen, patru clase de
operatori: aritmetici, relaionali, logici i de aciune la nivel de bit. Pentru
anumite sarcini, C are operatori suplimentari.

Operatorul de atribuire
Operatorul de atribuire poate fi folosit, n C, n cadrul oricrei expresii valide,
lucru care nu este permis n majoritatea limbajelor de programare (inclusiv
Pascal), care trateaz operatorul de atribuire ca pe un caz de instruciune
special. Sintaxa de aplicare a operatorului de atribuire n C este:

<Nume_variabil> = <Expresie>;

unde <Expresie> poate fi o constant sau o construcie legal de


complexitatea cerut n context. Atenie, se folosete = n loc de :=.

19
Membrul stng al atribuirii trebuie s fie o variabil sau un pointer, nu o funcie
sau o constant.

Conversii de tip la atribuire


Cnd variabilele de un anumit tip sunt amestecate cu variabile de alt tip, au loc
conversii de tip. ntr-o instruciune de atribuire, regula de conversie este simpl:
valoarea din membrul drept (al expresiei) al instruciunii de atribuire este
convertit la tipul din membrul stng. Pentru o mai bun nelegere a
fenomenului, fie exemplul de mai jos.

int nri;
char car;
float nrr;

void functie(void)
{
car=nri; /* Linia 1 */
nri=nrr; /* Linia 2 */
nrr=car; /* Linia 3 */
nrr=nri; /* Linia 4 */
}

n Linia 1, n variabila car ajung primii 8 bii cei mai puin semnificativi ai
variabilei nri. Dac nri este cuprins ntre 0 i 255, car i nri vor avea valori
identice .a.m.d.. Presupunnd c sistemul de calcul are cuvntul de 16 bii,
Tabelul 5 prezint posibilele pierderi de informaie care pot s apar la
conversia de tip n atribuiri.

Tipul destinaiei Tipul expresiei Posibile pierderi de informaie


signed char char Dac valoarea este > 127, destinaia
este negativ.
char short int Cei mai semnificativi opt bii
char int Cei mai semnificativi opt bii
char long int Cei mai semnificativi 24 bii
int long int Cei mai semnificativi 16 bii
int float Partea zecimal i, posibil, mai mult
float double Precizie, rezultat, rotunjit
double long double Precizie, rezultat, rotunjit
Tabelul 5 Tipuri de conversie frecvent utilizate

Atribuiri multiple
C permite atribuirea aceleeai valori mai multor variabile prin utilizarea atribuirii
multiple ntr-o singur instruciune de atribuire. De exemplu instruciunea:

x = y = z = 0;

20
permite setarea la 0 a variabilelor x,y,z. Programatorii profesioniti folosesc
masiv atribuirea multipl pentru a obine cod performant.
S mai adugm o observaie interesant pentru un programator profesionist. O
atribuire de tipul:
<Variabil>=<Variabil>+<Expresie> (1)
este echivalent semantic cu sintaxa:
<Variabil>+=<Expresie> (2)
Dei s-ar putea s vin peste mn unor programatori, acetia trebuie s tie
c pentru compilator sintaxa (2) este de preferat sintaxei (1) din punct de vedere
al calitii codului generat.
Aadar,
x=x+1
este totuna cu:
x+=1.

Operatori aritmetici
Tabelul 6 prezint operatorii aritmetici din C.

Operator Aciune
- Scdere, de asemenea i minus unar
+ Adunare
* nmulire
/ mprire
% Modul
-- Decrementare
++ Incrementare
Tabelul 6 Operatori aritmetici n C

Dintre operatorii prezentai n Tabelul 6, operatorii ++ i -- sunt specifici limbajului


C. Operatorul ++ adun 1 la variabila asociat. Operatorul -- scade 1 din
variabila asociat. Astfel c:
x=x+1;
este sinonim cu:
++x;
iar
x=x-1;
este sinonim cu:
x--;
Ambii operatori pot s fie plasai att nainte ct i dup variabila operat. Prin
urmare:
x=x+1;
poate fi scris:
++x ;
sau
x++;

21
Exist, totui, o diferen ntre forma cu prefix i forma cu sufix, dac operatorii
sunt utilizai ntr-o expresie. Atunci cnd operatorii preced variabila, C
efectueaz operaiile corespunztoare lor, nainte de a evalua expresia.
Atunci cnd operatorii succed variabila, C efectuiaz operaiile corespunztoare
lor, dup evaluarea expresiei. Majoritatea compilatoarelor C/C++ produc rapid
un cod obiect eficient pentru operaiile de incrementare i decrementare (cod
mai bun dect cel obinut prin utilizarea atribuirii clasice echivalente). Pe acest
considerent, recomandarea de a utiliza aceti operatori de cte ori este posibil
este fireasc. n sfrit, ordinea de preceden a operatorilor aritmetici este:

De ordinul cel mai nalt ++, --


- (minus unar)
*, /, %
De ordinul cel mai cobort +, -

Operatori relaionali i logici


Deoarece operatorii relaionali i logici lucreaz de multe ori mpreun, i
prezentm mpreun. Semnificaia celor dou tipuri de operatori este cunoscut
de la alte limbaje. Operatorii relaionali permit compararea (=punerea n relaie)
a operanzilor. Rezultatele comparrii pot fi combinate dup rigorile algebrei
Boole cu ajutorul operatorilor logici.
Att operatorii relaionali ct i cei logici au o preceden mai sczut dect
operatorii aritmetici. Deci, o expresie precum 8 > 1+5 este evaluat ca i cum ar
fi fost scris 8 > (1+5). n Tabelul 7 prezentm opertorii relationali i logici folosii
n C/C++.

Operatori relaionali
Operator Aciune
> Mai mare dect
>= Mai mare sau egal
< Mai mic dect
<= Mai mic sau egal
== Egal
!= Diferit
Operatori logici
Operator Aciune
&& AND (I)
|| OR (SAU)
! NOT (NEGAT)
Tabelul 7 Operatorii relaionali i logici n C.

Tabelul 8 prezint prioritile n relaia dintre operatorii relaionali i logici.

22
De ordinul cel mai nalt !
>, >=, <, <=
==, !=
&&
De ordinul cel mai cobort ||
Tabelul 8 Relaia de preceden ntre operatorii relaionali i logici
Evident, parantezele pot fi utilizate pentru a modifica ordinea fireasc de
evaluare a unei expresii relaionale i/sau logice.

Operatori de aciune pe bii


Spre deosebire de multe alte limbaje, C admite un complement deplin cu
operatorii de aciune pe bii. Deoarece C a fost proiectat s ia locul limbajului de
asamblare pentru majoritatea sarcinilor, el trebuie s fie capabil s asigure multe
operaii care pot fi executate n asamblor, inclusiv asupra biilor. Operaiile
asupra biilor se refer la testare, iniializare sau deplasare a biilor existeni ntr-
un octet sau ntr-un cuvnt care corespund tipurilor de date char i int i
variantelor acestora din standardul C. Operatorii de aciune asupra biilor nu pot
fi utilizai asupra tipurilor float, double, long double,void. n Tabelul 9
prezentm operatorii C pentru bii.

Operator Aciune
& AND
| OR
^ OR exclusiv (XOR)
~ Complement fa de 1 (NOT)
>> Deplasare la dreapta
<< Deplasare la stnga
Tabelul 9 Operatorii de aciune pentru bii

nelegerea transformrilor efective care au loc la utilizarea operatorilor AND, OR


i XOR este legat de analiza n spiritul legilor logicii Boole a unei expresii de
tipul:

<Operand_1> <Operator><Operand_2>

Aciunea operatorului este aplicat bit cu bit operanzilor, rezultnd o configuraie


de bii asupra crora se pot continua alte prelucrri.

Operatorii de deplasare a biilor >> i << deplaseaz toi biii dintr-o variabil la
dreapta sau la stnga. Sintaxa asociat este:

<Variabil> >> <Numr_de_poziii_de_shiftat>


sau
<Variabil> << <Numr_de_poziii_de_shiftat>

23
Sensul operaiei de shiftare este cel precizat la un curs de Bazele logice ale
sistemelor de calcul.

Precizri referitoare la operatorii suplimentari pot fi gsite n [1].

Operatorul ?
C propune un operator unar foarte puternic i util care poate nlocui anumite
instruciuni de forma dac atunci altfel.

Operatorul ? apare n expresii avnd forma general:

<Expresie_1> ? <Expreasie_2> : < Expresie_3>


unde:
-<Expresie_1>, <Expresie_2>, <Expresie_3> sunt expresii, cu precizarea
c <Expresie_1> este o expresie condiional;
-semantica construciei sintactice de mai sus este urmtoarea:

z Se evaluiaz <Expresie_1>;
z Dac <Expresie_1> este adevrat se evaluiaz <Expresie_2> i
rezultatul evalurii ei i se atribuie expresiei globale;
z Dac <Expresie_1> este fals. atunci se evaluiaz <Expresie_3> i
rezultatul evaluirii acesteia este atribuit expresiei globale.
Aceast semantic este evideniat i de exemplul de mai jos de utilizare
a operatorului ?.

X=24;
X=X<24 ? 1:X+1;

Acest cod este echivalent cu codul:

X=24;
if (X<24) X=1
else X=X+1;

Operatorii & i *
Un pointer este adresa din memorie a unei variabile. O variabil de tip pointer
este declarat explicit pentru a reine un pointer ctre un obiect de un tip
specificat. Cunoaterea adresei unei variabile poate fi de mare utilitate n
anumite situaii. n C pointerii au trei funcii principale.

z asigur o cale rapid de acces la elementele unei matrici;


z permit funciilor C s modifice parametrii de apelare;
z permit realizarea structurilor dinamice de date.
Pentru simplificarea lucrului cu pointeri au fost introdui operatorii & i *.
Operatorul & este un operator unar care permite recuperarea adresei din
memorie a unui element C precum i declararea de variabile sinonime.

24
O atribuire de tipul :

adr=&Numar_Elemente;

este util pentru a obine n variabila adr adresa din memorie a variabilei
Numar_Elemente. Aceast adres este adresa locaiei din memorie ncepnd de
la care se pstreaz coninutul variabilei Numar_Elemente.
Al doilea operator pentru pointeri este * , oarecum complementar operatorului
&. i operatorul * este unar, returnnd valoarea din variabila localizat la
adresa specificat. Astfel , dup execuia secvenei:

adr=&Numar_Elemente;
nr=*adr ;

variabila nr va conine aceeai valoare cu variabila Numar_Elemente,


presupunnd c cele dou variabile sunt compatibile ca tip.
Evident, exist, din punct de vedere al utilizatorului, primejdia de a utiliza confuz
aceti doi operatori, din moment ce * mai nseamn i nmulire iar & mai
nseamn i i logic la nivel de bii.
Variabilele care pstreaz pointeri trebuie declarate ca atare. Sintaxa de
declarare a unei variabile pointer este:

<Tip de baz> * <Nume_Variabila>;

Exemplu

#include <stdio.h>
void main(void)
{
int destinatar,sursa;
int *m;
sursa=10;
m=&sursa;
destinatar=*m;
printf (%d, destinatar);
}

Operatorii & i * sunt utilizai pentru a introduce valoarea 10 n variabila


destinatar .

Operatorul sizeof (cu aciune n timpul compilrii)

25
sizeof este un operator unar utilizat n timpul compilrii care returneaz lungimea
n octei a variabilei sau a specificatorului de tip dintre parantezele asociate de
sintax operatorului. Sintaxa de utilizare a operatorului:

sizeof ( <Nume_Variabila>)

sau

sizeof (<Specificator_ de_ tip>)

De remarcat faptul c n cazul unei variabile este permis i sintaxa:

sizeof <Nume_Variabila>

Acest operator este util n procesul de realizare a aplicaiilor portabile.

Operatorii . (punct) i -> (sgeat)


Sunt utilizai pentru a realiza referirea la elementele individuale ale structurilor i
uniunilor din C. Aa cum se va vedea, structurile i uniunile sunt tipuri de date
agregate la care se poate avea acces sub un singur nume.
Operatorul punct este utilizat atunci cnd se lucreaz cu structuri sau uniuni
efective. Operatorul sgeat este folosit mpreun cu un pointer la o structur
sau la o uniune. Astfel, anticipnd puin, dac avem codul:

struct tangajat
{
char nume[80];
int varsta;
float salariu;
} angajat;
struct tangajat *pangajat=&angajat;

are sens urmtorul cod:

angajat . salariu:=1100000;

Aceast atribuire este echivalent cu atribuirea:

pangajat->salariu=1100000;

De remarcat faptul c n C exist multe alte faciliti puse la dispoziia


programatorilor, precum: conversia automat n expresii, forarea tipurilor
expresiilor utiliznd modelatorii, utilizarea expresiilor prescurtate.
2.11 Comentarea programelor C/C++

26
Un comentariu este o not explicativ pentru programatori, ignorat complet de
compilator n C comentariile sunt delimitate de perechile de caractere /* */.
Compilatorul C ignor orice text aflat ntre aceti delimitatori.

Exemple de comentarii:

/* Un comentariu se poate ntinde pe mai multe linii


dac aceasta este dorina programatorului*/

sau

clrscr() /* Stergere ecran n mod text */


Acest tip de comentariu nu poate fi imbricat.

Compilatoarele C++ accept i comentarii care ncep cu secvena //, dar se pot
ntinde pe o singur linie, astfel:

clrscr() // Stergere ecran n mod text.

27
3 Reprezentarea structurilor de prelucrare n C/C++
Limbajul C nu propune o revoluie de fond n ceea ce privete problema
reprezentrii structurilor de prelucrare. Vine, ns, cu o serie de inovaii
interesante, n ceea ce privete flexibilitatea i varietatea propunerilor de
reprezentare. Nu spunem nici o noutate amintind c reprezentarea structurilor
de prelucrare se bazeaz pe combinarea, dac se poate, profesional, a
instruciunilor executabile ale limbajului. Potrivit standardelor ANSI C i ANSI
C++ instruciunile sunt mprite n urmtoarele grupe:
Instruciuni de selecie
Instruciuni iterative
Instruciuni de salt
Instruciuni de etichetare
Instruciuni bloc
Instruciunile de selecie cuprind enunurile if i switch.
n categoria instruciunilor iterative intr enunurile while, for i do-while.
Instruciunile de salt desemneaz n C instruciunile break, continue, goto i
return.
Instruciunile de etichetare includ enunurile case i default (implicate, esenial,
n sintaxa i semantica instruciunii switch i etichetele (discutate relativ la
instruciunea goto. Problematica instruciunilor expresie am discutat-o, pe larg,
n seciunea precedent. De asemenea, blocul de cod este, deja, o noiune cu
care ne-am familiarizat. De altfel, aa cum n Pascal, secvena de cod cuprins
ntre begin i end era numit i instruciune compus, standardul ANSI C++
propune, aceeai denumire, ca denumire alternativ pentru blocul de cod.

S atragem atenia asupra faptului c C++ adaug elemente sintactice


specifice pentru tratarea excepiilor de ctre programator. Nu toate
compilatoarele implementeaz, ns, acest suport important pentru a realiza
aplicaii robuste i fiabile n C++.

3.1 Ce se nelege prin adevrat i fals n C?


Mai multe instruciuni din C se bazeaz pe expresii condiionale pentru a
reprezenta un anumit tip de prelucrare. La fel ca n Pascal, sintaxa acestor
instruciuni C face supoziia c alegerea unei traiectorii de prelucrare depinde de
rezultatul evalurii acestor expresii condiionale. Teoretic, valorile admisibile
pentru o expresie condiional sunt adevrat i fals. Punctul de vedere al
limbajului C cu privire la adevr i fals este urmtorul:
Un rezultat al evalurii egal cu zero este interpretat ca fals.
Un rezultat nenul al evalurii este interpretat ca adevrat.
Aceast schimbare de optic n ceea ce privete adevrul i falsul este de bun
augur pentru scrierea de cod flexibil i eficient.

 Propunerea de standard ANSI C++ definete un tip de dat boolean numit


bool (care poate s aib doar valorile adevrat i fals. Ceea ce nu nseamn,
ns, c nu se pstreaz punctul de vedere al limbajui C relativ la adevr i fals.

28
3.2 Instruciuni de selecie n C
C admite dou tipuri de instruciuni de selecie: if i switch.

if
Sintaxa general a instruciunii if este urmtoarea:

if (<Expresie>) <Instruciune 1>;


else <Instruciune 2>;

<Instruciune 1> i <Instruciune 2> desemneaz o singur instruciune, un bloc


de instruciuni sau nici o instruciune. Clauza else este opional.
Dac <Expresie> este evaluat ca adevrat (adic rezultatul evalurii este orice
valoare diferit de zero), atunci este executat <Instruciune 1>; altfel, se
execut <Instruciune 2>. Evident, nu este obligatoriu s fie prezent clauza
else.
<Expresie> trebuie s returneze o valoare scalar (un ntreg, un caracter, un
pointer sau un numr real n virgul mobil). Un numr real n virgul mobil se
utilizeaz cu reinere pentru a controla o instruciune de selecie deoarece
ncetinete semnificativ execuia programului. Aceasta deoarece sunt necesare
mai multe instruciuni pentru a efectua o operaie n virgul mobil dect pentru a
executa operaii la nivel de caracter sau cu ntregi.
De semnalat faptul c, n situaia n care una din instruciunile asociate condiiilor
true sau false ale unui if este bloc de instruciuni atunci sintaxa corect este:

if (<Expresie>) {}
else {};

Modul de utilizare a instruciunii if poate fi urmrit i n exemplul de mai jos.


#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
void main()
{
int magic; /* Numar generat aleator */
int ghicit; /* Numar banuit */
magic=rand();
clrscr();
printf("Ghiceste numarul generat aleator:\n");
printf("Numarul generat aleator este cuprins intre 0 si %d",RAND_MAX);
scanf("%d",&ghicit);
if (ghicit==magic)
printf("Ati nimerit numarul generat!!!");
else
printf("Nu ati nimerit numarul generat!!!");
}

29
Instruciunea if poate fi imbricat. n caz de imbricare, clauza else se refer
ntotdeauna la cea mai apropiat instruciune if situat n amonte, n acelai bloc
cu else i neasociat nc cu un else, ca n exemplul:

#include <stdio.h>
#include <conio.h>
#include <string.h>;
void main()
{
float A,B,X;
clrscr();
gotoxy(20,12);
printf("____________________________________");
gotoxy(20,13);
printf(" Rezolvarea unei ecuatii de gradul I");
gotoxy(20,14);
printf(" A=");
gotoxy(20,15);
printf(" B=");
gotoxy(20,17);
printf("____________________________________");
gotoxy(20+strlen(" A="),14);
scanf("%f",&A);
gotoxy(20+strlen(" B="),15);
scanf("%f",&B);
gotoxy(20,17);
printf("_____________________________________");
if (A==0)
if (B==0)
{
gotoxy(20,16);
printf("Ecuatie nedetrminata!!!");
getch();
}
else
{
gotoxy(20,16);
printf("Ecuatie imposibila!!!"); getch();
}
else
{
X=B/A;
gotoxy(20,16);
printf("Solutia ecuatiei este:%f",X); getch();
}
}

30
Destul de frecvent instruciunea if este utilizat i n construcia numit
scara if-else-if avnd sintaxa general:

if (<Expresie_1>)
<Instruciune_1>;
else if (<Expresie_2>)
<Instruciune_2>;
else if (<Expresie_3>)
<Instruciune_3>;
:
:
else if (<Expresie_k>)
<Instruciune_k>;
:
Reamintim c, n anumite situaii, putem utiliza operatorul ? pentru a nlocui
instruciunea if-else de forma:

if (<Expresie>)
<Expresie_1>;
else
<Expresie_2>;

cu o construcie de forma:

<Expresie>?<Expresi_1>:<Expresie_2>;

switch
C permite reprezentarea structurilor alternative cu mai multe ramuri utiliznd n
acest scop instruciune switch avnd sintaxa:

switch (<Expresie>) {
case <Constanta_1>:
<Secvena_de_instruciuni_1>
break;
case <Constanta_2>:
<Secvena_de_instruciuni_2>
break;
:
case <Constanta_k>:
<Secvena_de_instruciuni_k>
break;
default
<secvena_de_instruciuni>
}

31
Semantica instruciunii este urmtoarea: se compar valoarea expresiei
<Expresie> cu valorile constantelor specificate n instruciunile case. Cnd se
ntlnete o coinciden, se execut secvena de instruciuni asociat acelui
case pn la instruciunea break sau pn cnd se ajunge la finalul instruciunii
switch. Instruciunea default se execut dac nu este ntlnit nici o
coinciden. Clauza default este opional i dac nu este prezent, atunci cnd
nu avem nici o coinciden nu se execut nici o aciune.
Standardul ANSI C stipuleaz c switch poate s aib cel mult 257 de clauze
case. Standardul propus de ANSI C++ recomand s se poat introduce cel mult
16.384 clauze case. n practic, din motive de eficien, se urmrete limitarea
numrului de clauze case ntr-o instruciune switch.
Instruciunea case nu poate fi utilizat dect n contextul instruciunii switch.
Instruciunea break este o instruciune de salt n C, fiind utilizat pentru a
determina ieirea forat din anumite tipuri de structuri (switch, for, do-while).
Ilustrm modul de utilizare a instruciunii switch prin exemplul de mai jos.

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
void main()
{
int x;
char Ras;
clrscr();
x=random(2);
switch(x+2){
case 3:
{
gotoxy(20,10);
printf("Switch atins...");
break;
}
default:
{
gotoxy(20,10);
printf("Switch ocolit...");
}
}
Ras=getch();
}

Evident i instruciunea switch poate fi imbricat.


De asemenea, facem urmtoarele precizri relativ la instruciunea switch:
-n acelai switch nu pot exista dou constante case cu valori identice.
Dou instruciuni switch, imbricate, pot s aib aceeai constant case.

32
-Dac n instruciunea switch sunt utilizate constante de tip caracter, ele
sunt automat convertite n ntregi.

3.3 Instruciuni iterative


n C, ca i n alte limbaje de programare evoluate, exist enunuri de limbaj
pentru a reprezenta:
structuri repetitive cu numr cunoscut de pai (for);
structuri repetitive cu numr necunoscut de pai, anterior condiionate
(while);
structuri repetitive cu numr necunoscut de pai, posterior condiionate
(do-while);
Structurile repetitive se mai numesc i bucle.

Bucla for (pentru structuri repetitive cu numr cunoscut de pai)


Conceptul general de <bucl for> se reflect ntr-o form sau alta n orice limbaj
de programare de nivel nalt. n C, acest concept are o implementare de o
flexibilitate i o putere neateptate. Sintaxa general a instruciunii for este:

for (<Iniializare>;<Condiie>;<Increment>) <Instruciune>;

O astfel de sintax permite multe variante constructive ale buclei for. n general
vorbind, ns:
-<Iniializare> este o instruciune de atribuire utilizat pentru a iniializa
variabila de control a buclei;
-<Condiie> este o expresie relaional care determin condiia de ieire
din bucl;
-<Increment> definete modul n care se modific variabila de control a
buclei de fiecare dat cnd aceasta se repet.
De remarcat faptul c cele trei seciuni trebuie separate prin punct i virgul.
Aadar, bucla for se execut ct timp <Condiie> este adevrat. Dac
<Condiie> devine fals, atunci execuia programului continu cu instruciunea
care urmeaz construciei for, dac aceasta exist.
Maniera clasic de utilizare a buclei for n C, o prezentm n exemplul de mai
jos.

#include <stdio.h>
#include <iostream.h>
#include <conio.h>
long int fact( int n);
void main()
{
clrscr();
gotoxy(20,12);
int nr;
cout<<"Introduceti numarul:";
cin>>nr;

33
gotoxy(20,14);
cout<<"Factorial("<<nr<<")="<<fact(nr);
getch();
}
long int fact(int n)
{
long int f;
int i;
f=1;
/*-------------------------------------------------------------------
/* Bucla for clasic cu o singur variabil de control
/*-------------------------------------------------------------------
for (i=2;i<=n;i++)
f=f*i;
return f;
}
Exemplul de cod C prezentat mai sus permite calculul factorialului pentru un
numr natural dat. Exemplul arat, anticipnd, modul de utilizare a conceptului
de funcie n C++.

Cteva variaiuni pe tema buclei for


Sintaxa C permite variante dintre cele mai neatepate de definire a unor bucle
for. Rigiditatea buclei for din Pascal este nlocuit n C cu o sintax care eman
mai mult putere, flexibilitate i aplicabilitate n situaii specifice de programare.
Una dintre cele mai folosite variaiuni folosete operatorul virgul, pentru a
permite ca bucla s fie controlat de dou sau mai multe variabile. De exemplu,
variabilele x i y controleaz urmtoarea bucl i amndou sunt iniializate n
interiorul instruciunii for.
:
for (x=0,y=0;x+y<10;++x)
{
y+=1; //Aceast scriere reste echivalent cu y=y+1;
printf(Y= %d,y);
}
:
Prezentm, mai jos, un exemplu practic de utilizare a unei bucle for controlat de
dou variabile: afiarea unui ir de caractere ncepnd de la ambele capete,
mergnd ctre mijlocul irului. Se observ prezena fiierului header <dos.h> n
care se afl prototipul funciei delay().

#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <dos.h>;

//Semnatura functie converg

34
void converg(int linie, char *mesaj);

//Functia principala
void main()
{
clrscr();
gotoxy(20,12);
converg(12,"Acesta este un test pentru functia converg().");
}

//Implementare functie converg


void converg(int linie, char *mesaj)
{
int i,j,ls,cs;
ls=(80-strlen(mesaj))/2;
cs=ls+strlen(mesaj)-1;

for (i=ls,j=cs;i<=j;i++,j--)
{
gotoxy(i,linie);printf("%c",mesaj[i-ls]);
delay(50); //prototipul in fisierul antet <dos.h>
gotoxy(j,linie);printf("%c",mesaj[strlen(mesaj)-1-cs+j]);
}
getch();
}

Ca un caz particular prezentm i sintaxa pentru o bucl infinit cu for

for ( ; ; )

Bucla while (pentru structuri repetitive cu numr necunoscut de pai


condiionate anterior)
A doua bucl disponibil n C este bucla while. Forma sa general este:

while (<Condiie>) <Instruciune>;

unde <Instruciune> este o instruciune vid, o instruciune sau un bloc de


instruciuni.. Condiia poate s fie orice expresie, fiind adevrat pentru orice
valoare nenul. Bucla se reia ct timp condiia este adevrat. Cnd condiia
devine fals, controlul programului trece la linia de cod urmtoare buclei, dac
aceasta exist.
Prezentm un exemplu de cod n care bucla while este utilizat pentru a simula,
eventual, execuia unei secvene de instruciuni pn cnd dorete liberul arbitru
al utilizatorului programului.

35
#include <stdio.h>
#include <conio.h>
#include <ctype.h> //Contine prototipul functiei toupper
void main()
{
int sw;
char ras;
sw=1;
/* Bucla while n aciune
while(sw)
{
gotoxy(20,12);
printf("Continuam(D,N):");
ras=getch();
if (toupper(ras)=='N')
sw=0;
}
}

Bucla do-while (repetitive cu numr necunoscut de pai condiionate


posterior)
Spre deosebire de buclele for i while, care testeaz condiia din bucl la
nceputul execuiei lor, bucla do-while o verific la sfrit. Aceasta nseamn c
bucla do-while se execut cel puin odat. Forma sa general este:

do {
<Instruciune>;
} while <Condiie>;

Bucla do-while se repet pn cnd <Condiie> devine fals. Dm, mai jos, un
exemplu practic de utilizare a buclei do-while (afiarea/ selectarea opiunilor unui
program C).
:
char prelopt()
{
int c;
clrscr();
gotoxy(20,9);
printf( "Optiunile programului...");
gotoxy(20,11);
printf("1-Preluare elemente vector");
gotoxy(20,12);
printf("2-Determinare suma");
gotoxy(20,13);
printf("3-Terminare program");

36
gotoxy(20,15);
printf("Optiunea Dvs.:");
/* Utilizare bucl do-while
do
c=getch();
while ((c!='1')&&(c!='2')&&(c!='3'));
return c;
};
:
Alte instruciuni C
Aa cum rezult i din exemplele prezentate, n C mai sunt intens folosite
urmtoarele instruciuni: return, exit, break , continue i goto.

Instruciunea return este utilizat pentru ntoarcerea dintr-o funcie. Este


considerat ca instruciune de salt deoarece determin execuia programului s
revin la prima instruciune dup funcia apelat n care apare return. Forma
general a instruciunii return este:

return [<Expresie>]

Aceast sintax arat c dac <Expresie> este prezent atunci rezultatul


evalurii expresiei este valoarea returnat de funcie. O funcie void nu trebuie
s returneze nimic, deci return poate s apar fr <Expresie>. ntr-o funcie
return poate s apar de cte ori este necesar. n C++ o funcie care nu este
void trebuie s returneze o valoare.

Funcia exit()

Este utilizat pentru ieirea imediat dintr-un program, returnnd, eventual un


cod de retur. Sintaxa de apel este:

exit (<Cod_de_retur>);

<Cod de retur> poate fi interpretat de procesul care a apelat programul, de


regul, sistemul de operare. Exit acioneaz ca un break generalizat.

Instruciunea break

Are dou utilizri. Poate fi folosit, dup cum am vzut deja pentru a ncheia un
case dintr-o instruciune switch, sau pentru a determina ncheierea imediat a
unei bucle.

Instruciunea continue
Foreaz trecerea la urmtoarea iteraie a unei bucle, determinnd ignorarea
restului codului iteraiei n care se afl.
Nu facem meniuni speciale referitor la instruciunea goto.

37
38
4 Operaii I/O relativ la perifericele standard
Ne propunem n acest modul s prezentm funciile C care fac parte din
sistemul I/O referitor la efectuarea operaiilor de introducere a datelor de la
tastatur i afiare a acestora pe ecranul monitorului.

4.1 Operaii la nivel de caracter


Cele mai simple funcii C pentru lucrul la nivel de caracter relativ la perifericele
standard au urmtoarele prototipuri:

int getch (void); { Fiierul antet depozitar :conio.h}


int getche (void); { Fiierul antet depozitar :conio.h}
int putchar (int car); {Fiierul antet depozitar :stdio.h}

Funcia getch() este utilizat pentru a citi un caracter de la tastatur fr ecou pe


ecranul monitorului , analog mecanismului readkey din Pascal.

Funcia getche() este utilizat pentru a citi un caracter de la tastatur cu ecou pe


ecranul monitorului.

Funcia putchar() se folosete pentru a scrie un caracter pe ecranul monitorului


n poziia curent a cursorului.

Dup cum sugereaz prototipul, getch() returneaz un ntreg. Totui, funcia


poate returna aceast valoare unei variabile de tip caracter deoarece caracterul
este coninut n octetul de ordin inferior.
Aceeai observaie este valabil i pentru funcia getche().
Dei din alt punct de vedere, i funcia putchar() poate fi apelat cu argument de
tip caracter deoarece ieirea pe ecran se refer, oricum, doar la octetul de ordin
inferior.
n cazul apariiei unei erori, putchar() returneaz EOF. Funcia macro EOF, este
definit n stdio.h i, n general este egal cu 1. Exemplul pe care l prezentm
permite citirea de caractere de la tastatur i, dac sunt litere mici, convertirea
lor la litere mari. Citirea se termin n momentul n care se tasteaz caracterul
ESC al crui cod backslash este \033.

#include <stdio.h>
#include <conio.h>
#include <ctype.h>
void main()
{
char car;
do
{
car=getche();
car=toupper(car);
putchar(car);

39
}
while (car!='\033');
}

Prototipul funciei toupper() se afl (aa cum am mai spus-o) n fiierul antet
ctype.h. Se observ c citirea se face cu ecou pe ecranul monitorului. Este cazul
s spunem c programatorul n C/C++ are de fcut o serie de descoperiri
folositoare n ceea ce privete oferta numeroaselor fiiere antet livrate odat cu
compilatorul. Prezentarea tuturor acestor funcii, fie i numai prina antet, nu este
de loc o treab uoar, din punct de vedere al volumului. De aceea. n acest
suport de curs adresm cititorului invitaia de a descoperi, cu ajutorul help-ului on
line i a unor cri care nu fac economie de spaiu, potenialul structurat n
fiierele antet.

4.2 Operaii la nivel de ir de caractere


Pentru operaii la nivel de ir de caractere C pune la dispoziie funciile avnd
urmtoarele prototipuri:

char *gets(char *sir);


int puts(const char *sir);

Funcia gets() citete un ir de caractere de la tastatur i l plaseaz la adresa


indicat de argumentul su.
Funcia puts() scrie pe ecran argumentul su, urmat de o linie nou.
Prototipurile acestor dou funcii se gsesc n stdio.h.
Exemplul care urmeaz arat modul de utilizare al funciilor gets() i puts() cnd
argumentul lui gets() este o variabil obinuit.

#include <stdio.h>
#include <conio.h>
void main()
{
char s[30];
clrscr();
gotoxy(20,10);
printf("Introduceti un sir de caractere:");
gets(s);
gotoxy(20,11);
printf("Sirul introdus :");
puts(s);
getch();
clrscr();
}

n exemplul de mai jos se arat modul de utilizare al funciilor gets() i puts()


cnd argumentul lui gets() este o variabil pointer la un ir de caractere.

40
#include <stdio.h>
#include <conio.h>
void main()
{
char s;
char *p;
clrscr();
gotoxy(20,10);
p=&s
printf("Introduceti un sir de caractere:");
gets(p);
gotoxy(20,11);
printf("Sirul introdus :");
puts(p);
getch();
clrscr();
}

Operaii I/O cu iruri de caractere se pot efectua i cu funciile scanf() i printf(),


mult mai versatile dect gets() i puts() , dup cum vom vedea n continuare.

4.3 Funcii I/O relativ la consol formatate


Funciile printf() i scanf() efectueaz operaii I/O formatate, adic pot scrie i,
respectiv, citi date n diverse formate specificate de programator. Funcia printf()
afieaz date formatate la consol. Funcia scanf(), complementul funciei
printf() citete date formatate de la tastatur. Ambele funcii pot lucra cu toate
tipurile de date existente n C. Prototipurile celor dou funcii sunt:

int scanf( const char *format [, address, ...]); {Fiierul antet gazd :stdio.h}
int printf(const char *format [, argument, ..]); {Fiierul antet gazd :stdio.h}

printf()
Returneaz, cu destinaia ecran, numrul de caractere scrise sau, dac apare o
eroare, o valoare negativ. Parametrul format se compune din dou tipuri de
simboluri. Primul tip l formeaz caracterele care vor fi afiate pe ecran. Al doilea
tip se refer la specificatorii de format cu ajutorul crora se stabilete modul n
care sunt afiate argumentele care urmeaz. Un specificator de format ncepe cu
un semn % i este urmat de un cod de format. Trebuie s existe acelai numr
de argumente ca i acela al specificatorilor de format i, totodat, specificatorii
de format i argumentele se asociaz n ordinea de la stnga la dreapta.

41
Codurile de format disponibile pentru printf() sunt:

Cod Format
%c Caracter
%d Numere ntregi n baza 10, cu semn
%I Numere ntregi n baza 10, cu semn
%e Notaie tiinific (cu litera e)
%E Notaie tiinific (cu litera E)
%f Numr zecimal n virgul mobil
%g Folosete %e sau %f , anume, care din ele este mai mic
%G Folosete %E sau %f , anume, care din ele este mai mic
%o Numr n octal, fr semn
%s ir de caractere
%u Numere ntregi zecimale fr semn
%x Numere hexazecimale fr semn (cu litere mici)
%X Numere hexazecimale, fr semn, cu litere mari
%p Afieaz un pointer
%n Argumentul asociat este un pointer de tip ntreg n care a fost
plasat numrul de caractere scrise pn atunci.
%% Afieaz un semn %

Pentru a nelege modul deosebit n care acioneaz codul %n urmrii exemplul


de mai jos.

#include <stdio.h>
#include <conio.h>
void main()
{
int numara;
printf("Acesta%n este un test...\n",&numara);
printf("%d",numara);
getch();
}

De remarcat faptul c specificatorii de format accept modelatori de format care


modific uor semnificia lor. De exemplu, se poate specifica un minim de
caractere permise la afiare, numrul de cifre zecimale i alinierea la stnga.
Modelatorul de format se afl ntre semnul % i codul pentru format. Codul de
mai jos poate forma o idee asupra utilitii modelatorilor de format.

#include <stdio.h>
#include <conio.h>
void main()
{
int numara;

42
clrscr();
printf("Acesta%n este un test...\n",&numara);
printf("Aliniere la dreapta.......\n");
printf("%10d\n",numara);
printf("Aliniere la stanga .......\n");
printf("%-d\n",numara);
printf("Completare cu zerouri.....\n");
printf("%010d\n",numara);
getch();
}

scanf()
Este o rutin de uz general pentru intrri de la consol. Ea poate s citeasc
toate tipurile de date ncorporate i s fac automat conversia numerelor n
format intern corect. Se aseamn mult cu complementara ei printf(). Ca funcie,
scanf() returneaz numrul de elemente crora li s-a atribuit cu succes o
valoare. Dac apare o eroare scanf() returneaz EOF. Argumentul format
determin modul n care vor fi citite valorile n variabilele din lista de argumente.
Codurile de format disponibile pentru scanf() sunt prezentate n tabelul de mai
jos.

Cod Format
%c Citete un singur caracter
%d Citete un numr ntreg n baza 10
%I Citete un numr ntreg n baza 10
%e Citete un numr n virgul mobil
%E Citete un numr n virgul mobil
%f Citete un numr n virgul mobil
%g Citete un numr n virgul mobil
%o Citete un numr n octal
%s Citete un ir de caractere
%u Numere ntregi zecimale fr semn
%x Citete un numr n hexazecimal
%p Citete un pointer
%n Argumentul asociat este un pointer de tip ntreg n care a fost
plasat numrul de caractere citite pn atunci.
%u Citete un ntreg fr semn
%[] Caut un set de caractere
Tabelul 10. O parte din codurile pentru formatarea operaiilor I/I relativ la
periferice standard

Primul exemplu de cod prezentat mai jos ilustreaz ideea de scanset posibil la
utilizarea funciei scanf(). Definirea unui scanset nseamn, de fapt c citirea
corespunztoare unei variabile este validat ct timp caracterele citite se
potrivesc celor definite n scanset.

43
Al doilea exemplu este conceput n ideea c valoarea variabilei n2 va fi citit
numai dup introducerea de la tastatur a dou caractere virgul. Acest
mecanism permite, printre altele, definirea ca separator la introducerea datelor a
altui caracter dect <CR>.

#include <stdio.h>
#include <conio.h>
void main()
{
char sir[3];
clrscr();

scanf("%[TOC]",&sir); //Citire cu scanset


printf("\n%s",sir);
getch();
}

#include <stdio.h>
#include <conio.h>
void main()
{
int n1,n2;
clrscr();
scanf("%d,,%d",&n1,&n2);
printf("%d\n",n1);
printf("%d\n",n2);
getch();
}

Atenie la necesitatea ca variabila n care se citete s fie un pointer!

Alte faciliti pentru lucrul cu consola


n categoria alte faciliti pentru lucrul cu consola includem, cu prioritate,
funciile clrscr(), clreol(), gotoxy(col,lin) ale cror valori de ntrebuinare sunt
identice celor din Borland Pascal. Chiar i sintaxa funciei gotoxy(col,lin) este
concordant n ceea ce privete ordinea parametrilor dup care se face
poziionarea cursorului.
Aadar:

clrscr() se utilizeaz pentru teregerea ferestrei text curente; fereastra


text curent implicit depinde de modul text n care se lucreaz. Caracteristicile
modurilor text recunoscute de C sunt prezentate n tabelul de mai jos.

44
Constanta Valoare Mod Text Caracterisrici
LASTMODE -1 Precedentul mod text
BW40 0 Black and white 40 coloane
C40 1 Color 40 coloane
BW80 2 Black and white 80 coloane
C80 3 Color 80 coloane
MONO 7 Monochrome 80 coloane
C4350 64 EGA and VGA 50 linii
Tabelul 11. Moduri video text standard

Aceste moduri text pot fi selectate cu ajutorul funciei textmode(), al crei antet
se afl tot n conio.h i face parte tot din arsenalul C de lucru cu ecranul n mod
text. Tot n mod text, putem controla culorile textului i ale fondului (background-
ul). Sintaxa funciilor cu care realizm controlul culorilor este:

textcolor(<Culoare>);
textbackground(<Culoare>);

Parametrul <Culoare> poate lua una din valorile prezentate n tabelul de mai jos:

Constanta Valoare Fond Text


BLACK 0 Da Da
BLUE 1 Da Da
GREEN 2 Da Da
CYAN 3 Da Da
RED 4 Da Da
MAGENTA 5 Da Da
BROWN 6 Da Da
LIGHTGRAY 7 Da Da
DARKGRAY 8 Da Da
LIGHTBLUE 9 Nu Da
LIGHTGREEN 10 Nu Da
LIGHTCYAN 11 Nu Da
LIGHTRED 12 Nu Da
LIGHTMAGENTA 13 Nu Da
YYELLOW 14 Nu Da
WHITE 15 Nu Da
BLINK 128 Nu ***
Tabelul 12. Valori admise pentru culoare text si fond. Moduri video text standard

*** Codul BLINK se adaug la culoarea textului pentru a obine efectul de


blinking.

45
clreol() se utilizeaz pentru tergerea liniei curente ncepnd cu coloana
pe care se afl cursorul i pn la sfritul liniei.
gotoxy(col,lin) permite poziionarea cursorului pe linia i coloana
specificate.
De asemenea, pot fi de interes, n anumite situaii, urmtoarele funcii:

window(css,lss,cdj,ldj);
Definete coordonatele ferestrei text active.

wherex();
Returneaz coloana curent a cursorului.

wherey();
Returneaz linia curent a cursorului.

gettext() i puttext()
Permit citirea/scrierea memoriei video n mod text, ca n exemplul de mai
jos.

#include <conio.h>

//Buffer pentru salvat coninut memorie-video


char buffer[4096];
int main(void)
{
int i;

// Comutare n modul text C4350


textmode( C4350);
clrscr();
for (i = 0; i <= 20; i++)
cprintf("Linia %d\r\n", i);

//Salvare coninut memorie video n variabila buffer


gettext(1, 1, 80, 24, buffer);
gotoxy(1, 25);
cprintf("Apasati o tasta pentru a sterge ecranul...");
getch();

//tergere ecran
clrscr();
gotoxy(1, 25);
cprintf(" Apasati o tasta pentru a restaura ecranul...");
getch();

46
//Refacere coninut memorie video, utiliznd datele salvate n variabila buffer
puttext(1, 1, 80, 24, buffer);

gotoxy(1, 25);
cprintf("Apasati o tasta pentru a termina...");
getch();
return 0;
}

Ca o aplicaie la cele prezentate pn n acest moment n legtur cu


programarea n C, prezentm codul care ncapsuleaz cteva noi faciliti de
lucru n mod text, sub forma unui fiier antet, care poate fi utilizat n orice
program C, dac este prezent directiva de compilare:

#Include facilcrt.h

Numele fiierului antet este, evident, facilcrt.h.

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

//Activare video-invers
void avideo()
{
textcolor(BLACK);
textbackground(WHITE);
}

//dezactivare video-invers
void dvideo()
{
textcolor(WHITE);
textbackground(BLACK);
}

//Afisare centrata text in interiorul unei linii


void acentext(int ls,int ld,int linia,char *sir)
{
int sw;
int col;
sw=(ls>=1) && (ls<=79) && (ld<=80) && (ld>=2) && (ls<ld);
sw=sw && ((ld-ls+1)>=strlen(sir));
if (sw)
{
col=ls+(ld-ls+1-strlen(sir))/2;

47
gotoxy(col,linia);
cprintf(sir);
}
}

//Construire fereastra cu rama dreptunghiulara de dimensiuni specificate


void makewin2(int ass,int oss,int adj,int odj)
{
short int i;
int sw;
sw=(ass>0) && (ass<81) && (adj>0) && (adj<81) && (ass<=adj);
sw=sw && (oss>0) && (oss<25) && (odj>0) && (odj<25) && (oss<=odj);
if(sw)
{
for(i=ass;i<=adj;i++)
{
gotoxy(i,oss-1);cprintf("\315");
gotoxy(i,odj+1);cprintf("\315");
}
for(i=oss;i<=odj;i++)
{
gotoxy(ass-1,i);cprintf("\272");
gotoxy(adj+1,i);cprintf("\272");
}
gotoxy(ass-1,oss-1);cprintf("\311");
gotoxy(adj+1,oss-1);cprintf("\273");
gotoxy(ass-1,odj+1);cprintf("\310");
gotoxy(adj+1,odj+1);cprintf("\274");
}
else
{
gotoxy(1,24);
printf("Coordonate ecran eronate!!!");
getch();
}
}

Ca un comentariu la exemplul de cod C prezentat mai sus i la alte exemple


prezentate deja, facem precizarea c directiva de includere #include este soluia
C pentru o modularizare a codului, orientat pe clasificarea tipurilor de
capabiliti de prelucrare n fiiere speciale numite fiiere antet. Fiierele antet
sunt incluse n codurile surs ale programelor noastre de cte ori avem nevoie
de o capabilitate al crei prototip se afl n acele fiiere antet.

48
5 Matrice i iruri
O matrice este o colecie de variabile de acelai tip, apelate cu acelai nume.
Accesul la un anumit element al matricei se face cu ajutorul unui indice. n C
toate matricile constau n locaii de memorie contigue. Cel mai mic indice
corespunde primului element iar cel mai mare ultimului element. Matricele pot
avea una sau mai multe dimensiuni. Ca i n alte limbaje, cea mai simpl matrice
este irul. n C irul este o matrice de caractere terminate cu un caracter NULL.
Aceast caracteristic ofer limbajului C mai mult putere i eficien dect
posed alte limbaje.
Semnalm, de asemenea, faptul c n C, exist o strns legtur ntre matrice
i pointeri.

5.1 Matrice cu o singur dimensiune


Forma general n declararea unei matrice cu o singur dimensiune este:

<Tip> <Nume_variabil>[<Dimensiune>];

<Tip> declar tipul de baz al matricei, care este tipul fiecrui element al
su.
<Dimensiune> indic numrul maximal de elemente pe care le poate
conine matricea.

 De reinut faptul c, n C, toate matricele au ca indice pentru primul


element pe 0.

Cantitatea de memorie necesar pentru nregistrarea unei matrice este direct


proporional cu tipul i mrimea sa. Pentru o matrice unidimensional, mrimea
total n octei este calculat astfel:

Total_octei = sizeof(<Tip>)*<Dimensiune>

 C nu controleaz limitele unei matrice. Putei depi ambele margini ale


unei matrice i scrie n alte variabile sau peste codul programului. Riscurile
i responsabilitile sunt de partea programatorilor.

5.2 Crearea unui pointer la o matrice


Un pointer la primul element al unei matrice se creeaz simplu, specificnd
numele matricei, fr nici un indice.
De exemplu, avnd :

float sir[10];

putem crea un pointer la primul element al matricei astfel:

49
float *p;
float sir[10];
p=sir;

5.3 iruri de caractere


De departe, cea mai utilizat matrice unidimensional este irul de caractere.
Reamintim faptul c n C un ir de caractere este definit ca o matrice de
caractere care se termin cu un caracter NULL. n convenie backslash un NULL
se reprezint prin \0 i are valoarea 0. Din acest motiv, matricele de tip caracter
se declar cu un caracter mai mult dect lungimea celui mai mare ir pe care l
vor conine. Dei C nu are date de tip ir permite constante ir. O constant ir
este o succesiune de caractere nchise ntre ghilimele. Nu este necesar s
introducei manual caracterul NULL la sfritul constantelor ir, compilatorul face
acest lucru automat.
C admite, totodat, o gam larg de funcii de manipulare a irurilor. Cele mai
des utilizate sunt prezentate n tabelul de mai jos.

Nume funcie Utilitate


strcpy(s1,s2) Copiaz s2 n s1
strcat(s1,s2) Concateneaz s2 la sfritul s1
strlen(s1) Returneaz lungimea lui s1
strcmp(s1,s2) Returneaz 0 dac s1 i s2 sunt identice; un numr
mai mic dect 0 dac s1<s2 n sens lexicografic; un
numr mai mare dect 0 dac s1>s2 n sens
lexicografic.
strchr(s1,ch) Returneaz un pointer la prima apariie a caracterului
ch n s1.
strstr(s1,s2) Returneaz un pointer la prima apariie a lui s2 n s1.
Tabelul 13. Funcii C pentru lucrul cu iruri de caractere pstrate n fiierul antet
string.h
 Atenie! strcmp() returneaz fals dac irurile sunt egale.

5.4 Matrici bi i multidimensionale


C admite matrice multidimensionale. Cea mai simpl form de matrice
multidimensional este cea cu dou dimensiuni. De fapt, o matrice
bidimensional este o matrice de matrice unidimensionale. Pentru a declara o
matrice bidimensional utilizm sintaxa:

<Tip> <Nume_variabil>[<Dimensiune_1>][<Dimensiune_2>];

De exemplu, o matrice bidimensional de ntregi, de mrime10/20 se declar


astfel:

int matr[10][20];

50
Adresarea elementelor matricei se bazeaz pe premiza c, dup fiecare
dimensiune, indexarea ncepe de la 0. De asemenea, facem precizarea c,
atunci cnd o matrice bidimensional este utilizat ca un argument pentru o
funcie, se transmite doar un pointer ctre primul element al matricei. ns,
parametrul care primete o matrice bidimensional trebuie s defineasc cel
puin numrul de coloane, necesare compilatorului pentru a indexa corect
matricea. De urmrit exemplul de mai jos de cod C care permite calculul sumei
elementelor strict pozitive de pe diagonala principala a unei matrice patratice .

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

// Declarare matrice bidimensionala


int matr[10][10];
int dimm;

//Functia care primeste ca argument o matrice . Declara numarul de coloane.


void sespdp( int m[ ][10])
{
int k,suma;
suma=0;
for (k=0;k<dimm;k++)
{
if (m[k][k]>0)
suma=suma+m[k][k];
}
clrscr();
gotoxy(20,12);
cprintf("Suma elementelor strict pozitive ddp: %d",suma);
getch();
}
//Functia principala
void main()
{
int i,j,el;
clrscr();
gotoxy(20,10);cprintf("Nr. de linii :");
scanf("%d",&dimm);
clrscr();
for(i=0;i<dimm;i++)
for(j=0;j<dimm;j++)
{
gotoxy(20,12);
cprintf("Elementul[ %d , %d ]=",i,j);
scanf("%d",& matr[i][j]);
}

51
//Apelare functie cu parametru matrice transmisa ca pointer static
sespdp(matr);
}

Evident, n cazul unei matrice multidimensionale, forma general de declarare


precum i modul de utilizare sunt deductibile din cazul bidimensional.
Sintaxa pentru declararea unei matrice multidimensionale este:

<Tip> <Nume_variabil>[<Dim_1>][<Dim_2>][Dim_n];

n ncheierea paragrafului referitor la matrice prezentm o aplicaie n care,


artm, totodat, primii pai spre modularizarea i interfaarea unui program C.

Este vorba de un program C care cerceteaz ortogonalitatea a doi vectori


reali. Se utilizeaz nc odat fiierul antet facilcrt.h .

#include<stdio.h>
#include<conio.h>
#include "facilcrt.h"
#include<stdlib.h>
//Directiva #define permite specificarea unor macrouri
#define lmaxs 100
#define optiuni "1234"
//Solutie modularizata C pentru problema determinrii
//ortogonalitatii a doi vectori reali
char prelopt();
void prelvec();
int ortogon();
float sir1[lmaxs],sir2[lmaxs];
int dims;
void main()
{
for(; ;)
{
switch (prelopt())
{
case '1':
{ prelvec();
break;
}
case '2':
{ ortogon();
break;
};
case '3': exit(0);
}

52
}
}
char prelopt()
{
char opt;
clrscr();
gotoxy(20,9);
cprintf("Optiunile programului....");
gotoxy(20,10);
cprintf("1- Preluare vectori");
gotoxy(20,11);
cprintf("2- Determinare ortogonalitate....");
gotoxy(20,12);
cprintf("3- Terminare program");
makewin2(20,9,55,12);
gotoxy(20,15);
cprintf("Optiunea Dvs.:");
makewin2(20,15,55,15);
do
{
gotoxy(20+strlen("Optiunea Dvs.:"),15);
opt=getch();
}
while (strchr(optiuni,opt)==NULL);
return opt;
}

void prelvec()
{
int i,col;
clrscr();
gotoxy(20,9);
cprintf("Dimensiune vectori:");
makewin2(20,9,20+strlen("Dimensiune vectori:"),9);
gotoxy(22+strlen("Dimensiune vectori:"),9);
col=strlen("Dimensiune vectori:");
makewin2(22+col,9,30+col,9);
gotoxy(23+col,9);
cscanf("%d",&dims);

clrscr();
gotoxy(20,9);
cprintf("Preluarea componentelor primului vector...");
makewin2(20,9,20+strlen("Preluarea componentelor primului vector..."),12);
for (i=0;i<dims;i++)
{

53
gotoxy(20,10);
cprintf("Elementul [ %d ]=",i);
cscanf("%f",&sir1[i]);
}
clrscr();
gotoxy(20,9);
cprintf("Preluarea componentelor celui de-al doilea vector...");
makewin2(20,9,20+strlen("Preluarea componentelor celui de-al doilea
vector..."),12);
for (i=0;i<dims;i++)
{
gotoxy(20,10);
cprintf("Elementul [ %d ]=",i);
cscanf("%f",&sir2[i]);
}
}

int ortogon()
{
float suma;
int i;
suma=0;
for (i=0;i<dims;i++)
suma=suma+sir1[i]*sir2[i];
clrscr();
if (suma)
{
gotoxy(20,10);
textcolor(RED+BLINK);
cprintf("Vectorii nu sunt ortogonali!!");
makewin2(20,10,21+strlen("Vectorii nu sunt ortogonali!!"),10);
getch();
textcolor(WHITE);
}
else
{
gotoxy(20,10);
textcolor(GREEN+BLINK);
cprintf("Vectorii sunt ortogonali!!");
makewin2(20,10,21+strlen("Vectorii sunt ortogonali!!"),10);
getch();
textcolor(WHITE);
};
}

54
Se cuvine s mai fac o parantez referitoare la insistena cu care apar n
programele C/C++ construcii sintactice care ncep cu #, precum #include,
#define. Aceste construcii fac parte din categoria instruciunilor care se
adreseaz compilatorului i se mai numesc i directive pentru preprocesor. dei
nu fac parte din limbajul C/C++ aceste directive lrgesc sfera de aciune a
programelor C/C++. Am vzut deja care este utilitatea directivei preprocesor
#include. S spunem, totodat, faptul c, directiva pentru preprocesor #define
permite definirea unor macrouri astfel:

#define <Nume_macrou> <Secven_de_caracter>

Oriunde n program apare <Nume_macrou> compilatorul l nlocuiete cu


<Secven_de_caractere>. Adic avem la dispoziie un instrument foarte util la
parametrizarea codului. S adugm c #define poate permite i definirea de
funcii macro, situaie n care numele macroului poate avea i argumente.
Exemplu:

#define ABS(a) (a)<0 ? (a) : (a)


:
printf(abs de 1 si 1%d %d,ABS(-1), ABS(1));

La compilarea acestei secvene, a care apare n definirea funciei macro va fi


nlocuit cu valorile 1 i 1.
Utilizarea unei funcii macro mrete viteza de execuie a codului.
Merit cercetate cu atenie i trucurile care pot fi realizate cu ajutorul directivei
#define. Semnalm c, aa cum se ntmpla i n Pascal, n C exist o serie de
directive pentru compilare condiional a codului surs. Din aceast categorie fac
parte #if, #endif, #else #ifdef, #ifndef, etc.

55
6 Pointeri
Un pointer este o variabil care poate conine o adres de memorie. Aceast
adres este localizarea n memorie a unui alt obiect (de regul o alt variabil).
De exemplu, dac o variabil conine adresa alteia, despre prima se spune c
este un pointer la cea de-a doua. O variabil de tip pointer se declar n C astfel:

<Tip> * <Nume>;

unde <Tip> este tipul de baz al pointerului iar <Nume> este numele variabilei
pointer. Tipul de baz al pointerului definete tipul de variabil ctre care indic
pointerul. Practic, orice tip de pointer poate s indice orice n memorie.
Problema este, ns, c aritmetica pointerilor este integral raportat la tipul
de baz al pointerului.

Operatori pentru pointeri


Exist doi operatori speciali pentru pointeri: * i &. & este un operator unar care
returneaz adresa din memorie a operandului su. Operatorul * returneaz
valoarea nregistrat la adresa care l urmeaz. Evident c operatorul & se aplic
oricrui tip de variabil dar operatorul * cere dup el, neaprat, o variabil
pointer.

Expresii cu pointeri
n general, expresiile care implic pointeri se conformeaz acelorai reguli ca i
celelalte expresii. Exist, totui, o serie de particulariti pe care le vom evidenia
n acest paragraf n ceea ce privete aritmetica pointerilor.
Astfel:
Atribuirile sunt permise ntre pointeri concordani ca tip.
Pointerilor li se poate aplica operatorul ++ (incrementare) ca mai jos
:
int *p;
int mat[10];
:
p=&mat[0];
:
p++; // Operatorul de incrementare aplicat pointerului p
p- -;
:
n urma aplicrii operatorului de incrementare pointerului p, care coninea adresa
primului element al tabloului unidimensional mat, offset-ul acestuia este
incrementat cu 2, adic att ct este lungimea n octei a tipului de baz al
pointerului p.
Pointerilor li se poate aplica operatorul - - (decrementare) .
n urma aplicrii operatorului de decrementare pointerului p, care coninea
adresa celui de-al doilea element al tabloului unidimensional mat, offset-ul
acestuia este decrementat cu 2, adic att ct este lungimea n octei a tipului de
baz al pointerului p.

56
De asemenea, putem aduna sau scdea ntregi la, sau din pointeri. De
exemplu:
:
p=p+10;
:
face ca p s indice al 10-lea element de acelai tip cu tipul de baz al lui p,
relativ la elementul curent. n exemplul de mai jos ilustrm utilitatea aritmeticii
pointerilor n contextul lucrului cu matrice.

#include<stdio.h>
#include<conio.h>
int matr[10][10]; //matrice de intregi bidimensionala
int *p; // pointer la intregi
int dimm;
void main()
{
int i,j,el;
clrscr();
gotoxy(20,10);cprintf("Dimensiune matrice :");
scanf("%d",&dimm);
clrscr();
for(i=0;i<dimm;i++)
for(j=0;j<dimm;j++)
{
gotoxy(20,12);
cprintf("Elementul[ %d , %d ]=",i,j);
scanf("%d",&el);
matr[i][j]=el;
};
p=&matr[0][0]; //p refera primul element al matricei
for (i=0;i<dimm;i++)
cprintf("\r\n Ref_poin=%d",*(p+i)); //modificare offset p in expresie
getch();
p=&matr[0][0];
for (i=0;i<dimm;i++)
{
cprintf("\r\n Ref_poin=%d",*(p));
p=p+1; //modificare offset p prin incrementare
}
getch();

p=&matr[0][0];
for (i=0;i<dimm;i++)
{
cprintf("\r\n Ref_poin=%d",*(p));
p++; //aplicare operator de incrementare

57
}
getch();
}

Pointerii pot fi comparati n cadrul expresiilor relaionale. Dai pointerii p


i q, este perfect valabil instruciunea:

if (p<q) cprintf (p indica o memorie de adresa mai mica decat q\n);

Evident, n C se poate vorbi de matrice de pointeri, de indirectare multipl i,


evident, de alocarea dinamic a memoriei aferente unor pointeri.

Funcii de alocare dinamic n C


Pointerii ofer suportul necesar pentru sistemul puternic de alocare dinamic a
memoriei n C. Alocarea dinamic este caracteristica prin care un program poate
obine memorie n timpul execuiei. Dup cum se tie, variabilelor globale li se
aloc memorie n timpul compilrii. Variabilele locale folosesc memoria de tip
stiv. n mod cert, nici variabilele globale nici cele locale nu pot fi adugate n
timpul execuiei programului. Exist situaii n care necesarul real de memorie
este cunoscut de-abia n timpul execuiei programului.

 Chiar dac C++ accept pe deplin sistemul de alocare dinamic al lui C,


el i definete propriul sistem, care conine mai multe mbuntiri fa de
cele din C.

Memoria alocat de funciile de alocare dinamic din C este obinut din HEAP-
zona de memorie liber situat ntre zona permanent a memoriei programului i
stiv.
Nucleul sistemului de alocare din C const din funciile malloc() i free().
Aceste instrumente de alocare lucreaz n pereche, folosind zona de memorie
liber pentru a stabili i a pstra o list cu memoria disponibil.
Funcia malloc() aloc memorie, avnd urmtorul prototip:

void *malloc(size_t numar_de_octei);

n acest prototip, numar_de_octei este numrul de octei din memorie pe care


dorim s-l alocm programului. Funcia malloc() returneaz un pointer de tipul
void, ceea ce nseamn c l putei atribui oricrui tip de pointer.

Prototipul funciei free este:

void free(void *p);

Funcia free returneaz n sistem memoria alocat anterior pointerului p. Este


esenial s nu se apeleze free cu un argument impropriu; deoarece acest fapt
poate aduce prejudicii gestiunii de ctre sistem a memoriei libere. Exemplul de
mai jos arat modul efectiv de utilizare a funciilor malloc i free, precum i

58
modul de utilizare a funciei memcpy, n situaia n care se dorete copierea
coninutului memoriei de la o anumit adres la alt adres. De remarcat,
totodat, faptul c bibliotecile C au numeroase alte funcii pentru a satisface
cerinele de alocare/ manipulare dinamic a memoriei n programele utilizator.

#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<string.h>
void main()
{
char c[20];
int *p;

//pointer generic
void *x;
int nr=10000;
p=&nr;
clrscr();
gotoxy(20,10);

//Alocare dinamica memorie incepand


//de la o adresa returnata in x
x=(int*) malloc(sizeof(int));

//Copiere 2 octeti din zona referita de p in zona referita de x


memcpy(x,p,sizeof(int));
printf("%d",*(int*)x);
getch();

//Utilizarea pointerului x pentru a referi un sir de caractere


gotoxy(20,11);
strcpy(c,"Sir de caractere");
x=(char*) malloc(21); //alocare cu conversie de tip
memcpy(x,c,21);
puts((char*)x);
getch();
free(x);
}

Programatorul Pascal recunoate n suportul oferit de malloc() i free() soluia


pentru problema alocrii de memorie la nivel de octet, ceea ce nseamn
responsabilitatea programatorului de a realiza conversiile necesare n procesul
de utilizare a memoriei astfel alocate, ca n programul de mai sus. C++ are
propria ofert pentru alocarea dinamic de memorie din perspectiv structurat.

59
7 Structuri
O structur este, pragmatic vorbind, un grup de variabile reunite sub acelai
nume, ceea ce permite un mod convenabil de manipulare a unor date care au
afiniti semantice ntre ele. O declarare de structur formeaz un ablon care
poate fi folosit pentru a crea structuri efective. n C, variabilele care fac parte din
structur se numesc membri ai structurii. Uzual, membrii structurii se mai
numesc i elemente sau cmpuri. Aa cum vom vedea mai jos, o structur
poate ncapsula i metode de prelucrare a datelor, dac programatorul dorete
s abstractizeze tipuri de date cu suport struct.
Sintaxa general pentru declararea unei structuri este:

struct <Nume_generic>
{
<Tip> <Nume_membru_1>;
<Tip> <Nume_membru_2>;
:
<Tip> <Nume_membru_n>;
:
<Tip returnat> <Nume functie>(<Lista de parametri>);

} <Variabila_1>,[<Variabila_k>];
n cazul n care n definiia structurii este ncapsulat i o metod atunci la
implementare se folosete sintaxa:

<Tip returnat> <Structur>::<Nume functie>(<Lista de parametri>);


{
//Corp funcie
};

Pentru mai mult claritate se poate urmri exemplul de mai jos.

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

typedef struct
{
char matricol[6];
char nume[30];
float media;
void setstud(char matr[],char num[],float med);
} TStud;
void TStud::setstud(char matr[],char num[],float med)
{
strcpy(matricol,matr);
strcpy(nume,num);
media=med;

60
};
void main()
{
clrscr();
TStud stud;
stud.setstud("12","Mihai Guramare",10);
printf("Matricol :%s\n",stud.matricol);
printf("Nume :%s\n",stud.nume);
printf("Media :%f",stud.media);
getch();
}

Dup cum se vede deja, numele variabilei structurate, urmat de un punct i


numele membrului permite adresarea acelui membru. Adic, n general vorbind:

<Variabila_structurat> . <Nume_membru>

n codul de mai jos se arat modul concret de declarare a unei structuri i de


asociere a acestei declaraii cu un nume de tip prin intermediul cuvntului cheie
typedef.

#include<conio.h>
#include<iostream.h>
#include<string.h>
void main()
{
typedef struct TPers{
char nume[30];
float salariu;
} TPers;
TPers pers;
strcpy(pers.nume,"Test typedef + struct.");
pers.salariu=1200000;
clrscr();
cout<<pers.nume<<"\r\n"<<pers.salariu;
getch();
}

n mod evident, structurile pot fi asociate i cu pointerii


prin declaraii asemntoare celor din codul alternativ de
mai jos.

#include<conio.h>
#include<iostream.h>
#include<string.h>
void main()
{

61
typedef struct TPers{
char nume[30];
float salariu;
} TPers;
TPers *pers;

alocare memorie pentru pers

strcpy(pers->nume,"Test relatie structura - pointer");


pers->salariu=1200000;
clrscr();
cout<<pers->nume<<"\r\n"<<pers->salariu;
getch();
}

O alt ntrebuinare a structurilor o reprezint posibilitatea de a defini cmpuri de


bii. Cmpurile de bii sunt mecanisme cu ajutorul crora programatorul poate
avea acces la coninutul variabilelor pn la nivel de bit.

Sintaxa pentru definirea unui camp de biti este:

typedef struct
{
tip1 nume1:lungime1;
tip2 nume2:lungime2;
...
tipn numen:lungimen;
} TOctet;

Tipurile pot lua una din valorile int, unsigned, signed, pentru majoritatea
compilatoarelor.

Cmpul de bii cu lungimea 1 este obligatoriu unsigned. A se vedea i


exemplul de mai jos.

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

typedef struct
{
unsigned bit :1;
unsigned :7;
unsigned :7;
unsigned bits:1;
} TOctet;
TOctet Octet;

62
int nr=1;
int *pointer;

void main()
{
int i;
pointer=&nr;
memcpy(&Octet,pointer,sizeof(int));
clrscr();
printf("Bitul 0 : %i\n",Octet.bit);
printf("Bitul de semn: %i\n",Octet.bits);
getch();
}

63
8 Uniuni
O uniune este o locaie de memorie care este partajat n momente diferite ntre
dou sau mai multe variabile diferite.
Sintaxa generala i modul de utilizare pot fi deduse din exemplul de mai jos.

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

typedef union
{
int codsal;
float salar;
} TUSal;

void main()
{
clrscr();
TUSal vunion;
vunion.codsal=10;
printf("Cod confidential salariu:%i\n",vunion.codsal);
vunion.salar=1000.50;
printf("Salariu :%f",vunion.salar);
getch();
}

n acest exemplu variabilele codsal i salar, de tipuri diferire, partajeaz


aceeai locaie de memorie, dar, important de tiut, n momente diferire ale
execuiei unui programului, dup cum se observ, de altfel i din exemplu.

ncheiem aici partea intitulat BAZELE C++. LIMBAJUL C, cu meniunea c


exist nenumrate alte aspecte ale programrii n C care necesit timp i
rbdare pentru a nelege toate consecinele stilului C de programare, nelegere
folositoare i n abordarea C++. Dintre aceste aspecte semnalez: fluxurile C,
abloanele C, suprascrierea funciilor, etc. Pentru toate acestea exist, ns
suport C++ mult mai adecvat i mai comod de multe ori pentru programarea cu
adevrat n spirit obiect orientat.

64
II Programarea C++

65
1 Introducere
Programarea orientat pe obiecte (POO) este expresia, n materie de codificare
a proiectelor, a paradigmei care presupune modelarea orientat pe obiecte a
sistemelor soft.

POO este o paradigm care ctig tot mai muli adereni datorit calitilor
pe care le au produsele i sistemele soft realizate n spiritul conceptelor i
principiilor promovate de aceasta. Rezultant a unor direcii diverse de
cercetare i experimentare (programare structurat, programare modular,
programare orientat pe structuri abstracte, reprezentarea cunotinelor n
sisteme expert, etc.) POO, aplicat corect poate rezolva, parial sau
integral, multe din problemele obsedante ale ingineriei softului, n genere:
reutilizarea codului, extinderea/modificarea cu minim de efort a sistemelor
soft, ascunderea detaliilor de implementare fa de anumite categorii de
utilizatori ai sistemelor soft. n acest mod platforma POO poate ajuta
programatorii i companiile de soft s realizeze produse i sisteme soft
performante, n timp util i la un pre sczut.

1. 1 Concepte POO
Orice demers de modelare orientat pe obiecte apeleaz la o serie de concepte
specifice paradigmei POO.
Astfel, pentru modelarea unui sistem soft se opereaz frecvent cu:
1. Concepte ale teoriei generale a sistemelor (sistem, subsistem,
descompunere, agregare, structur, etc.)
2. Concepte care provin din arsenalul conceptual al modelrii n genere
a sistemelor i produselor soft (modul, modularizare, interfa, tip de dat,
structur de date, ascunderea informaiei, etc.).
Tuturor acestora li se adaug principiile cu ajutorul crora aceste concepte devin
operaionale.
Paradigma POO a intrat n competiia pentru modernizarea i mbuntirea
real a procesului de realizare a unui sistem soft cu un set propriu de concepte i
principii.
Prezentm mai nti conceptele cheie ale paradigmei POO.

Conceptul de clas, prin care se desemneaz o colecie de obiecte (de natur


material sau spiritual) care au n comun faptul c pot fi caracterizate similar
din punct de vedere informaional i comportamental.

Este evident faptul c identificarea unei clase este n mod normal, rezultatul unui
demers cognitiv care presupune caracterizarea unui obiect prin nsuirile lui
(informaionale i comportamentale) care i definesc apartenena la o anumit
clas de obiecte. Aadar, conceptul de clas adun laolalt datele i metodele
de prelucrare a acestora.

n esen definirea unei clase se bazeaz pe analiza, clasificarea i


abstractizarea nsuirilor obiectelor de un anumit tip.

66
Acesta este un exerciiu de ndemnare a crui rezolvare o poate nva oricine
care ncearc, are rbdare cu el nsui i citete cum procedeaz iniiaii cnd
ntlnesc astfel de exerciii. Aa cum va reiei din implementarea conceptului de
clas n C++, de exemplu, conceptul de clas este o abstracie care
pregtete un anumit tip de background pentru descrierea soluiei unei
probleme date. Fr a intra prea mult n problem s amintim, totui, c
modelnd obiect orientat soluiile problemelor noastre ne asigurm o serie
de avantaje imediate i de perspectiv n ceea ce privete gestiunea relaiei
dintre domeniul problemei i domeniul soluiei n ingineria sistemelor soft.

Conceptul de obiect (instan a unei clase) este deja un concept cu valoare


operaional, prin care se desemneaz un obiect concret al unei clase
definitoare, caracterizat prin valori specifice ale atributelor informaionale.
Dac definirea unei clase pune, n primul rnd, probleme de natur conceptual,
manipularea unui obiect se bazeaz pe abilitile specifice limbajului referitoare
la alocarea de memorie pentru obiect (static sau dinamic), controlul strii
obiectului (= valorile atributelor informaionale) cu ajutorul metodelor proprii, etc.
Proprietile unui obiect sunt, n mare parte, proprietile unei clase. Calitatea
unui obiect depinde de calitatea clasei definitoare. Exist dou perspective din
care putem aprecia calitile unui obiect: perspectiva utilizator de obiect i
perspectiva specificator de clas definitoare. Utilizatorul de obiect este
interesat, practic, de calitatea interfeei obiectului, care permite o apreciere i
asupra potenialului informaional i comportamental al obiectului respectiv.
Munca unui specificator de clas definitoare poate fi apreciat dup potenialul
informaional i comportamental al clasei, accesibil prin intermediul unei interfee
care implementeaz principiul cine dorete date despre starea unui obiect al
unei clase trebuie s se mulumeasc cu deschiderea oferit n acest sens de
interfaa obiectului n cauz. Trdarea acestui principiu este o dovad de
neprofesionalism n abordarea obiect orientat a unei probleme.
Aa se ajunge c, pentru un programator, un obiect conteaz prin: identitate,
interfa(partajat n comun cu alte obiecte de acelai tip prin raportare la o
clas definitoare) i stare.

Identitatea unui obiect desemneaz procedeul prin care se asigur, n sistem,


unicitatea unui obiect. Cele mai multe limbaje rezolv aceast problem prin
asocierea instanei unei clase (=obiect) cu o anumit adres de memorie.

Interfaa unui obiect desemneaz mulimea metodelor unei clase cu ajutorul


crora obiectele clase comunic cu ambiana n care acestea exist.
Comunicarea ntre obiecte se realizeaz, dogmatic vorbind, prin mesaje.

Conceptul de stare a unui obiect prin care se desemneaz valorile atributelor


informaionale ale obiectului.
Conceptul de mesaj prin care se nelege un semnal emis de ctre un obiect
emitor ctre un obiect receptor, din iniiativa obiectului emitor.

67
Este evident faptul c obiectul care emite mesajul trebuie s cunoasc protocolul
de comunicaie al obiectului receptor.
De asemenea, se subnelege faptul c mesajul trimis de obiectul emitor va
provoca o reacie(= un rspuns) din partea obiectului receptor.

Conceptul de metod prin intermediul cruia se d o expresie procedeelor care


definesc comportamentul i, direct sau indirect, protocolul de comunicaie al unei
clase.
Pentru mai mult exactitate, este bine s se neleag faptul c "metoda" este o
denumire generic pentru un procedeu de prelucrare care face parte din
protocolul de comunicare al unei clase. Metoda poate fi implementat n C, de
exemplu, ca funcie, constructor sau destructor. Asupra semnificaiei noiunilor de
constructor i destructor vom mai reveni .

1. 2 Principiile POO
Noutatea POO, ca paradigm este ilustrat i de principiile pe care le
promoveaz pentru a completa potenialul oferit de concepte. Promovarea
sistematic a principiilor pe care le prezentm n continuare promite, dar
nu garanteaz, realizarea unor produse, sisteme sau platforme soft
remarcabile din punct de vedere al performanelor i al efortului de
ntreinere.

1.2.1 Principiul ncapsulrii


nelegerea acestui principiu presupune dou nivele de abordare.

@ Ca metod de concepie, ncapsularea se refer la capacitatea de a separa


aspectele externe ale unui obiect (interfaa), accesibile altor obiecte, de
aspectele implementaionale, interne obiectului, care sunt ascunse fa de
celelalte obiecte. Utilizatorul unui obiect poate accesa doar anumite metode ale
acestuia, numite publice, n timp ce atributele i celelalte metode i rmn
inaccesibile (acestea se numesc private).
ncapsularea este foarte important atunci cnd dorim s schimbm
implementarea anumitor metode (cu scopul de a optimiza un algoritm sau de a
elimina posibile erori).
ncapsularea ne va mpiedica s modificm toate caracteristicile obiectului iar
aplicaiile care utilizeaz obiectul nu vor avea de suferit deoarece protocolul de
comunicaie al obiectului motenit de la interfaa clasei (rezultatul ncapsulrii
ca metod de concepie) nu s-a schimbat.

@Ca implementare, la nivelul unui limbaj de programare, ncapsularea este


asigurat de exigenele sintactice specifice.

1.2.2 Principiul motenirii

68
Acest principiu este de mare utilitate n transmiterea sistematic a similaritilor
de la o clas la alta. Principiul poate fi aplicat cu succes doar n conjuncie cu
operatorii conceptuali complementari:generalizarea i specializarea.
Generalizarea apare n relaia dintre o clas i una sau mai multe versiuni mai
rafinate ale acesteia. Este, n limbajul de specialitate, relaia dintre clasa de
baz (sau superclas) i clasele derivate (sau subclase).
Atributele i operaiile comune sunt grupate n superclas i se spune c sunt
motenite de subclase.
Se poate spune c motenirea se refer la mecanismul de a transmite atribute i
operaii de-a lungul unei relaii de generalizare. Evident, simpla motenire a
proprietilor unei clase nu rezolv nici o problem din punct de vedere
conceptual. Utilitatea principiului motenirii este reliefat n condiiile aplicrii
operatorului de specializare, prin care subclasa rafineaz (specializeaz)
superclasa.
Implementarea motenirii nu creeaz probleme deosebite de nelegere i
utilizare.

1.2.3 Principiul polimorfismului


Prin aplicarea principiului motenirii se creeaz condiii pentru specializarea unei
superclase. Specializarea poate fi realizat prin adugarea de noi operaii celor
motenite sau prin redefinirea unora dintre operaiile motenite. Specializarea
orientat pe redefinirea operaiilor se afl la baza implementrii principiului
polimorfismului.
Ca rezultat final aplicarea principiului polimorfismului creeaz posibilitatea ca un
mesaj (n structura cruia intervine un nume de operaie) s genereze
rspunsuri diferite, n funcie de contextul n care este formulat mesajul.
O astfel de posibilitate este cu att mai valoroas cu ct gestiunea
contextului n care se formuleaz mesajul este asumat de ctre sistem.
Ca mecanism, aplicarea principiului presupune instituirea unui protocol pentru
evidena legturilor dintre clase i operaiile aferente, susceptibile de redefinire.

69
2 Implementarea C++ a POO
2.1 Definirea claselor
Pentru a putea lucra cu obiecte n C++ trebuie, n prealabil, s definim forma lor
general folosind n acest scop cuvntul cheie class. O clas este similar,
sintactic vorbind, cu o structur. Forma general a unei declaraii de clas care
nu motenete nici o alt clas este urmtoarea:

class <Nume_clasa> [:<Lista_claselor_de_baz>]


{
<Date i funcii particulare>
<Specificator de acces>:
<Date si functii>
<Specificator de acces>:
<Date si functii>
:
:
<Specificator de acces>:
<Date si functii>
} [<Lista de obiecte>];

<Lista de obiecte> este opional. Dac exist, ea declar obiecte din


acea clas.
<Specificator de acces> este unul din cuvintele cheie:
-public
-private
-protected.
Implicit, funciile i datele declarate ntr-o clas sunt proprii acelei clase, doar
membrii si avnd acces la ele.
<Lista_claselor_de_baz> indic, opional, clasele de la care se pot
moteni atribute informaionale i comportamentale.

 Pentru datele i funciile care fac parte din definiia unei clase se
obinuiesc i denumirile de variabile membre, respectiv, funcii membre
sau, pur i simplu, membri.

Folosind specificatorul de acces public, permitem funciilor sau datelor membre


s fie accesibile altor seciuni ale programului nostru. Odat utilizat un
specificator, efectul su dureaz pn cnd se ntlnete alt specificator de
acces sau se ajunge la sfritul declaraiei clasei. Pentru a reveni la modul privat
de declarare a membrilor, se folosete specificatorul de acces private.
Specificatorul protected are implicaii asupra vizibilitii membrilor unei clase n
cazul n care se face i motenire. Prezentm, n continuare, un exemplu de
definiie de clas, care ncapsuleaz date i operaii minimale referitoare la un
salariat al unei firme( nume, matricol, salariu).

70
#include <conio.h>
#include <string.h>
#include <iostream.h>

// Definitie clasa fara declarare de variabile obiect.


class Persoana
{
public:
char nume[30];
int matricol;
float salariu;
void setfields(char n[30], int m, float s);
void afis();
};

// Implementare functie setfields


void Persoana:: setfields(char *n, int m, float s)
{
strcpy(nume,n);
matricol=m;
salariu=s;
}

// Implementare functie afis


void Persoana:: afis()
{
clrscr();
cout<<nume<<"\n"<<salariu;
getch();
}

//Implementare functie principala


void main()
{

// Declarare variabila obiect


Persoana pers;

pers.setfields("Radu Vasile",1,10000);
pers.afis();
}

n exemplul prezentat am folosit specificatorul de acces public pentru a permite


funciei principale, care a declarat variabila obiect pers, accesul la membrii clasei
definitoare a variabilei pers. n programarea obiect orientat adevrat n C++,
efectul de ascundere a membrilor unei clase este intens utilizat, interzicnd

71
anumitor categorii de utilizatori accesul la membrii clasei, definind pentru
comunicaia cu alte clase i categorii de utilizatori ceea ce se numete interfaa
clasei.
Evident, se poate face o oarecare analogie ntre clas i structur; analogia
cade, ns, n momentul n care se pune problema manevrabilitii instanelor
celor dou tipuri de concepte sau atunci cnd este vorba de motenire i
polimorfism. Un exemplu ceva mai apropiat de realitatea preocuprilor unui
programator C++ poate fi programul care implementeaz o stiv de ntregi,
prezentat n continuare.

#include <iostream.h>
#include <conio.h>
#define SIZE 100

// Definirea clasei stack


class stack
{
int st[SIZE];
int top;
public:
void init();
void push(int i);
int pop();
};

//Implementare functie init


void stack::init()
{
top=0;
}

//Implementare functie push


void stack::push(int i)
{
if (top==SIZE)
{
gotoxy(20,24);
cout<<"Stiva este plina!!!";
getch();
return;
};
st[top]=i;
top++;
}

//Implementare functie pop

72
int stack::pop()
{
if(top==0)
{
gotoxy(20,24);
cout<<"Depasire inferioara stiva!!!";
getch();
return 0;
};
top--;
return st[top];
}

//Functia principala
void main()
{
int i;
stack st1,st2;
st1.init();
st2.init();
for (i=0;i<=9;i++)
{
st1.push(i);
st2.push(9-i);
}
clrscr();
for (i=0;i<=9;i++)
{
gotoxy(35,wherey()+1);
cout<<st1.pop()<<"*****";
cout<<st2.pop()<<endl;
}
getch();
}

2.2 Clase derivate. Constructori. Destructori. Obiecte C++


Modelarea obiect orientat a soluiei unei probleme de oarecare complexitate
pune, inevitabil i problema transmiterii similaritilor ntre clase care formeaz o
ierarhie sau o reea. Suportul C++ pentru rezolvarea acestei probleme l
reprezint posibilitatea ca o clas s fie derivat din una sau mai multe clase,
ceea ce nseamn posibilitatea de a abstractiza soluia cu scopul de a reutiliza
cod i de a adapta codul uor la cerine noi dac este cazul. Am vzut mai sus
sintaxa pentru motenire. S adugm, n plus la cele spuse mai sus, c n
<Lista_claselor_de_baz> clasele definitoare apar precedate, eventual, de un
modificator de protecie i sunt separate ntre ele prin virgul.

73
Modificatorii de protecie utilizai n <Lista_claselor_de_baz> definesc protecia
n clasa derivat a elementelor motenite. Prezentm sub form tabelar accesul
la elementele motenite de clasa derivat n funcie de protecia fiecrui element
i de modificatorul de protecie asociat n <Lista_claselor_de_baz>.

Tipul de acces al Modificatorul de protecie Accesul n clasa


elementului n clasa asociat clasei de baz la derivat la element
de baz definirea clasei
private private interzis
protected private private
public private private
private public interzis
protected public protected
public public public
Tabelul 14. Problematica accesului la membrii unei clase derivate

Concluzionnd, dac n clasa de baz accesul la element este private atunci n


clasa derivat accesul este interzis. n schimb, clasa derivat are acces la
elementele clasei de baz aflate sub incidena accesului protected/public.
Se mai poate observa, totodat, c dac la definirea clasei derivate se utilizeaz
modificatorul de protecie private, atunci elementele protejate n clasa de baz
prin protected sau public devin protejate private n clasa derivat; deci
inaccesibile unor clase care s-ar deriva eventual din clasa derivat.

Exemplu

#include <iostream.h>
class CB
{
protected:
int i,j;
//Pentru un program care utilizeaz aceast clas
//sau pentru alt clas care nu se afl n relaie
//de derivare cu CB I,j sunt private din punct de
//vedere al accesului. i,j sunt accesibile unei clase derivate.
public:
void setij(int a, int b) {i=a;j=b}
void dispij() { cout<<i<< <<j<<endl;}
}

class CD:public CB
{
int k;
public:
void setk(){k=I*j;}
void dispk(){cout<<k<<endl;}

74
}

void main()
{
CD ob;
ob.setij(2,3); //OK!
ob.dispij(); //OK
ob.setk();
ob.dispk ();
}

Motenirea protected a clasei de baz


Este posibil s se moteneasc o clas de baz ca protected. Cnd se
procedeaz astfel, toi membrii public i protected ai clasei de baz devin
membri protected ai clasei derivate.

Exemplu

#include <iostream.h>
class CB
{
protected:
int i,j;
//Pentru un program care utilizeaz aceast clas
//sau pentru alt clas care nu se afl n relaie
//de derivare cu CB i, j sunt private din punct de
//vedere al accesului. i,j sunt accesibile unei clase derivate.
public:
void setij(int a, int b) {i=a;j=b}
void dispij() { cout<<i<< <<j<<endl;}
}

class CD:protected CB
{
int k;
public:
void setk(){setij(10,20);k=I*j;}
void disptot(){cout<<k<< ;dispij();}
}

void main()
{
CD ob;
ob.setij(2,3); //ilegal!
ob.setk(); //OK!, membru public n CD

75
ob.setk();
ob.disptot (); //OK!
ob.dispij(); //ilegal! Membru protected n CD
}

Constructori i destructori
Este un fapt obinuit necesitatea ca unele elemente ale unui obiect s fie
iniializate. Pentru a degreva programatorul de o asemenea sarcin de rutin,
compilatorul C++ genereaz cod care permite obiectelor s se iniializeze
singure. Aceast iniializare automat este efectuat prin intermediul unei funcii
membru speciale a clasei definitoare numit constructor.

Constructorul este o funcie care are acelasi nume cu clasa.


Un constructor al unui obiect este apelat automat la crearea obiectului.
Un constructor al unui obiect este apelat o singur dat pentru obiecte
globale sau pentru cele locale de tip static.
Constructorul este o funcie fr tip ceea ce nu reclam, totui cuvntul
cheie void n locul tipului.
Pentru obiecte locale constructorul este apelat de fiecare dat cnd este
ntlnit declararea acestuia.

Complementul constructorului este destructorul. De multe ori un obiect trebuie


s efectueze anumite aciuni cnd este distrus.
Este evident faptul c obiectele locale sunt distruse la prsirea blocului n care
apar iar obiectele globale la terminarea programului.
Cnd este distrus un obiect, este apelat destructorul clasei definitoare.

Destructorul are acelai nume cu constructorul, dar precedat de un


caracter ~.
O clas are un singur destructor i acest destructor nu poate avea
parametri formali.
Att constructorul ct i destructorul, n C++ nu pot s returneze valori.

De semnalat faptul c n situaia n care programatorul nu specific un


constructor explicit la definirea unei clase, la crearea unei instane a clasei se
folosete constructorul implicit ataat de compilator fiecrei clase.
Constructorul implicit nu are parametri formali, ceea ce are drept consecin
faptul c nu este permis iniializarea la declarare a datelor membre ale
obiectelor.
De asemenea, constructorul implicit nu este generat n cazul n care clasa are
ataat un alt constructor fr parametri.
Programatorul poate nzestra clasa cu o proprie funcie constructor. n acest
scop trebuie inut cont de faptul c o metod constructor are ntotdeauna numele
clasei din care face parte.
Programatorul poate nzestra clasa i cu parametri formali ceea ce permite i o
formul elegant de iniializare a datelor membre ale obiectelor clasei respective.

76
 Foarte important mi se pare s semnalez i existena unui constructor
special, numit constructor de copiere. Acesta are rolul de a atribui datele unui
obiect altuia. Mai mult, poate fi apelat chiar la definirea obiectelor. Dac
programatorul nu definete propriul constructor de copiere, compilatorul adaug
automat un astfel de constructor. n exemplul de mai jos se pot urmri elemente
de sintax i semantic care trebuie cunoscute cnd se lucreaz cu constructori
n diferite ipostaze.

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

//Definire clas
class intreg
{
public:
int a;
//Constructor parametrizat
intreg(int v)
{
printf("Constructor parametrizat\n");
getch();
a=v;
}
//Constructor de copiere
intreg (intreg& v)
{
a=v.a;
printf("Constructor de copiere\n");
getch();
}
void dispa()
{
printf("a=%i\n",a);
getch();
};
};

void main()
{
clrscr();
//Declarare obiect static cu iniializare;
intreg x=100;
x.dispa();
//Declarare obiect static cu iniializare prin copiere
intreg y=x;

77
y.dispa();
}

Evident, o clas poate avea mai muli constructori, ceea ce este tot n beneficiul
programatorilor.

Crearea obiectelor n C++


Obiectele pot fi create static sau dinamic.
Aa cum s-a vzut i n exemplul de mai sus sintaxa pentru varianta static este:

<Clasa> <Obiect>[(<Lista de valori>)];


sau
<Clasa> <Obiect>[=<Valoare>];
Sintaxa ne arat c odat cu crearea instanei se poate face i iniializarea
datelor membre ale obiectului cu ajutorul constructorilor parametrizai.

Pentru a nelege alocarea dinamic a memoriei pentru obiecte trebuie s facem


o scurt prezentare a problematicii alocrii dinamice structurate a memoriei n
C++.

Operatori de alocare dinamic a memoriei n C++


n C, alocarea dinamic a memoriei este realizat cu ajutorul funciior malloc() i
free().
Din motive de compatibilitate i nu numai, aceste funcii sunt valabile i n C++.
Totodat, C++ are un sistem alternativ de alocare dinamic bazat pe operatorii
new i delete.
Sintaxa general pentru new i delete este:

<Pointer>=new <Tip>;
delete <Pointer> ;

<Pointer> este o variabil pointer, compatibil ca tip cu <Tip>. Aadar, <Pointer>


poate pstra adresa ctre zona de memorie n care ncap date avnd tipul <Tip>.
De subliniat c operatorul delete trebuie folosit doar cu un pointer valid, alocat
deja prin utilizarea operatorului new. n caz contrar, rezultatele sunt imprevizibile.
Fa de malloc()i free(), operatorii new i delete prezint cteva avantaje:
@ new aloc automat memorie suficient pentru a pstra obiectele de
tipul specificat. Nu mai este necesar folosirea operatorului sizeof.
@ new returneaz automat un pointer de tipul specificat. Nu mai este
necesar s folosim modelatorii de tip ca n cazul funciei malloc().
@ Att new ct i delete pot fi suprancrcai, ceea ce v permite crearea
unui sistem propriu de alocare dinamic a memoriei. Despre suprancrcare
vom discuta n paragrafele 2.4 i 2.7 .
n plus, operatorul new mai are i alte capabiliti:
@Permite iniializarea memoriei alocate unui tip de baz cu o valoare dat,
utiliznd sintaxa:

78
<Pointer>=new <Tip> (<Valoare_iniial>);
ca n exemplul:

int *p;
p=new int(10);

@Operatorul new permite alocarea de memorie pentru matrici, utiliznd


sintaxa:

<Pointer>=new <Tip> [Marime];

Memoria alocat unei matrici de operatorul new se elibereaz de ctre delete


apelat cu sintaxa:

delete [ ] <Pointer>

 Matricile nu pot fi iniializate n timpul alocrii.

Suntem n msur s prezentm soluia C++ pentru problema alocrii dinamice a


memoriei pentru obiecte.
Obiectelor li se poate aloca memorie dinamic folosind operatorul new. Cnd
procedai astfel se creeaz un obiect i se returneaz un pointer ctre el.
Obiectul creat dinamic se comport ca oricare altul. Cnd este creat este apelat
i funcia constructor. Cnd este eliberat se execut i funcia destructor.
Sintaxa general:

<Pointer_la_obiect>=new <Clasa>;

Dac <Clasa> are constructor parametrizat atunci se poate folosi sintaxa:

<Pointer_la_obiect>=new <Clasa>(<Lista_valori>);

pentru a realiza i iniializarea obiectului.

n sfrit, n cazul matricilor de obiecte, crora li se poate aloca memorie


dinamic, trebuie s ne asigurm c n cazul n care exist funcii constructor, una
va fi fr parametri. n caz contrar, compilatorul d eroare de sintax.

Modalitatea concret de utilizare a conceptului de constructor, precum i a


conceptului complementar, destructorul, poate fi desprins i din exemplul de
mai jos care reia modelarea obiect orientat a unei stive de ntregi.

#include <iostream.h>
#include <conio.h>
#define SIZE 100

79
// Definirea clasei stack
class stack
{
int st[SIZE];
int top;
public:
stack(); //constructor
~stack(); //destructor
void push(int i);
int pop();
};

//Implementare constructor
stack::stack()
{
top=0;
gotoxy(20,24);
cout<<"Stiva este initializata";
getch();
clrscr();
}
stack::~stack()
{
gotoxy(20,24);
cout<<"Stiva este distrusa!!";
getch();
clrscr();
}

//Implementare functie push


void stack::push(int i)
{
if (top==SIZE)
{
gotoxy(20,24);
cout<<"Stiva este plina!!!";
getch();
return;
};
st[top]=i;
top++;
}

//Implementare functie pop


int stack::pop()

80
{
if(top==0)
{
gotoxy(20,24);
cout<<"Depasire inferioara stiva!!!";
getch();
return 0;
};
top--;
return st[top];
}
//Functia principala
void main()
{
int i;
stack st1,st2;
for (i=0;i<=9;i++)
{
st1.push(i);
st2.push(9-i);
}
clrscr();
for (i=0;i<=9;i++)
{
gotoxy(35,wherey()+1);
cout<<st1.pop()<<"*****";
cout<<st2.pop()<<endl;
}
getch();
}

2.3 Funcii virtuale i polimorfism


C++ asigur suport pentru polimorfism att n timpul compilrii ct i pe timpul
execuiei unui program. Polimorfismul n timpul compilrii este legat de
posibilitatea de a suprancrca funciile i operatorii, problem pe care o vom
discuta n paragrafele 2.4 i 2.7.
Polimorfismul n timpul execuiei este obinut combinnd principiile motenirii
cu mecanismul funciilor virtuale.

Funcii virtuale
O funcie virtual este o funcie declarat virtual n clasa de baz i redefinit
ntr-un lan de derivare asociat respectivei clase de baz. O funcie virtual
definete o clas general de aciuni. O redefinire a ei introduce o metod
specific. n esen, o funcie virtual declarat n clasa de baz acioneaz ca
un substitut pentru pstrarea elementelor care specific o clas general de
aciuni, stabilind elementele de interfa. Redefinirea unei funcii virtuale ntr-o

81
clas derivat ofer operaiile efective pe care le execut funcia. Utilizate static,
funciile virtuale se comport ca oricare alt funcie membru a clasei .
Capabilitile funciilor virtuale ies n eviden atunci cnd sunt apelate n context
dinamic.

Exemplu
#include <iostream.h>
#include <conio.h>
//Clasa de baza care are doua functii membri publici
//o functie ordinara
//cealalta functie virtuala
class CB
{
public:
void f()
{
cout<<"CB::f()"<<endl;
getch();
}
virtual void g() //funcie virtual
{
cout<<"CB::g()"<<endl;
getch();
}
};

//Clasa derivata din clasa de baza


class CD:public CB
{
public:
void f()
{
cout<<"CD::f()"<<endl;
getch();
}
virtual void g()
{
cout<<"CD::g()"<<endl;
getch();
}
};

//Functie care permite utilizarea polimorfismului


//Parametrul functiei este un pointer la un obiect de tip CB
//De retinut ca un parametru de tip CD este compatibil
//cu tipul lui p

82
void ExecPolim(CB *p);

void main()
{
CB *pb=new CB;
CD *pd=new CD;
clrscr();
pb->f();
pb->g();
pd->f();
pd->g();
clrscr();
cout<<"Apel polimorfic in context CB"<<endl;
ExecPolim(pb);
cout<<"Apel polimorfic in context CD"<<endl;
ExecPolim(pd);
delete pb;
delete pd;
};

void ExecPolim(CB *p)


{
p->f();
p->g();
}

La prima vedere redefinirea unei funcii virtuale ntr-o clas derivat pare similar
cu suprancrcarea unei funcii. Nu este aa, deoarece exist mai multe
diferene:
@Prototipul pentru o funcie virtual redefinit trebuie s coincid cu
prototipul specificat n clasa de baz.
@Funciile virtuale nu pot s fie membri de tip static ai clasei din care fac
parte i nu pot fi nici friend
Funciile obinuite suport suprancrcarea; funciile virtuale suport
suprascrierea.
n cele ce urmeaz facem o serie de precizri relativ la clauza virtual.

Clauza virtual este motenit


Cnd o funcie virtual este motenit se motenete i natura sa virtual. Astfel
c, n situaia n care o clas derivat a motenit o funcie virtual i este folosit
drept clas de baz pentru o alt clas derivat, funcia virtual poate fi n
continuare suprascris. Altfel spus, o funcie rmne virtual indiferent de cte
ori este motenit.

Funciile virtuale sunt ierarhizate

83
Deoarece n C++ motenirea este ierarhizat este normal ca funciile virtuale s
fie, de asemenea, ierarhizate. Acestea nseamn c, atunci cnd o clas
derivat nu suprascrie o funcie virtual, este utilizat prima redefinire gsit n
ordinea invers derivrii.

S mai spunem c exist situaii n care programatorul vrea s se


asigure c toate clasele derivate suprascriu o funcie virtual sau
programatorul definete o clas de baz astfel nct s nu permit definirea
unei funcii virtuale n aceast clas. Pentru aceste dou situaii exist
funciile virtuale pure.

Sintaxa unei funcii virtuale pure este:

virtual <Tip> <Nume_funcie> [(<Lista)_de_parametri>)]=0;

O clas care conine cel puin o funcie virtual pur se numete clas
abstract. O clas abstract nu poate fi utilizat pentru crearea de obiecte dar
poate fi utilizat pentru a crea pointeri i referine spre astfel de clase permind
astfel manifestrile polimorfice n timpul execuiei.

2.4 Funcii suprancrcate


O modalitate C++ de realizare a polimorfismului o reprezint suprancrcarea
funciilor (overloading). n C++, dou sau mai multe funcii pot s aib acelai
nume ct timp declaraiile lor de parametri sunt diferite. n aceast situaie se
spune c funciile cu acelai nume sunt suprancrcate iar procesul este
numit suprancrcarea funciilor.
Cnd suprancrcai o funcie trebuie s respectai urmtoarele cerine:
@Listele de parametri ale diferitelor versiuni ale unei funcii trebuie s
difere;
@Versiunile pot diferi i din punct de vedere al tipului returnat; acest lucru
nu este, ns, obligatoriu. Odat specificate versiunile unei funcii respectnd
restriciile de mai sus, compilatorul este n msur s aleag metoda adecvat
unui apel specific.
Avantajele suprancrcrii, nu neaprat n context obiect orientat, pot fi desprinse
i din analiza exemplului de cod C++ de mai jos.

#include <iostream.h>
#include <conio.h>
//functia abs este definita in trei moduri diferite
int abs(int i);
double abs(double d);
long abs(long l);

void main()
{
clrscr();

84
cout<<abs(-10);
cout<<abs(-10.0);
cout<<abs(-10L);
getch();

}
int abs(int i)
{
gotoxy(20,10);cout<<"Varianta int !!! :";
return i<0 ?-i:i;
}
double abs(double d)
{
gotoxy(20,12);cout<<"Varianta double!!! :";
return d<0 ?-d:d;
}

long abs(long l)
{
gotoxy(20,14);cout<<"Varianta long !!! :";
return l<0 ?-l:l;
}

Acest program implementeaz i utilizeaz trei funcii cu acelai nume (abs())


dar diferite prin proprietile listelor de parametri formali. Fiecare returneaz un
mesaj specific i valoarea absolut a argumentului. Numele abs() reprezint
aciunea generic care urmeaz s fie efectuat, compilatorul fiind acela care
alege metoda potrivit tipului de parametru actual asociat cu numele funciei
generice. Este uor de bnuit puternicul impact al suprancrcrii n cazul
programrii generice.

2.5 Funcii inline


Aceste funcii sunt similare macrocomenzilor adresate preprocesoarelor,
compilatorul nlocuind fiecare apel de funcie inline cu corpul acesteia. Funciile
inline sunt destinate s sprijine implementarea eficient a tehnicilor OOP n C++.
Deoarece abordarea OOP necesit utilizarea extensiv a funciilor membre,
desele apeluri de funcii ar putea duce la scderea performanelor programelor.
Pentru funcii al cror cod este redus se poate utiliza specificatorul inline pentru a
evita acest inconvenient. Similaritatea macrocomenzi-funcii inline este doar
aparent. Spre deosebire de macrocomenzi, compilatorul consider funciile
inline ca funcii adevrate.
O funcie membru inline se declar astfel:

inline <Tip><Nume_Funcie>([<Lista de parametri>]);

2.6 Funcii prietene

85
Este posibil s se permit unei funcii care nu este membru al unei clase s aib
acces la membrii privai ai clasei declarnd-o ca funcie prieten a clasei (friend).
Aadar, o funcie prieten are acces la membrii private i protected ai clasei
creia i este prieten. Sintaxa pentru declararea unei funcii prietene este:

friend <Tip> >Nume_funcie>[(<Lista_parametri>)]


Declararea funciei friend se face n interiorul clasei dar implementarea nu este
legat de definirea clasei.
A se vedea i exemplul de mai jos pentru mai multe detalii.

#include<conio.h>
#include <iostream.h>

#define liber 0
#define ocupat 1

//Declarare anticipata clasa


class Clasa2;
class Clasa1
{
//<ocupat> daca o metoda a clasei a scris pe ecran
//<liber> in caz contrar
int stare;
public:
void setare_stare(int val);
friend int ecran_liber(Clasa1 a,Clasa2 b);
};

class Clasa2
{
//<ocupat> daca o metoda a clasei a scris pe ecran
//<liber> in caz contrar
int stare;
public:
void setare_stare(int val);
friend int ecran_liber(Clasa1 a,Clasa2 b);
};

void Clasa1::setare_stare(int val)


{
stare=val;
}

void Clasa2::setare_stare(int val)


{
stare=val;
}

86
int ecran_liber(Clasa1 a, Clasa2 b)
{
if (a.stare ||b.stare)
return 0;
else
return 1;
}

void main()
{
Clasa1 x;
Clasa2 y;
x.setare_stare(ocupat);
y.setare_stare(liber);
if (ecran_liber(x,y))
{
clrscr();
gotoxy(20,12);
cout<<"Ecranul este liber...";
getch();
}
else
{
clrscr();
gotoxy(20,12);
cout<<"Ecranul este ocupat...";
getch();
};
x.setare_stare(liber);
y.setare_stare(liber);
if (ecran_liber(x,y))
{
clrscr();
gotoxy(20,12);
cout<<"Ecranul este liber...";
getch();
}
else
{
clrscr();
gotoxy(20,12);
cout<<"Ecranul este ocupat...";
getch();
};
}

87
2.7 Suprancrcarea operatorilor
Polimorfismul este realizat n C++ i prin suprancrcarea operatorilor. Dup
cum s-a vzut n numeroase exemple, n C++ se pot folosi operatorii >> i <<
pentru a efectua operaii I/O relativ la consol. Aceti operatori pot efectua
aceste operaii suplimentare (tiut fiind faptul c pot funciona i ca operatorii de
shiftare la nivel de bii) deoarece operaiile sunt suprancrcate n fiierul antet
IOSTREAM.H. Cnd un operator este suprancrcat, el capt o semnificaie
suplimentar relativ la o anumit clas fr s-i piard vreunul din nelesurile
iniiale. Majoritatea operatorilor din C++ pot fi suprancrcai, stabilind
semnificaia lor relativ la o anumit clas.
Limbajul C++ permite suprancrcarea numai a operatorilor existeni n limbaj.
Dintre acetia nu pot fi suprancrcai operatorii: . :: ? : .
S mai precizm faptul c, prin suprancrcarea operatorilor nu se poate
schimba n-aritatea, prioritatea sau asociativitatea operatorilor, acestea fiind
elemente predefinite pentru tipuri predefinite i deci ele se vor menine i pentru
tipuri abstracte.
Prin n-aritate nelegem c operatorul este unar sau binar.
Suprancrcarea operatorilor se realizeaz cu ajutorul unor funcii membre sau
prietene speciale. Specificul acestora se afl n numele lor. El se compune din
cuvntul cheie operator i unul sau mai multe caractere care definesc operatorul
care se suprancarc. ntre cuvntul cheie operator i caracterele care definesc
operatorul care se suprancarc se afl cel puin un spaiu alb. Felul n care sunt
scrise funciile operator difer pentru cele de tip membru de cele de tip friend.

2.7.1 Crearea unei funcii operator membru


Funciile operator membru au sintaxa de implementare:

<Tip_returnat> <Nume_clas>::operator # (<Lista_argumente>)


{

//Operaii specifice

Deseori funciile operator returneaz un obiect din clasa asupra creia


opereaz, dar <Tip_returnat> poate fi orice tip valid.

# este o notaie pentru numele operatorului aa cum va fi folosit in program dup


redefinire. Deci, dac suprancrcm operatorul = atunci sintaxa prototipului
funciei membru va fi:

<Tip_returnat> operator =(<Lista_argumente>);

Funciile operator membre au un singur parametru sau nici unul. n cazul n care
au un parametru, acesta se refer la operandul din dreapta al operatorului.
Cellalt operand ajunge la operator prin intermediul pointerului special this.

88
Astfel stnd lucrurile, trebuie s avem grij de eventualitatea ca operandul din
stnga s fie o constant, ceea ce nseamn ca nu mai avem context de apel
pentru operatorul redefinit.
Inivitm cititorul s urmreasc exemplul de mai jos.

#include<conio.h>
#include<iostream.h>

//Clasa complex contine functia operator +


//ca membru
//operatorul + este extins la multimea numerelor complexe
class complex
{
float x,y;
public:
complex(){};
complex(float a,float b)
{
static i;
i++;
clrscr();
cout<<"Lucreaza constructorul...Obiectul->:"<<i;
getch();
x=a;
y=b;
};
void disp_nc();

//prototipul operatorului +
complex operator+(complex &op2);
};

void complex::disp_nc()
{
cout<<x<<"+i*"<<y;
};

//Implementare operator +
//Aceasta sintaxa transforma apelul <ob1+ob2>
//in +(ob2) ob1 fiind accesibil prin pointerul
//special <this>
complex complex::operator+(complex &op2)
{
complex temp;
temp.x=op2.x+x;
temp.y=op2.y+y;
return temp;

89
};

void main()
{
complex tamp1,tamp2;
complex *pod1,*pod2;
complex ob1(10,10),ob2(11,11);
clrscr();
gotoxy(20,10);cout<<"Primul numar complex ->:";
ob1.disp_nc();
getch();
gotoxy(20,11);cout<<"Al doilea numar complex->:";
ob2.disp_nc();
getch();
ob1=ob1+ob2;
gotoxy(20,13);cout<<"Suma numerelor complexe->:";
ob1.disp_nc();
getch();

pod1=new complex(200,200);
pod2=new complex(300,300);
tamp1=*pod1;

clrscr();
gotoxy(20,10);cout<<"Al treilea numar complex ->:";
tamp1.disp_nc();

tamp2=*pod2;
gotoxy(20,11);cout<<"Al patrulea numar complex ->:";
tamp2.disp_nc();

gotoxy(20,14);cout<<"Suma numerelor complexe->:";


tamp1=tamp1+tamp2;
tamp1.disp_nc();
getch();
}

2.7.2 Suprancrcarea operatorilor folosind o funcie friend


Se poate suprancrca un operator relativ la o clas folosind o funcie friend.
Deoarece un prieten nu este membru al clasei, nu are disponibil un pointer de tip
this. De aceea, unei funcii suprancrcate de tip friend operator I se vor
transmite explicit operanzii. Deci, dac suprancrcm un operator unar vom
avea un parametru, dac suprancrcm unul binar vom avea doi parametri.
Dac suprancrcm un operator binar, operandul din stnga este pasat n
primul parametruiar cel din stnga n al doilea parametru.

90
Invitm cititorul s urmreasc utilizarea funciilor friend la suprancrcare n
Exerciiul 6 de la Capitolul aplicativ al prezentului suport de curs.

2.8 Forma general a unui program n C++


Cu toate c stilurile individuale difer, majoritatea programelor n C++ au
urmtoarea form general:

#include
declaraii clase de baz
declaraii clase derivate
prototipuri de funcii nemembre
main()
{
:
}
definiii de funcii ne-membre

De remarcat, totodat, faptul c, n majoritatea proiectelor mari, toate


declaraiile de clase se pun ntr-un fiier antet i sunt incluse n fiecare modul.

91
3 Bazele sistemului I/O n C++
Pe lng faptul c permite sistemul de I/O din C, C++ definete propriul su
sistem I/O orientat pe obiecte. Ca i sistemul de I/O din C, cel din C++ este
complet integrat. Aceasta nseamn c diferitele tipuri de operaii I/O sunt doar
perspective diferite ale aceluiai mecanism. Aceast perspectiv integratoare
asupra operaiilor I/O are la baz, att n C ct i n C++, conceptul de flux
(stream).

3.1 Fluxuri n C i C++


Sistemul de fiiere din C i C++ este proiectat s lucreze cu o mare varietate de
echipamente, care include terminale, drivere de disc, drivere de unitate de
band, etc.

Chiar dac echipamentele difer, sistemul de fiiere din C i C++ le


transform ntr-un instrument logic numit flux (stream).

Toate fluxurile se comport la fel. Deoarece fluxurile sunt independente de


echipamente, o funcie care poate s scrie ntr-un fiier de pe hard poate fi
folosit cu aceeai sintax pentru a scrie la alt dispozitiv. Sistemul de fiiere
C/C++ recunoate dou tipuri de fluxuri:text i binar.

Fluxuri de tip text


Un flux de tip text este o secven de caractere. Standardul ANSI C permite (dar
nu impune) ca un flux de tip text s fie organizat n linii terminate cu un caracter
de linie nou. Totui, caracterul de linie nou din ultima linie este opional,
utilizarea sa fiind determinat de modul de implementare a compilatorului
(Majoritatea compilatoarelor de C/C++ nu ncheie fluxul de tip text cu un caracter
de linie nou. S mai semnalm faptul c, ntr-un flux de tip text pot s apar
anumite transformri cerute de mediul de operare gazd (De exemplu, un
caracter de linie nou poate fi nlocuit cu perechea nceput de rnd-linie nou.
Acesta este motivul pentru care nu exist o relaie biunivoc ntre caracterele
care sunt scrise sau citite i cele de la echipamentul extern.

Fluxuri binare
Un flux binar este o secven de octei ntr-o coresponden biunivoc cu cei de
la echipamentul extern.

Fiiere
n C/C++ un fiier poate s fie: un fiier de pe disc, tastatura, ecranul monitorului,
imprimanta,etc. Un flux se asociaz cu un anumit fiier efectund o operaie de
deschidere. Odat deschis fiierul, este posibil schimbul de date ntre el i
programul utilizator care l-a deschis.
De observat faptul, trivial pentru cunosctori, c nu toate fiierele au aceleai
posibiliti. De exemplu, un fiier de pe disc poate s admit un acces aleator la
datele stocate n el, n timp ce imprimanta nu o poate face. Astfel c, putem
concluziona, pentru claritate:

92
 Pentru sistemul I/O din C/C++ toate fluxurile sunt la fel dar nu i
fiierele.

Dac fiierul admite cereri de poziionare, deschiderea fiierului iniializeaz


pointerul de fiier la o valoare care indic nceputul fiierului. Pe msur ce se
fac operaii de citire/scriere, pointerul de fiier este incrementat corespunztor
naturii operaiei.
Un fiier se disociaz de un flux n urma operaiei de nchidere. Dac este nchis
un fiier deschis n operaii de scriere, coninutul fluxului asociat este scris la
dispozitivul extern (acest proces se numete flushing=golire a fluxului ).
Toate fiierele se nchid automat cnd programul se termin normal. n caz de
blocaj sau dac programul se termin ca urmare a apelului funciei abort()
fiierele nu se nchid.
Cu meniunea c n fiierul antet stdio.h se gsesc structurile de control de tip
FILE, indispensabile pentru lucrul cu fiiere n C, prezentm, n continuare
contextul C++ referitor la sistemul I/O.

3.2 Clasele de baz pentru fluxuri n C++


C++ asigur suportul pentru sistemul su de I/O n fiierul antet IOSTREAM.H. n
acest fiier antet sunt definite dou ierarhii de clase care admit operaii de I/O.
Clasa cu nivelul de abstractizare cel mai nalt se numete streambuf i asigur
operaiile de baz de intrare/ieire. Ca programatori, nu folosii streambuf direct
dect dac vei deriva propriile clase pentru efectuarea operaiilor I/O. A doua
ierarhie pornete cu clasa ios, care accept operaii I/O formatate. Din ea sunt
derivate clasele istream, ostream i iostream. Aceste clase sunt folosite pentru
a crea fluxuri capabile s citeasc, s scrie, respectiv s citeasc/ s scrie date
din/ la echipamentele externe. Clasa ios conine o serie de alte ramuri relativ la
lucrul cu fiiere pe care nu ne propunem s le studiem n cadrul acestui curs.

Fluxuri predefinite n C++


Cnd i ncepe execuia un program C++, se deschid automat patru fluxuri
predefinite, pe care le prezentm n tabelul de mai jos.

Flux Semnificaie Echipament implicit


cin Intrare standard Tastatura
cout Ieire standard Ecran
cerr Ieire standard pentru eroare Ecran
clog Versiune cu memorie tampon pentru Ecran
cerr
Tabelul 15. Fluxurile predefinite C++

Fluxurile cin, cout, cerr corespund fluxurilor stdin, stdout, stderr din C. Implicit,
fluxurile standard sunt folosite pentru a comunica cu consola. ns, n mediile
care admit redirecionarea I/O, fluxurile standard pot fi redirecionate spre alte
echipamente sau fiiere.

93
I/O formatate n C++
Sistemul de I/O din C++ v permite s formatai operaiile I/O, aa cum se
ntmpla i n cazul utilizrii funciilor C pentru operaii I/O, precum: printf,
cprintf, scanf,etc. De exemplu, se poate specifica mrimea unui cmp, baza
unui numr, numrul de cifre dup punctul zecimal,etc. Operatorii din C++
utilizai pentru introducerea informaiilor de formatare sunt >> i <<.
Exist dou ci nrudite, dar conceptual diferite, prin care se pot formata datele.
n primul rnd, putem avea acces direct la diferii membri ai clasei ios. n al
doilea rnd, putem folosi funcii speciale numite manipulatori, care pot fi incluse
n expresii de I/O.
Prezentm, n continuare modul de utilizare a manipulatorilor de formate, datorit
accesibilitii mai mari a acestora.
Manipulatorii standard sunt prezentai n tabelul de mai jos.

Manipulator Exemplu de folosire Efect


dec cout<<dec<<intvar; Convertete ntregi n cifre
zecimale; corespunde
formatului %d din C
endl cout<<endl Trimite o nou linie n
ostream i descarc
bufferul
ends cout<<ends Insereaz un caracter nul
ntr-un flux
flush cout<<flush Descarc bufferul fluxului
ostream
hex cout<<hex<<intvar; Conversie hexazecimal
cin>>hex>>intvar corespunztoare
formatului %x din ANSI C
oct cout<<oct<<intvar; Conversie octal (formatul
cin>>oct>>intvar; %o din C)
resetiosflags(long cout<<resetioflags(ios::dec); Reiniializeaz biii de
f) formatare specificai de
argumentul ntreg de tip
long
setbase(int baza) cout<<setbase(10); Stabilete baza de
cin>>setbase(8); conversie la argumentul
ntreg (trebuie s fie
0,8,10 sau 16). Valoarea 0
este baza implicit.
setfill(int ch) cout<<setfill(.); Stabilete caracterul
cin>>setfill( ); folosit pentru completarea
cmpurilor de mrime
specificat
setiosflags(long f) cout<<setiosflags(ios::dec); Stabilete biii de
cin>> setiosflags(ios::hex); formatare specificai de

94
argumentul ntreg de tip
long
setprecision(int p) cout<<setprecision(6); Stabilete precizia
cin>>setprecision(10); conversiei n virgul
mobil la numrul
specificat de zecimale
setw(int w) cout<<setw(6)<<var; Stabilete mrimea unui
cin>>setw(24)>>buf cmp la numrul specificat
de caractere
ws cin ws; Elimin spaiile libere din
fluxul de intrare
Tabelul 16. Manipulatori de formatare a operaiilor I/O n C++

Toi aceti manipulatori au prototipul n fiierul antet iomanip.h.

Pentru a utiliza manipulatorii setiosflags i resetiosflags trebuie cunoscui


indicatorii de formatare din tabelul de mai jos.

Nume indicator Ce efect are utilizarea indicatorului


ios :: skipws Elimin spaiile goale din intrare
ios :: left Aliniaz ieirea la stnga n interiorul limii cmpului
ios :: right Aliniaz ieirea la dreapta
ios :: scientific Folosete notaia tiinific pentru numerele n virgul
mobil.
ios :: fixed Folosete notaia zecimal pentru numere n virgul mobil
ios :: dec Folosete notaia zecimal pentru ntregi
ios :: hex Folosete notaia hexazecimal pentru ntregi
ios :: oct Folosete notaia octal pentru ntregi
ios :: uppercase Folosete litere mari pentru ieire
ios :: showbase Indic baza sistemului de numeraie n cadrul ieirii (prefixul
0x pentru hexazecimal i prefixul 0 pentru octal
ios :: showpoint Include un punct zecimal pentru ieiri n virgul mobil
ios :: showpos Include i semnul + la afiarea valorilor pozitive
ios :: unitbuf Golete toate fluxurile dup inserarea caracterlor ntr-un flux
Tabelul 16. Indicatori de formatare a operaiilor I/O n C++

Notaia ios :: <Nume_indicator> este folosit pentru a identifica indicatorul ca


pe un membru al clasei ios.
Exemplificm cele spuse mai sus prin codul C++ de mai jos.

#include<iostream.h>
#include<iomanip.h>
#include<conio.h>
#include<stdio.h>
void main()
{

95
double nr;
clrscr();
gotoxy(10,6);
nr=7./3.;
gotoxy(5,6);
cout<<"Afisare numar in virgula mobila/ format implicit...";
gotoxy(10,7);
cout<<nr;

gotoxy(5,9);
cout<<"Afisare numar in virgula mobila/ cu precizia specificata...";
gotoxy(10,10);
cout<<setprecision(10)<<nr;
gotoxy(5,12);
cout<<"Afisare numar in virgula mobila/ format virgula fixa...";
gotoxy(10,13);
cout.setf(ios::fixed);
cout<<setprecision(10)<<nr;

gotoxy(5,15);
cout<<"Afisare numar in virgula mobila/ format virgula fixa...";
gotoxy(10,16);
cout.setf(ios::scientific);
cout<<setprecision(10)<<nr;

gotoxy(5,18);
cout<<"Afisare numar in virgula mobila/ format virgula fixa...";
gotoxy(10,19);
cout.setf(ios::scientific|ios::showpos);
cout<<setprecision(10)<<nr;

getch();
}

Fiiere utilizator n C++


Chiar dac abordarea operaiilor I/O din C++ formeaz un sistem integrat,
operaiile cu fiiere (altele dect cele predefinite), sunt suficient de specializate
pentru a fi necesar s la discutm separat.
Pentru a efectua operaii I/O cu fiiere conform paradigmei C++, trebuie s
includei n programul Dvs. fiierul antet FSTREAM.H. Acesta definete mai
multe clase, printre care ifstream, ofstream i fstream. Aceste clase sunt
derivate din istream i, respectiv, din ostream la care ne-am referit i mai sus.

Deschiderea i nchiderea unui fiier


Un fiier se deschide n C++ legndu-l de un flux. nainte de a putea s
deschidei un fiier, trebuie, pentru nceput, s avei un flux. Exist trei tipuri de

96
fluxuri: de intrare, de ieire i de intrare/ieire. Pentru a crea un flux de intrare,
trebuie s-l declarai ca fiind din clasa ifstream. Pentru a crea un flux de ieire,
trebuie s-l declarai ca fiind din clasa ofstream. Fluxurile care efectuiaz att
operaii de intrare ct i operaii de ieire, trebuie declarate ca fiind din clasa
fstream. Odat declarat fluxul, o modalitate de a-i asocia un fiier extern o
reprezint utilizarea funciei open() avnd prototipul:

void open(const char *nume_fisier , int mod, int acces=filebuf::openprot);

nume_fisier este un nume extern de fiier care poate include i


specificarea cii de acces.
Valoarea parametrului mod determin modul de deschidere a fiierului.
Parametrul mod poate avea una sau mai multe din valorile prezentate n tabelul
de mai jos.

Nume mod Operaie


ios::app Adaug date n fiier
ios::ate Cnd se deschide pentru prima dat, opereaz
poziionarea n fiier la sfritul fiierului (ate nseamn la
sfrit)
ios::binary Deschide fiierul n mod binar, inhibnd interpretarea
caracterelor <CR> <LF>
ios::in Deschide fiierul pentru citire
ios::nocreate Nu efectueaz deschiderea fiierului dac acesta nu exist
deja
ios::noreplace Dac fiierul exist, ncercarea de a-l deschide pentru ieire
eueaz, cu excepia cazului n care ios::app sau ios::ate
sunt operate
ios::out Deschide fiierul pentru scriere
ios:trunc Trunchiaz fiierul dac el exist deja
Tabelul 17. Valorile parametrului care stabilete modul de deschidere a
unui fiier

Putei specifica mai mult de un mod de lucru pentru un fiier, folosind operatorul
pe bii SAU cu modurile respective. De exemplu, pentru deschiderea unui fiier
pentru ieire i poziionarea pointerului la sfritul lui se folosesc modurile
ios::out i ios::ate astfel:

ofstream oflux(o_fisier,ios::out | ios::ate);

ceea ce ne arat al doilea procedeu de deschidere a unui fiier, utiliznd


constructorul clasei ofstream sau, de ce nu, ifstream, dac este cazul.
Pentru a nchide un fiier, folosii funcia membru close(). Aceast funcie nu
preia nici un parametru i nu returneaz nici o valoare. De analizat utilizarea
funciei close() n exemplele care vor urma.

97
Scrierea i citirea fiierelor text
Sunt dou operaii foarte uoare, realizate apelnd la operatorii >> i << ntr-un
mod asemntor operaiilor referitoare la consola sistemului, cu deosebirea c n
loc s folosii cin i cout apelai la un flux legat de un fiier . Codul de mai jos
arat cum poate fi afiat pe ecranul monitorului coninutul unui fiier text.

#include <fstream.h>
#include <stdlib.h>
#include<conio.h>

//Functia principala a programului citeste linia de comanda a programului


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

// Linia de comanda a programului trebuie sa contina doi parametri


if (argc!=2)
{
cerr<<"Mod de utilizare : lisfis <nume fisier CPP>\n";
exit(0);
}

// Deschidere fisier text de nume specificat in argv[1]


ifstream in(argv[1],ios::in);
if (!in)
{
cerr<<"Fisierul nu poate fi deschis!";
exit(0);
}

char c;
clrscr();
while (in.get(c))
{
if (wherey()>20)
{
gotoxy(20,24);
cout<<"Press any key to continue...";
getch();
clrscr();
}
cout<<c;
}
in.close();
}

I/O n fiiere de tip binar

98
Exist dou modaliti de a scrie i citi date binare ntr-un fiier. Prima
modalitate se refer la utilizarea funciilor get() i put(). Aceste funcii sunt
orientate pe octei, ceea ce nseamn c get() va citi un octet de date iar put() va
scrie un octet de date.
Funcia get() are mai multe forme; o prezentm, n continuare, mpreun cu
omoloaga ei put(), pe cea mai des folosit:

istream &get(char &ch);


ostream &put(char ch);

Funcia get() citete un singur caracter din streamul asociat i memoreaz


valoarea sa n ch. De asemenea, se mai observ c funcia returneaz o
referin ctre flux. Funcia put() scrie ch n flux i returneaz fluxului o referin.
Ca un exemplu de utilizare a funciilor get() i put() prezentm codul de mai jos,
care realizeaz copierea unui fiier n altul. Dac numele executabilului asociat
acestui cod este copyf, atunci sintaxa de lansare n execuie a programului este:

copyf <fisier_sursa> <fisier_destinatie>

#include<stdlib.h>
#include <fstream.h>
void main(int argc, char *argv)
{
//Verific daca sunt suficiente argumente
if(argc<3)
{
cerr<<"Mod de utilizare : filecopy <fisier sursa> <fisier destinatie>\n";
exit(0);
}
//Deschide fisierul de intrare si il conecteaza la fluxul ins
ifstream ins(argv[1]);
if(!ins)
{
cerr<<"Nu pot deschide fisierul sursa:"<<argv[1];
exit(1);
}
//Deschide fisierul de iesire si il conecteaza la fluxul outs
ofstream outs(argv[2]);
if(!outs)
{
cerr<<"Nu pot deschide fisierul sursa:"<<argv[2];
exit(1);
}
//Citeste din sursa si scrie in destinatie
char c;
while(ins.get(c) && outs) outs.put(c);

99
}
A doua modalitate de a citi i scrie blocuri de date n binar este folosirea funciilor
din C++ read() i write(). Prototipurile lor sunt:

istream &read(unsigned char *buf, int numar);


ostream &write(const unsigned char *buf, int numar);

Funcia read() citete numar octei din fluxul asociat i l pune n buffer-ul indicat
de buf . Funcia write() scrie n fluxul asociat numar octei citii din buffer-ul spre
care indic buf.

Detectarea EOF
Putei s detectai sfritul fiierului folosind funcia membru eof() ,care are acest
prototip:

int eof();

Ea returneaz o valoare nenul cnd a fost atins sfritul fiierului; altfel,


returneaz zero. Utilizarea funciei eof() i alte elemente legate de lucrul cu
fiiere, prezentm n codul de mai jos, care realizeaz afiarea coninutului unui
fiier att n hexazecimal ct i n cod ASCII, atunci cnd codul asociat este
printabil.

#include <fstream.h>
#include <ctype.h>
#include <iomanip.h>
#include <stdlib.h>
#include<conio.h>
void main(int argc,char *argv[])
{
if (argc!=2)
{
cerr<<"Mod de utilizare : lishex <nume fisier CPP>\n";
exit(0);
}
ifstream in(argv[1],ios::in|ios::binary);
if (!in)
{
cerr<<"Fisierul nu poate fi deschis!";
exit(0);
}
register int i,j;
int count=0;
char c[16];
cout.setf(ios::uppercase);
clrscr();

100
while(!in.eof())
{
for(i=0;i<16 && !in.eof();i++)
{
in.get(c[i]);
}
if (i<16) i--;
for(j=0;j<i;j++)
cout<<setw(3)<<hex<<(int) c[j];
for(;j<16;j++)
cout<<"\t";
for(j=0;j<i;j++)
if(isprint(c[j])) cout<<c[j];
else cout<<".";
cout<<endl;
count++;
if(count==16)
{
count=0;
cout<<"Press ENTER to continue!";
getch();
clrscr();
cout<<endl;
}
}
in.close();
}

Accesul aleator n fiiere


n sistemul de I/O din C++, accesul aleator se efectueaz folosind funciile
seekg() i seekp(). Formele lor cele mai uzuale sunt:

istream &seekg(streamoff offset, seek_dir origine);


ostream &seekp(streamoff offset, seek_dir origine);

streamoff este un tip definit n IOSTREAM.H, capabil s conin cea mai mare
valoare valid pe care o poate avea offset, iar seek_dir este o enumerare care
are aceste valori:

ios::beg
ios::cur
ios::end

Sistemul de I/O din C++ opereaz cu doi pointeri asociai unui fiier. Unul este
pointerul de get , care specific unde va aprea urmtoarea operaie de intrare
n fiier. Cellalt este pointerul de put i specific unde va avea loc urmtoarea

101
operaie de ieire. Dup fiecare operaie de intrare sau ieire, pointerul
corespunztor este avansat automat, secvenial. Dar, folosirea funciilor seekg()
i seekp() permite un acces nesecvenial la datele din fiier.
seekg() i seekp() deplaseaz pointerul de nregistrare cu offset octei fa de
origine.

Cu meniunea c lucrul cu fiiere n C++ are nenumrate alte faete pentru a


cror prezentare nu dispunem de timpul i spaiul necesar, ncheiem aceast
scurt excursie n problematica fiierelor. n fine, pentru curioi facem i
precizarea c, nsui btrnul C are propria filozofie, extrem de puternic, n
ceea ce privete lucrul cu fiiere.

102
3 Programare generic n C++
n programarea profesional apar nenumrate situaii n care reutilizarea codului
presupune o soluie de un anumit tip pentru o problem dat. Situaia la care ne
referim n aceast seciune este, potenial vorbind, urmtoarea: Ce putem face
pentru a comprima codul surs n situaia n care structuri de date, diferite
ca tip, suport prelucrri similare.
Soluia acestei probleme de stil de programare o reprezint programarea
generic. Exprimndu-ne n termenii limbajului C, o funcie generic definete
un set general de operaii care vor fi aplicate unor tipuri de date diferite.
Ca un exemplu, o soluie generic pentru modelarea unei stive este un pretext
ideal pentru precizarea ideilor principale ale programrii generice.
Altfel spus, dac dorim o stiv, n care, de la caz la caz, s putem pstra numere
ntregi, numere reale sau iruri de caractere (deci tipuri de date diferite),
operaiile fiind aceleai ( push() i pop() ), este clar c ne aflm n situaia n
care avem nevoie de suport pentru scrierea de cod cu proprieti generice.
Dac n Pascal programarea generic se baza pe tipuri procedurale i
programarea la nivel de octet, n C++ exist suport evoluat pentru programare
generic, sub forma abloanelor. Cu un ablon, n C++ se poate crea o funcie
generic sau o clas generic.

Funcii TEMPLATE
O funcie template este o funcie ablon, avnd unul sau mai muli parametri
formali de un tip generic. n funcie de nevoile de utilizare a acestei funcii,
compilatorul genereaz funcii propriu-zise, nlocuind tipul generic cu un tip
concret. Tipul concret poate fi orice tip fundamental, derivat sau clas predefinit.
Considerm un exemplu. Fie funcia max(x,y) care returneaz valoarea maxim
a argumentelor sale. Tipul variabilelor x i y trebuie, obligatoriu, specificat n
momentul compilrii. Soluia clasic const n redefinirea (over-loading) funciei
max pentru fiecare tip al argumentelor x i y (de observat i cele spuse la
paragraful 2.2 relativ la funcii suprancrcate n C++).
Trebuie, aadar, s definim mai multe versiuni ale funciei max.

int max(int x, int y)


{
return (x>y) ? x : y;
}

float max(float x, float y)


{
return (x>y) ? x : y;
}

103
Mecanismul template permite definirea o singur dat a ablonului de funcii,
dup care se genereaz automat funciile propriu-zise n concordan cu
necesitile de utilizare, dar ,evident, n faza de compilare.

Sintaxa la specificare este:

template <class Nume_tip_generic_1 [,class Nume_tip_generic_n]>


Nume_ablon
definiie_ablon

De precizat urmtoarele:
@Caracterele < i > fac parte din sintaxa obligatorie.
@Lista de parametri formali ai unei funcii ablon trebuie s utilizeze toate
tipurile de date generice.
@n cazul funciilor template nu se fac conversii
@Funcia care are acelai nume i acelai numr de parametri cu o funcie
ablon se numete caz exceptat (Suprancrcarea explicit este prioritar).

Sintaxa la utilizare este:

Nume ablon (Expresie_1[, ,Expresie_n]);

Prezentm, n continuare, definiia funciei ablon max , urmat de o secven


client de utilizare.

template <class T>


T max(T x, T y)
{
return (x>y) ? x : y;
}

#include <conio.h>
#include<iostream.h>

//Definire sablon functie


template<class T>
T max(T x,T y)
{
return(x>y) ? x:y;
}
void main()
{
int i,j;
float k,l;

104
clrscr();
i=10;
j=2;
k=13;
l=-7;

//Exemple de utilizare sablon


gotoxy(20,10);cout<<"Apel max cu parametri variabili de tip float..."<<max(k,l);
gotoxy(20,12);cout<<"Apel max cu parametri variabili de tip int ..."<<max(i,j);
gotoxy(20,13);cout<<"Apel max cu parametri valoare float ..."<<max(13.,-7.);
getch();
}

Prezentm, totodat, un exemplu de funcie generic pentru compararea unor


date dup valoarea unei chei ncapsulate n aceste date.

#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <iostream.h>
#include <ctype.h>

//Definirea unei <functii generice> pentru compararea


//unor date dupa valoarea unei chei incapsulate
//in aceste date
template <class T>
int comp(T i1,T i2)
{
if (i1.key<i2.key) return -1;
if (i1.key==i2.key) return 0;
if (i1.key>i2.key) return 1;
};

//Structura aleasa pentru exemplificare


//cheia generica incapsulata este campul <key>
struct tpers
{
char np[30];
int key;
};

//Instantiere <struct tpers>


struct tpers tam,pers[50];

void main()
{

105
clrscr();
int i=0;

//***************************************
//Citire persoane de la tastatura
do
{
gotoxy(20,12);
cout<<"Numele persoanei:";clreol();
cin>>pers[i].np;
gotoxy(20,13);
cout<<"Matricola:";clreol();
cin>>pers[i].key;
gotoxy(20,14);
cout<<"Mai aveti(D,N):";
i++;
}

//***************************************
//Listare persoane pe ecranul monitorului
//in ordinea citirii de la tastatura
while(toupper(getch())!='N');
clrscr();
cout<<"Listare persoane in ordinea citirii de la tastatura..."<<endl;
cout<<"_______________________________________________"<<endl;
for(int j=0;j<i;j++)
{
if (wherey()>10)
{
cout<<"______________________________________________"<<endl;
cout<<"Pentru continuare apasati o tasta..."<<endl;
getch();
clrscr();
cout<<"Listare persoane in ordinea citirii de la tastatura..."<<endl;
cout<<"_______________________________________________"<<endl;
};
cout.width(30);cout.setf(ios::left);
cout<<pers[j].np<<" "<<pers[j].key<<endl;
};
getch();
//*************************************
//Sortare persoane
int sortat;
do
{
sortat=1;

106
for(int j=0;j<i-1;j++)
{
switch(comp(pers[j],pers[j+1]))
{
case 1: {
tam=pers[j];
pers[j]=pers[j+1];
pers[j+1]=tam;
sortat=0;
};
};
};
}
while(!sortat);

//****************************************
//Listare persoane dupa sortare in ordinea
//crescatoare a matricolelor
clrscr();
cout<<"Listare persoane dupa sortare........................."<<endl;
cout<<"____________________________________________"<<endl;
for(int k=0;k<i;k++)
{
if (wherey()>10)
{
cout<<"_____________________________________________"<<endl;
cout<<"Pentru continuare apasati o tasta..."<<endl;
getch();
clrscr();
cout<<"Listare persoane dupa sortare........................."<<endl;
cout<<"______________________________________________"<<endl;
};
cout.width(30);cout.setf(ios::left);
cout<<pers[k].np<<" "<<pers[k].key<<endl;
};
getch();
}

Clase TEMPLATE
O clas template definete un ablon pe baza cruia se pot genera clase
propriu-zise. Din acest motiv, o clas template se mai numete i clas generic
, clas generator sau metaclas.

Astfel c, o clas template devine o clas de clase, reprezentnd cel mai


nalt nivel de abstractizare admis de programarea obiect orientat.

107
n cadrul clasei ablon se pot declara atribute informaionale de un tip ambiguu,
care sunt particularizate n cadrul clasei generat pe baza ablonului. Evident, i
n acest caz, generarea se face n faza de compilare n concordan cu cerinele
clientului.
Sintaxa la specificarea clasei:

template <class T>


class nume_clas
{
:
};

Sintaxa la implementarea funciilor membre ale unei clase template:

template <class T> Tip returnat nume_clasa <T>::nume_funcie()


{
:
};

Pentru mai mult claritate prezentm i exemplul de mai jos.

#include <iostream.h>
#include <stdlib.h>
#include <conio.h>

const int SIZE = 10;

//***************************************
//Definire clasa matrice generica
template <class ATip>
class genmat
{
ATip a[SIZE];
public:
genmat();
ATip &operator [ ](int i); //Suprancrcare operator [ ]
};

//***************************************
//Implementare constructor clasa generica
template <class ATip> genmat<ATip>::genmat()
{
register int i;
for(i=0;i<SIZE;i++)
a[i]=i;
};

108
//***************************************
//Implementare supraincarcare operator [ ]
template <class ATip> ATip &genmat<ATip>::operator[ ](int i)
{
if(i<0 ||i>SIZE-1)
{
cerr<<"Valoare indice eronata...";
getch();
exit(1);
};
return a[i];
};

//***************************************
//Functia principala
void main()
{
genmat<int> intob;
genmat<double> doubob;
int i;
clrscr();
cout<<"Matrice de intregi..."<<endl;
for(i=0;i<SIZE;i++)
intob[i]=i;
for(i=0;i<SIZE;i++)
cout<<intob[i]<<endl;
getch();
clrscr();
cout<<"Matrice de reali dubla precizie..."<<endl;
for(i=0;i<SIZE;i++)
doubob[i]=(double)i/3;
for(i=0;i<SIZE;i++)
cout<<doubob[i]<<endl;
getch();
clrscr();
intob[100]=100;
};

Tot pentru exemplificare s considerm i o situaie deosebit de simpl. Ni se


cere s construim o clas template corespunztoare conceptului de stiv, din
care, ulterior, s se poat concretiza clase care simuleaz stiva pentru tipuri de
date diferite.

//Clasa sablon CSTack


template <Class T>

109
class Cstack
{
T * v; //pointer la varful stivei
T * p; //pointer la pozitia curenta din stiva
int dim; //dimensiunea stivei
public:
Cstack(int sz)
{
v=p=new T [dim=sz]; //alocare dinamica de memorie pentru p i v
}
~Cstack()
{
delete [ ] v;
}
void push(T a)
{
*p++=a;
};
T pop()
{
return *-p
}
}

Dup ce o astfel de clas template a fost declarat i definit, se poate trece


deja la instanierea de obiecte. Singura deosebire fa de folosirea unei clase
obinuite const n faptul c trebuie specificat tipul concret care nlocuiete tipul
generic T. Ca un exemplu, s instaniem un obiect stiv (CStack) , n care ncap
maximum 100 elemente de tip char.

CStack<char> sc(100);

n acest caz, compilatorul genereaz clasa ce rezult prin nlocuirea lui T cu


char, dup care instaniaz obiectul sc. Constructorul acestuia primete ca
argument valoarea 100. Pentru mai multe detalii urmrii exemplul de mai jos.

#include <iostream.h>
#include <conio.h>

// Definirea clasei stack. Se vede c instanele ei nu sunt protejate fa de


//excepii.
//Despre excepii urmeaz s discutm
template <class T>
class CStack
{
T *v;

110
T *top;
int dims;
public:
CStack( int sz) //constructor
{
v=top=new T[dims=sz];
}

~CStack() //destructor
{
delete [ ] v;
}

void push(T a) //Functia de inserare in stiva


{
*top++=a; //Notatie prescurtata echvalenta cu *top=a; top++
}

T pop()
{
return *--top; //Notatie prescurtata echibvalenta cu - -top; return *top
}
};

//Functia principala
void main()
{
int i;
//Primul exemplu de instantiere a stivei generice ;numere ntregi
CStack<int> st1(20);

//ncarcare stiva
for (i=0;i<=9;i++)
{
st1.push(i);
}

//Vizualizare continut stiva


clrscr();
for (i=0;i<=9;i++)
{
gotoxy(35, wherey()+1);
cout<<st1.pop()<<"*****";
}
getch();

111
//Al doilea exemplu de instantiere a stivei generice; caractere, ncepand cu A
CStack<char> st2(20);

//ncarcare stiva
for (i=65;i<75;i++)
{
st2.push((char) i);
}

//Vizualizare continut stiva


clrscr();
for (i=0;i<10;i++)
{
gotoxy(35, wherey()+1);
cout<<st2.pop()<<"*****";
}
getch();
}

112
4 Tratarea excepiilor
Programatorii adevrai trebuie s ia n calcul i posibilitatea de a crea programe
robuste, care fac fa att cerinelor specificate dar nerafinate suficient, ct i
cerinelor nespecificate dar formulate de utilizator, din diverse motive.
Programele care au aceste caliti se numesc robuste.
n programarea clasic soluia acestei probleme se putea numi, destul de exact
spus, programare defensiv. Seamn puin cu conducerea preventiv din
oferie dac ne gndim c programnd defensiv, n fond punem rul nainte,
deci nu ne bazm pe cumsecdenia i buna pregtire a utilizatorului.
Pentru a face fa cerinelor legate de problema tratrii excepiilor (aa se
numesc n jargon profesional erorile care apar n timpul execuiei programelor)
anumite limbaje de programare ofer suport adecvat. A include aici limbaje
precum Delphi, C++, Java, Visual C.
Nu toate compilatoarele de C++ ofer suport, dar standardul ANSI C++ cere
acest lucru n mod explicit. Compilatoarele din familia Borland incepnd cu
versiunea 4.0 ofer acest suport.
Esenialul din punctul de vedere al programatorului C++ este ca el s-i formeze
abilitatea de a scrie n jurul aplicaiilor cod C++ care ndeplinete funcia de
handler de excepii.
Suportul sintactic C++ pentru tratarea excepiilor se rezum la trei cuvinte cheie,
a cror semantic preliminar o prezentm n Tabelul xxxxx.

Cuvntul cheie Semnificaie


try Delimiteaz o poriune de cod n care se instituie
controlul sistemului asupra excepiilor n timpul rulrii.
throw Lanseaz o excepie de un anumit tip
catch Capteaz o excepie lansat
Tabelul 18 Cuvintele cheie ale limbajului C++ referitoare la tratarea excepiilor

Forma de baz a tratrii excepiilor


Aadar, atunci cnd programele dumneavoastr efectueaz prelucrarea
excepiilor, trebuie s includei n cadrul unui bloc try instruciunile pe care dorii
s le monitorizai n vederea unei excepii. Dac execuia unei instruciuni se
termin cu o eroare, trebuie s lansai o eroare corespunztoare aciunii funciei
n care se afl instruciunea. Programul plaseaz instruciunea throw n cadrul
blocului try-catch. Forma generalizat a blocului care capteaz i trateaz
erorile este:

try{
//blocul try
//if(eroare) throw valoare_excepie;
}
catch (Tip_excepie Nume_variabil ){
//Prelucrarea excepiei
}

113
n cadrul acestei forme generalizate, valoarea valoare_excepie lansat trebuie
s corespund tipului Tip_excepie .

Scrierea unui handler de excepii simplu


Pentru a nelege mai bine semantica unui handler de excepii, studiai
programul de mai jos.

#include <iostream.h>
void main()
{
cout<<"Start"<<endl;
try
{
cout<<"In interiorul blocului try"<<endl;
throw 100;
cout<<"Nu se va executa";
}
catch (int i)
{
cout<<"Am captat o excepie --valoarea este:";
cout<<i <<endl;
}
cout<<"Sfarsit";
};

Programul de mai sus implementeaz un bloc try-catch simplu. n loc s se


atepte ca programul s eueze datorit unei erori, se utilizeaz instruciunea
throw pentru lansarea erorii prezumtive. Dup ce blocul try lanseaz eroarea,
blocul catch o capteaz i prelucreaz valoarea transmis de instruciunea
throw. Este evident i din acest exemplu c mecanismul try-throw-catch ofer
suport pentru rezolvarea problemei tratrii excepiilor dar nu rezolv de la sine
aceast problem. Altfel spus, tratarea corect a excepiilor unui program
este o problem de atitudine ca proiectant i ca programator.

Lansarea excepiilor cu o funcie din cadrul blocului try


Atunci cnd programele apeleaz funcii din cadrul blocurilor try , C++ va
transmite excepia aprut ntr-o astfel de funcie n afara funciei dac nu exist
un bloc try n interiorul funciei.
Exemplul de mai jos arat cum se petrec lucrurile ntr-o astfel de situaie.

#include <iostream>
void XHandler(int test)
{
cout<<"Inauntrul functiei XHandler, test are
valoarea:"<<test<<endl;
if(test) throw test;

114
};

void main()
{
cout<<"Start:"<<endl;
try
{
cout<<"Inauntrul blocului try"<<endl;
XHandler(1);
XHandler(2);
XHandler(0);
}
catch(int i)
{
cout<<"Am captat o exceptie. Valoarea este:";
cout<<i<<endl;
};
cout<<"Sfarsit";
};

Plasarea unui bloc try intr-o funcie


Am vzut cum apare un bloc try n funcia principal a unui program. C++
permite blocuri try i n alte funcii ale unui program diferite de funcia principal.
Atunci cnd se plaseaz un bloc try ntr-o funcie C++ reiniializeaz blocul de
fiecare dat cnd intrai se intr n acea funcie. Programul urmtor ilustreaz
cele spuse.

#include <iostream.h>
void XHandler(int test)
{
try
{
if(test) throw test;
}
catch(int i)
{
cout<<"Am captat exceptia nr.: "<<i<<endl;
}
};
void main()
{
cout<<"Start: "<<endl;
XHandler(1);
XHandler(2);
XHandler(0);
XHandler(3);
cout<< "Sfarsit";

115
};

Un comentariu pe marginea celor prezentate pn acum ar fi urmtorul: o


instruciune catch se execut numai dac programul lanseaz o excepie n
cadrul blocului try situat imediat nainte. n caz c o astfel de excepie nu se
lanseaz blocul catch va fi ignorat.

Utilizarea mai multor instruciuni catch cu un singur


bloc try
Pe msur ce tratrile excepiilor devin tot mai complexe, uneori este necesar i
posibil ca un singur bloc try s lanseze excepii de mai multe tipuri. n cadrul
programelor dumneavoastr putei construi un handler de excepii astfel nct s
accepte captarea mai multor excepii. ntr-o astfel de situaie sintaxa general
este:

try
{
//instruciuni
}
catch (tip1)
{
//tratare excepie 1
}
catch(tip2)
{
//tratare excepie 2
}
:
catch(tipn)
{
//tratare excepie n
}

Cu acest amendament sintactic deducem c instruciunile catch pot capta orice


tip returnat, nu numai tipurile de baz acceptate de C++. Acest "fenomen" este
ilustrat n codul de mai jos.

#include <iostream.h>
void XHandler(int test)
{
try
{
if(test==0)
throw test;
if(test==1)
throw "Sir de caractere";

116
if(test==2)
throw 121.25;
}
catch(int i)
{
cout<<"Am captat exceptia #:"<<i<<endl;
}
catch(char *sir)
{
cout<<"Am captat exceptia de tip sir de
caractere:"<<sir<<endl;
}
catch(double d)
{
cout<<"Am captat exceptia #:"<<d<<endl;
}
};

void main()
{
XHandler(0);
XHandler(1);
XHandler(2);
cout<<"Sfarsit";
};

Blocuri catch generice (utilizarea operatorului puncte de


suspensie)
Programele scrise de dumneavoastr pot capta excepii din cadrul mai multor
blocuri try (de exemplu un bloc try care incapsuleaza mai multe functii care
lanseaza exceptii diferite din blocuri try diferite sau s utilizeze mai multe
instruciuni catch ntr-un singur bloc try. C++ permite, de asemenea, utilizarea
operatorului puncte de suspensie () pentru a capta orice tip de eroare care
apare ntr-un singur bloc try. Sintaxa care permite captarea tuturor erorilor care
apar ntr-un bloc try este prezentat mai jos.

try
{
//Instructiuni
}
catch()
{
//tratarea exceptiei
}

117
Pentru exemplificare propun codul de mai jos.

#include <iostream.h>
void XHandler(int test)
{
try
{
if(test==0)
throw test;
if(test==1)
throw 'a';
if(test==2)
throw 121.25;
}
catch()
{
cout<<"Am captat o exceptie"<<endl;
}
};

void main()
{
cout<<"Start:"<<endl;
XHandler(0);
XHandler(1);
XHandler(2);
cout<<"Sfarsit";
};

Evident, prelucrrile din cadrul blocului catch generic trebuie s fie independente
de tipul erorii.
Mecanismul captrii excepiilor explicite poate fi combinat cu mecanismul
excepiilor generice ca n exemplul de mai jos.

#include <iostream.h>
void XHandler(int test)
{
try
{
if(test==0)
throw test;
if(test==1)
throw 'a';
if(test==2)
throw 121.25;
}
catch(int i)

118
{
cout<<"Am captat o exceptie de tip intreg"<<endl;
}
catch()
{
cout<<"Am captat o exceptie generica"<<endl;
}
};

void main()
{
cout<<"Start:"<<endl;
XHandler(0);
XHandler(1);
XHandler(2);
cout<<"Sfarsit";
};

Restrictionarea exceptiilor
Pe msur ce programele dumneavoastr devin mai complexe, ele vor apela
frecvent funcii din cadrul unui bloc try. Atunci cnd programele dumneavoastr
apeleaz funcii dintr-un bloc try, putei restriciona tipurile de excepii pe care
funcia apelat le poate lansa. De asemenea putei preveni lansarea oricrei
excepii dintr-o anumit funcie.

Sintaxa pentru restricionare este:

tip_returnat nume_functie(lista_arg) throw(lista_tipuri )


{
//Cod functie
}

Sintaxa care inhib lansare oricrei excepii este:

tip_returnat nume_functie(lista_arg) throw()


{
//Cod functie
}

Este bine s subliniem c atunci cnd declarai o funcie cu clauza throw ea


poate s lanseze doar acele tipuri precizate n list. Dac funcia lanseaz orice
al tip programul este abortat.
Un exemplu n continuare.

119
#include <iostream.h>
void XHandler(int test) throw(int, char, double)
{
if(test==0)
throw test;
if(test==1)
throw 'a';
if(test==2)
throw 121.25;
}

void main()
{
cout<<"Start:"<<endl;
try
{
XHandler(0);
}
catch(int i)
{
cout<<"Am captat un intreg"<<endl;
}
catch(char c)
{
cout<<"Am captat un caracter"<<endl;
}
catch(double d)
{
cout<<"Am captat un double"<<endl;
}
cout<<"Sfarsit";
};

Relansarea unei excepii


n anumite situaii poate fi necesar s se relanseze o excepie din interiorul unui
handler de excepii. Dac relansai o excepie, C++ o va transmite unui bloc try
exterior dac acesta exist. Cea mai probabil situaie n care putei opta pentru
aceast variant este atunci cnd dorii s tratai o excepie n cadrul a dou
programe handler distincte. Pentru mai mult claritate urmrii exemplul de mai
jos.

#include <iostream.h>
void XHandler(void)
{
try
{

120
throw "Salve";
}
catch(char *)
{
cout<<"Am captat char* in XHandler "<<endl;
throw;
}
void main()
{
cout<<"Start"<<endl;
try
{
XHandler();
}
catch(char *)
{
cout<<"Am captat char * in main"<<endl;
}
cout<<"Sfarsit";
};

Mod de utilizare a excepiilor


Toate elementele prezentate au ncercat s demonstreze c C++ are o atitudine
activ fa de problema tratrii excepiilor. Suportul oferit de C++ l ajut pe
programator s defineasc un comportament al programului cnd se produc
evenimente anormale sau neateptate. O idee mai pragmatic de utilizare a
suportului C++ n situaii efective o putei desprinde din exemplul de mai jos.

#include <iostream.h>
void div (double a, double b)
{
try
{
if(!b) throw b;
cout<<"a/b="<<a/b<<endl;
}
catch(double b)
{
cout<<"Nu se poate imparti la zero"<<endl;
}
}

void main()
{
double i,j;
do

121
{
cout<<Introduceti numaratorul (0 pentru stop):"<<endl;
cin i;
cout<<Introduceti numitorul :"<<endl;
cin j;
div(i,j);
} while (i!=0);
};

122
III Cteva aplicaii care au n spate
C sau C++

123
1 Sortarea elementelor unui ir de numere reale prin metoda bulelor.
Program pretext pentru modularizare. Se utilizeaz fiierul antet facilcrt.h
prezentat n continuarea acestei seciuni.

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include"facilcrt.h"
#include<string.h>

#define _lms 100


#define _optiune "123"

void prelsir();
char prelopt();
void sort();

int dims;
float x[ _lms];

//Functia principala..
void main()
{
char op;
do
{
op=prelopt();
switch (op)
{
case '1': prelsir();
break;
case '2': sort();
break;
}
}
while (op!='3');
}

//Preluare optiuni program...


char prelopt()

{
char c;
do
{
textcolor(RED);

124
textbackground(CYAN);
clrscr();
gotoxy(20,8) ;cprintf("Optiunile programului sunt:");
gotoxy(20,9) ;cprintf("1-Preluare elemente sir");
gotoxy(20,10);cprintf("2-Sortare/afisare sir");
gotoxy(20,11);cprintf("3-Terminare program");
makewin2(20,8,60,11);
makewin2(20,14,60,14);
gotoxy(20,14);cprintf("Optiunea Dvs.:");
c=getch();
}
while (strchr(_optiune,c)==NULL);
return c;
};

//Preluare elemente sir...


void prelsir()
{
int i;
clrscr();
makewin2(20,5,60,5);
gotoxy(20,5);
printf("Dimensiune sir...");
gotoxy(20+strlen("Dimensiune sir..."),5);
scanf("%d",&dims);
makewin2(20,8,60,7+dims);
gotoxy(20,8);
for (i=0;i<dims;i++)
{
gotoxy(20,wherey());
printf("Element[%d]=",i);
scanf("%f",&x[i]);
}
};

//Determinare maxim...
void sort()
{
float aux;
int i,sortat;

//Sortare elemnete sir


do
{
sortat=1;
for(i=0;i<dims-1;i++)
{

125
if (x[i]>x[i+1])
{
aux=x[i];
x[i]=x[i+1];
x[i+1]=aux;
sortat=0;
}
}
}
while(!sortat);

//Afisare sir sortat


clrscr();
makewin2(20,5,60,5);
gotoxy(20,5);
printf("Sirul sortat este...");
makewin2(20,8,60,7+dims);
gotoxy(20,7);
for (i=0;i<dims;i++)
{
gotoxy(20,wherey()+1);
printf("Element[%d]= %6.2f",i,x[i]);
}
getch();
};

126
2 Fier antet care ncapsuleaz cteva faciliti de lucru n mod text, utile
pentru realizarea unor interfee agreabile ale programelor cu utilizatorii.
Numit n exemplul precedent prin facilcrt.h.

#include <conio.h>
#include <stdio.h>
#include <string.h>
#define css 1

//Afisare text dinspre capete...


void converg(int end,int linie,char *mesaj)
{
int i,j,ls,cs;
ls=(end-strlen(mesaj))/2;
cs=ls+strlen(mesaj)-1;

for (i=ls,j=cs;i<=j;i++,j--)
{
gotoxy(i,linie);
printf("%c",mesaj[i-ls]);
delay(50); //prototipul in fisierul antet <dos.h>
gotoxy(j,linie);
printf("%c",mesaj[strlen(mesaj)-1-cs+j]);
}
getch();
}

//Activare video-invers
void avideo()
{
textcolor(BLACK);
textbackground(WHITE);
}

//dezactivare video-invers
void dvideo()
{
textcolor(WHITE);
textbackground(BLACK);
}

//Afisare centrata text in interiorul unei linii


void acentext(int ls, int ld, int linia, char *sir)
{
int sw;
int col;
sw=(ls>=1) && (ls<=79) && (ld<=80) && (ld>=2) && (ls<ld);

127
sw=sw && ((ld-ls+1)>=strlen(sir));
if (sw)
{
col=ls+(ld-ls+1-strlen(sir))/2;
gotoxy(col,linia);
cprintf(sir);
}
}

//Construire fereastra cu rama dreptunghiulara de


//dimensiuni specificate
void makewin2(int ass, int oss, int adj, int odj)
{
short int i;
int sw;
sw=(ass>0) && (ass<81) && (adj>0) && (adj<81) &&
(ass<=adj);
sw=sw && (oss>0) && (oss<25) && (odj>0) && (odj<25) &&
(oss<=odj);
if(sw)
{
for(i=ass;i<=adj;i++)
{
gotoxy(i,oss-1);
printf("\315");
gotoxy(i,odj+1);
printf("\315");
}
for(i=oss;i<=odj;i++)
{
gotoxy(ass-1,i);
printf("\272");
gotoxy(adj+1,i);
printf("\272");
}
gotoxy(ass-1,oss-1);
printf("\311");
gotoxy(adj+1,oss-1);
printf("\273");
gotoxy(ass-1,odj+1);
printf("\310");
gotoxy(adj+1,odj+1);
printf("\274");
}
else
{
gotoxy(1,24);

128
printf("Coordonate ecran eronate!!!");
getch();
}
}

129
3 Aplicaie pretext pentru lucru cu tablouri, folosind pointeri.
Mai precis, codul prezentat mai jos rezolv urmtoarele probleme:
-alocarea dinamic a memoriei pentru un tablou bidimensional cu
numr de linii i coloane precizate;
-citirea elementelor unui tablou bidimensional;
-transpunerea unei matrice;
-afiarea elementelor unei matrice;

#include <conio.h>
#include<iostream.h>
int i,j;

//Alocare dinamica a memoriei pentru o matrice de intregi


//Numarul de linii si coloane sunt precizate prin lista de
//parametri

void almemmat(int **p,int nl,int nc)


{
for(i=0;i<nl;i++)
p[i]=new int[nc];
};

//Citirea elementelor matricei de intregi de la tastatura


void citmat(int **p,int nl,int nc)
{
for(i=0;i<nl;i++)
for(j=0;j<nc;j++)
{
gotoxy(10,12);
cout<<"Elementul["<<i<<","<<j<<"]=";
cin>>p[i][j];
};
};

//Afisarea matricei de intregi


void afismat(int **p,int nl,int nc)
{
for(i=0;i<nl;i++)
{
for(j=0;j<nc;j++)
cout<<p[i][j]<<" | ";
cout<<endl;
};
}

//Transpunerea matricei
void transpun(int **p,int **q,int nl,int nc)

130
{
for(i=0;i<nl;i++)
for(j=0;j<nc;j++)
q[j][i]=p[i][j];
};

//Functia principala
void main()
{
int **pmat;
int **q;
int nl=6,nc=2;
clrscr();
almemmat(pmat,nl,nc);
almemmat(q,nc,nl);
citmat(pmat,nl,nc);
transpun(pmat,q,nl,nc);
afismat(q,nc,nl);
getch();
};

131
4 Sortarea unui ir de numere ntregi prin metoda HEAP_SORT. Se
utilizeaz reprezentarea liniar a unui arbore binar.

#include<iostream.h>
#include<conio.h>

const int MAX_LIST_SIZE=100;


typedef int element;
typedef element list_type[MAX_LIST_SIZE];
typedef int boolean;

void walk_down(list_type list, int j, int n)


{
int i,k;
element ref;
boolean found_spot=0;
i=j;
ref=list[i];
k=2*i+1;
while((k<n) && !found_spot)
{
if(k<n-1)
if(list[k+1]>list[k])
++k;
if (list[k]>ref)
{
list[i]=list[k];
i=k;
k=2*i+1;
}
else
found_spot=1;
}
list[i]=ref;
}

void heap_sort(list_type list, int n)


{
int y;
element temp;
y=n/2-1;
while (y>=0)
{
walk_down(list,y,n);
--y;
}
y=n;

132
while(y>0)
{
temp=list[0];
list[0]=list[y-1];
list[y-1]=temp;
--y;
walk_down(list,0,y);
}
}

void main()
{
list_type list;
int i,nrel;
clrscr();
gotoxy(20,10);
cout<<"Numar de elemente in lista:";
cin>>nrel;
clrscr();
for(i=0;i<nrel;i++)
{
gotoxy(20,11);
clreol();
cout<<"Elementul[ "<<i<<" ]=";
cin>>list[i];
}
heap_sort(list,nrel);
clrscr();
for(i=0;i<nrel;i++)
cout<<list[i]<<endl;
getch();
}

133
5 Rasfoirea unui fiier text i contorizarea apariiilor unui caracter ntr-un
fisier text utiliznd fluxuri binare.

#include <fstream.h>
#include <stdlib.h>
#include "facilcrt.h"

char optiuni[]="1234";
char *nf;
int sfs;

//Semnatura functie prelopt()


char prelopt();

//Semnatura functie selnumef()


char *selnumef();

//Semnatura functie rasfft()


void rasfft(char *n);

//Semnatura functie detstatcar()


void detstatcar();

//Implementare functie principala


void main()
{
sfs=0;
do
{
switch(prelopt())
{
case '1': nf=selnumef();
break;
case '2': rasfft(nf);
break;
case '3': detstatcar();
break;
case '4': exit(0);
}
}
while (2>1);
}

//Implementare functie detstatcar()


void detstatcar()
{
char c;

134
int cont;
clrscr();
gotoxy(20,10);
cout<<"Caracterul:";
makewin2(20,10,60,11);
gotoxy(20+strlen("Caracterul:"),10);
cin>>c;
if(sfs)
{
ifstream in(nf,ios::in | ios::binary);
if(!in)
{
sfs=0;
gotoxy(1,24);
textcolor(RED+BLINK);
cprintf("Fisierul indicat nu poate fi deschis...");
getch();
sfs=0;
textcolor(WHITE);
}
else
{
char ch;
cont=0;
while(in)
{
in.get(ch);
if(ch==c)
cont++;
}
gotoxy(20,11);
cout<<"Numar de aparitii:"<<cont;
getch();
}
}
else
{
gotoxy(1,24);
textcolor(RED+BLINK);
cprintf("Selectati mai intai fisierul...");
getch();
textcolor(WHITE);
}
}

//Implementare functie selnumef()


char *selnumef()

135
{
char *n;
sfs=1;
clrscr();
gotoxy(20,10);
cout<<"Numele fisierului de rasfoit:";
makewin2(15,10,65,10);
do
{
strcpy(n,"");
gotoxy(20+strlen("Numele fisierului de rasfoit:"),10);
gets(n);
}
while(strlen(n)==0);
return n;
}

//Implementare functie rasfft()


void rasfft(char *n)
{
if(sfs)
{
//Deschid fluxul binar in in citire
ifstream in(n, ios::in | ios::binary);
if(!in)
{
sfs=0;
gotoxy(1,24);
textcolor(RED+BLINK);
cprintf("Fisierul indicat nu poate fi deschis...");
getch();
sfs=0;
textcolor(WHITE);
}
else
{
clrscr();
char ch;
while(in)
{
//Citesc un caracter din flux
in.get(ch);
if (wherey()>20)
{
gotoxy(1,24);
cout<<"Pentru continuare apasati o tasta...";
getch();

136
clrscr();
}
cout<<ch;
}
getch();
}
}
else
{
gotoxy(1,24);
textcolor(RED+BLINK);
cprintf("Selectati mai intai fisierul...");
getch();
textcolor(WHITE);
}
}

//Implementare functie prelopt()


char prelopt()
{
clrscr();
gotoxy(20,8);
cout<<"Optiunile programului...";
makewin2(20,8,60,8);
gotoxy(20,11);
cout<<"1-Selectare fisier text";
gotoxy(20,12);
cout<<"2-Rasfoire fisier text";
gotoxy(20,13);
cout<<"3-Contorizare aparitii caracter specificat";
gotoxy(20,14);
cout<<"4-Terminare program";
gotoxy(20,15);
cout<<" Alegerea Dvs.:";
makewin2(20,11,60,15);
gotoxy(20+strlen(" Alegerea Dvs.:"),15);
char op;
do
op=getch();
while (strchr(optiuni,op)==NULL);
return op;
}

137
6 Modelarea C a unor faciliti de lucru cu memoria video n mod text.
Exemplul de cod prezentat mai jos ilustreaz, n alt context, utilitatea
pointerilor, precum i o serie de elemente tehnice referitoare la
scrierea/citirea n/din memoria video, atunci cnd se lucreaz n mod text.

#ifndef _stdio_h
#include<stdio.h>
#define _stdio_h
#endif

#ifndef _conio_h
#include<conio.h>
#define _conio_h
#endif

#ifndef _string_h
#include<string.h>
#define _string_h
#endif

#define startcol1 16
#define startcol2 36
#define startcol3 56

#include<dos.h>
#include<iostream.h>
#include<stdlib.h>

//Variabila in care se pastreaza adresa memoriei video


char far *mem_vid;

int afcent(int lin,char s[80]);


void codasc();
void antet();
int mod_video();
void setvptr();
void scrie_car(int x,int y,char ch,int atrib);
void scrie_sir(int x,int y,char *p,int atrib);

//Functia returneaza modul video corespunzator


//echipamentului pe care se ruleaza programul
int mod_video()
{
union REGS r;
r.h.ah=15;
return int86(0x10,&r,&r)&255;
}

138
//Functia seteaza adresa memoriei video in functie de
//modul video curent
void setvptr()
{
int vmod;
vmod=mod_video();
if((vmod!=2)&&(vmod!=3)&&(vmod!=7))
{
cout<<"Video trebuie sa fie in modul text cu 80 de
coloane.";
exit(1);
}
if(vmod==7)
mem_vid=(char far *) 0xB0000000;
else mem_vid=(char far *)0xB8000000;
}

//Functia permite scrierea unui caracter direct


//in memoria video pe linie si coloana specificate
void scrie_car(int x,int y,char ch,int atrib)
{
char far *v;
v=mem_vid;
v+=(y*160)+(x-1)*2;
*v++=ch;
*v=atrib;
}

//Functia permite scrierea unui sir de caractere


//in memoria video pe linie si coloana specificata
void scrie_sir(int x,int y,char *p,int atrib)
{
register int i;
char far *v;
v=mem_vid;
v+=(y*160)+(x-1)*2;
for(i=y;*p;i++)
{
*v++=*p++;
*v++=atrib;
}
}

//Afisarea antetului tabelei de coduri ASCII


void antet()
{

139
gotoxy(1,1);
for(int i=0;i<78;i++)
printf("\xf");
gotoxy(16,2);printf("Cod Caracter");
gotoxy(36,2);printf("Cod Caracter");
gotoxy(56,2);printf("Cod Caracter\n");
for(i=0;i<78;i++)
printf("\xf");
}

//Afisare coduri ASCII pe trei coloane


void codasc()
{
int nrcan=2;
int i,j,cc;
int lin=1;
int col=1;
clrscr();
antet();
for(i=0;i<256;i++)
{
if(lin>19)
if(col==3)
{
gotoxy(1,24);
gotoxy(1,23);
for(j=0;j<78;j++)
printf("\xf");
printf("\nESC-pentru terminare\\Alta tasta pentru
continuare...");
if(getch()=='\033') return;
col=lin=1;
clrscr();
antet();
}
else
{
lin=1;
col++;
}
switch(col)
{
case 1:
{
cc=startcol1;
break;
}

140
case 2:
{
cc=startcol2;
break;
}
case 3:
{
cc=startcol3;
break;
};
}
lin++;
gotoxy(cc,nrcan+lin);printf("%i",i);
gotoxy(cc+7,nrcan+lin);printf("%c",(char)i);
};
gotoxy(1,23);
for(j=0;j<78;j++)
printf("\xf");
gotoxy(1,24);
printf("Pentru terminare apasati o tasta....");
getch();
}

//Afisare centrata text pe o linie specificata


int afcent(int lin,char s[80])
{
int col;
int parer=0;
if((lin<1)||(lin>24))
parer++;
if(!strlen(s))
parer=parer+2;
if(parer)
return parer;
col=(80-strlen(s))/2;
gotoxy(col,lin);
printf("%s",s);
return parer;
}

141
7 Modelarea C++ a operaiilor cu iruri de caractere. Problem pretext
pentru aplicarea corect a principiului ncapsulrii, pentru utilizarea n
funcie de cerine a constructorilor n specificarea comportamentului unei
clase, pentru redefinirea unor operatori uzuali n lucru cu iruri de
caractere (concatenarea polimorfic, adresarea unui caracter al tabloului
de caractere, etc.).

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

//*****************************************************
//Clasa modeleaza lucrul cu siruri de caractere in C++
//class string
{
int lsir; //lungimea sirului
char *psir; //tablou de caractere alocat dinamic
public:

//Constructor clasic; stringul contine sirul vid


string(int l=1);

//Constructor de copiere a unui obiect deja creat


string( string& x);

//Constructor de copiere care utilizeaza un sir


//obisnuit
string(char sir[]);

//Redefinire operator atribuire pentru copiere obiect


void operator=(string x);

//Redefinire operator atribuire pentru copiere sir


void operator=(char sir[]);

//Redefinire operator de testare egalitate intre doua


//siruri
int operator==(string & x);

//Redefinire operator de comparare >


int operator>(string & x);

//Redefinire operator de comparare <


int operator<(string & x);

//Concatenarea a doua siruri

142
string operator+(string & x);

//Redefinire operator + ca functie prietena


friend string operator+(string &x, char s[]);

//Redefinire operator + ca functie prietena


friend string operator+(char s[],string &x);

//Destructor clasa
~string();

//Returnare lungime sir ca functie prietena


friend int length(string &x);

//Extragere caracter din sir


char & operator[](int i);

//Extragere sir din obiect ca functie prietena


friend char * sir(string& x);
};

//*****************************************************
//Implementare functii membre

//Implementare constructor creare sir vid


string::string(int)
{
lsir=1;
psir=new char[1];
*psir=0;
}

//Implementare constructor de copiere obiect deja creat


string::string( string & x)
{
lsir=x.lsir;
psir=new char[lsir];
strcpy(psir,x.psir);
}
//****************************************************
//Implementare constructor de copiere sir obisnuit
string::string(char sir[])
{
lsir=strlen(sir)+1;
psir=new char[lsir];
strcpy(psir,sir);
}

143
//Implementare redefinire operator atribuire obiect
void string::operator=(string x)
{
delete psir;
lsir=x.lsir;
psir=new char[lsir];
strcpy(psir,x.psir);
}

//Implementare redefinire operator atribuire pentru copiere


//sir
void string::operator=(char sir[])
{
delete psir;
lsir=strlen(sir)+1;
psir=new char[lsir];
strcpy(psir,sir);
}

//Implementare redefinire operator de testare egalitate


//siruri
int string::operator==(string & x)
{
if(!strcmp(psir,x.psir))
return 1;
else
return 0;
}

//Implementare redefinire operator de comparare >


int string::operator>(string & x)
{
if (strcmp(psir,x.psir)>0)
return 1;
else
return 0;
}

//Implementare redefinire operator de comparare <


int string::operator<(string & x)
{
if (strcmp(psir,x.psir)<0)
return 1;
else
return 0;
};

144
//Implementare concatenare a doua siruri
string string::operator+(string & x)
{
string s;
strcat(s.psir,psir); strcat(s.psir,x.psir);
s.lsir=lsir+x.lsir-1;
return s;
}

//Implementare destructor
string::~string()
{
delete psir;
}

//Implementare redefinire operator []


char &string::operator[](int i)
{
return psir[i-1];
}

//implementare extragere sir ca functie prietena


char * sir(string &x)
{
return x.psir;
};

//Implementare redefinire operator de concatenare


//Varianta obiect+sir
string operator+(string &x, char s[])
{
string a;
strcat(a.psir,x.psir);
strcat(a.psir,s);
a.lsir=x.lsir+strlen(s);
return a;
};

//Implementare redefinire operator de concatenare


//Varianta sir+obiect
string operator+(char s[],string &x)
{
string a;
strcat(a.psir,s); strcat(a.psir,x.psir);
a.lsir=x.lsir+strlen(s);
return a;

145
};

146
8 Aplicatie care ilustreaza lucrul cu fisiere cu tip in C++
Din nou o problem pretext, care se refer la actualizarea unui fiier n care
se pstreaz ntrebrile unui test i rspunsurile corecte, presupunnd c o
ntrebare are mai multe alternative de rspuns.

#include <conio.h>
#include <stdio.h>
#include <iostream.h>
#include <ctype.h>
#include<stdlib.h>
#include <string.h>
#include <fstream.h>

char optiuni[]="1234567";
char *nf;
int sfs,nri;

//Tipul inregistrare
typedef struct struct_test
{
int nr_intrebare;
int alt_corecta;
} t_inr_fis;

//Variabila inregistrare
t_inr_fis inr;

//Functia permite preluarea optiunilor programului


char prelopt();

//Functia permite selectarea numelui fisierului de lucru


char *selnumef();

//Functia permite crearea fisierului


void crefis();

//Functia permite adaugarea de inregistrari in fisier


void adinfis();

//Functia permite steregerea unei inregistrari din fisier


void steinfis(int nrint);

//Functia permite vizualizarea inregistrarilor fisierului


void vizfis();

void selin(int ni);


//Implementare functie principala

147
void main()
{
char op;
sfs=0;
do
{
op=prelopt();
switch(op)
{
case '1': nf=selnumef();
break;
case '2': crefis();
break;
case '3': adinfis();
break;
case '4': {
clrscr();
gotoxy(10,12);
cout<<"Numar intrebare inregistrare de
sters:";
cin>>nri;
steinfis(nri);
break;
};
case '5': vizfis();
break;
case '6': {
clrscr();
gotoxy(10,12);
cout<<"Numar inregistrare de selectat:";
cin>>nri;
selin(nri);
break;
};
case '7': break;
}
}
while (op!='7');
};

void selin(int ni)


{
if (sfs)
{
ifstream ftestin;
ftestin.open(nf,ios::in|ios::binary);
ftestin.seekg((ni-1)*sizeof(t_inr_fis),ios::beg);

148
ftestin.read((unsigned char*) &inr,sizeof(t_inr_fis));
if(!ftestin.eof())
{
clrscr();
gotoxy(10,12);
cout<<"Nr. intrebare :";
cout<<inr.nr_intrebare;
gotoxy(10,13);
cout<<"Alternativa corecta:";
cout<<inr.alt_corecta;
getch();
ftestin.close();
};
}
else
{
gotoxy(1,24);
cout<<"Selectati sau creati mai intai un fisier!....";
getch();
}
};

void steinfis(int nrint)


{
ifstream ftestin;
ofstream fmanout;
if(!sfs)
{
cerr<<"Fisier neselectat....";
getch();
}
else
{
fmanout.open("man",ios::out|ios::binary);
clrscr();
ftestin.open(nf,ios::in|ios::binary);
while (!ftestin.eof())
{
ftestin.read((unsigned char*)&inr,sizeof(t_inr_fis));
if ((inr.nr_intrebare!=nrint)&&(!ftestin.eof()))
fmanout.write((unsigned char*) &inr,
sizeof(t_inr_fis));
};
fmanout.close();ftestin.close();
};
};

149
//Implementare crefis()
void crefis()
{
ofstream ftestout;
clrscr();
gotoxy(20,10);
cout<<"Nume fisier de creat:";
cin>>nf;
ftestout.open(nf,ios::out|ios::binary);
sfs=1;
char ras;
do
{
clrscr();
gotoxy(20,10);cout<<"Numar intrebare:";
cin>>inr.nr_intrebare;
gotoxy(20,11);cout<<"Raspuns corect :";
cin>>inr.alt_corecta;
ftestout.write((unsigned char *) &inr,
sizeof(t_inr_fis));
gotoxy(20,12);cout<<"Mai aveti de introdus(D,N):";
ras=getch();
}
while (!(toupper(ras)=='N'));
ftestout.close();
}

//Implementare adinfis()
void adinfis()
{
if (sfs)
{
ofstream ftestout;
clrscr();
gotoxy(20,10);
ftestout.open(nf,ios::app|ios::binary);
char ras;
do
{
clrscr();
gotoxy(20,10);cout<<"Numar intrebare:";
cin>>inr.nr_intrebare;
gotoxy(20,11);cout<<"Raspuns corect :";
cin>>inr.alt_corecta;
ftestout.write((unsigned char *) &inr,
sizeof(t_inr_fis));

150
gotoxy(20,12);cout<<"Mai aveti de introdus(D,N):";
ras=getch();
}
while (!(toupper(ras)=='N'));
ftestout.close();
}
else
{
gotoxy(1,24);
cout<<"Selectati sau creati mai intai un fisier!....";
getch();
}
}

//Implementare vizfis()
void vizfis()
{
if (sfs)
{
ifstream ftestin;
ftestin.open(nf,ios::in|ios::binary);
while (!ftestin.eof())
{
clrscr();
ftestin.read((unsigned char*)&inr,sizeof(t_inr_fis));
if(!ftestin.eof())
{
gotoxy(10,12);
cout<<"Nr. intrebare :";
cout<<inr.nr_intrebare;
gotoxy(10,13);
cout<<"Alternativa corecta:";
cout<<inr.alt_corecta;
getch();
};
};
ftestin.close();
}
else
{
gotoxy(1,24);
cout<<"Selectati sau creati mai intai un fisier!....";
getch();
}
}

151
//Implementare selnumef()
char *selnumef()
{
char *n;
sfs=1;
clrscr();
gotoxy(20,10);
cout<<"Numele fisierului de lucru:";
do
{
strcpy(n,"");
gotoxy(20+strlen("Numele fisierului de lucru:"),10);
gets(n);
}
while(strlen(n)==0);
return n;
}

//Implementare prelopt()
char prelopt()
{
clrscr();
gotoxy(20,8);
cout<<"Optiunile programului...";
gotoxy(20,9);
cout<<"__________________________________________";
gotoxy(20,11);
cout<<"1-Selectare fisier structura test";
gotoxy(20,12);
cout<<"2-Creare fisier structura test";
gotoxy(20,13);
cout<<"3-Adaugare date in fisierul structura test";
gotoxy(20,14);
cout<<"4-Stergerea unei inregistrari din fisier";
gotoxy(20,15);
cout<<"5-Vizualizare date fisier structura";
gotoxy(20,16);
cout<<"6-Afisare inregistrare de numar specificat";
gotoxy(20,17);
cout<<"7-Terminare program";
gotoxy(20,19);
cout<<"__________________________________________";
gotoxy(20,20);
cout<<" Alegerea Dvs.:";
gotoxy(20+strlen(" Alegerea Dvs.:"),20);
char op;

152
do
op=getch();
while (strchr(optiuni,op)==NULL);
return op;
};

153
BIBLIOGRAFIE MINIMAL
[1]. N. Barkakati Borland C++ 4, Ghidul programatorului,
Editura Teora, 1997
[2]. K., Jamsa, L. Klander Totul despre C i C++, Editura Teora,
2000
[3]. I. Mulea C++ pentru avansai, Editura
Microinformatica, 1994
[4]. L. Negrescu Limbajele C i C++ pentru nceptori,
Limbajul C++, volumul 2, Editura Albastr,
Cluj-Napoca, 2000
[5]. L. Negrescu Limbajele C i C++ pentru nceptori,
Limbajul C, volumul 1, Editura Albastr,
Cluj-Napoca, 2000
[6]. D. M. Popovici, C++. Tehnologia orientat pe obiecte.
I. M. Popovici, Aplicaii,
I. Tnase Teora, 1996

[7]. Herbert Schildt C++. Manual complet,


Teora, 1998
[8]. B.Silaghi Din tainele programrii n C++, Editura
Albastr, 1996

Lista crilor din care se poate nva cte ceva despre C++ si lumea
POO este deschis, la fel de deschis ca mintea oricrui student care nu
i-a greit culoarul pe care alearg pentru a deveni un profesionist.

154
Subiecte pentru examenul la disciplina
Programare Obiect Orientat, Anul II INFO

FUNDAMENTE

Locul limbajului C/C++ printre celelalte limbaje de programare.


Elemente caracteristice.

Tipuri de date fundamentale. Modificarea tipurilor de date


fundamentale.

Variabile n C/C++. Variabile locale. Variabile globale.


Modelatori de acces. Specificatori de clase de stocare.

Operatori n C/C++.

Reprezentarea structurilor de prelucrare n C/C++. Structuri


secveniale.

Reprezentarea structurilor de prelucrare n C/C++. Structuri


alternative.

Reprezentarea structurilor de prelucrare n C/C++. Structuri


repetitive.

Tablouri C/C++.

Pointeri. Relaia pointeri-matrice. Alocarea dinamic a


memoriei.

Structuri de date n programarea C/C++. nregistrri i cmpuri


de bii.

155
Uniuni.

PARADIGMA POO

Concepte n programarea obiect orientat.

Principii n programarea obiect orientat.

Implementarea conceptelor i principiilor OO n C++.

Constructori, destructori, crearea obiectelor n C++.

Metodele virtuale i polimorfismul n programarea OO n C++.

PROGRAMARE AVANSAT N C/C++

Suprancrcarea funciior n programarea C/C++.

Suprancrcarea operatorilor n programarea C++.

Funcii inline. Funcii prietene.

Fluxuri C/C++.

Programarea generic n C/C++. Funcii generice.

Programarea generic n C/C++. Clase generice.

Programarea excepiilor n C/C++.

156
Scurte consideraii relativ la problema evalurii la
disciplina POO

 Exemplu de formulare a subiectelor pentru


examenul scris la disciplina POO II INFO

Suprancrcarea operatorilor n programarea C++.

Ce este o clas abstract?

Definii noiunea de flux.

Tratarea excepiilor n C++.

Definii o clas care ncapsuleaz proprietile necesare pentru


a simula operaii cu iruri de caractere. Implementai trei metode,
dintre care una s fie inline.

 De citit, cel puin, cu rbdare


Cteva cuvinte despre felul n care vede autorul prezentului suport
de curs ntlnirea cu studentul n timpul sesiunii.
Indiferent de forma de evaluare, ntlnirea student- profesor, n
sesiune, ar trebui s fie reciproc avantajoas. Profesorul are de
ctigat multe, dac face efortul de a vedea n student nu doar un
subiect al examenului, ci un partener care s-a hotrt s se
confrunte cu el nsui. Studentul trebuie s aib nelepciunea de a
vedea n profesor, n cel mai ru caz, un sftuitor care nu-i
cunoate limitele. Autorul prezentului suport de curs i cunoate
limitele i ncearc permanent s i le depeasc. Acest exerciiu
de autodepire i-l poate asuma i studentul, cu ncredinarea c o

157
face pentru a confirma superioritatea omului n raport cu alte
vieuitoare i nu numai.
Pentru a m face mai bine neles, n cele ce urmeaz voi arunca
cteva idei care ar vrea s sugereze modul n care, ca profesor,
neleg s evaluez lucrarea unui student.

...Lucrarea unui student este o mic oper care vorbete despre


limitele autorului ei n momentul n care acesta a realizat-o.
Limitele acestei opere nu se refer, exclusiv, la ortografie, ci i la:
Modul n care este structurat discursul de rspuns la
fiecare subiect n parte.
Calitatea viziunii punctuale a studentului, pentru fiecare
subiect n parte.
Calitatea viziunii sistemice a studentului; conexiunile
ntre subiect i restul universului nu fac dect s arate,
odat n plus, inteligena acestuia.

Aadar, ideea este c, pentru un profesror normal, fiecare student


este un potenial creator de bijuterii n materie de cugetare pe
teme impuse, condiie necesar pentru a realiza n viitor bijuterii
n materie de cugetare i de alt natur, pe teme liber alese sau
impuse de viitoarea profesie.

158