Sunteți pe pagina 1din 154

Universitatea Transilvania

Facultatea de Matematic i Informatic


Catedra de Informatic







Note de curs despre

Programarea obiect orientat n C++
(incluznd bazele programrii n C i
aplicaii)





Dorin Bocu
2002-2003
Comment [DB1]:
2




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 de la specializarea informatic 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






3


















I BAZELE C++. LIMBAJUL C


















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
4
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 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.

5
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 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)
6
{
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.

Auto
Break
Case
Char
Const
Continue
Default
Do
double
else
enum
extern
float
for
goto
if
int
long
register
return
short
signed
sizeof
static
struct
switch
typedef
union
unsigned
void
volatile
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.

7
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



Seciunea de definire a tipurilor i
constantelor globale


Antet program principal

Seciunea declarativ


Seciunea executabil

n aceast seciune se includ bibliotecile
de care are nevoie programul

n aceast seciune sunt definite
constante sau tipuri de date necesare n
program



n aceast seciune se fac toate
declaraiile de variabile ale programului

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 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.
9
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.







Tip de dat Dimensiune reprezenatre
n bii
Domeniul valoric minimal
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
10
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 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.
11
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.

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()
{
12
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 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;
13
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:);
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++.
14
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.

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);

15
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 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.

16

Variabile globale statice
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.


17
Constante C
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*/


Constante de tip ir
18
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 :=. Membrul stng al atribuirii trebuie s
fie o variabil sau un pointer, nu o funcie sau o constant.
19

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;

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:
20
<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++;
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
21
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.

De ordinul cel mai nalt !
>, >=, <, <=
==, !=
&&
De ordinul cel mai cobort ||
Tabelul 8 Relaia de preceden ntre operatorii relaionali i logici
22
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>

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.
23

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:

Se evaluiaz <Expresie_1>;
Dac <Expresie_1> este adevrat se evaluiaz <Expresie_2> i rezultatul
evalurii ei i se atribuie expresiei globale;
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.

asigur o cale rapid de acces la elementele unei matrici;
permit funciilor C s modifice parametrii de apelare;
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.

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.
24
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)
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>)

25


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++
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
26

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.




























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
27
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.

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.
28
<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!!!");
}

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

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>;
:
30
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>
}

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.

31
#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.
-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:

32
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;
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
33
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
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]);
}
34
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.

#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:
35

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");
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()
36

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























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

#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:

40
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.





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()
{
41
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;
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
42
%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.

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
43
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.






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
44
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.

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);
45
cprintf("Apasati o tasta pentru a sterge ecranul...");
getch();

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

//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)
46
{
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;
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
47
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.




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 :

48
float sir[10];

putem crea un pointer la primul element al matricei astfel:

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];

49
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]);
}
//Apelare functie cu parametru matrice transmisa ca pointer static
sespdp(matr);
50
}

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);
}
}
}
char prelopt()
51
{
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++)
{
gotoxy(20,10);
cprintf("Elementul [ %d ]=",i);
cscanf("%f",&sir1[i]);
}
52
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);
};
}

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:
53

#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.


















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>;

54
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.
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;
55
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
}
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
56
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 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();
57
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.

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>);

58
} <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;
};
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;
59
} 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()
{
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>
60

typedef struct
{
unsigned bit :1;
unsigned :7;
unsigned :7;
unsigned bits:1;
} TOctet;
TOctet Octet;
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();
}
























61










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.

62





























II Programarea C++















63







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
64
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.
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.
65
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
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.
66
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.
















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>
67
<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).

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

// 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 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
{
69
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
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;
70
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.
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
elementului n clasa
de baz
Modificatorul de protecie
asociat clasei de baz la
definirea clasei
Accesul n clasa
derivat la element
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.
71
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;}
}

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>
72
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
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.

73
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.

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

