Sunteți pe pagina 1din 69

1

UNITILE LEXICALE

Unitile lexicale (cuvintele) limbajului C/C++ reprezint grupuri de caractere cu o semnificaie de sine
stttoare. Acestea sunt:
Identificatori;
Cuvinte cheie ale limbajului;

Identificatorii reprezint numele unor date (constante sau variabile), sau ale unor funcii. Identificatorul este
format dintr-un ir de litere, cifre sau caracterul de subliniere (underscore), trebuie s nceap cu o liter sau
cu caracterul de subliniere i s fie sugestivi.

Exemple: vitez, greutate_net, Viteza, Viteza1, GreutateNet
Identificatorii pot conine litere mici sau mari, dar limbajul C++ este senzitiv la majuscule i minuscule
(case-sensitive). Astfel, identificatorii viteza i Viteza sunt diferii.
Nu pot fi folosii ca identificatori cuvintele cheie. Identificatorii pot fi standard (ca de exemplu numele unor
funcii predefinite: scanf, clear, etc.) sau alei de utilizator.

Cuvintele cheie sunt cuvinte ale limbajului, mprumutate din limba englez, crora programatorul nu le
poate da o alt utilizare. Cuvintele cheie se scriu cu litere mici i pot reprezenta:
Tipuri de date (Exemple: int, char, double);
Clase de memorare (Exemple: extern, static, register);
Instruciuni (Exemple: if, for, while);
Operatori (Exemplu: sizeof).

2.5. DATE N LIMBAJUL C/C++

n program datele apar fie sub forma unor constante(valori cunoscute anticipat, care nu se modific), fie sub
forma de variabile. Constantele i variabilele sunt obiectele informaionale de baz manipulate ntr-un
program.

Fiecare categorie de date este caracterizat de atributele:
Nume;
Valoare;
Tip;
Clasa de memorare.
De primele trei tipuri de atribute ne vom ocupa n continuare, urmnd ca de atributul clas de memorare s
ne ocupm n paragraful 6.8.

Numele unei date
Numele unei date este un identificator i, ca urmare, trebuie s respecte regulile specifice identificatorilor.
Deasemenea, numrul de caractere care intr n compunerea unui identificator este nelimitat, ns, implicit,
numai primele 32 de caractere sunt luate n considerare. Aceasta nseamn c doi identificatori care au
primele 32 de caractere identice, difereniindu-se prin caracterul 33, vor fi considerai identici.

2.5.1. TIPURI DE DATE

Tipul unei date const ntr-o mulime de valori pentru care s-a adoptat un anumit mod de reprezentare n
memoria calculatorului i o mulime de operatori care pot fi aplicai acestor valori. Tipul unei date determin
lungimea zonei de memorie ocupat de acea dat. n general, lungimea zonei de memorare este dependent
de calculatorul pe care s-a implementat compilatorul..
2

Tipurile de baz sunt:
char codul unui caracter din setul local de caractere;
int numr ntreg, reflect n mod tipic mrimea natural din calculatorul utilizat;
float numr real, n virgul mobil, simpl precizie;
double numr real, n virgul mobil, dubl precizie.

n completare exist un numr de calificatori, care se pot aplica tipurilor de baz char, int, float sau double:
short, long, signed i unsigned. Astfel, se obin tipurile derivate de date. Short i long se refer la mrimea
diferit a ntregilor, iar datele de tip unsigned int sunt ntotdeauna pozitive. S-a intenionat ca short i long s
furnizeze diferite lungimi de ntregi, int reflectnd mrimea cea mai "natural" pentru un anumit calculator.
Fiecare compilator este liber s interpreteze short i long n mod adecvat propriului hardware; n nici un caz,
ns, short nu este mai lung dect long. Toi aceti calificatori pot aplicai tipului int. Calificatorii signed (cel
implicit) i unsigned se aplic tipului char. Calificatorul long se aplic tipului double. Dac ntr-o declaraie
se omite tipul de baz, implicit, acesta va fi int.

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

n header-ul <values.h> sunt definite constantele simbolice (cum ar fi: MAXINT, MAXSHORT,
MAXLONG, MINDOUBLE, MINFLOAT, etc.) care au ca valoare limitele inferioar i superioar ale
intervalului de valori pentru tipurile de date enumerate. (de exemplu MAXINT reprezint valoarea
ntregului maxim care se poate memora, etc. )

Fr a detalia foarte mult modul de reprezentare a datelor reale (de tip float sau double), vom sublinia faptul
c, pentru acestea, este important i precizia de reprezentare. Numrul de cifre de dup virgul determin
precizia de exprimare a numrului. Ce alte cuvinte, pe un calculator cu o precizie de 6 cifre semnificative,
dou valori reale care difer la a 7-a cifr zecimal, vor avea aceeai reprezentare. Pentru datele de tip float,
precizia de reprezentare este 6; pentru cele de tip double, precizia este 14, iar pentru cele de tip long double,
precizia este 20.
Lungimea zonei de memorie ocupate de o dat de un anumit tip (pe ci octei este memorat data) poate fi
aflat cu ajutorul operatorului sizeof.
Exemplu:
cout<<"Un int este memorat pe "<<sizeof(int)<<"octeti.\n";
Instruciunea are ca efect afiarea pe monitor a mesajului: Un int este memorat pe 2 octei.


2.5.2. CONSTANTE

O constant este un literal (o form extern de reprezentare) numeric, caracter sau ir de caractere. Numele
i valoarea unei constante sunt identice. Valoarea unei constante nu poate fi schimbat n timpul execuiei
3

programului n care a fost utilizat. Tipul i valoarea ei sunt determinate n mod automat, de ctre
compilator, pe baza caracterelor care compun literalul.

2.5.2.1. Constante ntregi

Constantele ntregi sunt literali numerici (compui din cifre), fr punct zecimal.
Constante ntregi n baza 10, 8 sau 16
Constante ntregi n baza 10
Exemple:
45
-78 // constante ntregi decimale (n baza 10), tip int
Constante ntregi octale
Dac n faa numrului apare cifra zero (0), acest lucru indic faptul c acea constant este de tipul int, in
baza opt (constant octal).
Exemple:
056
077 // constante ntregi octale, tip int
Constante ntregi hexagesimale
Dac n faa numrului apar caracterele zero (0) i x (sau X), acest lucru indic faptul c acea constant este
de tipul int, n baza 16 (constant hexagesimal). Amintim c n baza 16 cifrele sunt: 0-9, A (sau a) cu
valoare 10, B (sau b) cu valoare 11, C (sau c) cu valoare 12, D (sau d) cu valoare 13, E (sau e) cu valoare 14,
F (sau f) cu valoare 15.
Exemple:
0x45
0x3A
0Xbc // constante ntregi hexagesimale, tip int
Constante ntregi, de tipuri derivate
Dac secvena de cifre este urmat de L sau l, tipul constantei este long int.
Exemple:
145677L
897655l // tip decimal long int
Dac secvena de cifre este urmat de U sau u, tipul constantei este unsigned int.
Exemple:
65555u
Dac secvena de cifre este urmat de U (u) i L (l), tipul constantei este unsigned long int.
Exemple: 7899UL //tip decimal unsigned long int


2.5.2.2. Constante numerice, reale

Dac o constant numeric conine punctul zecimal, ea este de tipul double.
Exemplu:
3.1459 //tip double
Dac numrul este urmat de F sau f, constante este de tip float.
Dac numrul este urmat de L sau l, este de tip long double.
Exemplu:
0.45f //tip float
9.788L //tip long double
Constante reale n format tiinific
4

Numrul poate fi urmat de caracterul e sau E i de un numr ntreg, cu sau fr semn. n acest caz, constanta
este n notaie tiinific. n aceast form extern de reprezentare, numrul din faa literei E reprezint
mantisa, iar numrul ntreg care urmeaz caracterului E reprezint exponentul. In forma extern de
reprezentare, baza de numeraie este 10, deci valoarea constantei va fi dat de mantisa10
onent exp
.
Exemplu:
1.5e-2 //tip double, n notaie tiinific, valoare 1.510
2


2.5.2.3. Constante caracter

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

Constante caracter corespunztoare caracterelor imprimabile
O constant caracter corespunztoare unui caracter imprimabil se reprezint prin caracterul respectiv inclus
ntre apostroafe.
Exemplu:
Constant caracter Valoare
A 65
a 97
0 48
* 42
Excepii de la regula de mai sus le constituie caracterele imprimabile apostrof (') i backslash (\).
Caracterul backslash se reprezint: '\\'. Caracterul apostrof se reprezint: '\''.

Constante caracter corespunztoare caracterelor neimprimabile
Pentru caracterele neimprimabile, se folosesc secvene escape. O secven escape furnizeaz un mecanism
general i extensibil pentru reprezentarea caracterelor invizibile sau greu de obinut. n tabelul 2.2. sunt
prezentate cteva caractere escape utilizate frecvent.

Tabelul
2.2.

Constant
caracter
Valoare
(Cod
ASCII)
Denumi
rea
caracter
ului
Utilizare
\n 10 LF rnd nou (Line Feed)
\t 9 HT tabulator orizontal
\r 13 CR poziioneaz cursorul n coloana 1 din rndul
curent
5

\f 12 FF salt de pagin la imprimant (Form Feed)
\a 7 BEL activare sunet
O constant caracter pentru o secven escape poate apare ns, i sub o form n care se indic codul ASCII,
n octal, al caracterului dorit:
\ddd unde d este o cifr octal.
Exemple:
\11 (pentru \t)
reprezint constanta caracter backspace, cu codul 9 n baza 10, deci codul 11 n baza 8.
\15 (pentru \r)
reprezint constanta caracter CR, cu codul 13 n baza 10, deci codul 11 n baza 8.


2.5.2.4. Constante ir de caractere

Constanta ir este o succesiune de zero sau mai multe caractere, ncadrate de ghilimele. n componena unui
ir de caractere, poate intra orice caracter, deci i caracterele escape. Lungimea unui ir este practic
nelimitat. Dac se dorete continuarea unui ir pe rndul urmtor, se folosete caracterul backslash.

Caracterele componente ale unui ir sunt memorate ntr-o zon continu de memorie (la adrese succesive).
Pentru fiecare caracter se memoreaz codul ASCII al acestuia. Dup ultimul caracter al irului, compilatorul
plaseaz automat caracterul NULL (\0), caracter care reprezint marcatorul sfritului de ir. Numrul de
octei pe care este memorat un ir va fi, deci, mai mare cu 1 dect numrul de caractere din ir.
Exemple:
Acesta este un ir de caractere //constant ir memorat pe 32 octei
ir de caractere continuat\
pe rndul urmtor! //constant ir memorat pe 45 octei
ir \t cu secvene escape\n //constant ir memorat pe 26 octei
\n //constant caracter memorat pe un octet
\n //constanta ir memorat pe 2 octei (codul caracterului escape i terminatorul de ir)
a\a4 /*ir memorat pe 4 octei:
Pe primul octet: codul ASCII al caracterului a
Pe al doilea octet: codul ASCII al caracterului escape \a
Pe al treilea octet: codul ASCII al caracterului 4
Pe al patrulea octet: terminatorul de ir NULL, cod ASCII 0 */
\\ASCII\\ /*ir memorat pe 8 octei:
Pe primul octet: codul ASCII al caracterului backslah
Pe al doilea octet: codul ASCII al caracterului A
Pe al treilea octet: codul ASCII al caracterului S
Pe al patrulea octet: codul ASCII al caracterului S
Pe al 6-lea octet: codul ASCII al caracterului I
Pe al 7-lea octet: codul ASCII al caracterului I
Pe al 8-lea octet: codul ASCII al caracterului backslah
Pe al 9-ea octet: terminatorul de ir NULL, de cod ASCII 0 */
1\175a /*ir memorat pe 4 octei:
Primul octet: Codul ASCII al caracterul 1
Al 2-lea octet: codul ASCII 125 (175 in octal) al caracterului }
Al 3-lea octet: codul ASCII al caracterului a
Al 4-lea octet: codul ASCII 0 pentru terminatorul irului */

2.5.3. VARIABILE
6


Spre deosebire de constante, variabilele sunt date (obiecte informaionale) ale cror valori se pot modifica n
timpul execuiei programului. i variabilele sunt caracterizate de atributele nume, tip, valoare i clas de
memorare. Variabilele sunt nume simbolice utilizate pentru memorarea valorilor introduse pentru datele de
intrare sau a rezultatelor. Dac la o constant ne puteam referi folosind caracterele componente, la o variabil
ne vom referi prin numele ei. Numele unei variabile ne permite accesul la valoarea ei, sau schimbarea valorii
sale, dac este necesar acest lucru. Numele unei variabile este un identificator ales de programator. Ca
urmare, trebuie respectate regulile enumerate n seciunea identificatori.

Dac o dat nu are legturi cu alte date (de exemplu, relaia de ordine), vom spune c este o dat izolat. O
dat izolat este o variabil simpl. Dac datele se grupeaz ntr-un anumit mod (n tablouri - vectori,
matrici - sau structuri), variabilele sunt compuse (structurate).

n cazul constantelor, n funcie de componena literalului, compilatorul stabilea, automat, tipul constantei. n
cazul variabilelor este necesar specificarea tipului fiecreia, la declararea acesteia. Toate variabilele care vor
fi folosite n program, trebuie declarate nainte de utilizare.


2.5.3.1. Declararea variabilelor

Modul general de declarare a variabilelor este:
tip_variabile list_nume_variabile;
Se specific tipul variabilei(lor) i o list format din unul sau mai muli identificatori ai variabilelor de tipul
respectiv. ntr-un program n limbajul C++, declaraiile de variabile pot apare n orice loc n programul surs.
La declararea variabilelor, se rezerv n memorie un numr de octei corespunztor tipului variabilei, urmnd
ca ulterior, n acea zon de memorie, s fie depus (memorat, nregistrat) o anumit valoare.
Exemple:
int i, j;/*declararea var. simple i, j, de tip int. Se rezerv pentru i i j cte 16 bii (2octei)*/
char c; /* declararea variabilei simple c, de tip char. Se rezerv un octet. */
float lungime; /* declararea variabilei simple lungime; se rezerv 4 octei */







2.5.3.2. Iniializarea variabilelor n declaraii

n momentul declarrii unei variabile, acesteia i se poate da (asigna, atribui) o anumit valoare. n acest caz,
n memorie se rezerv numrul de locaii corespunztor tipului variabilei respective, iar valoarea va fi depus
(memorat) n acele locaii.
Forma unei declaraii de variabile cu atribuire este:
tip_variabil nume_variabil=expresie;
Se evalueaz expresia, iar rezultatul acesteia este asignat variabilei specificate.
Exemple:
char backslash=\\; //declararea i iniializarea variabilei simple backslash
int a=7*9+2; /* declararea variabilei simple a, de tip int i iniializarea ei cu valoarea 65*/
float radiani, pi=3.14;/*declararea variabilei radiani;declararea i iniializarea var. pi*/
short int z=3; //declararea i iniializarea variabilei simple z
7

char d=\011;
char LinieNoua=\n;
double x=9.8, y=0;

Compilatorul C++ furnizeaz mecanisme care permit programatorului s influeneze codul generat la
compilare, prin aa-numiii calificatori.
Acetia sunt:
const;
volatile.

Calificatorul const asociat unei variabile, nu va permite modificarea ulterioar a valorii acesteia, prin
program (printr-o atribuire). Calificatorul volatile (cel implicit) are efect invers calificatorului const. Dac
dup calificator nu este specificat tipul datei, acesta este considerat tipul implicit, adic int.
Exemple:
const float b=8.8;
volatile char terminator;terminator=@;terminator=*; //permis
b=4/5; //nepermisa modificarea valorii variabilei b
const w; volatile g; //w, g de tip int, implicit



2.5.3.3. Operaii de intrare/ieire

Limbajele C/C++ nu posed instruciuni de intrare/ieire, deci de citire/scriere (ca limbajul PASCAL, de
exemplu). n limbajul C aceste operaii se realizeaz cu ajutorul unor funcii (de exemplu, printf i scanf), iar
n limbajul C++ prin suprancrcarea operatorilor (definirea unor noi proprieti ale unor operatori existeni,
fr ca proprietile anterioare s dispar), mai precis a operatorilor >> i << . Vom folosi n continuare
abordarea limbajului C++, fiind, n momentul de fa, mai simpl. n limbajul C++ sunt predefinite
urmtoarele dispozitive logice de intrare/ieire:
cin - console input - dispozitivul de intrare (tastatura);
cout - console output - dispozitivul de ieire (monitorul).
Aa cum se va vedea n capitolul 9, cin i cout sunt, de fapt, obiecte (predefinite). Transferul informaiei se
realizeaz cu operatorul >> pentru intrare i operatorul << pentru ieire. Utilizarea dispozitivelor de
intrare/ieire cu operatorii corespunztori determin deschiderea unui canal de comunicaie a datelor ctre
dispozitivul respectiv. Dup operator se specific informaiile care vor fi citite sau afiate.
Exemple:
cout << var; /* afieaz valoarea variabilei var pe monitor*/
cin >> var; /* citete valoarea variabilei var de la tasatatur */

Sunt posibile operarii multiple, de tipul:
Exemple:
cout << var1 << var2 << var3;
cin >> var1 >> var2 >> var3;
n acest caz, se efectueaz succesiv, de la stnga la dreapta, scrierea, respectiv citirea valorilor variabilelor
var1, var2 i var3.

Operatorul >> se numete operator extractor (extrage valori din fluxul datelor de intrare, conform tipului
acestora), iar operatorul << se numete operator insertor (insereaz valori n fluxul datelor de ieire,
conform tipului acestora). Tipurile de date citite de la tastatur pot fi toate tipurile numerice, caracter sau ir
de caractere. Tipurile de date transferate ctre ieire pot fi: toate tipurile numerice, caracter sau ir de
8

caractere. Operanzii operatorului extractor (>>) pot fi doar nume de variabile. Operanzii operatorului insertor
(<<) pot fi nume de variabile (caz n care se afieaz valoarea variabilei), constante sau expresii. Utilizarea
dispozitivelor i operatorilor de intrare/ieire n C++ impune includerea fiierului iostream.h.
Exemple:
char c;
cout<<"Astept un caracter:"; //afiarea constantei ir de caractere, deci a mesajului
cin>>c; //citirea valorii variabilei c, de tip caracter
int a, b, e; double d;
cin>>a>>b>>e>>d; //citirea valorilor variabilelor a, b, e, d de tip int, int, int, double
cout<<"a="<<a<<"Valoarea expresiei a+b este:"<<a+b<<'\n';


2.6. OPERATORI I EXPRESII

Datele (constante sau variabile) legate prin operatori, formeaz expresii (figura 2.4). Operatorii care pot fi
aplicai datelor (operanzilor) depind de tipul operanzilor, datorit faptului c tipul unei date const ntr-o
mulime de valori pentru care s-a adoptat un anumit mod de reprezentare n memoria calculatorului i o
mulime de operatori care pot fi aplicai acestor valori.

Operatorii pot fi:
unari (necesit un singur operand);
binari (necesit doi operanzi);
ternari (trei operanzi).

O expresie este o combinaie corect din punct de vedere sintactic, format din operanzi i operatori.
Expresiile, ca i operanzii, au tip i valoare.


2.6.1. OPERATORI

Operatorul unar adres &, aplicat identificatorului unei variabile, furnizeaz adresa la care este memorat
aceasta. Poate fi aplicat oricrui tip de date i se mai numete operator de refereniere.
Exemplu:
int a;
cout<<"Adresa la care este memorata variabila a este:"<<&a;

Operatorul de atribuire(de asignare) este un operator binar care se aplic tuturor tipurilor de variabile. Este
folosit sub formele urmtoare:
nume_variabil=expresie;
sau: expresie1=expresie2;
Se evalueaz expresia din membrul drept, iar valoarea acesteia este atribuit variabilei din membrul stng.
Dac tipurile membrilor stng i drept difer, se pot realiza anumite conversii, prezentate n paragraful 2.7.
Exemplu:
float x; int a,b; x=9.18;
a=b=10;
int s; s=a+20*5; //rezultat: s=110
s=x+2; //rezultat s=11, deoarece s este int.

9

Aa cum se observ n linia a 2-a din exemplul precedent, operatorul de atribuire poate fi utilizat de mai
multe ori n aceeai expresie. Asociativitatea operatorului are loc de la dreapta la stnga. Astfel, mai nti
b=10, apoi a=b.

Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void main()
{
float x,y=4.25; char car=A; int a,b,c;
cout<<Val. lui y este:<<y<<\n; //Afiare: Val. lui y este:4.25
x=y; cout<<Val. lui x este:<<x<<\n; //Afiare: Val. lui x este:4.25
a=x;cout<<Val.lui a este:<<a<<\n; //Afiare:Val. lui a este:4, deoarece a de tip int!!!
c=b=a; cout<<b=<<b<<\tc=<<c<<\n; //Afiare: b=4 c=4
cout<<Introducei val. lui c:; cin>>c; // citire val. pentru c
cout<<Val. lui c este:<<c<<\n; //Afiare: Val. lui c este:4
}

Operatorul poate fi aplicat tipurilor de date ntregi, reale, caracter, i chiar iruri de caractere, aa cum vom
vedea n capitolele urmtoare (exemplu: char ir [10]=a5dfgthklj).

Operatori aritmetici unari:
Operator Semnificaie Exemple
- Minus unar -a
++ Operator de incrementare a++ sau
(adun 1 la valoarea operandului) ++a
-- Operator de decrementare a-- sau
(scade 1 din valoarea operandului) --a

Operatorul - unar schimb semnul operandului.
Exemplu:
int a,b; cout<<a=<<-a<<\n; b=-a;
cout<<b=<<b<<\n;
Operatorul - unar poate fi aplicat datelor ntregi, reale, caracter.

Operatorii de incrementare i decrementare pot fi aplicai datelor numerice sau caracter.
Ambii operatori pot fi folosii n form prefixat, naintea operandului, (++a, respectiv --a) sau postfixat,
dup operand (a++, respectiv a--).
Operatorul de decrementare -- care poate fi folosit n form prefixat (--a) sau postfixat (a--).

Utilizarea acestor operatori n expresii, n form prefixat sau postfixat, determin evaluarea acestora n
moduri diferite, astfel:

y=++x este echivalent cu: x=x+1;
y=x;
y=x++ este echivalent cu: y=x;
x=x+1;
y=--x este echivalent cu: x=x-1;
y=x;
y=x-- este echivalent cu: y=x;
x=x-1;
10


}
Operatori aritmetici binari:
Operator Semnificaie Exemple
+ Adunarea celor doi operanzi a+b
- Scderea celor doi operanzi a-b
* nmulirea celor doi operanzi a*b
/ mprirea celor doi operanzi a/b
% Operatorul modulo (operatorul rest) a%b
(furnizeaz restul mpririi operatorului stng la operatorul drept).