void main()
{
clrscr();
//Declarare obiect static cu iniializare;
intreg x=100; x.dispa(); //Declarare obiect static cu iniializare prin copiere intreg y=x;
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 .
75
n plus, operatorul new mai are i alte capabiliti:
Permite iniializarea memoriei alocate unui tip de baz cu o valoare dat,
utiliznd sintaxa:

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

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

Operatorul new permite alocarea de memorie pentru matrici, utiliznd sintaxa:

<Ponter>=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>
76
#define SIZE 100

// 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()
77
{
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 clas derivat ofer operaiile efective pe care le
78
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
void ExecPolim(CB *p);

void main()
{
79
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
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.
80

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();
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)
{
81
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
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 clasaclass Clasa2;class Clasa1{ //<ocupat> daca o metoda a clasei a scris pe
ecran
//<liber> in caz contrar
int stare;
82
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;
}

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
83
{
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();
};
}
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
84
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.
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;
};
85
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;
};


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 ->:";
86
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.
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.









87
























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
88
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:

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.
89

Flux Semnificaie Echipament implicit
cin Intrare standard Tastatura
cout Ieire standard Ecran
cerr Ieire standard pentru eroare Ecran
clog Versiune cu memorie tampon pentru cerr Ecran
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.

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;
cin>>hex>>intvar
Conversie hexazecimal
corespunztoare
formatului %x din ANSI C
oct cout<<oct<<intvar;
cin>>oct>>intvar;
Conversie octal (formatul
%o din C)
resetiosflags(long
f)
cout<<resetioflags(ios::dec); Reiniializeaz biii de
formatare specificai de
argumentul ntreg de tip
long
90
setbase(int baza) cout<<setbase(10);
cin>>setbase(8);
Stabilete baza de
conversie la argumentul
ntreg (trebuie s fie 0,8,10
sau 16). Valoarea 0 este
baza implicit.
setfill(int ch) cout<<setfill(.);
cin>>setfill( );
Stabilete caracterul folosit
pentru completarea
cmpurilor de mrime
specificat
setiosflags(long f) cout<<setiosflags(ios::dec);
cin>> setiosflags(ios::hex);
Stabilete biii de
formatare specificai de
argumentul ntreg de tip
long
setprecision(int p) cout<<setprecision(6);
cin>>setprecision(10);
Stabilete precizia
conversiei n virgul mobil
la numrul specificat de
zecimale
setw(int w) cout<<setw(6)<<var;
cin>>setw(24)>>buf
Stabilete mrimea unui
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++
91

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()
{
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++
92
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 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);

93
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.

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;
94
}
in.close();
}

I/O n fiiere de tip binar
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);
}
95
//Citeste din sursa si scrie in destinatie
char c;
while(ins.get(c) && outs) outs.put(c);
}
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();
while(!in.eof())
96
{
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 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.
97
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.






































3 Programare generic n C++
98
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;
}

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]>
99
Nume_ablon
definiie_ablon

Sintaxa la utilizare este:

Nume ablon<Expresie_1[, ,Expresie_n]>;
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).
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;

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.);
100
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()
{
clrscr();
int i=0;

//***************************************
//Citire persoane de la tastatura
do
{
gotoxy(20,12);
cout<<"Numele persoanei:";clreol();
cin>>pers[i].np;
gotoxy(20,13);
101
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;
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;
};
};
};
102
}
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.

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:

103
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;
};

//***************************************
//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];
};

//***************************************
104
//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>
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;
105
};
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;
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()
106
{
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();

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


107


























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.
108

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
}
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";
};
109

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;
};

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.
110
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";
};

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
}
111
:
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";
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)
112
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
}

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";
};

113
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)
{
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 )
114
{
//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.


#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;
}
115
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
{
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)
116
{
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
{
cout<<Introduceti numaratorul (0 pentru stop):"<<endl;
cin i;
cout<<Introduceti numitorul :"<<endl;
cin j;
div(i,j);
} while (i!=0);
};























117






































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




118















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;
119
case '2': sort();
break;
}
}
while (op!='3');
}

//Preluare optiuni program...
char prelopt()

{
char c;
do
{
textcolor(RED);
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]);
120
}
};

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

//Sortare elemnete sir
do
{
sortat=1;
for(i=0;i<dims-1;i++)
{
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();
};







121















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);
122
}

//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;
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");
123
}
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);
printf("Coordonate ecran eronate!!!");
getch();
}
}






























124













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

















126










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)
127
{
int y;
element temp;
y=n/2-1;
while (y>=0)
{
walk_down(list,y,n);
--y;
}
y=n;
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();
}





128










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;
129
case '4': exit(0);
}
}
while (2>1);
}

//Implementare functie detstatcar()
void detstatcar()
{
char c;
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
{
130
gotoxy(1,24);
textcolor(RED+BLINK);
cprintf("Selectati mai intai fisierul...");
getch();
textcolor(WHITE);
}
}

//Implementare functie selnumef()
char *selnumef()
{
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();
131
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();
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;
132
do
op=getch();
while (strchr(optiuni,op)==NULL);
return op;
}





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);
133
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;
}

//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;
134
for(i=y;*p;i++)
{
*v++=*p++;
*v++=atrib;
}
}

//Afisarea antetului tabelei de coduri ASCII
void antet()
{
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
{
135
lin=1;
col++;
}
switch(col)
{
case 1:
{
cc=startcol1;
break;
}
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);
136
return parer;
}








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 <
137
int operator<(string & x);

//Concatenarea a doua siruri
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;
138
psir=new char[lsir];
strcpy(psir,sir);
}

//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;
139
};

//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);
140
return a;
};













































141

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
void main()
{
char op;
sfs=0;
142
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);
ftestin.read((unsigned char*) &inr,sizeof(t_inr_fis));
if(!ftestin.eof())
{
clrscr();
143
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();
};
};


//Implementare crefis()
void crefis()
{
144
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));
gotoxy(20,12);cout<<"Mai aveti de introdus(D,N):";
ras=getch();
}
while (!(toupper(ras)=='N'));
145
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();
}
}



//Implementare selnumef()
char *selnumef()
{
146
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;
do
op=getch();
while (strchr(optiuni,op)==NULL);
return op;
147
};












































BIBLIOGRAFIE MINIMAL

148
[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,
I. M. Popovici,
I. Tnase

C++. Tehnologia orientat pe obiecte.
Aplicaii,
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.















Subiecte de meditaie importante pentru cei care
studiaz disciplina Programare Obiect Orientat din
perspectiv C++
149


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.

Uniuni.


PARADIGMA POO

Concepte n programarea obiect orientat.

150
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++.






Scurte consideraii relativ la problema evalurii la
disciplina POO

Evaluarea studenilor la POO se va face cu ajutorul a dou lucrri de
verificare; prima lucrare urmrete verificarea cunotinelor referitoare la bazele
151
programrii n C, cea de-a doua lucrare urmrind verificarea cunotinelor
referitoare la programarea n spirit obiect orientat utiliznd suportul C++.
Coninutul lucrrilor va fi prezentat i discutat n cadrul tutorialelor planificate.

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 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,
152
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.























LUCRARE DE VERIFICARE PE PARCURS NR. 1
Programare Obiect Orientat
Semestrul I/2002-2003

153
Subiect teoretic
Suportul C++ pentru programarea generic

Subiect aplicativ

S se scrie codul C++ care simuleaz comportarea unui browser de texte
cod ASCII.
Funiile minimale ale browser-ului:
-Selectarea unui fiier text de lucru.
-Crearea unui fiier text.
-Rsfoirea unui fiier text.
-Cutarea unui cuvnt specificat n fiierul text selectat.
-Alte funcii, la alegere.


Conf. Dr. Dorin Bocu



















LUCRARE DE VERIFICARE PE PARCURS NR. 2
Programare Obiect Orientat
Semestrul I/2002-2003

154
Subiect teoretic
Fluxuri C/C++. Lucrul cu fiiere n C++.

Subiect aplicativ

S se scrie codul C++ care simuleaz lucrul cu iruri de caractere,
cunoscut fiind faptul c n C/C++ nu exist suport natural pentru lucrul cu
iruri de caractere.
Astfel, se vor defini mecanisme obiect orientate cu ajutorul crora s
putem avea acces la operaii asupra irurilor de caractere, obinuite n alte
limbaje de programare: atribuirea unui ir de caractere ctre o variabil de
un tip convenabil (redefinire operator =), concatenarea a dou iruri de
caractere (redefinire operator +), extragerea unui subir de caractere
dintr-un ir de caractere (redefinire operator -), recuperarea lungimii unui
ir de caractere, etc.

Conf. Dr. Dorin Bocu

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