Operatorul modulo se aplic numai operanzilor ntregi (de tip int sau char). Ceilali operatori aritmetici binari
pot fi aplicai datelor ntregi sau reale.
Dac ntr-o expresie cu 2 operanzi i un operator binar aritmetic, ambii operanzi sunt ntregi, rezultatul
expresiei va fi tot un numr ntreg. De exemplu, la evaluarea expresiei 9/2, ambii operanzi fiind ntregi,
rezultatul furnizat este numrul ntreg 4.
Operatorii prezentai respect o serie de reguli de preceden (prioritate) i asociativitate, care determin
precis modul n care va fi evaluat expresia n care acetia apar. n tabelul 2.3 sunt prezentai operatorii
anteriori, n ordinea descresctoare a prioritii. Precedena operatorilor poate fi schimbat cu ajutorul
parantezelor.

Tabelul 2.3.
Clas de operatori Operatori Asociativitate
Unari - (unar) ++ -- de la dreapta la stnga
Multiplicativi * / % de la stnga la dreapta
Aditivi + - de la stnga la dreapta
Atribuire = de la dreapta la stnga

Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void main()
{
int rezult, a=20,b=2,c=25,d=4; rezult=a-b;
cout<<a-b=<<rezult<<\n; // Afiare: a-b=18
rezult=a+b; cout<<a+b=<<rezult<<\n; // Afiare: a+b=22
rezult=a*b;cout<<c*b=<<rezult<<\n; // Afiare: c*b=50
rezult=a/d; cout<<a/d=<<rezult<<\n; // Afiare: a/d=5
rezult=c%b; cout<<c%b=<<rezult<<\n; // Afiare: c%b=1
rezult=c/b*d; cout<<c/b*d=<<rezult<<\n; // Afiare: c/b*d=48
rezult= -b+a; cout<<-b+a=<<rezult<<\n; // Afiare: -b+a=18
rezult= -(b+a); cout<<-(b+a)=<<rezult<<\n; // Afiare: -(b+a)=-22
rezult=b+c*d;cout<<b+c*d=<<rezult<<\n; // Afiare: b+c*d=102
rezult=(b+c)*d;cout<<(b+c)*d=<<rezult<<\n; // Afiare: (b+c)*d=108
}

Operatori aritmetici binari compui
Operator Semnificaie Exemple
+= a=a+b a+=b
-= a=a+b a-=b
*= a=a*b a*=b
11

/= a=a/b a/=b
%= a=a%b a%=b
Aceti operatori se obin prin combinarea operatorilor aritmetici binari cu operatorul de atribuire i sunt
folosii sub forma urmtoare:
expresie1 operator= expresie2;
Rezultatul obinut este acelai cu rezultatul obinut prin:
expresie1 = expresie1 operator expresie2;
Toi aceti operatorii modific valoarea operandului stng prin adunarea, scderea, nmulirea sau mprirea
acestuia prin valoarea operandului drept.
Construcia x+=1 genereaz acelai rezultat ca expresia x=x+1.
Observaiile referitoare la operatorii aritmetici binari sunt valabile i pentru operatorii aritmetici binari
compui. Operatorii aritmetici binari compui au aceeai prioritate i asociativitate ca i operatorul de
atribuire.

Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void main()
{
int a,b; float c=9.3; a=3; b=8;
cout<<a=<<a<<\n; //Afiare a=3
a+=b; cout<<a=<<a<<\n; //Afiare a=11
a-=b; cout<<a=<<a<<\n; //Afiare a=-5
a*=b; cout<<a=<<a<<\n; //Afiare a=24
a/=b; cout<<a=<<a<<\n; //Afiare a=0
a%=b; cout<<a=<<a<<\n; //Afisare a=3
}

Operatori relaionali binari
Operator Semnificaie Exemple
== Egal cu a==b
!= Diferit de a!=b
< Mai mic dect a<b
<= Mai mic sau egal a<=b
> Mai mare dect a>b
>= Mai mare sau egal a>=b
Primii doi operatori mai sunt numii operatori de egalitate. Operatorii relaionali servesc la compararea
valorilor celor doi operanzi i nu modific valorile operanzilor. Rezultatul unei expresii n care apare unul
din operatorii relaionali binari este ntreg i are valoarea zero (0) dac relaia este fals, sau valoarea unu (1)
(sau diferit de 0 n cazul compilatoarelor sub UNIX), dac relaia este adevrat. Aceti operatorii pot fi
aplicai datelor de tip ntreg, real sau char.
Regulile de preceden i asociativitate ale acestor operatori sunt prezentate n tabelul 2.4.

Tabelul 2.4.
Clas de operatori Operatori Asociativitate
Unari - (unar) ++ -- de la dreapta la stnga
Multiplicativi * / % de la stnga la dreapta
Aditivi + - de la stnga la dreapta
Atribuire = de la dreapta la stnga
Relaionali < <= > >= de la stnga la dreapta
12

De egalitate == != de la stnga la dreapta
Atribuire i aritmetici binari = *= /= %= += -= de la dreapta la stnga

Observaie: Deosebirea dintre operatorii == (relaional, de egalitate) i = (de atribuire) const n faptul c
primul nu modific valoarea nici unuia dintre operanzii si, pe cnd cel de-al doilea modific valoarea
operandului stng (vezi exemplul urmtor)

Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void main()
{
int a=1, b=20, lim=100; int rezult; rezult=a<b;
cout<<a<b=<<rezult<<\n;
// Afiare: a<b=1 (sau o alt valoare diferit de zero pentru alte compilatoare)
rezult=a<=b;
//operatorul realional <= are prioritate mai mare dect cel de atribuire
cout<<a<=b=<<rezult<<\n;
// Afisare: a<b=1 (sau o alta valoare diferit de zero pentru alte compilatoare)
rezult=a>b; cout<<a>b=<<rezult<<\n; // Afiare: a<b=0
rezult=a+10>=lim; cout<<a+10>=lim=<<rezult<<\n;
/* Operatorul + are prioritate mai mare dect operatorul >= . Afiare: a+10>=lim=0 */
rezult=a+(10>=lim); cout<<a+(10>=lim)=<<rezult<<\n;
/* Schimbarea prioritatii operatorilor prin folosirea parantezelor; Afiare: a+(10>=lim)=1 */
rezult=a==b;
cout<<a==b=<<rezult<<\n; // Afiare: a==b=0
cout<<a=<<a<<\n; // Afiare: a=1
cout<<b=<<b<<\n; // Afiare: b=20
rezult=a=b; cout<<a=b=<<rezult<<\n; // Afiare: a=b=20
cout<<a=<<a<<\n; // Afiare: a=20
cout<<b=<<b<<\n; // Afiare: b=20
rezult=5>b>10;cout<<b=<<b<<\n; // Afiare: b=20
cout<<5>b>10=<<rezult<<\n; //Echivalent cu (5>b)>10 Afiare: 5>b>10=0
}

Operatori logici pe cuvnt
Operator Semnificaie Exemple
! Not (negaie logic) !(a==b)
&& And (conjuncie, i logic) (a>b) && (b>c)
|| Or (disjuncie, sau logic) (a>b) || (b>c)
Aceti operatori pot fi aplicai datelor de tip ntreg, real sau caracter. Evaluarea unei expresii n care intervin
operatorii logici se face conform tabelului 2.5.

Tabelul 2.5.
x y !x x&&y x||y
adevrat (1) adevrat (1) fals (0) adevrat (1) adevrat (1)
adevrat (1) fals (0) fals (0) fals (0) adevrat (1)
fals (0) adevrat (1) adevrat (1) fals (0) adevrat (1)
fals (0) fals (0) adevrat (1) fals (0) fals (0)
13

Expresia !expresie are valoarea 0 (fals) dac expresia-operand are o valoare diferit de zero i valoarea unu
(adevrat) dac expresia-operand are valoarea zero.
Expresia expresie1||expresie2 are valoarea diferit de 0 (true) dac FIE expresie1, FIE expresie2 au valori
diferite de zero.
Expresia expresie1 && expresie2 are valoarea diferit de 0 (true) dac AMBELE expresii-operand (
expresie1 i expresie2) au valori diferite de zero.

Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void main()
{ int a=0, b=10, c=100, d=200; int rezult; rezult=a&&b;
cout<<a&&b=<<rezult<<\n; //Afiare a&&b=0
rezult=a||b; cout<<a||b=<<rezult<<\n;//Afiare a||b=1 (sau valoare nenula)
rezult=!a;cout<<!a=<<rezult<<\n; //Afiare !a=1 (sau valoare nenula)
rezult=!b; cout<<!b=<<rezult<<\n; //Afiare !b=0
rezult=(a>b) || (b>c);cout<<(a>b) || (b>c)=<<rezult<<\n;
//Afiare (a>b) || (b>c) =1(sau valoare nenula)
rezult=!(c<d);cout<<!(c<d)=<<rezult<<\n;//Afiare !(c>d)=0
rezult=(a-b)&&1;cout<<(a-b)&&1=<<rezult<<\n;
//Afiare (a-b)&&1 =1(sau valoare nenula)
rezult=d||b&&a;cout<<d||b&&a=<<rezult<<\n;//Afiare d||b&&a =1
}// n evaluarea expresiilor din exemplu, s-au aplicat prioritile operatorilor, indicate n tabelul. 2.6.
Tabelul 2.6.
Clas de operatori Operatori Asociativitate
Unari ! - (unar) ++ -- de la dreapta la stnga
Multiplicativi * / % de la stnga la dreapta
Aditivi + - de la stnga la dreapta
Atribuire = de la dreapta la stnga
relaionali < <= > >= de la stnga la dreapta
de egalitate == != de la stnga la dreapta
logici && de la stnga la dreapta
logici || de la stnga la dreapta
atribuire i aritmetici binari = *= /= %= += -= de la dreapta la stnga

Exerciiu: S se scrie un program care citete un numr real i afieaz 1 dac numrul citit aparine unui
interval ale crui limite sunt introduse tot de la tastatur, sau 0 n caz contrar.
#include <iostream.h>
void main()
{
double lmin, lmax, nr;cout<<"Numar=";cin>>nr;
cout<<Limita inferioar a intervalului:; cin>>lmin;
cout<<Limita superioar a intervalului:; cin>>lmax;
cout<<(nr>=lmin && nr<=lmax); }

Operatori logici pe bit
Operator Semnificaie Exemple
~ Negaie (cod complementar fa de unu) ~a
& AND (Conjuncie, i logic pe bit a & 0377
| OR (Disjuncie, sau logic pe bit) a | 0377
14

^ XOR (Sau exclusiv logic pe bit) a^b
<< Deplasare stnga 0377 << 2
>> Deplasare dreapta 0377 >> 2

Aceti operatori nu se aplic numerelor reale, ci numai datelor de tip ntreg sau caracter. Primul operator este
unar, ceilali binari. Operatorii acioneaz la nivel de bit, la nivelul reprezentrii interne (n binar), conform
tabelelului 2.7.

Tabelul
2.7.

x y x&y x | y x^y ~x
1 1 1 1 0 0
1 0 0 1 1 0
0 1 0 1 1 1
0 0 0 0 0 1

Operatorul ~ are aceeai prioritate ca i ceilali operatori unari. El furnizeaz complementul fa de unu al
unui ntreg, adic va schimba fiecare bit de pe 1 n zero i invers. Operatorii de deplasare pe bit (<< i >>)
efectueaz deplasarea la stnga sau la dreapta a operandului stng, cu numrul de bii indicai de operandul
drept. Astfel, x<<2 deplaseaz biii din x la stnga, cu dou poziii, introducnd zero pe poziiile rmase
vacante.
Exemple:
int a=3; //Reprezentare intern a lui a (pe 2 octei): 0000000000000011
int b=5; //Reprezentare intern a lui b (pe 2 octei): 0000000000000101
int rez=~a;
cout<<"~"<<a<<'='<<rez<<'\n'; //~3= -4
//Complementul fa de unu este: 1111111111111100 (n octal: 0177777774 (!a= - 4)
rez=a & b; cout<<a<<'&'<<b<<'='<<rez<<'\n'; //3&5=1
//a&b=0000000000000001 =1
rez=a^b; cout<<a<<'^'<<b<<'='<<rez; // 3^5= 6
//a ^b = 0000000000000110
rez=a|b; cout<<a<<'|'<<b<<'='<<rez; //3|5= 7
//a | b = 0000000000000111
rez=a<<2; cout<<a<<"<<"<<3<<'='<<rez; //3<<2=16=2*2
3

//a<<2= 0000000001100000
rez=5>>2; cout<<b<<">>"<<2<<'='<<rez; //5>>2=1=5/2
2

//b>>2= 0000000000000001

Operatorul binar ^ i gsete o utilizare tipic n expresii ca: x&^077, care mascheaz ultimii 6 bii ai lui x
pe zero.
Operatorul & este adesea utilizat n expresii ca x&0177, unde seteaz toi biii pe zero, cu excepia celor de
ordin inferior din x.
Operatorul | este utilizat n expresii ca: x&MASK , unde seteaz pe unu biii care n x i masca MASK sunt
setai pe unu.
Operatorii logici pe bit & i | sunt diferii de operatorii logici && i || (pe cuvnt).
Deplasarea la stnga a unei date cu n poziii este echivalent cu nmulirea valorii acesteia cu 2
n
. Deplasarea
la dreapta a unei date fr semn cu n poziii este echivalent cu mprirea valorii acesteia cu 2
n
.
Combinnd operatorii logici pe bit cu operatorul de atribuire, se obin operatorii:
&=, ^=, |=, <<=, >>=.
15


Operatorul condiional
Este un operator ternar (necesit 3 operanzi), utilizat n construcii de forma:
expresie1?expresie2:expresie3

Se evalueaz expresia1. Dac aceasta are o valoare diferit de zero, atunci tipul i valoarea ntregii expresii
vor fi aceleai cu tipul i valoarea expresiei2. Altfel (dac expresie1 are valoarea zero), tipul i valoarea
ntregii expresii vor fi aceleai cu tipul i valoarea expresiei3. Deci operatorul condiional este folosit pentru
a atribui ntregii expresii tipul i valoarea expresiei2 sau a expresiei3, n funcie de o anumit condiie. Acest
lucru este echivalent cu:
Dac expresie1 diferit de zero
Atunci evalueaz expresie2
Altfel evalueaz expresie3
Exemplu:
int semn=(x<0)?-1:1
Dac x<0, atunci semn=-1, altfel semn=1.

Operatorul virgul
Este utilizat n construcii de forma:
expresie1 , expresie2
Operatorul virgul foreaz evaluarea unei expresii de la stnga la dreapta. Tipul i valoarea ntregii expresii
este dat de tipul i valoarea expresiei2. Operatorul virgul este folosit n instruciunea for. Operatorul
virgul are cea mai mic prioritate.
Exemplu:
int x, c, y;
cout<<Astept val. ptr. y:; cin>>y;
x=(c=y, c<=5); /* c va primi valoarea lui y (citit); se verific dac c este mai mic sau
egal cu 5. Daca nu, x=0; daca da, x=1 sau x=valoare diferit de zero)*/
x++, y--; //nti este incrementat x, apoi este decrementat y
Operatorul sizeof()
Este un operator unar, care are ca rezultat numrul de octei pe care este memorat o dat de un anumit tip.
Operandul este un tip sau o dat (constant sau variabil) de un anumit tip.
Exemple:
cout<<sizeof(int); // afieaz numrul de octei pe care este memorat un ntreg (2)
cout<<sizeof(ab6*);// afieaz 5, nr. de octei pe care este memorat constanta ir ab6*

Operatorul (tip)
Este un operator unar care apare n construcii numite cast i convertete tipul operandului su la tipul
specificat ntre paranteze.
Exemple:
int a; (float) a; // convertete operandul a (care era de tip ntreg) n float

n afara operatorilor prezentai, exist i alii, pe care i vom enumera n continuare. Despre aceti operatori
vom discuta n capitolele viitoare, cnd cunotinele acumulate vor permite acest lucru.

Operatorul unar *
Este operator unar, numit i operator de defereniere. Se aplic unei expresii de tip pointer i este folosit
pentru a accesa coninutul unei zone de memorie spre care pointeaz operatorul. Operatorii & (adres) i *
sunt complementari.
Exemplu: Expresia *a este nlocuit cu valoarea de la adresa coninut n variabila pointer a.
16


Operatorii parantez
Parantezele rotunde ( ) se utilizeaz n expresii, pentru schimbarea ordinii de efectuare a operaiilor, sau la
apelul funciilor. La apelul funciilor, parantezele rotunde ncadreaz lista parametrilor efectivi. Din acest
motiv, parantezele rotunde sunt numite i operatori de apel de funcie.
Exemplu:
double sum(double a, double b);
/*declar. funciei sum, care primete 2 argumente reale(double) i returneaz o valoare tip double */
void main()
{
. . .
double a=sum(89.9, 56.6); //apelul funciei sum, cu parametri efectivi 89.9 i 56.6
int s0=6; double s1=(s0+9)/a; //folosirea parantezelor n expresii
. . .
}

Operatorii de indexare
Operatorii de indexare sunt parantezele ptrate []. Acestea includ expresii ntregi care reprezint indici ai
unui tablou.

Operatori de acces la membri structurilor
Operatorii ::, ., ->, .* i ->* permit accesul la componentele unei structuri. Ei vor fi studiai n capitolul 7.

n tabelul 2.8. sunt prezentai toi operatorii, grupai pe categorii, cu prioritile lor i regulile de
asociativitate. Operatorii dintr-o categorie au aceeai prioritate.

Tabelul 2.8.
N
r
.
Clas de
operatori
Operatori Asociativitate
1
.
Primari () [] . -> :: de la stnga la dreapta
2
.
Unari ! ~ ++ -- sizeof (tip)
-(unar) *(defereniere)
&(refereniere)
de la stnga la dreapta
3
.
Multiplicativi * / % de la stnga la dreapta
4
.
Aditivi + - de la stnga la dreapta
5
.
Deplasare pe bit << >> de la stnga la dreapta
6
.
Relaionali < <= > >= de la stnga la dreapta
7
.
De egalitate == != de la stnga la dreapta
8
.
& (I logic pe bit) de la stnga la dreapta
9
.
^ (XOR pe bit) de la stnga la dreapta
17

1
0
.
| (SAU logic pe bit) de la stnga la dreapta
1
1
.
&& de la stnga la dreapta
1
2
.
|| de la stnga la dreapta
1
3
.
Condiional ?: de la dreapta la stnga
1
4
.
De atribuire = += -= *= %=
&= ^= |= <<= >>=
de la dreapta la stnga
1
5
.
Virgul , de la stnga la dreapta


2.6.2. EXPRESII
Prin combinarea operanzilor i a operatorilor se obin expresii. Tipul unei expresii este dat de tipul
rezultatului obinut n urma evalurii acesteia. La evaluarea unei expresii se aplic regulile de prioritate i
asociativitate a operatorilor din expresie. Ordinea de aplicare a operatorilor poate fi schimbat prin folosirea
parantezelor. La alctuirea expresiilor, este indicat evitarea expresiilor n care un operand apare de mai
multe ori.

2.6.3. CONVERSII DE TIP
La evaluarea expresiilor, se realizeaz conversii ale tipului operanzilor. Conversiile sunt:
Automate;
Cerute de evaluarea expresiilor;
Cerute de programator (prin construciile cast), explicite.

Conversiile automate sunt realizate de ctre compilator:
char, short int -> int
Ele sunt realizate de fiecare dat cnd ntr-o expresie apar operanzi de tipul char sau short int.
Conversiile cerute de evaluarea expresiilor sunt efectuate n cazurile n care n expresii apar operanzi de
tipuri diferite. naintea aplicrii operatorilor, se realizeaz conversia unuia sau a ambilor operanzi:
Dac un operand este de tip long int, cellalt este convertit la acelai tip; tipul expresiei este long int.
Dac un operand este de tipul double, cellalt este convertit la acelai tip; tipul expresiei este double.
Dac un operand este de tipul float, cellalt este convertit la acelai tip; tipul expresiei este float.
Conversiile explicite (cerute de programator) se realizeaz cu ajutorul construciilor cast.
Exemplu:
int x=3; float y; y=(float)x/2;
nainte de a se efectua mprirea celor 2 operanzi, operandul x (ntreg) este convertit n numr real simpl
precizie. Dup atribuire, valoarea lui y va fi 1.5. Dac nu ar fi fost folosit operatorul de conversie n expresia
y=x / 2, operanzii x i 2 fiind ntregi, rezultatul mpririi este ntreg, deci y ar fi avut valoarea 1.

IMPLEMENTAREA STRUCTURII SECVENIALE
18


Structura secvenial este o niruire de secvene de prelucrare (instruciuni), plasate una dup alta, n ordinea n
care se dorete execuia acestora.





























Implementarea structurii secveniale se realizeaz cu ajutorul instruciunilor:
Instruciunea vid
Sintaxa: ;
Instruciunea vid nu are nici un efect. Se utilizeaz n construcii n care se cere prezena unei instruciuni, dar
nu se execut nimic (de obicei, n instruciunile repetitive).
Exemple:
int a;
. . . . . .
int j;
;
for (;;)
{
. . . .
}
Instruciunea expresie
Sintaxa: expresie;
sau: apel_funcie;

Reprezentarea structurii secveniale cu
ajutorul schemei logice ( figura 3.1.):
Reprezentarea structurii secveniale cu
ajutorul pseudocodului:

instr1;
instr2;
. . . . .
S1
S2
Sn
Figura 3.1. Schema logic pentru structura
secvenial
19

Exemple:
int b, a=9;
double c;
b=a+9;
cout<<a;
c=sqrt(a);
clrcsr();//apelul funciei predefinite care terge ecranul; prototipul n headerul conio.h

Instruciunea compus (instruciunea bloc)
Sintaxa: {
declaratii;
instr1;
instr2;
. . . .
}
ntr-un bloc se pot declara i variabile care pot fi accesate doar n corpul blocului. Instruciunea bloc este
utilizat n locurile n care este necesar prezena unei singure instruciuni, ns procesul de calcul este mai
complex, deci trebuie descris n mai multe secvene.




DECLARAREA TABOURILOR

Numim tablou o colecie (grup, mulime ordonat) de date, de acelai tip, situate ntr-o zon de memorie
continu (elementele tabloului se afl la adrese succesive). Tablourile sunt variabile compuse (structurate),
deoarece grupeaz mai multe elemente. Variabilele tablou au nume, iar tipul tabloului este dat de tipul
elementelor sale. Elementele tabloului pot fi referite prin numele tabloului i indicii (numere ntregi) care
reprezint poziia elementului n cadrul tabloului.

n funcie de numrul indicilor utilizai pentru a referi elementele tabloului, putem ntlni tablouri
unidimensionale (vectorii) sau multidimensionale (matricile sunt tablouri bidimensionale).

Ca i variabilele simple, variabilele tablou trebuie declarate nainte de utilizare.
Modul de declarare:
tip nume_tablou[dim_1][dim_2][dim_n];
unde:tip reprezint tipul elementelor tabloului; dim_1,dim_2,...,dim_n sunt numere ntregi sau expresii
constante ntregi (a cror valoare este evaluat la compilare) care reprezint limitele superioare ale indicilor
tabloului.
Exemple:
//1
int vect[20]; // declararea tabloului vect, de maximum 20 de elemente, de tipul int.
// Se rezerv 20*sizeof(int)=20 * 2 = 40 octei
//2
double p,q,tab[10];
// declararea variabilelor simple p, q i a vectorului tab, de maximum 10 elemente, tip double
//3
#define MAX 10
char tabc[MAX]; /*declararea tabloului tabc, de maximum MAX (10) elemente de tip char*/
//4
20

double matrice[2][3]; // declararea tabloului matrice (bidimensional),
// maximum 2 linii i maximum 3 coloane, tip double


4.2. TABLOURI UNIDIMENSIONALE

Tablourile unidimensionale sunt tablouri cu un singur indice (vectori). Dac tabloul conine dim_1 elemente,
indicii elementelor au valori ntregi din intervalul [0, dim_1-1].
La ntlnirea declaraiei unei variabile tablou, compilatorul aloc o zon de memorie continu (dat de produsul
dintre dimensiunea maxim i numrul de octei corespunztor tipului tabloului) pentru pstrarea valorilor
elementelor sale. Numele tabloului poate fi utilizat n diferite expresii i valoarea lui este chiar adresa de nceput
a zonei de memorie care i-a fost alocat. Un element al unui tablou poate fi utilizat ca orice alt variabil (n
exemplul urmtor, atribuirea de valori elementelor tabloului vector). Se pot efectua operaii asupra fiecrui
element al tabloului, nu asupra ntregului tablou.

Exemplu:
// Declararea tabloului vector
int vector[6];

// Iniializarea elementelor tabloului
vector[0]=100;
vector[1]=101;
vector[2]=102;
vector[3]=103;
vector[4]=104;
vector[5]=105;

Exemplu:
double alpha[5], beta[5], gama[5];
int i=2;
alpha[2*i-1] = 5.78;
alpha[0]=2*beta[i]+3.5;
gama[i]=aplha[i]+beta[i]; //permis
gama=alpha+beta; //nepermis

Variabilele tablou pot fi iniializate n momentul declarrii:
declaraie_tablou=list_valori;
Valorile din lista de valori sunt separate prin virgul, iar ntreaga list este inclus ntre acolade:
Exemple:
//1
int vector[6]={100,101,102,103,104,105};


[0] [5]
//2
double x=9.8;
double a[5]={1.2, 3.5, x, x-1, 7.5};

vector
vector
100 101 102 103 104 105
100
101
102
103
104
105
vector[0]

vector[1]
vector[2]

vector[3]
vector[4]
vector[5]
Figura 4.1.
21

La declararea unui vector cu iniializarea elementelor sale, numrul maxim de elemente ale tabloului poate fi
omis, caz n care compilatorul determin automat mrimea tabloului, n funcie de numrul elementelor
iniializate.
Exemplu:
char tab[]={ A, C, D, C};


[0] [3]

float data[5]={ 1.2, 2.3, 3.4 };



[0] [4]
Adresa elementului de indice i dintr-un tablou unidimensional poate fi calculat astfel:
adresa_elementului_i = adresa_de_baz + i - lungime_element

Exerciii:
//1 Citirea elementelor unui vector:
double a[5];
int i;
for (i=0; i<5; i++)
{ cout<<a["<<i<<]=; //afiarea unui mesaj prealabil citirii fiecrui element
cin>>a[i]; //citirea valorii elementului de indice i
}
//Sau:
double a[20]; int i, n;
cout<<Dim. Max. =; cin>>n;
for (i=0; i<n; i++)
{ cout<<a[<<i<<]=;
cin>>a[i];
}
//2 Afiarea elementelor unui vector:
cout<<Vectorul introdus este:\n;
for (i=0; i<n i++)
cout<<a[i]<< ;
//3 Afiarea elementelor unui vector n ordine invers:
cout<<Elementele vectorului n ordine invers:\n;
for (i=n-1; i>=0 i++)
cout<<a[i]<< ;
//3 Vectorul sum (c) a vectorilor a i b, cu acelai numr de elemente:
for (i=0; i<n i++)
c[i]=a[i]+b[i];
//4 Vectorul diferen (c) a vectorilor a i b, cu acelai numr de elemente:
for (i=0; i<n i++)
c[i]=a[i] - b[i];
//5 Produsul scalar (p) a vectorilor a i b, cu acelai numr de elemente:
p= a b
i i
i
n
-
=

0
1
double p=0;
tab
A B
1
C

D

data 1.2 2.3 3.4 ? ?
22

for (i=0; i<n i++)
p += a[i] - b[i];


4.2. TABLOURI BIDIMENSIONALE

Din punct de vedere conceptual, elementele unui tablou bidimensional sunt plasate n spaiu pe dou direcii.
Matricea reprezint o aplicaie natural a tablourilor bidimensionale.
n matematic:
q
11
q
12
q
13
. . . q
1n

q
21
q
22
q
23
. . . q
2n

Q= . . . . . . . . . . . . . . . . . . . . . . . . . . Q
m n

q
m1
q
m2
q
m3
. . . q
mn


n limbajele C/C++ (indicii de linie i de coloan pornesc de la 0):
q
00
q
01
q
02
. . . q
0 1 ,n

q
10
q
11
q
12
. . . q
1 1 ,n
Q
m n

. . . . . . . . . . . . . . . . . . . . . . . . . . . .
q
m1 0 ,
q
m1 1 ,
q
m1 2 ,
. . . q
m n 1 1 ,


Exemplu:
double q[3][2]; // declararea matricii q, cu maxim3 linii i 2 coloane, tip double

n memorie, elementele unei matrici sunt memorate pe linii:
q
00
q
01
q
10
q
11
q
20
q
21
. . .
Dac notm cu k poziia n memorie a unui element, valoarea lui k = i - m + j (unde m este numrul maxim de
linii, i este indicele de linie, j este indicele de coloan).


Dac se dorete iniializarea elementelor unei matrici n momentul declarrii acesteia, se poate proceda astfel:
int mat[4][3] = {
{10, -50, 3},
{32, 20, 1},
{-1, 1, -2},
{7, -8, 19} };
Prin aceast construcie, elementele matricii mat se iniializeaz n modul urmtor:
mat[0][0]=10, mat[0][1]=-50, mat[0][2]=3
mat[1][0]=32, mat[1][1]=20, mat[1][2]=1
mat[2][0]=-1, mat[2][1]=1, mat[2][2]=-2
mat[3][0]=7, mat[3][1]=-8, mat[3][2]=19

La declararea unei matrici i iniializarea elementelor sale, se poate omite numrul maxim de linii, n schimb,
datorit modului de memorare, trebuie specificat numrul maxim de coloane:
int mat[][3] = {
{10, -5, 3},
{32, 20, 1},
{-1, 1, -2},
{7, -8, 9} };
q[0][0] q[0][1] q[0][2]
. . . . . . . q[0][n-1] q[1][0] . . . . . .
q[m-1][0]
. . .
q[m-1][n-1]
Q=
23

Construcia are acelai efect ca precedenta.
int mat[][3] = {
{1, 1},
{ -1},
{3, 2, 1}};
mat reprezint o matrice 3 - 3, ale crei elemente se iniializeaz astfel:
mat[0][0]=1, mat[0][1]=1, mat[1][0]=-1, mat[2][0]=3, mat[2][1]=2, mat[2][2]=1
Elementele mat[0][2], mat[1][1], mat[1][2] nu sunt initalizate. Ele au valoarea zero dac tabloul este global i
valori iniiale nedefinite dac tabloul este automatic.

Construciile utilizate la iniializarea tablourilor bidimensionale se extind pentru tablouri multidimensionale, cu
mai mult de doi indici.
Exemplu:
int a[2][2][3]={
{ {10, 20}, {1, -1}, {3, 4}},
{ {20, 30}, {50, -40}, {11, 12}}
};
Exerciiu: S se citeasc de la tastatur elementele unei matrici de maxim 10 linii i 10 coloane. S se afieze
matricea citit.
#include <iostream.h>
void main(void)
{int A[10][10]; int nr_lin, nr_col; cout<<"Nr. linii:"; cin>>nr_lin;
cout<<"Nr. coloane:"; cin>>nr_col;int i, j;
//citirea elementelor unei matrici
for (i=0; i<nr_lin; i++)
for (j=0; j<nr_col; j++) {
cout<<"A["<<i<<","<<j<<"]="; //afiarea unui mesaj prealabil citirii
cin>>A[i][j];
}
//afiarea elementelor matricii
for (i=0; i<nr_lin; i++) {
for (j=0; j<nr_col; j++)
cout<<A[i][j]<<'\t';
cout<<'\n'; // dup afiarea elementelor unei linii, se trece pe linia urmtoare
}
}




4.3. IRURI DE CARACTERE

irurile de caractere sunt tablouri de caractere, care au ca ultim element un terminator de ir, caracterul null
(zero ASCII), \0.
Exemplu:
char tc[5] = {a, b, c, d, e}; // tablou de caractere
char sc[5] = {a, b, c, d, \0}; // irul de caractere cu elementele abcd
Limbajul C/C++ permite iniializarea unui tablou de caractere printr-o constant ir (ir ntre ghilimele), care
include automat caracterul null. Deci ultima iniializare este echivalent cu:
char sc[5] = abcd; //sau cu
24

char sc[] = abcd;

Exemplu:
char tc[5] = {a, b, c, d, e};
char sc[5] = {a, b, c, d, \0};
char sc1[5] = abcd;
char s[10];
cout<<sc<<\n; //afieaz abcd
cout<<tc<<\n;
//eroare: tabloul de caractere nu conine terminatorul de ir, deci nu poate fi afiat ca ir
cout<<s<<\n; // eroare: tablou neiniializat
cout<<sc1[2]; // afieaz al treilea element din irul sc1
sc1[1]=K; // elementului din ir de indice 1 i se atribuie valoarea K;


4.3.1. FUNCII PENTRU OPERAII CU IRURI DE CARACTERE

Funciile pentru operaii cu iruri se gsesc n header-ul <string.h>.

strlen (nume_ir)
Returneaz un numr ntreg ce reprezint lungimea unui ir de caractere, fr a numra terminatorul de ir.

strcmp (ir_1, ir_2)
Funcia compar cele dou iruri date ca argument i returneaz o valoare ntreag egal diferena dintre
codurile ASCII ale primelor caractere care nu coincid.

strcpy (ir_destinaie, ir_surs)
Funcia copie irul surs n irul destinaie. Pentru a fi posibil copierea, lungimea irului destinaie trebuie s
fie mai mare sau egal cu cea a irului surs, altfel pot apare erori grave.

strcat (ir_destinaie, ir_surs)
Funcia concateneaz cele dou iruri: irul surs este adugat la sfritul irului destinaie. Tabloul care conine
irul destinaie trebuie s aib suficiente elemente.

VARIABILE POINTER

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








Variabil pointer
ptrx
Variabil
x
5
Nume variabil

Valoare
1024
1024 adres 1028
Figura 5.1. Variabile pointer
25


n figura 5.1, variabila x este memorat la adresa 1024 i are valoarea 5. Variabila ptrx este memorat la adresa
de memorie 1028 i are valoarea 1024 (adresa variabilei x). Vom spune c ptrx pointeaz ctre x, deoarece
valoarea variabilei ptrx este chiar adresa de memorie a variabilei x.


5.1.1. DECLARAREA VARIABILELOR POINTER

Sintaxa declaraiei unui pointer de date este:
tip - identificator_pointer;
Simbolul - precizeaz c identificator_pointer este numele unei variabile pointer de date, iar tip este tipul
obiectelor a cror adres o va conine.
Exemplu:
int u, v, - p, - q; // - p, - q sunt pointeri de date (ctre int)
double a, b, - p1, - q1; // - p1, - q1 sunt pointeri ctre date de tip double

Pentru pointerii generici, se folosete declaraia:
void - identificator_pointer;
Exemplu:
void - m;
Aceasta permite declararea unui pointer generic, care nu are asociat un tip de date precis. Din acest motiv, n
cazul unui pointer vid, dimensiunea zonei de memorie adresate i interpretarea informaiei nu sunt definite, iar
proprietile difer de ale pointerilor de date.
5.1.2. INIIALIZAEA VARIABILELOR POINTER

Exist doi operatori unari care permit utilizarea variabilelor pointer:
& - operatorul adres (de refereniere) - pentru aflarea adresei din memorie a unei variabile;
- - operatorul de indirectare (de defereniere) - care furnizeaz valoarea din zona de memorie spre care
pointeaz pointerul operand.

n exemplul prezentat n figura 5.1, pentru variabila ntreag x, expresia &x furnizeaz adresa variabilei
x. Pentru variabila pointer de obiecte int, numit ptr, expresia - ptr nseamn coninutul locaiei de
memorie a crei adres este memorat n variabila ptr. Expresia - ptr poate fi folosit att pentru
aflarea valorii obiectului spre care pointeaz ptr, ct i pentru modificarea acesteia (printr-o operaie de
atribuire).

Exemplu:
int x, y, - ptr;
// ptr- variabil pointer ctre un int; x,y-variabile predefinite, simple, de tip int
x=5; cout<<Adresa variabilei x este:<<&x<<\n;
cout<<Valoarea lui x:<<x<<\n;
ptr=&x; // atribuire: variabila ptr conine adresa variabilei x
cout<<Variabila pointer ptr are valoarea:<<ptr;
cout<< si adreseaza obiectul:<< - ptr<<\n;
y=- ptr; cout<<y=<<y<<\n; // y=5
x=4; cout<<x=<<x<<\n; cout<<- ptr=<<- ptr<<\n;
// x si - ptr reprezinta acelasi obiect, un intreg cu valoarea 4
x=70; // echivalenta cu - ptr=70;
y=x+10; // echivalenta cu y=- ptr+10

26

n exemplul anterior, atribuirea ptr=&x se execut astfel: operatorul & furnizeaz adresa lui x; operatorul =
atribuie valoarea (care este o adres) variabilei pointer ptr.
Atribuirea y=- ptr se realizeaz astfel: operatorul - acceseaz coninutul locaiei a crei adres este coninut n
variabila ptr; operatorul = atribuie valoarea variabilei y.

Declaraia int - ptr; poate fi, deci, interpretat n dou moduri, ambele corecte:
ptr este de tipul int - ( ptr este de tip pointer spre int)
- ptr este de tipul int (coninutul locaiei spre care pointeaz variabila ptr este de tipul int)
Construcia tip - este de tipul pointer ctre int.
Atribuirea x=8;este echivalent cu ptr=&x; - p=x;

Variabilele pointer, alturi de operatorii de refereniere i de defereniere, pot apare n expresii.
Exemple:
int x, y, - q; q=&x;
- q=8; // echivalent cu x=8;
q=&5; // invalid - constantele nu au adres
- x=9; // invalid - x nu este variabil pointer
x=&y; //invalid: x nu este variabil pointer, deci nu poate fi folosit cu operatorul de indirectare
y=- q + 3; // echivalent cu y=x+3;
- q = 0; // seteaz x pe 0
- q += 1; // echivalent cu ( - q)++ sau cu x++
int - r; r = q;
/* copiaz coninutul lui q (adresa lui x) n r, deci r va pointa tot ctre x (va conine tot adresa lui x)*/
double w, - r = &w, - r1, - r2; r1= &w; r2=r1;
cout<<r1=<<r1<<\n; //afieaz valoarea pointerului r1 (adresa lui w)
cout<<&r1=<<&r1<<\n; // afieaz adresa variabilei r1
cout<<- r1= <<- r1<<\n;
double z=- r1; // echivalent cu z=w
cout<<z=<<z<<\n;
5.1.3. POINTERI GENERICI

La declararea pointerilor generici ( void - nume; ) nu se specific un tip, deci unui pointer void i se pot atribui
adrese de memorie care pot conine date de diferite tipuri: int, float, char, etc. Aceti pointeri pot fi folosii cu
mai multe tipuri de date, de aceea este necesar folosirea conversiilor expliciteprin expresii de tip cast, pentru a
preciza tipul datei spre care pointeaz la un moment dat pointerul generic.

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

Pe baza exemplului anterior, se pot face observaiile:
1. Conversia tipului pointer generic spre un tip concret nseamn, de fapt, precizarea tipului de pointer pe care
l are valoarea pointerului la care se aplic conversia respectiv.
2. Conversia tipului pointer generic asigur o flexibilitate mai mare n utilizarea pointerilor.
27

3. Utilizarea n mod abuziv a pointerilor generici poate constitui o surs de erori.


5.2. OPERAII CU POINTERI

n afara operaiei de atribuire (prezentat n paragraful 5.1.2.), asupra variabilelor pointer se pot realiza operaii
de comparare, adunarei scdere (inclusiv incrementare i decrementare).

Compararea valorilor variabilelor pointer
Valorile a doi pointeri pot fi comparate, folosind operatorii relaionali, ca n exemplul:

Exemplu:
int - p1, - p2;
if (p1<p2)
cout<<p1=<<p1<<<<<p2=<<p2<<\n;
else cout<<p1=<<p1<<>=<<p2=<<p2<<\n;

O operaie uzual este compararea unui pointer cu valoarea nul, pentru a verifica dac acesta adreseaz
un obiect. Compararea se face cu constanta simbolic NULL (definit n header-ul stdio.h) sau cu valoarea
0.

Exemplu:
if (!p1) // sau if (p1 != NULL)
. . . . . ; // pointer nul
else . . . . ; // pointer nenul

Adunarea sau scderea
Sunt permise operaii de adunaresau scdere ntre un pointer de obiecte i un ntreg:
Astfel, dac ptr este un pointer ctre tipul tip (tip - ptr;), iar n este un ntreg, expresiile
ptr + n i ptr - n
au ca valoare, valoarea lui ptr la care se adaug, respectiv, se scade n - sizeof(tip).
Un caz particular al adunrii sau scderii dintre un pointer de date i un ntreg (n=1) l reprezint
incrementarea i decrementarea unui pointer de date. n expresiile ptr++, respectiv ptr--, valoarea variabilei
ptr devine ptr+sizeof(tip), respectiv, ptr-sizeof(tip).
Este permis scderea a doi pointeri de obiecte de acelai tip, rezultatul fiind o valoare ntreag care
reprezint diferena de adrese divizat prin dimensiunea tipului de baz.

Exemplu:
int a, - pa, - pb;
cout<<&a=<<&a<<\n; pa=&a; cout<<pa=<<pa<<\n;
cout<<pa+2<<pa+2<<\n; pb=pa++; cout<<pb=<<pb<<\n;
int i=pa-pb; cout<<i=<<i<<\n;


5.3. POINTERI I TABLOURI

n limbajele C/C++ exist o strns legtur ntre pointeri i tablouri, deoarece numele unui tablou este un
pointer (constant!) care are ca valoare adresa primului element din tablou. Diferena dintre numele unui tablou
i o variabil pointer este aceea c unei variabile de tip pointer i se pot atribui valori la execuie, lucru imposibil
pentru numele unui tablou. Acesta are tot timpul, ca valoare, adresa primului su element. De aceea, se spune c
28

numele unui tablou este un pointer constant (valoarea lui nu poate fi schimbat). Numele unui tablou este
considerat ca fiind un rvalue(right value-valoare dreapta), deci nu poate apare dect n partea dreapt a unei
expresii de atribuire. Numele unui pointer (n exemplul urmtor, - ptr) este considerat ca fiind un lvalue(left
value-valoare stnga), deci poate fi folosit att pentru a obine valoarea obiectului, ct i pentru a o modifica
printr-o operaie de atribuire.

Exemplu:
int a[10], - ptr; // a este definit ca &a[0]; a este pointer constant
a = a + 1; // ilegal
ptr = a ; // legal: ptr are aceeai valoare ca i a, respectiv adresa elementului a[0]
// ptr este variabil pointer, a este constant pointer.
int x = a[0]; // echivalent cu x = - ptr; se atribuie lui x valoarea lui a[0]

Deoarece numele tabloului a este sinonim pentru adresa elementului de indice zero din tablou, asignarea
ptr=&a[0] poate fi nlocuit, ca n exemplul anterior, cu ptr=a.


5.3.1. POINTERI I IRURI DE CARACTERE

Aa cum s-a artat n capitolul 4, un ir de caractere poate fi memorat ntr-un vector de caractere. Spre
deosebire de celelalte constante, constantele ir de caractere nu au o lungime fix, deci numrul de octei alocai
la compilare pentru memorarea irului, variaz. Deoarece valoarea variabilelor pointer poate fi schimbat n
orice moment, cu mult uurin, este preferabil utilizarea acestora, n locul tablourilor de caractere (vezi
exemplul urmtor).

Exemplu:
char sir[10]; char - psir;
sir = hello; // ilegal
psir = hello; // legal
Operaia de indexare a elementelor unui tablou poate fi realizat cu ajutorul variabilelor pointer.

Exemplu:
int a[10], - ptr; // a este pointer constant; ptr este variabil pointer
ptr = a; // ptr este adresa lui a[0]
ptr+i nseamn ptr+(i - sizeof(int)), deci: ptr + i & a[i]
Deoarece numele unui tablou este un pointer (constant), putem concluziona (figura 5.2):
a+i & a[i]
a[i] - (a+i)












a=&a[0] a+1=&a[1] . . . a+9=&a[9]
a=a[0] (a+1)=a[1] . . . (a+9)=a[9]
ptr
a
a[0] a[1] . . . . a[9]

Figura 5.2. Legtura dintre pointeri i tablouri
29


Exerciiu: S se scrie urmtorul program (care ilustreaz legtura dintre pointeri i vectori) i s se urmreasc
rezultatele execuiei acestuia.
#include <iostream.h>
void main(void)
{int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int - pi1 = a ;
int - pi2 = &a[0]; int - pi3;
cout<<a=<<a<<&a=<<&a<<- a=<<- a<<\n;
cout<<a+1=<<(a+1)<< &a[1]=<< &a[1]<<\n;
cout<<a[1]=<<a[1]<< - (a+1)=<< - (a+1)<<\n;
cout<<pi1=<<pi1<<pi2=<<pi2<<\n; int x=- pi1;
/* x primete valoarea locaiei a carei adres se afl n variabila pointer pi1, deci valoarea lui a[0] */
cout<<x=<<x<<\n; x=- pi1++; // echivalent cu - (pi1++) x=1
cout<<x=<<x<<\n; x=( - pi1)++;
/* x=0: nti atribuirea, apoi incrementarea valorii spre care pointeaz pi1. n urma incrementrii,
valoarea lui a[0] devine 1 */
cout<<x=<<x<<\n; cout<<- pi1<<\n;x=- ++pi1; //echivalent cu - (++pi1)
cout<<x=<<x<<\n; x=++( - pi1); cout<<x=<<x<<\n; pi1=a;
pi3=pi1+3;
cout<<pi1=<<pi1<<- pi1=<<- pi1<<&pi1=<<&pi1<<\n;
cout<<pi3=<<pi3<<- pi3=<<- pi3<<&pi3=<<&pi3<<\n;
cout<<pi3-pi1=<<(pi3-pi1)<<\n; //pi3-pi1=3
}

Exerciiu: S se scrie urmtorul program (legtura pointeri-iruri de caractere) i s se urmreasc rezultatele
execuiei acestuia.
#include <iostream.h>
void main(void)
{int a=-5, b=12, - pi=&a; double u=7.13, v=-2.24, - pd=&v;
char sir1[]=sirul 1, sir2[]=sirul 2, - psir=sir1;
cout<<a=<<a<< &a=<<&a<< b=<<b<< &b=<<&b<<\n;
cout<<- pi=<<- pi<<pi=<<pi<< &pi=<<&pi<<\n;
cout<<- pd=<<- pd<<pd=<<pd<< &pd=<<&pd<<\n;
cout<<- sir1=<<- sir1<< sir1=<<sir1<< &sir1=<<&sir1<<\n;
// *sir1=s sir1=sirul 1 &sir1=0xffd6
cout<<- sir2=<<- sir2<< sir2=<<sir2<< &sir2=<<&sir2<<\n;
// *sir2=s sir2=sirul 2 &sir1=0xffce
cout<<- psir=<<- psir<< psir=<<psir<< &psir=<<&psir<<\n;
// *psir=s psir=sirul 1 &sir1=0xffcc
cout<<sir1+2=<<(sir1+2)<< psir+2=<<(psir+2)<<\n;
// sir1+2=rul 1 psir+2=rul 1
cout<<- (sir1+2)=<< - (sir1+2)<<\n;
// *(sir1+2)=r valoarea elementului de indice 2
void - pv1, - pv2;
pv1=psir; pv2=sir1;
cout<<pv1=<<pv1<<&pv1=<<&pv1<<\n;
cout<<pv2=<<pv2<<&pv2=<<&pv2<<\n;
pi=&b; pd=&v; psir=sir2;
cout<<- pi=<<- pi<<pi=<<pi<< &pi=<<&pi<<\n;
cout<<- pd=<<- pd<<pd=<<pd<< &pd=<<&pd<<\n;
30

cout<<- psir=<<- psir<<psir=<<psir<< &psir=<<&psir<<\n;
}

Exerciiu: S se scrie un program care citete elementele unui vector de ntregi, cu maxim 20 elemente
i nlocuiete elementul maxim din vector cu o valoare introdus de la tastatur. Se va folosi aritmetica
pointerilor.
#include <iostream.h>
void main()
{ int a[20];
int n, max, indice; cout<<Nr. elemente:; cin>>n;
for (i=0; i<n; i++)
{ cout<<a[<<i<<]=; cin>>- (a+i);}
// citirea elementelor vectorului
max=- a; indice=0;
for (i=0; i<n; i++)
if (max<=- (a+i))
{ max=- (a+i); indice=i;}
// aflarea valorii elementului maxim din vector i a poziiei acestuia
int val;
cout<<Valoare de inlocuire:; cin >> val;
- (a+indice)=val;
// citirea valorii cu care se va nlocui elementul maxim
for (i=0; i<n; i++)
cout<<- (a+i);<<'\t';
cout<<'\n';
// afiarea noului vector
/* n acest mod de implementare, n situaia n care n vector exist mai multe elemente a cror valoare
este egal cu valoarea elementului maxim, va fi nlocuit doar ultimul dintre acestea (cel de indice
maxim).*/
}


5.3.2. POINTERI I TABLOURI MULTIDIMENSIONALE

Elementele unui tablou bidimensional sunt pstrate tot ntr-o zon continu de memorie, dar inconvenientul
const n faptul c ne gndim la aceste elemente n termeni de rnduri (linii) i coloane (figura 5.3). Un tablou
bidimensional este tratat ca un tablou unidimensional ale crui elemente sunt tablouri unidimensionale.
int M[4][3]={ {10, 5, -3}, {9, 18, 0}, {32, 20, 1}, {-1, 0, 8} };
Compilatorul trateaz att M, ct i M[0], ca tablouri de mrimi diferite. Astfel:
cout<<Marime M:<<sizeof(M)<<\n; // 24 = 2octei - 12elemente
cout<<Marime M[0]<<sizeof(M[0])<<\n; // 6 = 2octei - 3elemente
cout<<Marime M[0][0]<<sizeof(M[0][0])<<\n; // 4 octei (sizeof(int))








10 5 -3

9 18 0

32 20 1

-1 0 8
M[0]

M[1]

M[2]

M[3]
Matricea M
Matricea M are 4 linii i 3 coloane.
Numele tabloului bidimensional, M, refer ntregul tablou;
M[0] refer prima linie din tablou;
M[0][0] refer primul element al tabloului.

Figura 5.3. Matricea M
31




Aa cum compilatorul evalueaz referina ctre un tablou unidimensional ca un pointer, un tablou bidimensional
este referit ntr-o manier similar. Numele tabloului bidimensional, M, reprezint adresa (pointer) ctre primul
element din tabloul bidimensional, acesta fiind prima linie, M[0] (tablou unidimensional). M[0] este adresa
primului element (M[0][0]) din linie (tablou unidimensional), deci M[0] este un pointer ctre int: M = M[0] =
&M[0][0]. Astfel, M i M[linie] sunt pointeri constani.

Putem concluziona:
M este un pointer ctre un tablou unidimensional (de ntregi, n exemplul anterior).
- M este pointer ctre int (pentru c M[0] este pointer ctre int), i - M = - (M + 0)
-
M[0].
- - M este ntreg; deoarece M[0][0] este int, - - M=- ( - M)
-
- (M[0])=- (M[0]+0)
-
M[0][0].

Exerciiu: S se testeze programul urmtor, urmrind cu atenie rezultatele obinute.
#include <iostream.h>
#include <conio.h>
void main()
{int a[3][3]={{5,6,7}, {55,66,77}, {555,666,777}};
clrscr();
cout<<"a="<<a<<" &a="<<&a<<" &a[0]="<<&a[0]<<'\n';
cout<<"Pointeri catre vectorii linii\n";
for (int i=0; i<3; i++){
cout<<" *(a+"<<i<<")="<<*(a+i);
cout<<" a["<<i<<"]="<<a[i]<<'\n';
}
// afiarea matricii
for (i=0; i<3; i++){
for (int j=0; j<3; j++)
cout<<*(*(a+i)+j)<<'\t'; //sau:
cout<<*(a[i]+j)<<'\t';
cout<<'\n';
}
}


5.4. TABLOURI DE POINTERI

Un tablou de pointeri este un tablou ale crui elemente sunt pointeri. Modul general de declarare a unui tablou
de pointeri:
tip - nume_tablou[dim];

S considerm exemplul n care se declar i se iniializeaz tabloul de pointeri str_ptr (figura 5.4.):
char - str_ptr[3] = { Programarea, este, frumoas! };






Figura 5.4. Tabloul de pointeri str_ptr
str_ptr


Programarea

este

frumoas!
str_ptr[0]

str_ptr[1]

str_ptr[2]
Deoarece operatorul de indexare [ ] are
prioritate mai mare dect operatorul de
defereniere , declaraia char str_ptr[3]
este echivalent cu char (str_ptr[3]), care
precizeaz c str_ptr este un vector de trei
elemente, fiecare element este pointer ctre
caracter.
32






n ceea ce privete declaraia: char - (str_ptr[3]), se poate observa:
1. str_ptr[3] este de tipul char - (fiecare dintre cele trei elemente ale vectorului str_ptr[3] este de tipul
pointer ctre char);
2. - (str_ptr[3]) este de tip char (coninutul locaiei adresate de un element din str_ptr[3] este de tip char).
Fiecare element (pointer) din str_ptr este iniializat s pointeze ctre un ir de caractere constant. Fiecare dintre
aceste iruri de caractere se gsesc n memorie la adresele memorate n elementele vectorului str_ptr: str_ptr[0],
str_ptr[1], etc.

S ne amintim de la pointeri ctre iruri de caractere:
char - p=heLLO;
- ( p+1) = e
-
p[1] = e;
n mod analog:
str_ptr[1] = este;
- ( str_ptr[1] + 1) = s;
-
str_ptr[1][1]=s;

Putem conculziona:
str_ptr este un pointer ctre un pointer de caractere.
- str_ptr este pointer ctre char. Este evident, deoarece str_ptr[0] este pointer ctre char, iar
- str_ptr = - (str_ptr [0] + 0 )
-
str_ptr[0].
- - str_ptr este un de tip char. Este evident, deoarece str_ptr[0][0] este de tip char, iar
- - str_ptr=- ( - str_ptr)
-
- (str_ptr[0])=- (str_ptr[0]+0)
-

str_ptr[0][0].


5.5. POINTERI LA POINTERI

S revedem exemplul cu tabloul de pointeri str_ptr. irurile spre care pointeaz elementele tabloului pot fi
accesate prin str_ptr[index], ns deoarece str_ptr este un pointer constant, acestuia nu i se pot aplica operatorii
de incrementare i decrementare. Este ilegal :
for (i=0;i<3;i++)
cout<<str_ptr++ ;

De aceea, putem declara o variabil pointer ptr_ptr, care s pointeze ctre primul element din str_ptr. Variabila
ptr_ptr este pointer ctre pointer i se declar astfel:
char - - ptr_ptr;

n exemplul urmtor este prezentat modul de utilizare a pointerului la pointer ptr_ptr (figura 5.5).

Exemplu:
char - - ptr_ptr;
char - str_ptr[3] = { Programarea, este, frumoas! };
char - - ptr_ptr;
ptr_ptr = str_ptr;


str_ptr


Programarea

este

frumoas!

ptr_ptr
Dup atribuire, i str_ptr i ptr_ptr
pointeaz ctre aceeai locaie de memorie
(primul element al tabloului str_str). n
timp ce fiecare element al lui str_str este un
pointer, ptr_ptr este un pointer ctre pointer.
Deoarece ptr_ptr este un pointer variabil,
valoarea lui poate fi schimbat:
33











Referitor la declaraia char - - ptr_ptr, putem concluziona:
ptr_ptr este de tipul char- - (ptr_ptr este pointer la pointer ctre char);
- ptr_ptr este de tipul char- (coninutul locaiei ptr_ptr este de tipul pointer ctre char);
- - ptr_ptr este de tipul char ( - - ptr_ptr - ( - ptr_ptr); coninutul locaiei - ptr_ptr este de tipul
char).

5.6. MODIFICATORUL const N DECLARAREA POINTERILOR

Modificatorul const se utilizeaz frecvent n declararea pointerilor, avnd urmtoarele roluri:

Declararea unui pointer spre o dat constant
const *tip nume_pointer=dat_constant;

Exemplu:
const char *sirul=azi;
//variabila sirul este pointer spre un ir constant de caractere
Atribuirile de forma:
*sirul=coco;
*(sirul+2)=A;
nu sunt acceptate, deoarece pointerul sirul pointeaz ctre o dat constant (ir constant).

Declararea unui pointer constant ctre o dat care nu este constant
tip * const nume_pointer=dat_neconst;

Exemplu:
char * const psir=abcd; const char *sir=un text;
sir=alt sir; //incorect, sir pointeaz ctre dat constant
psir=sir; //incorect, deoarece psir este pointer constant

Declararea unui pointer constant ctre o dat constant
const tip * const nume_pointer=dat_constant;

Exemplu:
const char * const psir1="mnP";
*(psir1+2)='Z'; // incorect, data spre care pointez psir1 este constant
psir1++; // incorect, psir1 este pointer constant



STRUCTURA UNEI FUNCII
34


Un program scris n limbajul C/C++ este un ansamblu de funcii, fiecare dintre acestea efectund o activitate
bine definit. Din punct de vedere conceptual, funcia reprezint o aplicaie definit pe o mulime D
(D=mulimea, domeniul de definiie), cu valori n mulimea C (C=mulimea de valori, codomeniul), care
ndeplinete condiia c oricrui element din D i corespunde un unic element din C.

Funciile comunic prin argumennte: ele primesc ca parametri (argumente) datele de intrare, efectueaz
prelucrrile descrise n corpul funciei asupra acestora i pot returna o valoare (rezultatul, datele de ieire).
Execuia programului ncepe cu funcia principal, numit main. Funciile pot fi descrise n cadrul aceluiai
fiier, sau n fiiere diferite, care sunt testate i compilate separat, asamblarea lor realizndu-se cu ajutorul
linkeditorului de legturi.

O funcie este formata din antet si corp:
antet_funcie
{
corpul_funciei
}
Sau:
tip_val_return nume_func (lista_declaraiilor_param_ formali)
{
declaraii_variabile_locale
instruciuni
return valoare
}
Prima linie reprezint antetul funciei, n care se indic: tipul funciei, numele acesteia i lista declaraiilor
parametrilor formali. La fel ca un operand sau o expresie, o funcie are un tip, care este dat de tipul valorii
returnate de funcie n funcia apelant. Dac funcia nu ntoarce nici o valoare, n locul tip_vali_return se
specific void. Dac tip_val_return lipsete, se consider, implicit, c acesta este int. Nume_funcie este un
identificator.
Lista_declaraiilor_param_formali (ncadrat ntre paranteze rotunde) const ntr-o list (enumerare) care
conine tipul i identificatorul fiecrui parametru de intrare, desprite prin virgul. Tipul unui parametru poate
fi oricare, chiar i tipul pointer. Dac lista parametrilor formali este vid, n antet, dup numele funciei, apar
doar parantezele ( ), sau (void).

Corpul funciei este un bloc, care implementeaz algoritmul de calcul folosit de ctre funcie. n corpul funciei
apar (n orice ordine) declaraii pentru variabilele locale i instruciuni. Dac funcia ntoarce o valoare, se
folosete instruciunea return valoare. La execuie, la ntlnirea acestei instruciuni, se revine n funcia
apelant.
n limbajul C/C++ se utilizeaz declaraii i definiii de funcii.
Declaraia conine antetul funciei i informeaz compilatorul asupra tipului, numelui funciei i a listei
parametrilor formali (n care se poate indica doar tipul parametrilor formali, nu i numele acestora). Declaraiile
de funcii se numesc prototipuri, i sunt constituite din antetul funciei, din care pot lipsi numele parametrilor
formali.
Definiia conine antetul funciei i corpul acesteia. Nu este admis definirea unei funcii n corpul altei funcii.

O form nvechit a antetului unei funcii este aceea de a specifica n lista parametrilor formali doar numele
acestora, nu i tipul. Aceast libertate n omiterea tipului parametrilor constituie o surs de erori.
tipul_valorii_returnate nume_funcie (lista_parametrilor_ formali)
declararea_parametrilor_formali
{
35

declaraii_variabile_locale
instruciuni
return valoare
}


6.2. APELUL I PROTOTIPUL FUNCIILOR

O funcie poate fi apelat printr-o construcie urmat de punct i virgul, numit instruciune de apel, de forma:
nume_funcie (lista_parametrilor_efectivi);
Parametrii efectivi trebuie s corespund cu cei formali ca ordine i tip. La apel, se atribuie parametrilor formali
valorile parametrilor efectivi, dup care se execut instruciunile din corpul funciei. La revenirea din funcie,
controlul este redat funciei apelante, i execuia continu cu instruciunea urmtoare instruciunii de apel, din
funcia apelant. O alt posibilitate de a apela o funcie este aceea n care apelul funciei constituie operandul
unei expresii. Acest lucru este posibil doar n cazul n care funcia returneaz o valoare, folosit n calculul
expresiei.

Parametrii declarai n antetul unei funcii sunt numii formali, pentru a sublinia faptul c ei nu reprezint valori
concrete, ci numai in locul acestora pentru a putea exprima procesul de calcul realizat prin funcie. Ei se
concretizeaz la execuie prin apelurile funciei.
Parametrii folosii la apelul unei funcii sunt parametri reali, efectivi, concrei, iar valorile lor vor fi atribuite
parametrilor formali, la execuie. Utilizarea parametrilor formali la implementarea funciilor i atribuirea de
valori concrete pentru ei, la execuie, reprezint un prim nivel de abstractizare n programare. Acest mod de
programare se numete programare procedural i realizeaz un proces de abstractizare prin parametri.

Variabilele declarate n interiorul unei funcii, ct i parametrii formali ai acesteia nu pot fi accesai dect n
interiorul acesteia. Aceste variabile sunt numite variabile locale i nu pot fi accesate din alte funcii. Domeniul
de vizibilitate a unei variabile este poriunea de cod la a crei execuie variabila respectiv este accesibil. Deci,
domeniul de vizibilitate a unei variabile locale este funcia n care ea a fost definit (vezi i paragraful 6.8.).
Exemplu:
int f1(void)
{ double a,b; int c;
. . .
return c; // a, b, c - variabile locale, vizibile doar n corpul funciei
}
void main()
{ . . . . . . // variabile a i b nu sunt accesibile n main()
}
Dac n interiorul unei funcii exist instruciuni compuse (blocuri) care conin declaraii de variabile, aceste
variabile nu sunt vizibile n afara blocului.
Exemplu:
void main()
{ int a=1, b=2;
cout << "a=<<a<< b=<<b<< c=<<c\n; // a=1 b=2, c nedeclarat
. . . . . . . .
{ int a=5; b=6; int c=9;
cout << "a=<<a<< b=<<b<<\n; // a=5 b=6 c=9
. . . . . . . .
}
cout << "a=<<a<< b=<<b<< c=<<c\n; // a=1 b=6, c nedeclarat
36

. . . . . . . . . . . .
}

Exerciiu: S se scrie urmtorul program (pentru nelegerea modului de apel al unei funcii) i s se
urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void f_afis(void)
{
cout<<Se execut instruciunile din corpul funciei\n;
double a=3, b=9.4; cout<<a<<*<<b<<=<<a*b<<\n;
cout<<Ieire din funcie!\n; }

void main()
{
cout<<Intrare n funcia principal\n;
f_afis( ); //apelul funciei f_afis, printr-o instruciune de apel
cout<<Terminat MAIN!\n; }

Exerciiu: S se scrie un program care citete dou numere i afieaz cele mai mare divizor comun al acestora,
folosind o funcie care l calculeaz.
#include <iostream.h>
int cmmdc(int x, int y)
{
if (x==0 || y==1 || x==1 || y==0) return 1;
if (x<0) x=-x;
if (y<0) y=-y;
while (x != 0){
if ( y > x )
{int z=x; x=y; y=z; }
x-=y; // sau: x%=y;
}
return y;}

void main()
{
int n1,n2; cout<<n1=;cin>>n1; cout<<n2=;cin>>n2;
int diviz=cmmdc(n1,n2);
cout<<Cel mai mare divizor comun al nr-lor:<<n1<< i ;
cout<<n2<< este:<<diviz<<\n;
/* sau:
cout<<Cel mai mare divizor comun al nr-lor:<<n1<< i ;
cout<<n2<< este:<<cmmdc(n1,n2)<<\n;*/ }

Exerciiu: S se calculeze valoarea lui y, u i m fiind citite de la tastatur:
z=2e ( 2 (u) + 1, m) + e (2 u
2
- 3, m + 1), unde:
e (x,n) = sin( ) cos( ) ix ix
i
n
2
1 =

, (x) =
2
1
x
e

+ , e : R x N R, : R R

#include <iostream.h>
37

#include <math.h>
double omega(double x, int n)
{ double s=0; int i;
for (i=1; i<=n; i++) s+=sin(i*x)*cos(i*x);
return s;
}

double psi( double x)
{ return sqrt( 1 + exp (- pow (x, 2)));}

void main()
{double u, z; int m; cout<<u=; cin>>u; cout<<m=; cin>>m;
z=2*omega(2* psi(u) + 1, m) + omega(2*pow(u,2) - 3, m+1); cout<<z=<<z<<\n; }

n exemplele anterioare, nainte de apelul funciilor folosite, acestea au fost definite (antet+corp). Exist cazuri
n care definirea unei funcii nu poate fi fcut naintea apelului acesteia (cazul funciilor care se apeleaz unele
pe altele). S rezolvm ultimul exerciiu, folosind declaraiile funciilor omega i psi, i nu definiiile lor.

Exerciiu:
#include <iostream.h>
#include <math.h>
double omega(double, int);
// prototipul funciei omega - antet din care lipsesc numele parametrilor formali
double psi(double); // prototipul funciei psi

void main()
{double u, z; int m; cout<<u=; cin>>u; cout<<m=; cin>>m;
z=2*omega(2* psi(u) + 1, m) + omega(2*pow(u,2) - 3, m+1); cout<<z=<<z<<\n; }

double omega(double x, int i); // definiia funciei omega
{ double s=0; int i;
for (i=1; i<=n; i++) s += sin (i*x) * cos (i*x);
return s; }

double psi( double x) // definiia funciei psi
{ return sqrt( 1 + exp (- pow (x, 2))); }

Prototipurile funciilor din biblioteci (predefinite) se gsesc n headere. Utilizarea unei astfel de funcii impune
doar includerea n program a headerului asociat, cu ajutorul directivei preprocesor #include.
Programatorul i poate crea propriile headere, care s conin declaraii de funcii, tipuri globale,
macrodefiniii, etc.

Similar cu declaraia de variabil, domeniul de valabilitate (vizibilitate) a unei funcii este:
fiierul surs, dac declaraia funciei apare n afara oricrei funcii (la nivel global);
funcia sau blocul n care apare declaraia.


6.3. TRANSFERUL PARAMETRILOR UNEI FUNCII

Funciile comunic ntre ele prin argumente (parametrii).
38


Exist urmtoarele moduri de transfer (transmitere) a parametrilor ctre funciile apelate:
Transfer prin valoare;
Transfer prin pointeri;
Transfer prin referin.



6.3.1. TRANFERUL PARAMETRILOR PRIN VALOARE

n exemplele anterioare, parametrii de la funcia apelant la funcia apelat au fost transmii prin valoare. De la
programul apelant ctre funcia apelat, prin apel, se transmit valorile partametrilor efectivi, reali. Aceste valori
vor fi atribuite, la apel, parametrilor formali. Deci procedeul de transmitere a parametrilor prin valoare const n
ncrcarea valorii parametrilor efectivi n zona de memorie a parametrilor formali (n stiv). La apelul unei
funcii, parametrii reali trebuie s corespund - ca ordine i tip - cu cei formali.

Exerciiu: S se scrie urmtorul program (care ilustreaz legtura dintre pointeri i vectori) i s se urmreasc
rezultatele execuiei acestuia.
void f1(float intr,int nr)// intr, nr - parametri formali
{
for (int i=0; i<nr;i++) intr *= 2.0;
cout<<Val. Param. intr=<<intr<<\n;// intr=12
}
void main()
{
float data=1.5; f1(data,3);
// apelul funciei f1; data, 3 sunt parametri efectivi
cout<<data=<<data<<\n;
// data=1.5 (nemodificat)
}

Fiecare argument efectiv utilizat la apelul funciei este evaluat, iar valoarea este atribuit parametrului formal
corespunztor. n interiorul funciei, o copie local a acestei valori va fi memorat n parametrul formal. O
modificare a valorii parametrului formal n interiorul funciei (printr-o operaie din corpul funciei), nu va
modifica valoarea parametrului efectiv, ci doar valoarea parametrului formal, deci a copiei locale a parametrului
efectiv (figura 6.1.). Faptul c variabila din programul apelant (parametrul efectiv) i parametrul formal sunt
obiecte distincte, poate constitui un mijloc util de protecie. Astfel, n funcia f1, valoarea parametrului formal
intr este modificat (alterat) prin instruciunea ciclic for. n schimb, valoarea parametrului efectiv (data) din
funcia apelant, rmne nemodificat.
n cazul transmiterii parametrilor prin valoare, parametrii efectivi pot fi chiar expresii. Acestea sunt evaluate, iar
valoarea lor va iniializa, la apel, parametrii formali.
Exemplu:
double psi(int a, double b)
{
if (a > 0) return a*b*2;
else return -a+3*b; }
void main()
{ int x=4; double y=12.6, z; z=psi ( 3*x+9, y-5) + 28;
cout<<z=<<z<<\n; }

Copiere valoare
intr
data
1.5
1.5
Figura 6.1. Transmiterea prin
valoare
39

Transferul valorii este nsoit de eventuale conversii de tip. Aceste conversii sunt realizate automat de
compilator, n urma verificrii apelului de funcie, pe baza informaiilor despre funcie, sau sunt conversii
explicite, specificate de programator, prin operatorul cast.
Exemplu:
float f1(double, int);
void main()
{
int a, b; float g=f1(a, b); // conversie automat: int a -> double a
float h=f1( (double) a, b); // conversie explicit
}

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

6.3.2. TRANSFERUL PARAMETRILOR PRIN POINTERI

n unele cazuri, parametrii transmii unei funcii pot fi pointeri (variabile care conin adrese). n aceste cazuri,
parametrii formali ai funciei apelate vor fi iniializai cu valorile parametrilor efectivi, deci cu valorile unor
adrese. Astfel, funcia apelat poate modifica coninutul locaiilor spre care pointeaz argumentele (pointerii).

Exerciiu: S se citeasc 2 valori ntregi i s se interschimbe cele dou valori. Se va folosi o funcie de
interschimbare.
#include <iostream.h>
void schimb(int *, int *); //prototipul functiei schimba
void main()
{
int x, y, *ptx, *pty; ptx=&x; pty=&y;
cout<<x=;cin>>x;cout<<y=;cin>>y;cout<<x=<<x;cout<<y=<<y<<\n;
cout<<"Adr. lui x:"<<&x<<" Val lui x:"<<x<<'\n';
cout<<"Adr.lui y:"<<&y<<" Val y:"<<y<<'\n'; cout<<"Val. lui ptx:"<<ptx;
cout<<" Cont. locaiei spre care pointeaz ptx:<<*ptx<<'\n';
cout<<"Val. lui pty:"<<pty;
cout<<"Cont. locaiei spre care pointeaz pty:"<<*pty;
schimba(ptx, pty);
// SAU: schimba(&x, &y);
cout<<"Adr. lui x:"<<&x<<" %x Val lui x: %d\n, &x, x);
cout<<"Adr. y:"<<&y<<" Val lui y:"<<y<<'\n';cout<<"Val. lui ptx:"<<ptx;
cout<<" Cont. locaiei spre care pointeaz ptx:<<*ptx<<'\n';
cout<<"Val. lui pty:"<<pty;
cout<<" Cont. locaiei spre care pointeaz pty:"<<*pty<<'\n';
}
void schimb( int *p1, int *p2)
{
cout<<"Val. lui p1:"<<p1;
cout<<" Cont. locaiei spre care pointeaz p1:"<<*p1<<'\n';
cout<<"Val. lui p2:"<<p2;
cout<<" Cont. locaiei spre care pointeaz p2:"<<*p2<<'\n';
int t = *p1; // int *t ; t=p1;
40

*p2=*p1; *p1=t;
cout<<"Val. lui p1:"<<p1;
cout<<" Cont. locaiei spre care pointeaz p1:<<*p1<<'\n';
cout<<"Val. lui p2:"<<p2;
cout<<" Cont. locaiei spre care pointeaz p2:"<<*p2<<'\n';
}
Dac parametrii funciei schimb ar fi fost transmii prin valoare, aceast funcie ar fi interschimbat copiile
parametrilor formali, iar n funcia main modificrile asupra parametrilor transmii nu s-ar fi pstrat. n figura
6.2. sunt prezentate mecanismul de transmitere a parametrilor (prin pointeri) i modificrile efectuate asupra lor
de ctre funcia schimb.















Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
double omega (long *k)
{
cout<<"k=", k);
// k conine adr. lui i
cout<<*k=;
cout<<k<<\n;
// *k = 35001
double s=2+(*k)-3;
// s = 35000
cout<<s=<<s<<\n;
*k+=17; // *k = 35017
cout<<*k=<<*k;
cout<<\n;
return s; }

void main()
{
long i = 35001; double w;
cout<<"i="<<i;cout<<"Adr.lui i:"<<&i<<'\n';
w=omega(&i); cout<<i=<<i<< w=<<w<<\n; // i = 350017 w = 35000
}


y
x
Parametrii formali p1 i p2, la apelul
funciei schimb, primesc valorile
parametrilor efectivi ptx i pty, care
reprezint adresele variabilelor x i y.
Astfel, variabilele pointer p1 i ptx,
respectiv p2 i pty pointeaz ctre x i
y. Modificrile asupra valorilor
variabilelor x i y realizate n corpul
funciei schimb, se pstreaz i n
funcia main.
0x34
0x5A
pty
10 30 30 10
0x34 0x5A
ptx
0x34
p1
0x5A
p2
Figura 6.2. Transmiterea parametrilor unei funcii prin pointeri
0x451

n funcia main

n funcia omega

35001 (apoi 35017)
i
0x451 (adr.lui i)
k
35000
s
35000
w
Figura 6.3. Transferul parametrilor prin pointeri
41

6.3.2.1. Funcii care returneaz pointeri

Valoarea returnat de o funcie poate fi pointer, aa cum se observ n exemplul urmtor:
Exemplu:
#include <iostream.h>
double *f (double *w, int k)
{ // w conine adr. de nceput a vectorului a
cout<<"w="<<w<<" *w="<<*w<<'\n'; // w= adr. lui a ;*w = a[0]=10
return w+=k;
/*incrementeaza pointerului w cu 2(val. lui k); deci w pointeaz ctre elementul de indice 2 din vectorul
a*/
}
void main()
{double a[10]={10,1,2,3,4,5,6,7,8,9}; int i=2;
cout<<"Adr. lui a este:"<<a;
double *pa=a; // double *pa; pa=a;
cout<<"pa="<<pa<<'\n' // pointerul pa conine adresa de nceput a tabloului a
// a[i] = * (a + i)
// &a[i] = a + i
pa=f(a,i); cout<<"pa="<<pa<<" *pa="<<*pa<<'\n';
// pa conine adr. lui a[2], adica adr. a + 2 * sizeof(double);
*pa=2;
}


6.3.3. TRANSFERUL PARAMETRILOR PRIN REFERIN

n acest mod de transmitere a parametrilor, unui parametru formal i se poate asocia (atribui) chiar obiectul
parametrului efectiv. Astfel, parametrul efectiv poate fi modificat direct prin operaiile din corpul funciei
apelate.

n exemplul urmtor definim variabila br, variabil referin ctre variabila b. Variabilele b i br se gsesc, n
memorie, la aceeai adres i sunt variabile sinonime.

Exemplu:
#include <stdio.h>
#include <iostream.h>
void main()
{
int b,c;
int &br=b; //br referin la alt variabil (b)
br=7;
cout<<"b="<<b<<'\n'; //b=7
cout<<"br="<<br<<'\n'; //br=7
cout<<"Adr. br este:"<<&br; //Adr. br este:0xfff4
printf("Adr. b este:"<<&b<<'\n'; //Adr. b este:0xfff4
b=12; cout<<"br="<<br<<'\n'; //br=12
cout<<"b="<<b<<'\n'; //b=12
c=br; cout<<"c="<<c<<'\n'; //c=12
}
c
b, br
7 12
12
Figura 6.4. Variabilele referin b, br
42


Exemplul devenit clasic pentru explicarea apelului prin referin este cel al funciei de permutare
(interschimbare) a dou variabile.

Fie funcia schimb definit astfel:
void schimb (double x, double y)
{ double t=x; x=y; y=t; }

void main()
{ double a=4.7, b=9.7;
. . . . . . . . . . .
schimb(a, b); // apel funcie
. . . . . . . . . . . }

Pentru ca funcia de interschimbare s poat permuta valorile parametrilor efectivi, n limbajul C/C++
parametrii formali trebuie s fie pointeri ctre valorile care trebuie interschimbate:

void pschimb(double *x, double *y)
{ int t=*x; *x=*y; *y=t; }
void main()

{ double a=4.7, b=9.7;
. . . . . . . . . . .
pschimb(&a, &b); // apel funcie
/* SAU:
double *pa, *pb;
pa=&a; pb=&b;
pschimb(pa, pb);*/
. . . . . . . . . . . }












n limbajul C++ acceai funcie de permutare se poate defini cu parametri formali de tip referin.

void rschimb(double &x, double &y)
{ int t=x; x=y; y=t; }
void main()
{ double a=4.7, b=9.7;
. . . . . . . . . . . . . . .
rschimb(a, b); // apel funcie
. . . . . . . . . . . . . . . }
Se atribuie pointerilor x i y valorile
pointerilor pa, pb, deci adresele
variabilelor a i b. Funcia pschimb
permut valorile spre care pointeaz
pointerii x i y, deci valorile lui a i b
(figura 6.5).

Parametri funciei schimb sunt transmii
prin valoare: parametrilor formali x, y li se
atribuie (la apel) valorile parametrilor
efectivi a, b. Funcia schimb permut
valorile parametrilor formali x i y, dar
permutarea nu are efect asupra parametrilor
efectivi a i b.

pschimb
&a
&b
4.7
*x
*y
aux
main
a
b
4.7 9.7
9.7 4.7
Figura 6.5. Transferul parametrilor
prin pointeri
rschimb
4.7 aux
main
x;
a
y;b
4.7 9.7
9.7 4.7
Figura 6.6. Transferul parametrilor prin
referin

43


n acest caz, x i y sunt sinonime cu a i b (nume diferite pentru aceleai grupuri de locaii de memorie).
Interschimbarea valorilor variabilelor de x i y nseamn interschimbarea valorilor variabilelor a i b (fig. 6.6.).

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

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

Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
#include <stdio.h>

double func(int a, double b, double *c, double &d)
{cout<<"*********************** func *****************\n";
cout<<"a="<<a<<" b="<<b; //a=7 (a=t prin val); b=21 (b=u prin val)
cout<<" c="<<c<<" *c="<<*c<<'\n'; // c=ffe(c=w=&u) *c=21
cout<<" d="<<d; //d=17
cout<<"Adr d="<<&d<<'\n'; //Adr d=ffe6 (adr d=adr v)
a+=2; cout<<"a="<<a<<'\n'; //a=9
d=2*a+b; cout<<"d="<<d<<'\n'; //d=39
/*c=500;
cout<<" c="<<c<<" *c="<<*c<<'\n'; // c=ffe(c=w=&u) *c=21*/
cout<<"*********************** func *****************\n";
return b+(*c);
}

void main()
{cout<<"\n\n \n MAIN MAIN";
int t=7; double u=12, v=17, *w, z; cout<<"u="<<u<<'\n'; //u=12
w=&u; *w=21;
cout<<"t="<<t<<" u="<<u<<" v="<<v; //t=7 u=12 v=17 *w=21
cout<<" *w="<<*w<<" u="<<u<<'\n'; //*w=21 u=21
printf("w=%x Adr. u=%x\n",w,&u); //w=ffee Adr. u=ffee
44

printf("v=%f Adr v=%x\n",v,&v); //v=17.000 Adr v=ffe6
z=func(t,u,w, v);
cout<<"t="<<t<<"u="<<u<<"v="<<v; //t=7 u=21 (NESCHIMBATI) v=39 (v=d)
cout<<" *w="<<*w<<" z="<<z<<'\n'; //*w=21 w=ffee z=42
printf(" w=%x\n",w);
}

Exemplul ilustreaz urmtoarele probleme:
La apelul funciei func, parametrii t i u sunt transmii prin valoare, deci valorile lor vor fi atribuite parametrilor
formali a i b. Orice modificare a parametrilor formali a i b, n funcia func, nu va avea efect asupra
parametrilor efectivi t i u. Al treilea parametru formal al funciei func este transmis prin pointeri, deci c este de
tip double * (pointer ctre un real), sau *c este de tip double.

La apelul funciei, valoarea pointerului w (adresa lui u : w=&u) este atribuit pointerului c. Deci pointerii w i c
conin aceeai adres, pointnd ctre un real. Dac s-ar modifica valoarea spre care pointeaz c n func (vezi
instruciunile din comentariu *c=500), aceast modificare ar fi reflectat i n funcia apelant, deoarece
pointerul w are acelai coninut ca i pointerul c, deci pointeaz ctre aceeai locaie de memorie. Parametrul
formal d se transmite prin referin, deci, n momentul apelului, d i v devin similare (d i v sunt memorate la
aceeai adres). Modificarea valorii variabilei d n func se reflect, deci, i asupra parametrului efectiv din
funcia main.

Exerciiu: S se scrie urmtorul program (care ilustreaz legtura dintre pointeri i vectori) i s se urmreasc
rezultatele execuiei acestuia.
#include <iostream.h>
#include <stdio.h>
double omega(long &k)
{printf("Adr k=%x Val k=%ld\n",&k,k); //Adr k=fff2 Val k=200001
double s=2+k-3;cout<<"s="<<s<<'\n'; //s=200000
k+=17;printf("Adr k=%x Val k=%ld\n",&k,k); //Adr k=fff2 Val k=200018
return s;
}
void main()
{long a=200001;
printf("Adr a=%x Val a=%ld\n",&a,a); //Adr a=fff2 Val a=200001
double w=omega(a); cout<<"w="<<w<<'\n'; //s=200000
}

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

Exemplu:
#include <iostream.h>
#include <stdio.h>
int func(const int &a)
{printf("Adr a=%x Val a=%d\n",&a,a);int b=2*a+1;
45

//modificarea valorii parametrului a nu este permis
cout<<"b="<<b<<'\n';return b;}
void main()
{const int c=33;int u;printf("Adr c=%x Val c=%d\n",&c,c);
u=func(c);cout<<"u="<<u<<'\n'; }



6.3.4. TRANSFERUL PARAMETRILOR CTRE FUNCIA main

n situaiile n care se dorete transmiterea a unor informaii (opiuni, date iniiale, etc) ctre un program, la
lansarea n execuie a acestuia, este necesar definirea unor parametri ctre funcia main. Se utilizeaz trei
parametrii speciali: argc, argv i env. Trebuie inclus headerul stdarg.h.
Prototipul funciei main cu parametri n linia de comand este:
main (int argc, char *argv[ ], char *env[ ])

Dac nu se lucreaz cu un mediu de programare integrat, argumentele transmise ctre funcia main trebuie
editate (specificate) n linia de comand prin care se lanseaz n execuie programul respectiv. Linia de
comand tastat la lansarea n execuie a programului este format din grupuri de caractere delimitate de spaiu
sau tab. Fiecare grup este memorat ntr-un ir de caractere. Dac se lucreaz cu un mediu integrat (de exemplu,
BorlandC), selecia comanzii Arguments din meniul Run determin afiarea unei casete de dialog n care
utilizatorul poate introduce argumentele funciei main.

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

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

Exerciiu: S se implementeze un program care afieaz argumentele transmise ctre funcia main.
#include <iostream.h>
#include <stdarg.h>
void main(int argc, char *argv[], char *env[])
{cout<<"Nume program:"<<argv[0]<<'\n';//argv[0] contine numele programului
if(argc==1)
cout<<"Lipsa argumente!\n";
else
for (int i=1; i<argc; i++){
cout<<"Argumentul "<<i<<":"<<argv[i]<<'\n';
}


6.4. TABLOURI CA PARAMETRI

46

n limbajul C, cazul parametrilor tablou constituie o excepie de la regula transferului parametrilor prin valoare.
Numele unui tablou reprezint, de fapt, adresa tabloului, deci a primului element din tablou.

Exerciiu: S se afle elementul minim dintr-un vector de maxim 10 elemente. Se vor scrie dou funcii: de citire
a elementelor vectorului i de aflare a elementului minim:
#include <iostream.h>
int min_tab(int a[], int nr_elem)
{int elm=a[0];
for (int ind=0; ind<nr_elem; ind++)
if (elm>=a[ind]) elm=a[ind];
return elm;
}
void citireVector(int b[], int nr_el)
{ for (int ind=0; ind<nr_el; ind++){
cout<<"Elem "<<ind+1<<"="; cin>>b[ind];}
}
void main()
{
int a[10]; int i,j,n; cout<<"n="; cin>>n;
citireVector(a,n);
int min=min_tab(a,n); cout<<"Elem. min:"<<min<<'\n'; }

Aceleeai problem poate fi implementat folosind aritmetica pointerilor:

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

Din exemplele anterioare se poate observa:
1. Prototipul funciei min_tab poate fi unul dintre:
int min_tab(int a[], int nr_elem);
int min_tab(int *a, int nr_elem);
2. Echivalene:
int *a int a[]
a[i] *(a+i)
47

3. Apelul funciilor:
citireVector(a,n);
int min=min_tab(a,n);
4. Pentru tablourile unidimensionale, la apel, nu trebuie specificat numrul de elemente. Dimensiunea tabloului
trebuie s fie cunoscut n funcia care l primete ca parametru. De obicei, dimensiunea tabloului se transfer
ca parametru separat (nr_elem).

Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
#include <stdio.h>
double omega(int j, double x, double t[], double *w)
{double s; cout<<"n funcia omega:";
cout<<"j="<<j<<" t[j]="<<t[j]<<" t[j+1]="<<t[j+1]<<'\n';
//j=2 (=i din main)
//t[j]=-3.21 t[j+1]=7.44
cout<<"j="<<j<<" w[j]="<<w[j]<<" w[j+1]="<<w[j+1]<<'\n';
//j=2 (=i din main)
//w[j]=-21.16 w[j+1]=92.2
t[j]=100; *(t+j+1)=200; w[j]=300; *(w+j+1)=400;
cout<<"Dup atribuiri:\n";
cout<<"j="<<j<<" t[j]="<< t[j]<<" t[j+1]="<<t[j+1]<<'\n';
//Dup atribuiri:
//j=2
//t[j]=100 t[j+1]=200
//w[j]=300 w[j+1]=400
cout<<"j="<<j<<" w[j]="<<w[j]<<" w[j+1]="<<w[j+1]<<'\n';
int i=2*j+1; x=x+2.29*i; s=x+2*t[0]-w[1];
cout<<"i="<<i<<" x="<<x<<" s="<<s<<'\n';
//i=5 x=1.123+2.29+5 s=x+2*1.32-(-15.34)
return s;
}
void switch1(double *x, double *y)
{double t=*x; *x=*y; *y=t;}
void switch2(double &x, double &y)
{double t; t=x;x=y;y=t;}
void main()
{double a=123, b=456, u=1.123;
int i=2;
double r[]={1.32, 2.15, -3.21, 7.44, -15.8};
double q[]={12.26, -15.34, -21.16, 92.2, 71.6};
cout<<"i="<<i<<" u="<<u<<'\n';
double y=omega(i,u,r,q);
cout<<"i="<<i<<" u="<<u<<'\n';
//i=2 u=....
cout<<"omega(i,u,r,q)=y="<<y<<'\n';
cout<<"r[i]="<<r[i]<<" r[i+1]="<<r[i+1]<<;
cout<<" q[i]="<<q[i]<<" q[i+1]="<<q[i]<<'\n';
//r[i]=100 r[i+1]=200 q[i]=300 q[i+1]=400
cout<<"a="<<a<<" b="<<b<<'\n'; //a=123 b=456
switch1(&a,&b);
48

cout<<"Rez. intersch. a="<<a<<" b="<<b<<'\n'; //a=456 b=123
switch2(a,b);
cout<<"Rez. intersch. a="<<a<<" b="<<b<<'\n'; //a=123 b=456
cout<<"r[i]="<<r[i]<<" r[i+1]="<<r[i+1]<<'\n';
switch1(r+i,r+i+1);
cout<<"Rez. intersch. r[i]="<<r[i]<<" r[i+1]="<<r[i+1]<<'\n';
switch2(r[i],r[i+1]);
//switch2(*(r+i),*(r+i+1));
cout<<"Rez. intersch. r[i]="<<r[i]<<" r[i+1]="<<r[i+1]<<'\n';
}

n exemplul anterior, parametrii formali i i x din funcia omega sunt transmii prin valoare; parametrii t i w
sunt parametri tablou, transmii prin referin (referin i pointeri). n funcia switch1 parametrii sunt transmii
prin pointeri. n funcia switch2 parametrii sunt transmii prin referin.

Pentru tablourile multidimensionale, pentru ca elementele tabloului s poat fi referite n funcie, compilatorul
trebuie informat asupra modului de organizare a tabloului.
Pentru tablourile bidimensionale (vectori de vectori), poate fi omis doar precizarea numrului de linii,
deoarece pentru a adresa elementul a[i][j], compilatorul utilizeaz relaia: &mat[i][j]=&mat+(i*
N+j)*sizeof(tip), n care N reprezint numrul de coloane, iar tip reprezint tipul tabloului.

Exerciiu: Fie o matrice de maxim 10 linii i 10 coloane, ale crei elemente se introduc de la tastatur. S se
implementeze dou funcii care afieaz matricea i calculeaz elementul minim din matrice.

#include <iostream.h>
int min_tab(int a[][10], int nr_lin, int nr_col)
{int elm=a[0][0];
for (int il=0; il<nr_lin; il++)
for (int ic=0; ic<nr_col; ic++)
if (elm>=a[il][ic]) elm=a[il][ic];
return elm;
}
void afisare(int a[][10], int nr_lin, int nr_col)
{
for (int i=0; i<nr_lin; i++)
{for (int j=0; j<nr_col; j++) cout<<a[i][j]<<'\t';
cout<<'\n';
}
}
void main()
{
int mat[10][10];int i, j, M, N;cout<<"Nr. linii:"; cin>>M;
cout<<"Nr. coloane:"; cin>>N;
for (i=0; i<M; i++)
for (j=0; j<N; j++)
{ cout<<"mat["<<i<<","<<j<<"]="; cin>>mat[i][j];}
afisare(mat, M, N);
int min=min_tab(mat, M, N);
cout<<"Elem. min:"<<min<<'\n';
}
49


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

Exemplu:
#include <iostream.h>
#include <stdio.h>
double &func(double &a, double b)
{ printf("n funcie:\n");
printf("Val a=%f Adr a=%x\n", a, &a); //Val a=1.20 Adr a=fffe
cout<<"b="<<b<<'\n'; //b=2.2
a=2*b+1; printf(" Dup atrib: val a=%f Adr a=%x\n", a, &a);
//Val a=5.40 Adr a=fffe
return a;
}
void main()
{double c=1.2;cout<<"***************MAIN****************\n";
printf("Val c=%f Adr c=%x\n",c, &c); //Val c=1.20 Adr c=fffe
double d; printf("Adr. d=%x\n", &d); //Adr. d=ffe6
d=func(c,2.2);
printf("Val d=%f Adr d=%x\n", d, &d); //Val d=5.40 Adr d=ffe6
}


6.5. FUNCII CU PARAMETRI IMPLICII

Spre deosebire de limbajul C, n limbajul C++ se pot face iniializri ale parametrilor formali. Parametrii
formali iniializai se numesc parametri implicii. De exemplu, antetul funciei cmmdc (care calculeaz i
returneaz cel mai mare divizor comun al numerelor ntregi primite ca argumente) poate avea aceasta form:
int cmmdc(int x, int y=1);

Parametrul formal y este iniializat cu valoarea 1 i este parametru implicit. La apelul funciilor cu parametri
implicii, unui parametru implicit, poate s-i corespund sau nu, un parametru efectiv. Dac la apel nu i
corespunde un parametru efectiv, atunci parametrul formal va primi valoarea prin care a fost iniializat (valoarea
implicit). Dac la apel i corespunde un parametru efectiv, parametrul formal va fi iniializat cu valoarea
acestuia, negijndu-se astfel valoarea implicit a parametrului formal. n exemplul anterior, la apelul:
int div=cmmdc(9);
x va lua valoarea 9, iar y va lua valoarea 1 (implicit).

Dac n lista de parametri formali ai unei funcii exist i parametri implicii i parametri neiniializai,
parametrii implicii trebuie s ocupe ultimele poziii n list, nefiind permis intercalarea acestora printre
parametrii neiniializai.


6.6. FUNCII CU NUMR VARIABIL DE PARAMETRI
50


n limbajele C i C++ se pot defini funcii cu un numr variabil de parametri. Parametrii care trebuie s fie
prezeni la orice apel al funciei se numesc parametri fici, ceilali se numesc parametri variabili. Parametrii
fici preced parametrii variabili. Prezena parametrilor variabili se indic n antetul funciei prin trei puncte care
se scriu dup ultimul parametru fix al funciei.

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

Funciile cu un numr variabil de parametri sunt, de obicei, funcii de bibliotec (ex: printf, scanf) i se definesc
folosind nite macrouri speciale care permit accesul la parametrii variabili i se gsesc n headerul stdarg.h.


6.7. FUNCII PREDEFINITE

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

Pentru ca funciile predefinite s poat fi utilizate, fiierele header n care se gsesc prototipurile acestora
trebuie inclus n funcia (programul) apelant printr-o directiv preprocesor (exemplu #include <stdio.h>).
Deasemenea, utilizatorul i poate crea propriile headere proprii. Pentru a putea utiliza funciile proprii, el
trebuie s includ aceste headere n programul apelant (exemplu #include "my_header.h").

Pentru funciile predefinite, au fost create fiiere header orientate pe anumite numite tipuri de aplicaii. De
exemplu, funciile matematice se gsesc n headerul <math.h>. Headerul <stdlib.h> care conine funcii
standard. Headerul <values.h> definete o serie de constante simbolice (exemplu MAXINT, MAXLONG) care
reprezint, n principal, valorile maxime i minime ale diferitelor tipuri de date.

6.7.1. Funcii matematice (headerul <math.h>)

Funcii aritmetice
Valori absolute
int abs(int x);
Returneaz un ntreg care reprezint valoarea absolut a argumentului.
long int labs(long int x);
Analog cu funcia abs, cu deosebirea c argumentul i valoarea returnat sunt de tip long int.
double fabs(double x);
Returneaz un real care reprezint valoarea absolut a argumentului real.

Funcii de rotunjire
double floor(double x);
Returneaz un real care reprezint cel mai apropiat numr, fr zecimale, mai mic sau egal cu x
(rotunjire prin lips).
double ceil(double x);
Returneaz un real care reprezint cel mai apropiat numr, fr zecimale, mai mare sau egal cu x
(rotunjire prin adaos).
51


Funcii trigonometrice
double sin(double x);
Returneaz valoarea lui sin(x), unde x este dat n radiani. Numrul real returnat se afl n
intervalul [-1, 1].
double cos(double x);
Returneaz valoarea lui cos(x), unde x este dat n radiani. Numrul real returnat se afl n
intervalul [-1, 1].
double tan(double x);
Returneaz valoarea lui tg(x), unde x este dat n radiani.

Funcii trigonometrice inverse
double asin(double x);
Returneaz valoarea lui arcsin(x), unde x se afl n intervalul [-1, 1]. Numrul real returnat (n
radiani) se afl n intervalul [-pi/2, pi/2].
double acos(double x);
Returneaz valoarea lui arccos(x), unde x se afl n intervalul [-1, 1]. Numrul real returnat se
afl n intervalul [0, pi].
double atan(double x);
Returneaz valoarea lui arctg(x), unde x este dat n radiani. Numrul real returnat se afl n
intervalul [0, pi].
double atan2(double y, double x);
Returneaz valoarea lui tg(y/x), cu excepia faptului ca semnele argumentelor x i y permit
stabilirea cadranului i x poate fi zero. Valoarea returnat se afl n intervalul [-pi,pi]. Dac x i y
sunt coordonatele unui punct n plan, funcia returneaz valoarea unghiului format de dreapta
care unete originea axelor carteziene cu punctul, fa de axa absciselor. Funcia folosete,
deasemenea, la transformarea coordonatelor cartezine n coordonate polare.

Funcii exponeniale i logaritmice
double exp(double x);
long double exp(long double x);
Returneaz valoarea e .
double log(double x);
Returneaz logaritmul natural al argumentului ( ln(x) ).
double log10(double x);
Returneaz logaritmul zecimal al argumentului (lg (x) ).
double pow(double baza, double exponent);
Returneaz un real care reprezint rezultatul ridicrii bazei la exponent ( ).
double sqrt(double x);
Returneaz rdcina ptrat a argumentului

x .
double hypot(double x, double y);
Funcia distanei euclidiene - returneaz
2 2
y x + , deci lungimea ipotenuzei unui triunghi
dreptunghic, sau distana punctului P(x, y) fa de origine.

Funcii de generare a numerelor aleatoare
int rand(void) <stdlib.h>
Genereaz un numr aleator n intervalul [0, RAND_MAX].

6.7.2. Funcii de clasificare (testare) a caracterelor
x
baza
onent exp
52

Au prototipul n headerul <ctype.h>. Toate aceste funcii primesc ca argument un caracter i returneaz
un numr ntreg care este pozitiv dac argumentul ndeplinete o anumit condiie, sau valoarea zero
dac argumentul nu ndeplinete condiia.

int isalnum(int c);
Returneaz valoare ntreag pozitiv daca argumentul este liter sau cifr. Echivalent cu:
isalpha(c)||isdigit(c)
int isalpha(int c);
Testeaz dac argumentul este liter mare sau mic. Echivalent cu isupper(c)|| islower(c).
int iscntrl(int c);
Testeaz dac argumentul este caracter de control (neimprimabil).
int isdigit(int c);
Testeaz dac argumentul este cifr.
int isxdigit(int c);
Testeaz dac argumentul este cifr hexagesimal (0-9, a-f, A-F).
int islower(int c);
Testeaz dac argumentul este liter mic.
int isupper(int c);
Testeaz dac argumentul este liter mare.
int ispunct(int c);
Testeaz dac argumentul este caracter de punctuaie (caracter imprimabil, dar nu liter sau
spaiu).
int isspace(int c);
Testeaz dac argumentul este spaiu alb (' ', '\n', '\t', '\v', '\r')
int isprint(int c);
Testeaz dac argumentul este caracter imprimabil, inclusiv blancul.

6.7.3. Funcii de conversie a caracterelor (prototip n <ctype.h>)
int tolower(int c);
Funcia schimb caracterul primit ca argument din liter mare, n liter mic i returneaz codul
ASCII al literei mici. Dac argumentul nu este liter mare, codul returnat este chiar codul
argumentului.
int toupper(int c);
Funcia schimb caracterul primit ca argument din liter mic, n liter mare i returneaz codul
acesteia. Dac argumentul nu este liter mic, codul returnat este chiar codul argumentului.

6.7.4. Funcii de conversie din ir n numr (de citire a unui numr dintr-un ir)
(prototip n <stdlib.h>)
long int atol(const char *npr);
Funcia convertete irul transmis ca argument (spre care pointeaz npr) ntr-un numr cu semn,
care este returnat ca o valoare de tipul long int. irul poate conine caracterele '+' sau '-'. Se
consider c numrul este n baza 10 i funcia nu semnalizeaz eventualele erori de depire
care pot apare la conversia din ir n numr.
int atoi(const char *sir);
Converteste irul spre care pointeaza sir ntr-un numr ntreg.
double atof(const char *sir);
Funcia converteste irul transmis ca argument ntr-un numr real cu semn (returneaz valoare de
tipul double). n secvena de cifre din ir poate apare litera 'e' sau 'E' (exponentul), urmat de
caracterul '+' sau '-' i o alt secven de cifre. Funcia nu semnaleaz eventualele erori de
depire care pot apare.
53



6.8. CLASE DE MEMORARE

Definiii:
Variabilele declarate n afara oricrei funcii sunt variabilele globale.
Variabilele declarate n interiorul unui bloc sunt variabilele locale.
Poriunea de cod n care o variabil este accesibil reprezint scopul (domeniul de vizibilitate) al
variabilei respective.

Parametrii formali ai unei funcii sunt variabile locale ale funciei respective.
Domeniul de vizibilitate al unei variabile locale este blocul n care variabila respectiv este definit.
n situaia n care numele unei variabile globale coincide cu numele unei variabile locale, variabila local o
"mascheaz" pe cea global, ca n exemplul urmtor: n interiorul blocului din funcia main s-a redefinit
variabila a, care este variabil local n interiorul blocului. Variabila local a mascheaz variablila global
numit tot a.

Exemplu:
#include <stdio.h>
void main()
{ int a,b; a=1; b=2;
printf("n afara blocului a=%d b=%d\n", a, b);
{int a=5; b=6;
printf("n interiorul blocului a=%d b=%d\n",a,b);
}
printf("n afara blocului a=%d b=%d\n", a, b);
}

n cazul variabilelor locale, compilatorul aloc memorie n momentul execuiei blocului sau funciei n care
acestea sunt definite. Cnd execuia funciei sau blocului se termin, se elibereaz memoria pentru acestea i
valorile pentru variabilele locale se pierd.

Definiii:
Timpul de via a unei variabile locale este durata de execuie a blocului (sau a funciei) n care aceasta
este definit.
Timpul de via a unei variabile globale este durata de execuie a programului.

n exemplul urmtor, variabila ntreag x este vizibil att n funcia main, ct i n funcia func1 (x este
variabila global, fiind definit n exteriorul oricrei funcii). Variabilele a i b sunt variabile locale n funcia
main (vizibile doar n main). Variabilele c i d sunt variabile locale n funcia func1 (vizibile doar n func1).
Varabila y este variabil extern i este vizibil din punctul n care a fost definit, pn la sfritul fiierului
surs (n acest caz, n funcia func1).

Exemplu:
int x;
void main()
{int a,b;
//- - - - - - - - -
}
int y;
54

void func1(void)
{int c,d;
//- - - - - - - -
}


Clase de memorare

O variabil se caracterizeaz prin: nume, tip, valoare i clas de memorare.
Clasa de memorare se specific la declararea variabilei, prin unul din urmtoarele cuvinte cheie:
auto;
register;
extern;
static.
Clasa de memorare determin timpul de via i domeniul de vizibilitate (scopul) unei variabile (tabelul 6.1).
Exemplu:
auto int a;
static int x;
extern double y;
register char c;

Clasa de memorare auto
Dac o variabil local este declarat fr a se indica n mod explicit o clas de memorare, clasa de
memorare considerat implicit este auto. Pentru acea variabil se aloc memorie automat, la intrarea n
blocul sau n funcia n care ea este declarat. Deci domeniul de vizibilitate al variabilei este blocul sau
funcia n care aceasta a fost definit. Timpul de via este durata de execuie a blocului sau a funciei.

Clasa de memorare register
Variabilele din clasa register au acelai domeniu de vizibilitate i timp de via ca i cele din clasa auto.
Deosebirea fa de variabilele din clasa auto const n faptul c pentru memorarea variabilelor register,
compilatorul utilizeaz regitrii interni (ceea ce conduce la creterea eficienei). Unei variabile pentru care
se specific drept clas de memorare register, nu i se poate aplica operatorul de refereniere.

Clasa de memorare extern
O variabil global declarat fr specificarea unei clase de memorare, este considerat ca avnd clasa de
memorare extern. Domeniul de vizibilitate este din momentul declarrii pn la sfritul fiierului surs.
Timpul de via este durata execuiei fiierului. O variabil din clasa extern este iniializat automat cu
valoarea 0.

Clasa de memorare static
Clasa de memorare static are dou utilizri distincte:
Variabilele locale statice au ca domeniu de vizibilitate blocul sau funcia n care sunt definite, iar ca
timp de via - durata de execuie a programului. Se iniializeaz automat cu 0.
Variabilele globale statice au ca domeniu de vizibilitate punctul n care au fost definite pn la sfritul
fiierului surs, iar ca timp de via - durata execuiei programului.


Tabelul 6.1.
Clasa de
memorare
Variabila Domeniu vizibilitate Timp de via
55

auto
(register)
local (intern) Blocul sau funcia Durara de execuie a blocului
sau a funciei
extern global Din punctul definirii, pn la
sfritul fiierului (ROF)
Alte fiiere
Durara de execuie a blocului
sau a programului
static global ROF -"-
local Bloc sau funcie -"-
nespecificat global Vezi extern Vezi extern
local Vezi auto Vezi auto


6.9. MODURI DE ALOCARE A MEMORIEI

Alocarea memoriei se poate realiza n urmtoarele moduri:
alocare static;
alocare dinamic;
alocare pe stiv.
Se aloc static memorie n urmtoarele cazuri:
pentru instruciunile de control propriu-zise;
pentru variabilele globale i variabilele locale declarate n mod explicit static.
Se aloc memorie pe stiv pentru variabilele locale.
Se aloca dinamic memorie n mod explicit, cu ajutorul funciilor de alocare dinamica, aflate n headerul
<alloc.h>.
Exemplu:
int a,b; double x;
double f1(int c, double v)
{int b;
static double z;
}
double w;
int f1(int w)
{double a;
}
void main()
{double b, c; int k;
b=f1(k,c);
}


6.9.1. Alocarea memoriei n mod dinamic

Pentru toate tipurile de date (simple sau structurate), la declararea acestora, compilatorul aloc automat un
numr de locaii de memorie (corespunztor tipului datei). Dimensiunea zonei de memorie necesar pentru
pstrarea valorilor datelor este fixat naintea lansrii n execuie a programului. n cazul declarrii unui tablou
de ntregi cu maximum 100 de elemente vor fi alocai 100*sizeof(int) locaii de memorie succesive. n situaia
n care la un moment dat tabloul are doar 20 de elemente, pentru a aloca doar atta memorie ct este necesar n
momentul respectiv, se va aloca memorie n mod dinamic.

56

Este de dorit ca n cazul datelor a cror dimensiune nu este cunoscut a priori sau variaz n limite largi, s se
utilizeze o alt abordare: alocarea memoriei n mod dinamic. n mod dinamic, memoria nu mai este alocat n
momentul compilrii, ci n momentul execuiei. Alocarea dinamic elimin necesitatea definirii complete a
tuturor cerinelor de memorie n momentul compilrii. n limbajul C, alocarea memoriei n mod dinamic se face
cu ajutorul funciilor malloc, calloc, realloc; eliberarea zonei de memorie se face cu ajutorul funciei free.
Funciile de alocare/dezalocare a memoriei au prototipurile n header-ele <stdlib.h> i <alloc.h>:

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

Eliberarea memoriei (alocate dinamic cu una dintre funciile malloc, calloc sau realloc) se realizeaz cu ajutorul
funciei free.
void free(void *ptr);

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

Exerciiu: S se scrie un program care implementeaz funcia numit introd_val. Funcia trebuie s permit
introducerea unui numr de valori reale, pentru care se aloc memorie dinamic. Valorile citite cu ajutorul
funciei introd_val sunt prelucrate n funcia main, apoi memoria este eliberat.
#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
float *introd_val()
/* pentru a putea realiza eliberarea memoriei n funcia main, funcia introd_val trebuie s returneze
adresa de nceput a zonei de memorie alocate dinamic */
{double *p; int nr;printf("Numr valori:"); scanf("%d", nr);
if (!(p=(float*)malloc(nr*sizeof(float))) ){
printf("Memorie insuficient!\n");return NULL;
}
for (int i=0; i<nr; i++){
printf("Val %d=", i+1); scanf("%lf", p+i); return p;}
}
void main()
{float *pt; pt=introd_val();
// prelucrare tablou
57

free(pt);
}

Exerciiu: S se scrie un program care citete numele angajailor unei ntreprinderi. Numrul angajailor este
transmis ca argument ctre funcia main. Alocarea memoriei pentru cei nr_ang angajai, ct i pentru numele
fiecruia dintre acetia se va face n mod dinamic.
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
void main(int argc, char *argv[])
{char **ang_ptr;
char *nume;
int nr_ang, i;
if (argc==2){
nr_ang=atoi(argv[1]);/* numrul angajailor este transmis ca argument ctre funcia main. El este
convertit din ir de caractere n numr */
ang_ptr=(char**)calloc(nr_ang, sizeof(char*));
if ((ang_ptr==0){
printf("Memorie insuficient!\n");exit(1);}
nume=(char*)calloc(30, sizeof(char));
for (i=0; i<nr_ang; ++i){
printf("Nume angajat:");
scanf("%s",nume);
ang_ptr[i]=(char*)calloc(strlen(nume)+1, sizeof(char));
strcpy(ang_ptr[i], nume);
}
free(nume);
printf("\n");
for (i=0; i<nr_ang; i++)
printf("Angajat nr %d: %s\n", i+1, ang_ptr[i]);
}
else
printf("Lansare n execuie: %s numr_de_angajai\n", argv[0]);
}

n limbajul C++alocarea dinamic a memoriei i eliberarea ei se pot realiza cu operatorii new i delete.
Folosirea acestor operatori reprezint o metod superioar, adaptat programrii orientate obiect.
Operatorul new este un operator unar care returneaz un pointer la zona de memorie alocat dinamic. n situaia
n care nu exist suficient memorie i alocarea nu reuete, operatorul new returneaz pointerul NULL.
Operatorul delete elibereaz zona de memorie spre care pointeaz argumentul su.

Sintaxa:
tipdata_pointer = new tipdata;
tipdata_pointer = new tipdata(val_iniializare);
//pentru iniializarea datei pentru care se aloc memorie dinamic
tipdata_pointer = new tipdata[nr_elem]; //alocarea memoriei pentru un tablou

delete tipdata_pointer;
delete [nr_elem] tipdata_pointer; //eliberarea memoriei pentru tablouri

58

Tipdata reprezint tipul datei (predefinit sau obiect) pentru care se aloc dinamic memorie, iar tipdata_pointer
este o variabil pointer ctre tipul tipdata.

Pentru a putea afla memoria RAM disponibil la un moment dat, se poate utiliza funcia coreleft:
unsigned coreleft(void);

Exerciiu: S se aloce dinamic memorie pentru o dat de tip ntreg:
int *pint;
pint=new int;
//Sau:
int &i=*new int;
i=100; //i permite referirea la ntregul pstrat n zona de memorie alocat dinamic

Exerciiu: S se aloce dinamic memorie pentru o dat real, dubl precizie, iniializnd-o cu valoarea -7.2.
double *p;
p=new double(-7.2);
//Sau:
double &p=* new double(-7.2);

Exerciiu: S se aloce dinamic memorie pentru un vector de m elemente reale.
double *vector; vector=new double[m];
Exemplu: S se urmreasc rezultatele execuiei urmtorului program, care utilizeaz funcia coreleft.
#include <iostream.h>
#include <alloc.h>
#include <conio.h>
void main()
{ int *a,*b; clrscr();
cout<<"Mem. libera inainte de alocare:"<<coreleft()<<'\n';
cout<<"Adr. pointerilor a si b:"<<&a<<" "<<&b<<'\n';
cout<<"Valorile pointeri a si b inainte de alocare:"<<a<<" "<<b<<'\n';
a=new int; b=new int[10];
cout<<"Mem. libera dupa alocare:"<<coreleft()<<'\n';
cout<<"Valorile pointerilor a si b dupa alocare:"<<a<<" "<<b<<'\n';
cout<<"Continutul memoriei alocate:\n"<<"*a="<<*a<<"\n*b="<<*b<<'\n';
for (int k=0;k<10;k++) cout<<"\nb["<<k<<"]="<<b[k]; cout<<'\n';
getch();
*a=1732;
for (int u=0;u<10;u++) b[u]=2*u+1;
cout<<"Cont. zonelor alocate dupa atribuire:"<<"\n*a="<<*a<<"\nb=";
for (u=0;u<10;u++) cout<<"\nb["<<u<<"]="<<b[u];
delete a; delete b;
cout<<"Mem. libera dupa eliberare:"<<coreleft()<<'\n';
cout<<"Valorile pointerilor a si b dupa eliberare:"<<a<<" "<<b<<'\n';
cout<<"Continutul memoriei eliberate:\n"<<"*a="<<*a<<"\n*b="<<*b<<'\n';
for (k=0;k<10;k++) cout<<"\nb["<<k<<"]="<<b[k]; cout<<'\n'; cout<<b[3];
getch();
}



59


6.10. FUNCII RECURSIVE

O funcie este numit funcie recursiv dac ea se autoapeleaz, fie direct (n definiia ei se face apel la ea
nsi), fie indirect (prin apelul altor funcii). Limbajele C/C++ dispun de mecanisme speciale care permit
suspendarea execuiei unei funcii, salvarea datelor i reactivarea execuiei la momentul potrivit. Pentru fiecare
apel al funciei, parametrii i variabilele automatice se memoreaz pe stiv, avnd valori distincte. Variabilele
statice ocup tot timpul aceeai zon de memorie (figureaz ntr-un singur exemplar) i i pstreaz valoarea de
la un apel la altul. Orice apel al unei funcii conduce la o revenire n funcia respectiv, n punctul urmtor
instruciunii de apel. La revenirea dintr-o funcie, stiva este curat (stiva revine la starea dinaintea apelului).

Un exemplu de funcie recursiv este funcia de calcul a factorialului, definit astfel:
fact(n)=1, dac n=0;
fact(n)=n*fact(n-1), dac n>0;

Exemplu: S se implementeze recursiv funcia care calculeaz n!, unde n este introdus de la tastatur:
#include <iostream.h>
int fact(int n)
{if (n<0){
cout<<"Argument negativ!\n";
exit(2);
}
else if (n==0) return 1;
else return n*fact(n-1);
}
void main()
{int nr, f; cout<<"nr="; cin>>nr;
f=fact(nr); cout<<nr<<"!="<<f<<'\n';
}

Se observ c n corpul funciei fact se apeleaz nsi funcia fact. Presupunem c nr=4 (iniial, funcia fact este
apelat pentru a calcula 4!). S urmrim diagramele din figurile 6.7. i 6.8. La apelul funciei fact, valoarea
parametrului de apel nr (nr=4) iniializeaz parametrul formal n. Pe stiv se memoreaz adresa de revenire n
funcia apelant (adr1) i valoarea lui n (n=4) (figura 6.7.a.). Deoarece n>0, se execut intruciunea de pe
ramura else (return n*fact(n-1)). Funcia fact se autoapeleaz direct. Se memoreaz pe stiv noua adres de
revenire i noua valoare a parametrului n (n=3) (figura 6.7.b.).
La noul reapel al funciei fact, se execut din nou intruciunea de pe ramura else (return n*fact(n-1)). Se
memoreaz pe stiv adresa de revenire i noua valoare a parametrului n (n=2) (figura 6.7.c.). La noul reapel al
funciei fact, se execut din nou intruciunea de pe ramura else (return n*fact(n-1)). Se memoreaz pe stiv
adresa de revenire i noua valoare a parametrului n (n=1) (figura 6.7.d.). La noul reapel al funciei fact, se
execut din nou intruciunea de pe ramura else (return n*fact(n-1)). Se memoreaz pe stiv adresa de revenire i
noua valoare a parametrului n (n=0) (figura 6.7.e.).
n acest moment n=0 i se revine din funcie cu valoarea 1 (1*fact(0)=1*1), la configuraia stivei din figura
6.7.d.) (se cur stiva i se ajunge la configuraia din figura 6.7.d.). n acest moment n=1 i se revine cu
valoarea 2*fact(1)=2*1=2, se cura stiva i se ajunge la configuraia stivei din figura 6.7.c. n acest moment
n=2 i se revine cu valoarea 3*fact(2)=3*2=6, se cura stiva i se ajunge la configuraia stivei din figura 6.7.b.
Se cur stiva i se ajunge la configuraia stivei din figura 6.7.a.. n acest moment n=3 i se revine cu valoarea
4*fact(3)=4*6=24.
O funcie recursiv poate fi realizat i iterativ. Modul de implementare trebuie ales n funcie de problem.
Dei implementarea recursiv a unui algoritm permite o descriere clar i compact, recursivitatea nu conduce
6
3
24
4
fact
60

la economie de memorie i nici la execuia mai rapid a programelor. n general, se recomand utilizarea
funciilor recursive n anumite tehnici de programare, cum ar fi unele metode de cutare (backtracking).















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

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

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

void main()
{int n; clrscr();
cout<<MAXLONG<<'\n';
for (n=10; n<=40; n++) {
clock_t t1, t2, t3;
cout<<CLK_TCK<<'\n';
t1=clock(); long int f1=iterativ_fib(n);
Figura 6.7. Configuraia stivei
adr1
n=4
(a)
adr2
n=3
adr1
n=4
(b)
adr2
n=2
adr2
n=3
adr1
n=4
(c)
adr2
n=1
adr2
n=2
adr2
n=3
adr1
n=4

(d)
0!=1
adr2
n=0
adr2
n=1
adr2
n=2
adr2
n=3
adr1
n=4
(e)
61

t2=clock(); long f2=recursiv_fib(n); t3=clock();
double timp1=(double)(t2-t1)/CLK_TCK;
double timp2=(double)(t3-t2)/CLK_TCK;
printf("ITERATIV: %10ld t=%20.10lf\n",f1,timp1);
printf("RECURSIV: %10ld t=%20.10lf\n",f2,timp2);
cout<<"Apasa o tasta....\n"; getch();
} }

n exemplul anterior, pentru msurarea timpului de execuie s-a utilizat funcia clock, al crei prototip se afl n
header-ul time.h. Variabilele t1, t2 i t3 sunt de tipul clock_t, tip definit n acelai header. Constanta simbolic
CLK_TCK definete numrul de bti ale ceasului, pe secund.

n general, orice algoritm care poate fi implementat iterativ, poate fi implementat i recursiv. Timpul de
execuie a unei recursii este semnificativ mai mare dect cel necesar execuiei iteraiei echivalente.

Exerciiu: S se implementeze i s se testeze un program care:
a) Genereaz aleator i afieaz elementele unui vector ;
b) Sorteaz aceste elemente, cresctor, aplicnd metodele de sortare BubbleSort, InsertSort, i QuickSort;
c) S se compare viteza de sortare pentru vectori de diverse dimensiuni (10,30,50,100 elemete).

Metoda BubbleSort a fost prezentat n capitolul 4.

Metoda QuickSort reprezint o alt metod de sortare a elementelor unui vector. Algoritmul este recursiv:
se mparte vectorul n dou partiii, fa de un element pivot (de obicei, elementul din "mijlocul vectorului").
Partiia stng ncepe de la indexul i (la primul apel i=0), iar partiia dreapt se termin cu indexul j (la
primul apel j=n -1) (figura 6.9.).







Partiia stng este extins la dreapta (i incrementat) pn cnd se gsete un element mai mare dect pivotul;
partiia dreapt este extins la stnga (j decrementat) pn cnd se gsete un element mai mic dect pivotul.
Cele dou elemente gsite, vect[i] i vect[j], sunt interschimbate.
Se reia ciclic extinderea partiiilor pn cnd i i j se "ncrucieaz" (i devine mai mare ca j). n final, partiia
stng va conine elementele mai mici dect pivotul, iar partiia dreapt - elementele mai mari dect pivotul, dar
nesortate.
Algoritmul este reluat prin recursie pentru partiia stng (cu limitele ntre 0 i j ), apoi pentru partiia dreapt
(cu limitele ntre i i n-1 ). Recursia pentru partea stng se oprete atunci cnd j atinge limita stng (devine
0), iar recursia pentru partiia dreapt se oprete cnd i atinge limita dreapt (devine n-1).




SUBALGORITM QuickSort (vect[ ], stg, drt) //la primul apel stg = 0 si drt = n - 1
NCEPUT SUBALGORITM
i stg
j drt
j i
. . . . . . .
0 n - 1
0
pivot i
j
n - 1
Figura 6.9. Sortare prin metoda QuickSort
62

DAC i < j ATUNCI
NCEPUT
pivot=vect[(stg+drt)/2]
CT TIMP i <= j REPET
//extinderea partiiilor stnga i dreapta pn cnd i se ncrucieaz cu j
NCEPUT
CT TIMP i<drt si vect[i]<pivot REPET
i = i + 1
CT TIMP j<stg si vect[j] >pivot REPET
j = j - 1
DAC i<=j ATUNCI
NCEPUT //interschimb elementele vect[i] i vect[j]
auxvect[i]
vect[i] vect[j]
vect[j] aux
i i+1
j j-1
SFRIT
SFRIT
DAC j > stg ATUNCI // partiia stng s-a extins la maxim, apel qiuckSort pentru ea
CHEAM QuickSort(vect, stg, j)
DAC i < drt ATUNCI // partiia dreapt s-a extins la maxim, apel qiuckSort pentru ea
CHEAM QuickSort(vect, i, drt)
SFRIT
SFRIT SUBALGORITM

Metoda InsertSort (metoda inseriei)
Metoda identific cel mai mic element al vectorului i l schimb cu primul element. Se reia procedura pentru
vectorul iniial, fr primul element i se caut minimul n acest nou vector, etc.

SUBALGORITM InsertSort (vect[ ], nr_elem)
NCEPUT SUBALGORITM
CT TIMP i< nr_elem REPET
NCEPUT
pozMincautMinim(vect, i) // se apeleaz algoritmul cautMinim
auxvect[i]
vect[i] vect[pozMin]
vect[pozMin] aux
i i+1
SFRIT
SFRIT SUBALGORITM

Funcia cautMin(vect[ ], indexIni, nr_elem) caut elementul minim al unui vector, ncepnd de la poziia
indexIni i returneaz poziia minimului gsit.

Mod de implementare (Se va completa programul cu instruciunile care obin i afieaz timpului necesar
ordonrii prin fiecare metod. Se vor compara rezultatele pentru un vector de 10, 30, 50, 100 elemente):
#include <stdlib.h>
#include <stdio.h>
63

#include <time.h>
#define TRUE 1
#define FALSE 0
void gener(double v[], int n)
//functia de generare aleatoare a elementelor vectorului v, cu n elemente
{for (int i=0; i<n; i++)
v[i]=1.0*rand()/100000;
}
void afis(double v[], int n)
//functia de afisare a vectorului
{for (int i=0; i<n; i++)
printf("%10.2f",v[i]);
printf("\n");
}
void copie_vect(double v1[], double v[], int n)
//functie de "duplicare "a unui vector; copie vectorul v in vectorul v1
{for (int i=0; i<n; i++)
v1[i]=v[i];
}
void bubbleSort(double v[], int n)
{int gata; gata=FALSE;
while (!gata){
gata=TRUE;
for (int i=0; i<n-1; i++)
if (v[i]>=v[i+1]){
double aux=v[i];
v[i]=v[i+1];
v[i+1]=aux;
// printf("Interschimbare element %d cu %d",i,i+1);
// afis(v,n);
gata=FALSE;}
}
}
int cautMin(double v[], int indexIni, int n)
// cauta elementul minim, incepnd de la pozitia indexIni, inclusiv
{ double min=v[indexIni];
int pozMin=indexIni;
for (int i=indexIni; i<n; i++)
if (v[i]<=min){
min=v[i]; pozMin=i;
}
return pozMin;
}
void insertSort(double v[], int n)
{ int i;
for (i=0; i<n; i++){
int poz=cautMin(v, i, n);
double aux=v[i];
v[i]=v[poz];
v[poz]=aux;
64

}
}
void quickSort(double v[], int stg, int drt)
{int i,j; i=stg; j=drt; double pivot, aux;
if (i<j){
pivot=v[(stg+drt)/2];
while (i<=j){ //extindere partitie st si dr pana i se incrucis cu j
while (i<drt && v[i]<pivot) i++;
while (j>stg && v[j]>pivot) j--;
if (i<=j){
aux=v[i];v[i]=v[j];v[j]=aux; //interschimbare elemente
i++; j--;
}
}
if (j>stg) quickSort(v, stg, j);
if (i<drt) quickSort(v, i, drt);
}
}
void main()
{
clock_t ti,tf; int n; //n = nr elemente vector
printf("Nr componente vector:"); scanf("%d", &n);
double v[200], v1[200], v2[200], v3[200];
gener(v, n);
copie_vect(v1,v,n);
printf("\nInainte de ordonare: v1="); afis(v1, n); ti=clock();
bubbleSort(v1,n); tf=clock(); printf("\nDupa ordonare : v1=");afis(v1, n);
printf("%10.7f", dif_b);
printf("\n\n****** INSERT SORT ******\n");
copie_vect(v2,v,n);
printf("\nInainte de ordonare INSERT: v2="); afis(v2, n);
insertSort(v2,n); printf("\nDupa ordonare INSERT: v2=");afis(v2, n);
int st=0; int dr=n-1; copie_vect(v3, v, n);
printf("\n\n****** QUICK SORT ******\n");
printf("\nInainte ordonare QUICK: v3="); afis(v3, n);
quickSort(v3, st, dr); printf("\nDupa ordonare QUICK: v3="); afis(v3, n);
}

6.11. POINTERI CTRE FUNCII

Aa cum s-a evideniat n capitolul 5, exista trei categorii de variabilele pointer:
Pointeri cu tip;
Pointeri generici (void);
Pointeri ctre funcii.

Pointerii ctre funcii sunt variabile pointer care conin adresa de nceput a codului executabil al unei funcii.
Pointerii ctre funcii permit:
Transferul ca parametru al adresei unei funcii;
Apelul funciei cu ajutorul pointerului.

65

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

Exerciiu: S se implementeze un program care calculeaz o funcie a crei valoare este integrala altei funcii.
Pentru calculul integralei se va folosi metoda trapezelor.

Relaia pentru calculul integralei prin metoda
trapezelor pentru
}
b
a
dx x f ) ( este:
I = (f(a)+f(b))/2 +

=
+
1
1
) * (
n
k
h k a f
S se calculeze
}
+ + +
+
b
a
x
x
e
) 1 ln( 3 . 0 1
2 . 0
4
2
| |
dx,
cu o eroare mai mic dect eps (valoarea erorii introdus de la tastatur).

#include <conio.h>
#include <math.h>
#include <iostream.h>
double intrap(double a, double b, long int n, double (*f)(double))
{double h,s=0; long k;
if (a>=b) return 0;
if (n<=0) n=1;
h=(b-a)/n;
for (k=1; k<n; k++) s+=f(a+k*h);
return ((f(a)+f(b))/2+s)*h;
}

void main()
{long int j; double p,q; double eps, d2;double dif;
cout<<"Marg. inf:";cin>>p; cout<<"Marg. sup:";cin>>q;
cout<<"Eroare:";cin>>eps; j=1;
double d1=intrap(p, q, j, functie);
do{
j*=2;
if (j>MAXLONG || j<0) break;
d2=intrap(p, q, j, functie);
h
a x x x . . . . .x x b
f(x)
Figura 6.9. Calculul integralei prin metoda trapezelor
66

dif=fabs(d1-d2); d1=d2;
cout<<"Nr.intervale "<<j<<" Val.integralei "<<d2<<'\n';
}while (dif>eps);
cout<<"\n\n-----------------------------------------------\n";
cout<<"Val. integralei: "<<d2<<" cu eroare de:"<<eps<<'\n';
}

STRUCTURI

Structurile grupeaz date de tipuri diferite, constituind definiii ale unor noi tipuri de date. Componentele unei
structuri se numesc membrii (cmpurile) structurii. La declararea unei structuri se pot preciza tipurile,
identificatorii elementelor componente i numele structurii.
Forma general de declarare a unei structuri:

struct identificator_tip_structura {
lista_de_declaratii_membrii;
} lista_identificatori_variabile; n care:

struct este un cuvnt cheie (obligatoriu)
identificator_tip_structura reprezint numele noului tip (poate lipsi)
lista_de_declaratii_membri este o list n care apar tipurile i identificatorii membrilor structurii
lista_identificatori_variabile este o list cu identificatorii variabilelor de tipul declarat.

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

Declaraia de mai sus poate apare sub forma:
struct data {
int zi;
char luna[11];
int an;
};
struct data data_nasterii, data_angajarii;
/*Variabilele data_nasterii i data_angajarii sunt date de tipul data */

Se poate omite numele noului tip de date:
struct {
int zi;
char luna[11];
int an;
67

} data_naterii, data_angajrii;

Iniializarea variabilelor de tip nou, definit prin structur, se poate realiza prin enumerarea valorilor membrilor,
n ordinea n care acetia apar n declaraia structurii. Referirea unui membru al structurii se realizeaz cu
ajutorul unui operator de baz, numit operator de selecie, simbolizat prin . .Operatorul are prioritate maxim.
Membrul stng al operatorului de selecie precizeaz numele variabilei de tipul introdus prin structur, iar
membrul drept-numele membrului structurii, ca n exemplul urmtor:
Exemplu:
struct angajat{
char nume[20], prenume[20];
int nr_copii;
double salariu;
char loc_nastere[20];
};
struct angajat a1= {"Popescu", "Vlad", 2, 2900200, "Galati"};
a1.nr_copii = 3;
strcpy(a1.nume, "Popesco");

Variabilele de acelai tip pot apare ca operanzi ai operatorului de atribuire. n acest caz atribuirile se fac
membru cu membru. n exemplul anterior am declarat i iniializat variabila a1, de tip angajat. Declarm i
variabila a2, de acelai tip. Dac dorim ca membrii variabilei a2 s conin aceleai valori ca membrii variabilei
a1 (a1 si a2 de tip angajat), putem folosi operatorul de atribuire, ca n exemplul urmtor:
struct angajat a2;
a2=a1;

Aa cum s-a observat din exemplul anterior, structurile pot avea ca membri tablouri (structura angajat are ca
membrii tablourile de caractere loc_natere[20], nume[20], prenume[20]). Deasemenea, variabilele de tip
definit prin structur pot fi grupate n tablouri.
Exemplu:
struct persoana{
char nume[20], prenume[20];
int nr_copii;
double salariu;
char loc_nastere[20];
}angajati[100];
/* S-au declarat noul tip numit persoana i variabila numit angajati, care este un vector (cu maxim 100 de
elemente), ale crui elemente sunt de tipul persoana */
//Iniializarea elementelor vectorului angajai[100]
for (int i=0; i<100; i++){
cout<<"Intruduceti datele pentru angajatul "<<i+1<<'\n';
cout<<"Numele :"; cin>>angajati[i].nume;
cout<<"Prenumele :"; cin>>angajai[i].prenume;
cout<<"Nr. copii:"; cin>> angajai[i].nr_copii;
cout<<"Locul naterii:"; cin>> angajai[i].loc_natere;
}
Limbajul C permite definirea de structuri ale cror membri sunt tot structuri:
Exemplu:
struct data{
int zi;
char luna[11];
68

int an;
};
struct persoana{
char nume[20], prenume[20];
int nr_copii;
double salariu;
char loc_natere[20];
struct data data_naterii;
};
struct persoana p1={"Popescu","Vasile",1,4000000,"Galati",{22,"Mai",1978}};
//Modificarea membrului data_naterii pentru variabila p1 de tip persoana:
p1.data_nateri.zi=23;
strcpy(p1.data_nateri.luna, "Februarie");
p1.data_nasteri.an=1980;

Dac se dorete transmiterea ca parametri ai unor funcii a datelor de tip definit de utilizator prin structuri, acest
lucru se realizeaz numai cu ajutorul pointerilor spre noul tipi.
De exemplu, este necesar ca variabila p1, de tip persoana, s fie prelucrat n funcia f, n acest caz, funcia va
primi ca parametru un pointer spre tipul persoana. Funcia va avea prototipul:
void f(struct persoana *q);
Apelul funciei se realizeaz astfel: f(&p1);
n corpul funciei f, accesul la membrii varibilei q, de tip persoana, se realizeaz astfel:
(*q).nume;
(*q).prenume;
(*q).data_naterii.an; , etc.
Pentru a simplifica construciile anterioare, se foloseste operatorul de selecie indirect (->):
q->nume;
q->prenume;
q->data_naterii.an , etc.

Structurile sunt utilizate n mod frecvent la definirea unor tipuri de date recursive (n implementarea listelor,
arborilor, etc.). Un tip de date este direct recursiv dac are cel puin un membru care este de tip pointer spre el
nsui.
Exemplu:
struct nod{
char nume[100];
int an;
struct nod *urmator;
};
Aa cum se observ din exemplu, funcia cit_pers primete ca parametru pointerul ptr_pers, ctre tipul persoana.
Pentru a acesa membri structurii, n corpul funciei, se folosete operatorul de selecie indirect ( ). n funcia
main, se aloc memorie dinamic (cu ajutorul operatorului new). La afiare, n funcia printf, irul specificator de
format se continu pe rndul urmtor (folosirea caracterului \ pentru continuare).

8.1. CARACTERISTICILE GENERALE ALE FIIERELOR
Noiunea de fiier desemneaz o colecie de informaii memorat pe un suport permanent (de obicei discuri
magnetice), perceput ca un ansamblu, creia i se asociaz un nume (n vederea conservrii i regsirii
ulterioare).
Caracteristicile unui fiier (sub sistem de operare MS-DOS) sunt :
Dispozitivul logic de memorare (discul);
69

Calea (n structura de directoare) unde este memorat fiierul;
Numele i extensia;
Atributele care determin operaiile care pot fi efectuate asupra fiierului (de exemplu: R-read-only - citire;
W-write-only scriere; RW-read-write citire/scriere; H-hidden - nu se permite nici mcar vizualizarea; S-
system - fiiere sistem asupra crora numai sistemul de operare poate realiza operaii operaii, etc.).
Lucrul cu fiiere n programare ofer urmtoarele avantaje:
Prelucrarea de unei cantiti mari de informaie obinut din diverse surse cum ar fi execuia prealabil a
unui alt program;
Stocarea temporar pe suport permanent a informaiei n timpul execuiei unui program pentru a evita
suprancrcarea memoriei de lucru;
Prelucrarea aceleeai colecii de informaii prin mai multe programe.

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