Sunteți pe pagina 1din 233

CPP

1
1 Constante, variabile i expresii .................................................................................... 5
1.1 Tipuri fundamentale ............................................................................................. 5
1.2 Variabile ............................................................................................................... 5
1.3 Modificatori de tip ................................................................................................ 6
1.4 Operatorul typedef ................................................................................................ 7
1.5 Constante .............................................................................................................. 7
1.6 Constante cu nume ............................................................................................... 9
1.7 Expresii aritmetice .............................................................................................. 10
1.8 Tablouri .............................................................................................................. 13
1.9 Instruciunea de atribuire .................................................................................... 15
1.10 Prototipuri de funcii. Biblioteci de prototipuri ............................................... 16
1.11 Operaii de intrare / ieire ................................................................................ 17
1.12 Funcia main .................................................................................................... 21
1.13 Execuia unui program .................................................................................... 22
1.14 Operatorul sizeof ............................................................................................. 22
1.15 Operatorii ++ i - - ........................................................................................... 23
1.16 Operaii cu numere ntregi la nivel de bit ........................................................ 26
1.16.1 Operatori de deplasare ............................................................................... 26
1.16.2 Operaii logice la nivel de bit .................................................................... 28
2 Structuri de control fundamentale ............................................................................. 31
2.1 Algoritme ............................................................................................................ 31
2.2 Expresii relaionale ............................................................................................. 32
2.3 Expresii booleene ............................................................................................... 33
2.4 Operatorul if ....................................................................................................... 34
2.5 Operatorul switch ............................................................................................... 37
2.6 Operatorul ? ........................................................................................................ 38
2.7 Operatorul while ................................................................................................. 38
2.8 Operatorul do-while ........................................................................................... 41
2.9 Operatorul for ..................................................................................................... 42
2.10 Operatorul , ...................................................................................................... 46
3 Funcii ........................................................................................................................ 48
3.1 Funcii standard .................................................................................................. 48
3.2 Definirea funciilor ............................................................................................. 49
3.3 Prototipuri de funcii .......................................................................................... 51
3.4 Compilarea separat a funciilor ......................................................................... 52
3.5 Funcii cu parametri tablouri ............................................................................. 53
3.6 Suprancrcarea funciilor .................................................................................. 58
3.7 Transmiterea parametrilor ctre funcii .............................................................. 60
3.8 Recursivitatea ..................................................................................................... 65
3.9 Funcii generice .................................................................................................. 66
3.10 Funcii C standard de manipulare a caracterelor .............................................. 67
4 Pointeri i referine .................................................................................................... 70
4.1 Pointeri ............................................................................................................... 70
4.1.1 Declararea variabilelor tip pointerilor ......................................................... 71
4.2 Referine ............................................................................................................. 75
4.3 Pointeri la funcii ................................................................................................ 78
4.4 Interpretarea instruciunilor ce conin pointeri ................................................... 79
4.5 Pointeri i tablouri unidimensionale ................................................................... 81
4.6 iruri tip C .......................................................................................................... 85
2
4.7 Pointeri i tablouri multidimensionale .............................................................. 88
4.8 Parametrii funciei main. Parametrii liniei de comand ..................................... 92
4.9 Alocarea dinamic a memoriei .......................................................................... 93
5 Fiiere tip C ............................................................................................................. 102
5.1 Fiiere tip text ................................................................................................... 103
5.1.1 Funcii intrare / ieire cu format ................................................................ 104
5.1.2 Funcii intrare / ieire tip caracter .............................................................. 106
5.2 Fiiere text tip ir de caractere .......................................................................... 110
5.3 Fiiere binare .................................................................................................... 112
6 Structuri tip C i uniuni ........................................................................................... 117
6.1 Structuri ............................................................................................................ 117
6.2 Uniuni ............................................................................................................... 120
7 Clase ....................................................................................................................... 122
7.1 Definirea unei clase .......................................................................................... 123
7.1.1 Definirea unei clase ................................................................................... 123
7.1.2 Pointerul this .............................................................................................. 128
7.1.3 Spaii de nume ........................................................................................... 128
7.2 Constructori i destructori ................................................................................ 129
7.2.1 Constructori ............................................................................................... 129
7.2.2 Destructori ................................................................................................. 133
7.3 Funcii prietene ................................................................................................. 134
7.4 Determinarea tipului unei expresii ................................................................... 136
8 Siruri tip C++ ........................................................................................................... 139
8.1 Clasa string ....................................................................................................... 139
9 Suprancrcarea operatorilor ................................................................................... 143
9.1 Suprancrcarea operatorului de atribuire ........................................................ 144
9.2 Suprancrcarea operatorilor aritmetici ............................................................ 146
9.3 Suprancrcarea operatorilor << i >> .............................................................. 148
10 Motenirea ............................................................................................................. 151
10.1 Pointeri la obiecte. Operatorii new i delete .................................................. 151
10.2 Motenirea .................................................................................................... 155
10.2.1 Definirea unei clase derivate ................................................................... 155
10.2.2 Specificatorii de acces ............................................................................. 157
10.3 Funcii virtuale. Polimorfism ........................................................................ 163
10.4 Destructori virtuali ........................................................................................ 170
10.5 Date i funcii statice ..................................................................................... 171
10.5.1 Date statice .............................................................................................. 171
10.5.2 Funcii statice .......................................................................................... 173
11 Fiiere tip C++ ....................................................................................................... 176
11.1 Fiiere text ..................................................................................................... 177
11.1.1 Funcii intrare / ieire cu format .............................................................. 177
11.1.2 Funcii intrare / ieire tip caracter ............................................................ 179
11.2 Fiiere binare ................................................................................................. 181
11.3 Fiiere text tip string ...................................................................................... 184
12 Tratarea excepiilor ................................................................................................ 186
12.1 Excepii .......................................................................................................... 186
12.2 Excepii lansate de funcii ............................................................................. 188
12.3 Excepii standard ........................................................................................... 189
12.4 Excepii intrare / ieire .................................................................................. 191
13 Aplicaii ................................................................................................................ 194
3
13.1 Funcii de timp ............................................................................................... 194
13.2 Fire de execuie ............................................................................................. 195
13.3 Funcia system ............................................................................................... 197
14 Biblioteca de abloane standard ............................................................................ 199
14.1 Clase generice ................................................................................................ 199
14.2 Containere, iteratori i algoritme generice ................................................... 201
14.3 Vectori ........................................................................................................... 202
14.3.1 Parcurgerea vectorilor cu iteratori ........................................................... 204
14.3.2 Stergerea i inserarea de elemente .......................................................... 206
14.3.3 Sortarea componentelor unui vector ........................................................ 208
14.3.4 Cutarea unui element ntr-un vector ...................................................... 210
14.3.5 Copierea unui container. Iteratori pentru streamuri ................................ 212
14.4 Liste ............................................................................................................... 214
14.4.1 Parcurgerea listelor .................................................................................. 214
14.4.2 Sortarea listelor ........................................................................................ 215
14.4.3 Inversarea elementelor listelor ................................................................ 216
14.4.4 Inserarea i tergerea elementelor din liste .............................................. 217
14.4.5 Copierea listelor ...................................................................................... 219
14.5 Parcurgerea irurilor tip string cu iteratori .................................................... 220
14.6 Numere complexe .......................................................................................... 221
Anexa 1. Reprezentarea informaiilor ....................................................................... 224
A.1 Reprezentarea numerelor ntregi n sistemul binar ......................................... 224
A.2 Deplasarea numerelor binare cu semn ........................................................... 228
A.3 Reprezentarea numerelor reale ....................................................................... 229
A.4 Reprezentarea caracterelor ............................................................................. 231
Anexa 2. Prioritile i asociativitatea operatorilor ................................................... 233
4
Partea I Programarea procedural
1 Constante, variabile i expresii
1.1 Tipuri fundamentale
In matematic variabilele se clasific dup tipul lor. Tipul unei variabile este
mulimea valorilor pe care le poate lua acea variabil i operaiile ce se pot efectua cu
acele valori. De exemplu, operaiile tipului real sunt + - * /, pentru tipul ntreg se
adaug restul mpririi a dou numere ntregi, simbolizat %. Tipul unei variabile este
fcut explicit cu o declaraie de tip. Tipurile predefinite n limbajul C++ sunt cele din
tabelul 1.
Tabelul 1. Tipuri de baz ale limbajului C++
Tip Semnificaie
Dimensiune
n octei
Domeniu de
valori
Operaii
int Numere ntregi 4
[-2
31
2
31
)
+-*/%
float
Numere reale n virgul
mobil scurt
4 ) 10 10 (
38 38
+-*/
double
Numere reale n virgul
mobil lung
8 ) 10 10 (
307 307
+-*/
char
Caractere n cod ASCII i
numere ntregi pe un octet
1
[-2
7
2
7
)
+-*/%
wchar_t
Numere pozitive i caractere
UNICODE pe doi octei
2
[0 2
16
)
+-*/%
bool Valoare boolean 1 false,true
and, or,
not
Pentru fiecare tip exist constante predefinite ce dau limitele minim i maxim ale
domeniului de valori.
Menionm c, pentru tipurile char i int, primul bit este utilizat pentru semn, ceilali
bii sunt bii ai numrului. In cazul tipului bool valoarea false este reprezentat prin
zero iar true prin unu.
1.2 Variabile
Numele unei variabile este format din cifre, litere i caracterul _ (underscore), i
ncepe totdeauna cu o liter sau caracterul _. Literele mari sunt diferite de cele mici.
De exemplu abc i Abc sunt dou nume de variabile diferite. Instruciunea de
declarare a tipului are forma
tip list de variabile;
Lista de variabile este format din nume de variabile separate de virgule. Diagrama
sintactic este cea de mai jos.
5
De exemplu, instruciunile
int a;
char b;
declar o variabil a de tipul int i o variabil b de tipul char. Conform instruciunii
de declarare a tipului de mai sus, mai multe variabile de acelai tip pot fi declarate cu
o singur instruciune, scriind numele lor separate de virgule. De exemplu,
instruciunea
float f1, f2, f3;
declar trei variabile de tipul float. O variabil poate fi iniializat la declararea tipului
ei, conform urmtoarei diagrame sintactice
De exemplu, instruciunea
double d = 1 + sin(2.4);
declar o variabil de tip double pe care o iniializeaz la valoarea 1+sin(2.4). O alt
mod de iniializare a unei variabile la declararea tipului ei este dat de diagrama de mai
jos
Valoarea cu care se iniializeaz variabila este expresia din paranteze. De exemplu,
instruciunea
double d (1.2 cos(1.7));
declar o variabil de tip double i o iniializeaz la valoarea 1.2 cos(1.7);
Menionm c tipul bool nu este definit n limbajul C.
1.3 Modificatori de tip
Modificatorii de tip schimb domeniul de valori pe care le poate lua o variabil de tip
int sau char. Aceti modificatori sunt:
unsigned. La utilizarea acestui modificator, valorile variabilelor sunt pozitive.
Toi biii sunt bii ai numrului. De exemplu, tipul unsigned int are domeniul
de valori [0 2
31
),

iar tipul unsigned char are domeniul de valori [0 2
8
) ,
signed. Valorile variabilelor sunt numere cu semn. Primul bit este bit de semn,
6
short. Acest modificator se aplic tipului int. De exemplu, tipul short int are
domeniul de valori [-2
15
2
15
),

iar tipul unsigned short int are domeniul de
valori [0 2
16
). Tipul wchar_t este tipul unsigned short int predefinit.
long
1.4 Operatorul typedef
Operatorul typedef permite s definim tipuri de date bazate pe tipuri existente. Forma
instruciunii este
typedef tip-existent tip-nou
Exemple. Instructiunea
typedef float REAL32
definete tipul REAL32 ce poate fi utilizat n locul tipului float.
In limbajul C nu exist tipul predefinit bool. Putem s definim tipul bool folosind
tipul char cu instruciunea
typedef char bool
1.5 Constante
Tipurile de constante din limbaj corespund tipurilor de date.
Constante ntregi
Constantele ntregi sunt numere ntregi scrise n bazele 8, 10 sau 16.
constantele zecimale sunt numere ntregi reprezentate n baza 10. Ele nu pot
ncepe cu cifra 0. Exemple de constante zecimale sunt :
275, -325, +12
constante hexazecimale sunt numere ntregi reprezentate n baza 16. Ele ncep
cu 0x sau 0X. Cifrele hexazecimale sunt 0, , 9 i A F sau a f. Exemple
de constante hexazecimale :
0x1E sau 0x1e sau 0X1e sau 0X1E care reprezint valoarea zecimal
30
-0x2f sau -0x2F, sau 0x02F reprezint valoarea zecimal -47.
constante octale sunt numere ntregi reprezentate n baza 8. Ele ncep
obligatoriu cu cifra 0. Exemple de constante octale :
016 reprezint numrul zecimal 14 (s se arate c (14)
10
= (16)
8
)
-014 reprezint numrul zecimal -12 (s se arate c (-12)
10
= (-14)
8
).
Constante reale
Constantele reale sunt numere reale n simpl sau dubl precizie. Partea subunitar
este separat de cea ntreag prin punct zecimal.
constante reale n virgul mobil scurt. Exemple :
1.5 -4.23 27.0
Constantele reale pot avea exponent, un numr ntreg ce reprezint puterea lui
zece cu care se nmulete constanta. De exemplu numrul 2.31*10
1
se scrie ca
2.31e1 sau 2.31e+1 sau +2.31E1
Numrul real -41.2* 10
-1
se scrie ca i constant real
-41.2e-1 sau -4.12
7
constante reale n virgul mobil lung. Se scriu dup aceleai reguli ca i
constantele reale n virgul mobil scurt i sunt urmate de sufixul L sau l. De
exemplu, numrul real 1,5 se scrie ca i constant n virgul mobil lung
1.5L sau 15e-1L
Constante de tip caracter
constante de tip caracter reprezint un caracter al codului ASCII pe un octet.
Caracterele se scriu ntre apostrofuri. De exemplu, caracterul ASCII a se scrie
a sau echivalent, ca i constante ntregi, 0x61 sau 97
Caracterul ASCII A se scrie
A sau echivalent, 0x41 sau 65.
Caracterul 1 n codul ASCII este
1 sau echivalent, 0x31 sau 49.
Un alt mod de a defini constante tip caracter este de a le scrie sub forma \xhh
unde h este o cifr hexazecimal. Numrul hexazecimal hh reprezint
echivalentul hexazecimal al caracterului n codul ASCII. De exemplu,
caracterele a i A se reprezint ca \x61 i respective \x41. Caracterul 1
se reprezint ca \x31. Caracterele speciale ale codului ASCII se reprezint
folosind secvena de evitare
\n CR
\r LF
\t tab orizontal
\ ghilimele
\ apostrof
\\ backslash
\? semnul intrebrii
\0 null (valoarea 0 pe un octet)
constante tip ir de caractere. Ele reprezint un ir de caractere ASCII scris
ntre ghilimele. De exemplu
abcd
Un ir de caractere este reprezentat de codurile ASCII ale caracterelor pe cte
un octet, urmate de un octet ce conine valoarea 0. Sirul anterior se reprezint
ca
a b c d \0
Caracterele speciale se reprezint n interiorul unui ir folosind secvena de
evitare. De exemplu
ab\c
a\\bc
abc\n
Menionm diferena ntre constanta tip caracter a i constanta tip ir de
caractere a. Constanta tip caracter a se reprezint pe un singur octet,
constanta a se reprezint pe doi octei.
8
constante tip caracter UNICODE corespund tipului wchar_t. Ele se definesc
sub forma L\xhhhh unde h reprezint o cifr hexazecimal.
Constante booleene
constante booleene sunt true i false i se reprezint prin valorile unu i respective
zero.
1.6 Constante cu nume
In program putem defini constante cu nume n urmtoarele feluri
utilizarea directivei define . Compilatoarele limbajelor C i C++ au un
preprocessor care modific programul surs nainte de compilare.
Preprocesorul citete diversele directive i modific programul surs
corespunztor acestora. Directiva define ce definete o constant are forma
# define nume valoare
unde valoare este interpretat de preprocessor ca un ir de caractere. De
exemplu, directiva
# define PI 3.14
are ca efect nlocuirea numelui PI n program cu irul de caractere 3.14
enumerri. O enumerare definete constante ntregi sau un tip ntreg i valorile
asociate acelui tip. Instruciunea enum de definire a unor constante ntregi are
forma
Instruciunea enum de declarare a unui tip ntreg i a valorilor asociate lui are
forma
De exemplu,
enum CLRX {aaa, bbb, ccc};
definete tipul CLRX i trei constante aaa, bbb, ccc aferente acestui tip, prima
are valoarea zero i fiecare constant urmtoare are o valoare mrit cu unu :
aaa = 0
bbb = 1
ccc = 2
In program constantele sunt nlocuite cu valorile lor. Valoarea fiecrei
constante poate fi specificat printr-o expresie ntreag constant. De exemplu
enum cstval {ppp = 2, dd, cc = -1, nn = 2 + 3 * 4};
definete tipul cstval i constantele de acest tip
9
ppp = 2
dd = 3
cc = -1
nn = 14
Instructiunea
enum BAZA {BIN = 2, HEX = 16, OCT = 8, DEC = 10};
definete tipul BAZA i constantele aferente
BIN = 2
HEX = 16
OCT = 8
DEC = 10
Putem defini variabile corespunznd tipului definit prin enum. Aceste
variabile pot primi ca valori doar constantele definite n instruciunea enum.
Fie de exemplu tipul enumx definit mai jos
enum enumx {ena, enb, enc};
Instruciunea urmtoare definete variabila z de tipul enumx
enumx z;
Putem atribui o valoare variabilei z astfel
z = ena;
Instruciunea enum are i o form mai simpl
enum {list de nume};
care definete doar constante i nu un tip. Orice constant definit cu
instruciunea enum poate fi utilizat ca orice constant ntreag.
utilizarea cuvntului cheie const. O asemenea instruciune are forma
diagramelor sintactice de mai jos

unde tip este un tip al limbajului iar valoare este o expresie constant. De
exemplu, instruciunile :
const int a = 7, n(-2);
const char b = a;
const float c = 2.5e-2 * 4.14;
const double x = sin(0.2) + cos(1.5);
const float z = log(12.5) / 2.3, y(2 + ln(1.7));
definesc constantele a, n, b, c, x, z i y, ce au valorile specificate n
instruciune.
1.7 Expresii aritmetice
Expresiile aritmetice sunt formate din constante, variabile i funcii. Operatorii sunt +
- * i / pentru operanzi reali, iar n cazul operanzilor de tip ntreg, i % (restul
10
mpririi a dou numere ntregi). Restul mpririi a dou numere ntregi, a i b, se
definete astfel
a % b = a (a / b) * b
De exemplu
19 % 4 = 3 19 / 4 = 4
11 % 5 = 1 11 / 5 = 2
Pentru gruparea termenilor se folosesc paranteze rotunde, ( i ). De exemplu, expresia
b a
b a
+

se scrie ca
(a b) / (a + b)
iar expresia
2
2
2
* *
m
x c x b a
+
+ +
se scrie ca
(a + b * x + c * x * x) / (2 + m*m)
Expresia
b
c
c
b
a
+
se scrie ca
a / (b / c + c / b)
Funciile matematice standard uzuale ale limbajelor C i C++ sunt cele de mai jos
acos cos exp ceil fabs pow
asin sin log floor sqrt
atan tan log10
Funcia floor(x) calculeaz valoarea ]
x
(cel mai mare numr ntreg cuprins n x), iar
funcia ceil(x) calculeaz valoarea 1
x
(cel mai mic numr ntreg mai mare ca x).
Toate funciile de mai sus au argumente de tip double i rezultatul de tip double.
Funcia pow are prototipul
double pow(double a, double b)
i calculeaz expresia a
b
. Apelarea unei funcii se face scriind numele funciei ca
termen ntr-o expresie urmat n paranteze de parametrii actuali. Exemple de
expresii aritmetice i scrierea lor sunt prezentate mai jos. Vom presupune c
variabilele din aceste expresii au fost declarate n prealabil de tip double i au primit
valori.
x
x b x a
+
+
75 . 2
) sin( * ) ( cos *
2
(a*cos(x)*cos(x)+b*sin(x))/(2.75+fabs(x))
5
2x x
e e

+
(exp(x)+exp(-2*x))/5
) cos( 1 ln ) 2 log( x x + + +
log10(fabs(x)+2)+log(fabs(1+cos(x)))
5 . 3
) (
+
+
a
y x pow(x+y, a+3.5)
11
Menionm c, n expresii putem folosi orice fel de constante ntregi, reale sau
caracter. De exemplu, expresia a + 27 se poate scrie
a + 27
sau
a + 0x1b
sau
a + 033
Constantele hexazecimal 0x1b i octal 033 reprezint valoarea zecimal 27.
Expresia
x + 100 se poate scrie
x + 100
sau
x + 0x64
sau
x + d
Codul ASCII al caracterului d este 0x64. La evaluarea unei expresii constantele
hexazecimale, octale sau caracter sunt convertite n numrul ntreg corespunztor.
Evaluarea expresiilor aritmetice se face innd cont de prioritile operatorilor i de
asociativitatea lor.
Prioritatea operatorilor Asociativitate
+ unar, - unar la dreapta
* / % la stnga
+ - la stnga
Conform tabelei de mai sus operatorii *, / i % au o prioritate mai mare dect + i - .
Asociativitatea la stnga a operatorilor nseamn urmtorul mod de execuie. Expresia
a / b / c
este interpretat ca
(a / b) / c
De exemplu, expresia 8 / 4 / 2 este interpretat ca (8 / 4) / 2 i are rezultatul 1.
Expresia
x / y * z
este interpretat ca
(x / y ) * z
adic operatorii / i * ce au aceeai prioritate se execut de la stnga la dreapta.
Reamintim c, pentru a modifica ordinea de execuie o operaiilor, se utilizeaz
paranteze rotunde.
Deoarece n expresii intervin operanzi de diverse tipuri, se fac conversii. Regulile
dup care compilatorul face aceste conversii sunt urmtoarele:
tipul float se convertete la double,
tipurile char i short int se convertesc la int,
tipurile unsigned char i unsigned short int se convertesc la unsigned int,
dac n expresie exist un operand de tipul long int, tipul int i unsigned int
se convertesc la long int. Tipul expresiei se determin conform tabelei de mai
jos
int long double
int int long double
12
long long long double
double double double double

Menionm n final c, tipurile char, short int i variantele lor unsigned char, unsigned
short int i float sunt doar pentru memorare. Calculele se efectueaz doar cu variabile
de tip int, long int i double.
Valoarea unei expresii poate fi convertit ntr-un tip diferit dac este nevoie.
Exist dou forme ale expresiilor de conversie a tipurilor.
Prima form a expresiei de conversie de tip este
(tip) expresie
De exemplu, dac i este o variabil ntreag cu valoarea 7 i f este o variabil de tip
double cu valoarea 3.47
int i = 7 ;
double = 3.47 ;
expresia
(i + f) % 2
nu este corect deoarece expresia in parantezele rotunde are tipul double. Expresia
(int)(i + f) % 2
are tipul int i este corect, rezultatul ei este 5.
In limbajul C++ este posibil nc o form de convertire a expresiilor, cu forma
tip(expresie)
De exemplu, expresia anterioar se poate scrie
int(i + f) % 2
Menionm c se pot face conversii ntre toate tipurile standard existente n limbaje.
Conversia de la un tip real la un tip ntreg se face prin trunchiere, valoarea 3.71
convertit la int este 3, iar valoarea -3.4 convertit la int este -3.
1.8 Tablouri
Un tablou este o mulime de elemente de acelai tip. Tablourile sunt tipuri structurate
simple. Instruciunea de declarare a unui tablou cu o dimensiune este urmtoarea
tip nume [ numr ntreg] ;
unde numr ntreg reprezint numrul de elemente ale tabloului. Elementele tabloului
sunt
nume[0], nume[1], , nume[numr ntreg 1]
De exemplu instruciunea
int a[10];
declar un vector cu zece elemente de tip int. Elementele vectorului sunt
a[0], a[1], , a[9].
Dimensiunea unui tablou este fixat la declararea sa i nu se poate schimba.
Un tablou poate fi iniializat la declararea sa scriind valorile elementelor ntre acolade,
{}, i separate de virgule. Exemple de instruciuni ce declar tablouri i le atribuie
valori
double x[3] = {1.32, -2.15, 4.45};
char c[4] = {a, b, c, x};
Ultimul tablou este reprezentat n memorie astfel
a b c x
13
In cazul n care lista de valori este mai scurt dect numrul de elemente declarate,
ultimele elemente sunt iniializate cu zero. In cazul iniializrii unui tablou, la
declararea lui putem omite numrul de elemente al tabloului. De exemplu, putem scrie
char x[] = {#, >, m};
Compilatorul calculeaz dimensiunea tabloului din numrul de valori utilizate pentru
iniializare. Instruciunea precedent este echivalent cu instruciunea
char x[3] = {#, >, m};
Menionm c un vector de caractere poate fi iniializat cu o constant tip ir de
caractere. De exemplu, putem scrie
char s[] = abc;
Reamintim c o constant ir de caractere este terminat printr-un octet 0, deci
vectorul declarat are 4 componente, a, b, c i \0 si este reprezentat n memorie
ca
a b

c \0
Instruciunea precedent este echivalent cu oricare dintre instruciunile urmtoare:
char s[4] = abc;
char s[4] = {a, b, c , \0};
char s[4] = {0x61, 0x62, 0x63, 0};
char s[4] = {97, 98, 99, 0} ;
Un tablou poate avea oricte dimensiuni. Diagrama sintactic a declaraiei unui tablou
este urmtoarea
De exemplu, instruciunea
float b[7][3]
declar o matrice cu apte linii i trei coloane. Elementele matricei sunt :
b[0][0] b[0][1] b[0][2]

b[6][0] b[6][1] b[6][2]
Elementele tablourilor sunt memorate pe linii. Un tablou cu mai multe dimensiuni
poate fi de asemenea iniializat la declararea sa. Fie de definit matricea m cu elemente
ntregi, pozitive
1
]
1

3 7 3
5 2 1
m
Instruciunea corespunztoare este
int m[2][3] = {{1, 2, 5},{3, 7, -3}};
La utilizarea ntr-o expresie, indicii elementelor tablourilor pot fi orice expresii
ntregi. Presupunem urmtoarele declaraii de tablouri
double a[10], b;
int i, j, y[3][4];
14
Urmtoarele expresii ce conin elemente de tablouri :
) sin( ) cos(
*
b b
y b a
ij i

+
(a[i]+b*y[i][j])/(cos(b)-sin(b))
1 ,
) cos(
+
+
j i
b
y e
exp(cos(b)) + y[i][j + 1]
2
3 2
+
n jk
b a
a[j][k] + b[2 * n 3] * b[2 * n 3]
23 12
* y x
x[1][2] * y[2][3]
La utilizarea elementelor unui tablou, [] este un operator de selecie ce are doi
operanzi: un nume de tablou i un indice. El se aplic asupra unui nume de
tablou i selecteaz un element al acelui tablou. De exemplu a[0] selecteaz
primul element al tabloului a, iar b[0] selecteaz prima linie a tabloului b.
Aplicnd nc o dat operatorul de selecie asupra lui b[0], de exemplu b[0][0]
selecteaz primul element din prima linie a lui b. Operatorul [] este asociativ la
stnga.
In acelai mod, operatorul de apelare a unei funcii (), aplicat asupra unui nume
de funcie returneaz valoarea calculat de funcie. De exemplu cos(1.2)
reprezint aplicarea operatorului () asupra numelui funciei cos.
Prioritile i asociativitatea operatorilor
Operator Asociativitate
[] () la stnga
+ unar, - unar, (tip) la dreapta
* / % la stnga
+ - la stnga
1.9 Instruciunea de atribuire
O operaie definit pentru toate tipurile fundamentale este atribuirea. Operatorul
de atribuire = atribuie o valoare unei variabile. Forma instruciunii de atribuire este
variabil = expresie;
De exemplu, urmtoarele instruciuni atribuie valori variabilelor x , y i z .
float x, y, z;
x = -1.34;
y = sin(x) + cos(x * x);
z = (x + y) / (y + cos(x) * cos(x));
Menionm c, la atribuire, expresia din partea dreapt este convertit n tipul
variabilei din stnga. Fie de exemplu instruciunile
int a;
double x = 2.7;
a = x;
Variabila ntreag a primeste valoarea 2.
Limbajele C i C++ au operatori speciali pentru scrierea prescurtat a instruciunilor
de atribuire, +=, -=, *=, /= i %=. Aceti operatori se definesc astfel:
Considerm o variabil x i o expresie e. Instruciunea
x op= e;
este echivalent cu
15
x = x op e;
De exemplu, instruciunea
x = x + cos(y) ;
se scrie prescurtat
x += cos(y) ;
Tabelul urmtor prezint aceti operatori
Forma prescurtat a operatorilor de atribuire
Instruciune Forma prescurtat
x = x + e x += e
x = x e x -= e
x = x * e x *= e
x = x / e x /= e
x = x % e x %= e
Ali operatori de acest tip vor fi prezentai ulterior. Menionm n final c, un operator
de atribuire are doi operanzi i ca rezultat valoarea operandului din stnga. Operanzii
de atribuire sunt asociativi la dreapta (se execut de la dreapta la stnga). Fie de
exemplu instruciunea
int x, y, z = 1;
Instruciunea
x = y = z;
atribuie variabilelor x i y valoarea 1. Instruciunea
x += y += z;
atribuie variabilei y valoarea 2 i variabilei z valoarea 3. De ce?
1.10 Prototipuri de funcii. Biblioteci de prototipuri
Atunci cnd compilatorul ntlnete un apel la o funcie, el trebuie s poat verifica
concordana ntre parametrii actuali i cei formali i are nevoie de tipul rezultatului
funciei pentru a face conversiile necesare evalurii expresiei. Pentru aceasta este
nevoie de o definiie a funciei n care apar tipurile parametrilor i tipul rezultatului.
Aceast definiie se numete ablon sau prototip i are forma
tip numefuncie(tip, tip, , );
De exemplu, funcia sin are un singur parametru de tip double,iar rezultatul este de tip
double; prototipul funciei sin este
double sin(double);
Limbajele C i C++ au biblioteci standard cu prototipurile funciilor limbajului. De
asemenea, utilizatorul poate defini biblioteci cu prototipuri. Toate aceste biblioteci
sunt semnalate compilatorului cu directiva include
# include nume_bibliotec
Aceste biblioteci sunt fiiere numite fiiere header sau antet. Directiva include este
diferit n cazul limbajului C de cea din limbajul C++.
In cazul limbajului C fiierele header au extensia h. De exemplu, biblioteca cu
prototipurile funciilor intrare/ieire tip C este stdio.h, biblioteca cu prototipurile
funciilor matematice este math.h, biblioteca cu prototipurile funciilor de prelucrat
iruri tip C este string.h, etc. In consecin, n cazul unui program n limbajul C vom
semnala compilatorului aceste biblioteci cu directivele
# include <stdio.h>
# include <math.h>
16
In limbajul C++ fiierele header nu au extensie. De exemplu, biblioteca cu
prototipurile funciilor intrare/ieire tip C++ este iostream. La utilizarea n limbajul
C++, bibliotecile specifice limbajului C sunt redefinite ca <cstdio>, <cmath>,
<cstring>, etc. In plus, toate funciile standard ale limbajelor C i C++ sunt grupate
ntr-un spaiu de nume denumit std. In consecin, putem semnala compilatorului
bibliotecile standard iostream i math astfel
# include <iostream>
# include <cmath>
using namespace std;
Putem defini propriile biblioteci cu prototipuri pe care s le semnalm compilatorului
cu directiva include. Numele propriilor biblioteci cu prototipuri sunt scrise ntre
ghilimele.
1.11 Operaii de intrare / ieire
Orice aplicaie ce ruleaz pe un calculator are un director curent asociat i fiiere
standard de intrare i ieire. Fiierul standard de intrare este tastatura iar cel de ieire
este ecranul. In program, orice fiier este asociat unui obiect numit stream. Exist
dou tipuri de fiiere: text i binare. Ele vor fi prezentate detaliat ntr-un capitol
ulterior. Fiierele standard asociate unei aplicaii sunt de tipul text. Fiierul text este
este compus dintr-un ir de caractere grupate n linii. Liniile constau din zero sau mai
multe caractere urmate de un caracter \n. Streamul de intrare asociat tastaturii are
denumirea cin, streamul de ieire asociat ecranului se numete cout. Mai exist alte
dou streamuri cerr i clog pentru scrierea mesajelor de eroare.
Operatorul de scriere a datelor
Operatorul de scriere a datelor este <<. El insereaz date n streamul de ieire. De
exemplu, secvena de instruciuni
int i = 123;
cout << i = << i;
afiaz pe ecran
i = 123
Operatorul << insereaz n stream valoarea expresiei din dreapta sa. De exemplu,
expresia
<< i=
insereaz n stream irul de caractere i= , expresia
<< i
insereaz n stream valoarea variabilei i, 123, etc.
Pentru a afia valori pe mai multe linii, trebuie ca dup fiecare linie s scriem
caracterul \n, care este predefinit ca endl. De exemplu, fie instruciunile
int j = -7;
double x = 1 + sin(0.2);
Pentru a afia valorile variabilelor j si x pe dou linii, vom scrie
cout << j = << j << endl << x = << x << endl;
sau
cout << j = << j << \n << x = << x << \n;
sau
cout << j = << j << \n << x = << x << \n;
sau, echivalent, cu doua instruciuni cout
cout << j = << j << endl;
cout << x = << x << endl;
Operatorul << poate scrie orice tip predefinit de date: int, float, iruri de caractere, etc.
17
Operatorul de citire a datelor
Operatorul de citire dintr-un stream este >>. El extrage date din streamul de intrare i
le atribuie unor variabile. Operatorul >> este urmat de numele variabilei ce va
memora valoarea citit. De exemplu, secvena de instruciuni
int a;
cin >> a;
va citi o valoare introdus de la tastatur i o va atribui variabilei a (expresia >>a
citete o valoare de la tastatur i o atribuie variabilei a). O instruciune cin poate citi
oricte date din stream. Fie instruciunea
int a, b ;
Instruciunea
cin >> a >> b;
citete dou valori de la tastatur i le atribuie variabilelor a i b. Ea poate fi scris ca
cin >> a;
cin >> b;
Valorile introduse de la tastatur sunt analizate i atribuite variabilelor de ctre
instruciunea cin. Pentru fiecare variabil se procedeaz astfel :
se citesc i se ignor toate caracterele spaiu, \t sau \n (acesta din urm este
generat la apsarea tastei Return),
se citesc urmtoarele caractere corespunznd tipului variabilei sau pn la
ntlnirea unui caracter spaiu, \t sau \n i valoarea citit se atribuie
variabilei.
Fie de exemplu valorile 25 i 17 de citit pentru variabilele de tip ntreg a i b cu una
din instruciunile precedente. Ele pot fi introduse de la tastatur separate de un spaiu
ca
irul introdus este analizat astfel :
se citesc toate caracterele spaiu, \t sau \n pn la prima cifra ntlnit i se
ignor (n acest caz primul caracter este diferit de spaiu, \t sau \n),
se citesc apoi toate caracterele pn la primul caracter diferit de cifr, deoarece
trebuie citit un numr ntreg, i rezult numrul 25.
Se procedeaz la fel pentru al doilea numr :
se citete i se ignor spaiul,
se citesc cifrele pn la primul caracter diferit de cifr i rezult numrul 17.
Aceleai valori pot fi introduce ca
Fie de iniializat prin citire o variabil x tip caracter la valoarea A. Variabila este
definit cu instruciunea
char x;
Instruciunea de citire este
cin >> x;
Putem introduce caracterul A astfel:
sau
18
Citirea caracterului se face dup regula de mai sus : se citesc i se ignor toate
caracterele spaiu, \t sau \n i se citete un caracter care este atribuit variabilei x.
Valorile introduse de la tastatur sunt analizate i atribuite variabilelor de ctre
instruciunea cin doar dup introducerea unui caracter \n.
Reamintim c biblioteca de prototipuri pentru streamurile cin, cout, etc are numele
iostream. Pentru a modifica formatul de scriere sau citire a datelor putem utiliza
manipulatori definii n biblioteca iomanip. Pentru scrierea sau citirea unui numr
ntreg n instruciunile cout sau cin n diferite baze se utilizeaz manipulatorii
hex pentru baza 16
dec pentru baza 10
oct pentru baza 8
La nceperea execuiei unui program baza 10 este implicit.
Fie urmtorul exemplu
int a ;
cin >> hex >> a ;
cout << a << endl;
Presupunem introdus de la tastatur irul de caractere de mai jos
Valoarea atribuit prin citire variabilei a este 27. De ce ?
Valoarea afiat este 27. Pentru a afia valoarea variabilei a n baza 16 trebuie s
scriem
cout << hex << a << endl ;
Pentru afiarea bazei se utilizeaz manipulatorii:
showbase pentru scrierea bazei
noshowbase pentru a nu scrie baza
Exemplu. Fie instruciunea
int k = 20;
Tabloul urmtor prezint exemple de utilizare a manipulatorilor pentru a afia pe
ecran valoarea variabilei k.
cout << k; 20
cout << hex << k; 14
cout << showbase << hex << k; 0x14
cout << oct << k; 24
cout << showbase << oct << k; 024
In cazul numerelor reale avem manipulatorii:
fixed numrul este scris fr exponent
scientific numrul este scris cu exponent
Exemplu. Fie instruciunea
float x = 122.63;
Tabloul urmtor prezint exemple de utilizare a manipulatorilor pentru a afia pe
ecran valoarea variabilei x.
cout << x; 122.63
cout << fixed << x; 122.63
cout << scientific << x; 1.226300e+002
19
Funciile urmtoare sunt apelate de operatorul de scriere << :
setbase(int)
setw(int)
setfill(char)
setprecision(int)
Funcia setbase(int) indic baza n care va fi afiat un numr ntreg, 8, 10 sau 16.
Funcia setw(int) d dimensiunea cmpului n caractere pe care este scris un numr.
Valoarea implicit a acestui manipulator este 0. Dac dimensiunea cmpului nu este
specificat, sau este prea mic, numrul este scris pe cte caractere este necesar.
Funcia setfill(char) indic un caracter cu care se umplu spaiile libere ale unui cmp.
Valoarea implicit a acestui caracter este spaiul. Funcia setprecision(int) d numrul
de cifre cu care este scris un numr real.
Exemplu. Fie instruciunile
int x = 23;
double pi(3.1459);
Tabloul urmtor prezint exemple de utilizare a funciilor operatorului <<.
cout << setw(5) << x; 23
cout << x; 23
cout << setbase(16) << x: 17
cout << dec << setw(3) << setfill(*) << x; *23
cout << pi << endl; 3.1459
cout << setprecision(3) << pi << endl; 3.15
cout << setprecision(4) << pi << endl; 3.146
cout << setprecision(6) << pi << endl; 3.1459
Exemplu. Fie instruciunea
float z = 12.64;
Tabelul urmtor prezint exemple de utilizare a funciilor anterioare la afiarea
variabilei z cu instruciunea cout.
cout << setprecision(3) << z; 12.6
cout << setw(8) << z; 12.64
cout << setw(8) << setfill(*) << z; ***12.64
cout << setw(15) << scientific << z; 1.264000e+001
Manipulatorii urmtori specific modul de cadrare al valorilor scrise :
left - cadrare la stnga
right cadrare la dreapta
Menionm c dimensiunea cmpului prescris de funcia setw(int) se aplic
doar urmtorului numr de scris. Ceilali manipulatori rman la valoarea
prescris pan sunt modificai.
Exemplu. Fie instruciunile
int x ;
cin >> x ;
cout << hex << x << endl ;
cout << x << endl ;
20
Valoarea variabilei x este afiat n baza 16 cu ambele instruciuni, deoarece
manipulatorul de scriere a bazei are valoarea hex. Pentru a afia din nou variabilele
ntregi n baza 10 trebuie s scriem o instruciune
cout << dec << x << endl ;
1.12 Funcia main
Orice program scris n limbajele C sau C++ se compune din funcii care se apeleaz
unele pe altele. Definiia unei funcii este
tip numefunctie (lista de parametri)
{
instruciuni
}
Una din funcii are numele main iar execuia programului ncepe cu aceast funcie.
Prototipul acestei funcii este
int main();
Semnificaia acestui prototip este urmtoarea. Funcia main are ca rezultat o valoare
ntreag i nu are parametri. Corpul funciei este o instruciune compus, adic o
secven de instruciuni scrise ntre acolade, { i }. Corpul funciei conine i o
instruciune return ce termin execuia funciei i transmite n programul appelant
valoarea calculat de funcie.
Programul poate conine comentarii. Comentariile plasate ntre delimitatorii /* i */ se
pot ntinde pe mai multe linii. Comentariile ce ncep cu caracterele // se ntind pe o
singur linie.
Putem scrie acum primul program care citete o valoare ntreag de la tastatur i
afieaz ptratul ei.
// program care se citeste o valoare intreaga si calculeaza patratul ei
# include <iostream>
using namespace std;
int main()
{
int i, j;
cout << introduceti o valoare intreaga << endl;
/* se citeste o valoare intreaga */
cin >> i;
cout << valoarea introdusa este << i << endl;
/* se calculeaza patratul valorii citite */
j = i * i;
/* se afisaza valoarea calculata */
cout << patratul valorii este << j << endl;
return 0;
}
Menionm c funcia main() returneaz valoarea 0 cu instruciunea
return 0;
Rezultatul rulrii programului este cel de mai jos.
21
1.13 Execuia unui program
Reamintim etapele de execuie a unui program.
Prima etap este compilarea programului. In aceast etap programul este
verificat pentru erori sintactice. Dac programul nu conine erori sintactice
compilatorul genereaz un program obiect traducnd fiecare instruciune a
programului ntr-o serie de instruciuni elementare ale calculatorului. Fiecare
fiier surs este compilat separat. Din fiecare fiier surs rezult un fiier
obiect.
Etapa a doua este editarea legturilor. In aceast etap sunt ataate
programului funciile din biblioteci. Atunci cnd compilatorul ntlnete un
apel de funcie (de exemplu sin, cos, etc.), sau o operaie intrare/ieire, el
genereaz doar o secven de apel la funcie. Funciile respective sunt
precompilate n biblioteci speciale i programul editor de legturi ataeaz
aceste funcii programului obiect. Editorul de legturi genereaz un program
executabil din toate fiierele obiect. El este un fiier cu extensia exe.
In etapa a treia programul excutabil este ncrcat n memorie i executat.
1.14 Operatorul sizeof
Operatorul sizeof se aplic asupra unei expresii sau asupra unui tip i are ca rezultat
numrul de octei de memorie utilizai. Exist dou forme ale acestui operator
sizeof (tip)
sizeof (expresie)
De exemplu, expresia
sizeof(int)
are ca rezultat valoarea 4, expresia
sizeof (char)
are valoarea 1, etc.
In cazul unui tablou rezultatul este numrul total de octei ocupat de tablou. Fie
instruciunea
double a[5];
Expresia
sizeof(a)
are valoarea 40 iar expresia
sizeof(a) / sizeof(a[0]
d numrul elementelor tabloului a.
In cazul cand operandul este o expresie, operatorul sizeof d numrul de octei ocupat
de rezultatul expresiei. Fie de exemplu instruciunile
int x;
double m;
Expresia
sizeof(x + m)
are valoarea 8, deoarece tipul expresiei este double.
22
Exemplu. Vom scrie un program care s afieze numrul de octei utilizai pentru
memorarea tipurilor fundamentale. Vrem ca rezultatele s fie afiate pe ecran astfel:
Numarul de octeti utilizati
int : ....
char : ....
float : ....
double : .
vectorul float a[10] : .
expresia a[0]+b : ....
Pentru a afia datele deplasate la stnga cu un numr de spaii vom scrie un caracter
tab, \t. Programul este urmtorul :
// dimensiunea tipurilor standard
# include <iostream>
using namespace std;
int main()
{
float a[10], b;
cout << Numarul de octeti utilizati: << endl;
// scrie dimensiunea tipurilor standard
cout << \tint: << sizeof(int) << endl;
cout << \tchar: << sizeof(char) << endl;
cout << \tfloat: << sizeof(float) << endl;
cout << \tdouble: << sizeof(double) << endl;
// scrie dimensiunea unui vector
cout << \tvectorul float a[10]: << sizeof(a) << endl;
// scrie dimensiunea rezultatului unei expresii
cout << \texpresia a[0]+b: << sizeof(a[0]+ b) << \n;
}
Rezultatul rulrii programului este prezentat mai jos.
Menionm c este echivalent dac n instruciunea cout utilizm caracterul \n, sau
endl, sau irul de caractere \n. irului de caractere \tint: duce la scrierea
caracterului \t i a irului int: . Instruciunea
cout << \tint: << sizeof(int) << endl;
putea fi scris ca
cout << \t << int: << sizeof(int) << endl;
1.15 Operatorii ++ i - -
Operatorul ++ incrementeaz o variabil ntreag cu valoarea unu, operatorul - -
decrementeaz o variabil ntreag cu unu. Aceti operatori pot fi :
23
prefix
++x, --x
postfix
x++, x- -
Expresiile ++x i x++ reprezint instruciunea
x = x + 1
iar expresiile - -x i x- - reprezint instruciunea
x = x 1
Cazul operatorilor prefix, ++x, --x
O expresie de forma
f(++x);
este scrierea prescurtat a expresiilor:
x = x + 1;
f(x);
In acelai fel, expresia
f(--x);
reprezint scrierea prescurtat a expresiilor:
x = x 1;
f(x);
Modul de execuie a expresiei este urmtorul: se incrementeaz sau decrementeaz
valoarea variabilei x cu unu; valoarea incrementat sau decrementat se utilizeaz mai
departe n calcule.
Exemplu. Fie declaraia de variabile
int i = 1, x;
Instruciunea
x = ++i;
reprezint scrierea prescurtat a secvenei de instruciuni
i = i + 1;
x = i;
Dup execuia instruciunii x = ++i variabilele au valorile i = 2 i x = 2.
Exemplu. Fie declaraia de variabile
int j = 3, k;
Instruciunea
k = --j;
reprezint scrierea prescurtat a secvenei de instruciuni
j = j 1;
k = j;
Dup execuia instruciunii variabilele au valorile j = 2 i k = 2.
Exemplu. Fie secventa de instruciuni
int i = 1;
cout << i = << i << endl;
cout << i = << ++i << endl;
cout << i = << i << endl;
Valorile afiate vor fi
i = 1
i = 2
i = 2
deoarece a doua instructiune cout este echivalent cu instruciunile
cout << i = ;
i = i + 1;
24
cout << i << endl;
Exemplu. Fie urmtoarele declaraii.
double a[4] = {1.2, -5, 8, 3};
double r;
int i = 1, k = 1;
Secvena de instruciuni
i = i +1;
r = a[i];
se poate scrie
r = a[++i];
Expresia ++i este evaluat la 2, iar r primete valoarea a[2] = 8.
Secvena de instruciuni
k = k 1;
r = a[k];
se poate scrie
r = a[--k];
Expresia --k este evaluat la 0 iar r primete valoarea a[0] = 1.2
Cazul operatorilor postfix, x++, x--
O expresia de forma
f(x++);
reprezint scrierea prescurtat a expresiilor
f(x);
x = x + 1;
In acelai mod, expresia
f(x--);
reprezint scrierea prescurtat a expresiilor:
f(x);
x = x 1;
Modul de execuie a expresiei este urmtorul : se utilizeaz n calcule valoarea
variabilei x (neincrementate sau nedecrementate). Se incrementeaz / decrementeaz
apoi variabila x.
Exemplu. Fie cele dou secvene de instruciuni de mai jos :
int a, b;
b = 3;
a = b++;
Expresia
a = b++;
corespunde secvenei de instruciuni :
a = b;
b = b + 1;
In consecin, expresia b++ are valoarea 3 (valoarea neincrementat a variabilei) i
apoi se incrementeaz b. Avem rezultatul
a = 3
b = 4
Exemplu. Fie instructiunile :
int j = 1;
cout << j = << j << endl;
cout << j = << j++ << endl;
cout << j = << j << endl;
Valorile afiate vor fi :
25
j = 1
j = 1
j = 2
deoarece a doua instruciune cout este echivalent cu instruciunile :
cout << j = << j;
j = j + 1;
cout << endl;
Exemplu. Fie secvena de instruciuni de mai jos :
int i;
double x[4] = {2.4e1, 14.4, -3.1 0};
double d;
i = 1;
d = x[i++];
Instruciunea
d = x[i++];
corespunde secvenei de instruciuni :
d = x[i];
i = i + 1;
Expresia i++ are valoarea 1 i apoi se incrementeaz i. Avem deci
d = 14.4
i
i = 2
Fie acum secvena de instruciuni urmtoare :
int j;
double x[4] = {2.4e1, 14.4, -3.1 0};
double d;
j = 1;
d = x[++j];
Instruciunea
d = x[++j];
corespunde secvenei de instruciuni :
j = j + 1;
d = x[j];
In consecin expresia ++j are valoarea 2 i avem
d = -3.1
i
j = 2
1.16 Operaii cu numere ntregi la nivel de bit
1.16.1 Operatori de deplasare
Deplasarea la stnga a unui ntreg cu un bit reprezint nmulirea acelui numr cu doi.
Deplasarea la dreapta a unui ntreg cu un bit reprezint ctul mpririi acelui numr
cu doi. De exemplu, prin deplasarea numrului 7 la dreapta cu un bit se obine
rezultatul 3. Operatorii de deplasare a unui numr ntreg cu un numr de bii sunt <<
pentru deplasare la stnga i >> pentru deplasare la dreapta. Expresia de deplasare a
unui numr ntreg are forma
26
Rezultatul expresiei din stnga este numrul ntreg ce va fi deplasat. Expresia din
dreapta d numrul de bii cu care se face deplasarea. Deplasarea se face dup regulile
deplasrii numerelor binare cu semn, vezi anexa. (La deplasarea la dreapta se propag
bitul de semn, la deplasarea la stnga se adaug zerouri). Dac expresia de deplasat
este de tipul unsigned biii adugai sunt zerouri.
Exemple. Fie instruciunea
int x = 7 >> 1;
Variabila x primete valoarea 3 (ctul npririi lui 7 la 2 este 3).
Fie instruciunile de mai jos
int a = 0xff; int y = 0xff;
int b; int c;
b = a << 4; c = y >> 4;
Numrul a, reprezentat pe patru octei, are valoarea hexazecimal
a = 000000ff
Numrul a deplasat la stnga cu 4 bii este
00000ff0
Numrul y deplasat la dreapta cu 4 bii este
0000000f
Numrul 0xff convertit n zecimal este 255. Care este valoarea numerelor 0xf i 0xff0
n zecimal?
Fie dou variabile ntregi, i si j i secvena de instruciuni :
i = 7;
j = i >> 1;
Variabila j va primi valoarea 3. Reamintim c 7 / 2 = 3.
Ca un alt exemplu, s definim constantele X, Y, Z i R care s aibe valorile 1, 2, 4, 8,
folosind instruciunea enum.
enum {X = 1, Y = X << 1, Z = Y << 1, R = X << 3};
Limbajele C i C++ au operatorii de atribuire <<= i >>= pentru scrierea prescurtat a
instruc iunilor ce conin operatorii << i >>. Instruciunea
x = x << n ;
se scrie prescurtat
x <<= n ;
iar instruciunea
x = x >> n ;
se scrie prescurtat
x >>= n ;
Vom ncheia acest paragraf cu un program care deplaseaz numere ntregi i afiaz
valoarea lor n zecimal i hexazecimal. Reamintim c pentru scrierea sau citirea unui
numr ntreg n instruciunile cout sau cin n diferite baze se utilizeaz manipulatorii :
hex pentru baza 16
dec pentru baza 10
oct pentru baza 8
La nceperea execuiei unui program baza 10 este implicit.
Vom exemplifica utilizarea operatorilor de deplasare deplasnd dou variabile ntregi
la stnga i la dreapta i vom afia rezultatele n bazele 10 i 16.
27
# include <iostream>
using namespace std;
/* uitlizarea operatorilor de deplasare */
int main()
{
int x = 10;
cout << x = << dec << x << << hex << showbase << x << endl;
// deplaseaz variabila a la stanga cu un bit
x = x << 1;
cout << x deplasat la stanga cu 1 bit =
<< dec << x << << hex << showbase << x << endl;
int b = 50;
cout << b = << dec << b << << hex << showbase << b << endl;
// deplaseaz variabila b la dreapta cu 3 pozitii
b = b >> 3;
cout << b deplasat la dreapta cu 3 biti =
<< dec << b << << hex << showbase << b << endl;
return 0;
}
Rezultatele rulrii programului sunt prezentate n figura de mai jos.
1.16.2 Operaii logice la nivel de bit
Limbajele C i C++ au urmtorii operatori pentru operaii logice la nivel de bit
i logic (and) notat &
sau logic (or) notat |
sau excusiv (xor) notat ^
complement fa de unu notat ~
Aceti operatori se definesc cu tabelele de adevr urmtoare
a b a&b a|b a^b
0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 1 0
a ~a
0 1
1 0

Operatorii &, | ^ sunt operatori binari. Expresiile cu aceti operatori logici au forma
urmtoare
28
Operaiile sunt aplicate asupra fiecrei perechi de bii din cei doi operanzi. Operatorul
~ este operator unar. Expresiile cu acest operator au forma urmtoare
Operatorul ~ complementeaz fiecare bit din expresia ntreag.
Exemple. Fie urmtoarea secven de program :
int a, b, c, d, e;
a = 0xf000;
b = 0xabcd;
c = a & b;
d = a | b;
e = a ^ b;
Rezultatele sunt
c = 0xa000
d = 0xfbcd
e = 0x5bcd
In primul caz, la calculul valorii c = a & b, vom exemplifica doar calculul expresiei
0xf & 0xa = 0xa
Rezultatul se obine conform calculului de mai jos.
0 1 0 1
0 1 0 1
& 1 1 1 1
Pentru calculul valorii e = a ^ b vom calcula expresia
0xf ^ 0xa = 0x5
Rezultatul se obine conform calculului de mai jos
1 0 1 0
0 1 0 1
^ 1 1 1 1
Pentru calculul valorii d = a | b vom calcula expresia
0xf | 0xa = 0xf
Rezultatul se obine conform calculului de mai jos
1 1 1 1 |
1 0 1 0
------------------
1 1 1 1
Expresia ~a are valoarea 0x0fff. De ce?
Limbajele C i C++ au operatorii &=, |= i ^= pentru scrierea prescurtat a
instruciunilor de atribuire ce conin operatori &, | i ^. De exemplu expresia
x = x & a ;
Se scrie prescurtat
x &= a ;
Reamintim c operatorii <<, >>, &, | i ~ sunt operatori aritmetici.
29
Pentru a selecta unui numr de bii dintr-o numr ntreg se definete un ir de bii
numit masc i se efectueaz operaia & ntre numrul iniial i masc. De exemplu,
pentru a selecta biii unei cifre hexazecimale vom utiliza ca masc valorile 0x1, 0x2,
0x4 i 0x8. Pentru a selecta cifrele octale dintr-un numr ntreg vom utiliza ca masc
valorile 07, 070, 0700, etc. Pentru a selecta cifrele hexazecimale dintr-un numr ntreg
vom utiliza ca masc valorile 0xf, 0xf0, 0xf00, etc.
Exemplu. Fie variabila ntreag a = 0x6dbc. Vrem ca n variabila ntreag b s
selectm ultimul octet, apoi ultimii 10 bii i n final primii 4 bii ai variabilei a.
Inversarea unor bii din variabila a este prezentat n finalul exemplului.
// operatii logice la nivel de bit
# include <iostream>
using namespace std;
int main()
{
int a = 0x6dbc, b;
cout << a = << hex << showbase << a << endl;
// selecteaza ultimul octet din a
b = a & 0xff;
cout << ultimul octet din a = << hex << showbase << b << endl;
b = a & 0x3ff;
// selecteaza ultimii 10 biti din a
cout << ultimii 10 biti din a = << hex << showbase << b << endl;
// selecteaz primii patru biti din a
b = a & 0xf000;
cout << primii 4 biti din a = << hex << showbase << b << endl;
// pastram primii opt biti si inversam ultimii opt biti din a
b = a ^ 0x00ff;
cout << ultimii 8 biti inversati din a = << hex << showbase << b << endl;
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
S se explice de ce, n cazul al doilea, masca este 0x3ff;
30
2 Structuri de control fundamentale
2.1 Algoritme
Programele reprezint formulri concrete ale unor algoritme ce prelucreaz structuri
de date. Un algoritm este format dintr-un ir finit de aciuni bine definite i neambigue
pentru rezolvarea unei probleme. Fiecare aciune trebuie s poat fi executat ntr-un
interval finit de timp.
Orice algoritm se poate descompune ntr-un numr finit de etape. El poate fi
reprezentat printr-un ir de aciuni astfel nct efectul general al acestor aciuni s
conduc la rezultatul dorit al calculului.
In cazul cel mai simplu un algoritm poate fi descompus ntr-un numr de aciuni
secveniale care se reprezint n felul urmtor
s1; s2; sn;
Pentru executarea unei aciuni n funcie de ndeplinirea unei condiii avem operatori
condiionali
Operatorul if cu formele
if (condiie) s1;
sau
if (condiie) s1; else s2;
condiie este o expresie boolean care are valoarea advrat sau fals. Aciunea
s1 se execut cnd condiie are valoarea adevrat.
Operatorul switch este generalizarea operatorului if
switch(i)
i = 1: s1;
i = 2: s2;
..
i = n: sn;
In funcie de valoarea lui i se execut una dintre aciunile s1, s2, , sn.
Aceti operatori se caracterizeaz prin faptul c au o singur intrare i o singur ieire.
Fiecare operator este interpretat n irul de calcule ca o singur aciune, indiferent de
coninutul su. Operatorii anteriori sunt suficieni pentru a descrie clasele de calcule
ce se pot descompune ntr-un numr cunoscut de aciuni.
Pentru a descrie calculele repetate cnd numrul de aciuni nu este cunoscut exist
operatorii while i do.
Operatorul while are forma
while (condiie)
s;
Aciunea s se execut atta timp ct expresia boolean condiie are valoarea
adevrat.
Operatorul do are forma
do
s;
while (condiie)
In acest caz aciunea s se execut atta timp ct condiie are valoarea adevrat.
Menionm c n cazul operatorului do aciunea s se execut cel puin o dat,
n timp ce pentru operatorul while este posibil ca aciunea s s nu se execute
niciodat.
31
Operatorul for se utilizeaz atunci cnd numrul de execuii ale unei aciuni
este dinainte cunoscut. Operatorul are o variabil de control ce se poate
modifica la fiecare iteraie. Forma acestui operator este
for (i = instruciune1; condiie; instruciune2)
s;
Operatorul include o instruciune1 ce specific valoarea iniial a variabilei
de control, i o instruciune2 ce poate modifica valoarea variabilei de control
dup fiecare iteraie. Aciunea s se execut att timp ct expresia boolean
condiie are valoarea adevrat. Operatorul for este echivalent cu urmtoarele
instruciuni
instruciune1;
while(condiie)
s;
instruciune2;
Menionm c testul condiiei se face nainte de execuia aciunii s.
Operatorii prezentai se numesc structuri de control fundamentale. In construcia unui
program structurile de control i structurile de date sunt inseparabile. Structurile
fundamentale de date sunt
structuri simple: numere ntregi, reale, caractere.
structuri complexe tablouri, fiiere.
Tablourile au un numr cunoscut de elemente. Ele se prelucreaz de regul cu
operatorul for. Fiierele secveniale au un numr de elemente necunoscut n avans. Ele
se prelucreaz de regul cu operatorul while.
Exemplu. Algoritmul de calcul pentru n! care este definit ca

n
i
i n
1
!
s = 1;
for i = 1; i <= n; i = i + 1
s = s * i;
2.2 Expresii relaionale
O operaie definit pentru tipurile de date fundamentale este compararea.
Operatorii relaionali ai limbajelor C i C++ sunt, n ordinea prioritilor
<, <=, >, >=
= =, !=
O expresie relaional are urmtoarea form
Rezultatul evalurii unei expresii relaionale este fals sau adevrat (false sau true).
Prioritile operatorilor aritmetici sunt mai mari dect ale operatorilor relaionali.
Exemple. Fie urmtoarele instruciuni de atribuire
int a = 2, b = 3, c = 6;
In tabela de mai jos sunt prezentate exemple de expresii relaionale i rezultatul
evalurii lor.
32
Expresie relaional Valoare
a*b >= c true
b+2 > a *c false
a+b = = 3 false
a != b true
b/a = = 1 true
Reamintim c n limbajul C++ valoarea true este reprezentat prin 1 iar valoarea false
prin 0. La scrierea valorii unei variabile booleene valoarea afiat este 0 sau 1, dup
cum variabila are valoarea false, respectiv true. Pentru afiarea valorii booleene ca
true, respectiv false se utilizeaz manipulatorul boolalpha.
Fie urmtoarea instruciune de declarare a unei variabile de tip bool
bool r;
Putem avea urmtoarele instruciuni de atribuire
r = a + b = = c;
r = a b >= 2;
r = a * a != -b;
Variabila r poate avea valorile true sau false.
In final reamintim c operatorul = este operator de atribuire, iar operatorul = = este
operator de comparare. Instruciunea
a = b
atribuie variabilei a valoarea variabilei b, iar expresia
a = = b
este o expresia relaional care are ca rezultat valoarea true sau valoarea false.
2.3 Expresii booleene
Operatorii booleeni ai limbajelor C i C++ sunt, n ordinea prioritilor
!
&&
| |
care reprezint operatorii nu (not), i (and), respectiv sau (or). Operatorul nu este
operator unar. Aceti operatori se definesc folosind tabelele de adevr.
x y x && y x | | y
false false false false
false true false true
true false false true
true true false true
x !x
false true
true false
Rezultatul evalurii unei expresii booleene este true sau false. In cursurile de logic
operatorii booleeni se noteaz astfel:
nu (not)
i (and)
sau (or)
33
Exemple de expresii booleene i scrierea lor sunt prezentate mai jos :
) || &( & ) (
||! !
|| & &
) || ( ! ) (
& &
c b a c b a
b a b a
c b a c b a
b a b a
b a b a



Pentru scrierea simpl a expresiilor booleene sunt importante dou teoreme


numite legile lui DeMorgan
b a b a
b a b a


) (
) (
care se demonstreaz cu ajutorul tabelelor de adevr.
In final menionm c operatorii booleeni and i or sunt
comutativi
a b b a
a b b a


asociativi la stnga
c b a c b a
c b a c b a


) (
) (
distributivi
) ( ) ( ) (
) ( ) ( ) (
c a b a c b a
c a b a c b a


In final prezentm prioritatea (precedena) i asociativitatea operatorilor
Operator Asociativitate
[ ] ( ) stnga
++ -- + - ! ~ sizeof (tip) dreapta
* / % stnga
+ - stnga
<< >> stnga
< <= > >= stnga
= = != stnga
& stnga
^ stnga
| stnga
&& stnga
| | stnga
= += -= *= /= %= <<= >>= &= |= ^= stnga
2.4 Operatorul if
Acest operator execut o anumit instruciune n funcie dac o anumit condiie este
ndeplinit sau nu. Forma operatorului if este
if(expresie)
S1;
else
S2;
34
Dac expresie este diferit de zero se execut instruciunea S1 altfel instruciunea S2.
Operatorul if poate avea i o form simplificat
if(expresie)
S;
In care se execut instruciunea S dac expresie are valoare diferit de zero.
Ca prim exemplu vom scrie un program care s testeze dac un ntreg este divizibil cu
altul. Cei doi ntregi se citesc de la tastatur. Pentru a testa dac un ntreg n este
divizibil cu un alt ntreg d, vom calcula expresia n % d, restul mpririi lui n la d.
# include <iostream>
using namespace std;
int main()
{
int n, d;
cout << introduceti doi intregi : ;
cin >> n >> d;
if(n % d == 0)
cout << n << este divizibil cu << d << endl;
else
cout << n << nu este divizibil cu << d << endl;
return 0;
}
Un exemplu de execuie a programului este dat mai jos.
Un alt exemplu este calculul maximului a dou numere ntregi citite de la tastatur.
// calculul maximului a doua numere intregi
# include <iostream>
using namespace std;
int main()
{
int n, m;
cout << introduceti doi intregi : << endl;
cin >> n >> m;
cout << maximul dintre << m << si << n << este ;
if(n > m)
cout << n << endl;
else
cout << m << endl;
return 0;
}
Un exemplu de rulare a programului este prezentat mai jos.
35
Instruciunile din expresia operatorului if pot fi instruciuni compuse, sau blocuri de
instruciuni, adic un ir de instruciuni cuprinse ntre acolade. Ca exemplu, fie
ordonarea descresctoare a dou numere ntregi citite de la tastatur.

// ordonarea descrescatoare a dou numere intregi citite de la tastatura
# include <iostream>
using namespace std;
int main()
{
int x, y;
cout << introduceti doi intregi : ;
cin >> x >> y;
if(x < y)
{
int temp = x;
x = y;
y = temp;
}
cout << numerele ordonate descrescator : << x << , << y << endl;
return 0;
}
Un exemplu de execiie a programului este cel de mai jos.
Menionm c o instruciune if poate conine alte instruciuni if. De exemplu, putem
avea instruciunea compus
if (e1)
if (e2)
s1;
else
s2;
else
if(e3)
s3;
else
s4;
unde e1, e2, e3 sunt expresii booleene. Dac expresia boolean e1 are valoarea
adevrat, (este diferit se zero), se execut instruciunea if(e2), n caz contrar se
execut instruciunea if(e3).
36
2.5 Operatorul switch
Acest operator execut o instruciune din mai multe posibile. Fiecare instruciune este
etichetat cu o constant ntreag. Instruciunea conine o expresie ntreag ce
determin ce etichet trebuie aleas. Forma operatorului switch este urmtoarea
switch(expresie)
{
case expint: instructiune
case expint: instructiune
.
case expint: instructiune
}
Una dintre etichete poate fi default. In acest caz, dac expresia din instruciunea
switch nu are nici una din valorile etichetelor din instruciunile case, se trece la
execuia instruciunilor cu eticheta default.
Pentru ieirea din instruciunea switch se utilizeaz instruciunea break.
Exemplu. Vom citi dou numere ntregi n dou variabile x i y i un operator +, -, *, /
sau % ntr-o variabil tip char i vom calcula rezultatul operaiei corespunztoare.
Programul este urmtorul.
// calculator cu numere intregi
#include <iostream>
using namespace std;
int main()
{
int x, y;
char oper;
cout << intoduceti doi intregi : ;
cin >> x >> y;
cout << introduceti un operator : ;
cin >> oper;
switch(oper)
{
case + :
cout << x << oper << y << "=" << x + y;
break;
case - :
cout << x << oper << y << "=" << x y;
break;
case * :
cout << x << oper << y << "=" << x * y;
break;
case / :
cout << x << oper << y << "=" << x / y;
break;
case % :
cout << x << oper << y << "=" << x % y;
break;
default :
37
cout << eroare;
break;
}
cout << endl;
return 0;
}
Menionm c instruciunile corespunztoare etichetelor sunt urmate de instruciunea
break ce asigur ieirea din operatorul switch. Rezultatul rulrii programului este cel
de mai jos.
2.6 Operatorul ?
Acest operator este o form simplificat a operatorului if. Forma lui este
expresie ? S1 : S2;
Dac expresie are o valoare diferit de zero, se execut instruciunea S1, altfel
instruciunea S2.
Vom rezolva din nou problema divizibilitii a dou numere.
# include <iostream>
using namespace std;
int main()
{
int k, m;
cout << intoduceti doi intregi : ;
cin >> k >> m;
cout << k << ((k % m)? " nu ": "") << " este divizibil cu " << m <<
endl;
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
Instruciunea
((k % m)? " nu ": "")
are ca rezultat irul de caractere nu cnd k nu divide m sau irul n caz contrar.
2.7 Operatorul while
Operatorul while execut repetat un grup de instruciuni. Forma operatorului while
este
while (expresie)
S;
38
instruciunea S se execut atta timp ct expresia este diferit de zero (are valoarea
adevrat). Instruciunea S poate fi o instruciune compus, format dintr-o secven de
instruciuni, cuprinse ntre acolade, { i }.
Vom exemplifica utilizarea acestui operator calculnd suma elementelor unui vector a
cu patru componente. Elementele vectorului a au indicii 0, 1, 2 i 3.

3
0 i
i
a s
Vom utiliza o variabil f de tip float pentru a calcula suma, care va fi pus iniial la
valoarea zero i vom executa repetat instruciunea
i
a s s +
pentru i lund valori de la 0 la 3. Programul pseudocod este urmtorul.
s = 0;
i = 0;
while(i < 4)
s = s + a[i];
i = i + 1;
Programul este urmtorul
#include <iostream>
using namespace std;
/* calculul sumei componentelor unui vector */
int main()
{
float a[4] = {2.34, -7.32, 2.5e-1, 73};
int i;
float s;
s = 0;
i = 0;
while(i < 4)
{
s = s + a[i];
i = i + 1;
}
cout << suma componentelor este << s << endl;
return 0;
}
Putem rescrie partea de calcul din program astfel
s = 0;
i = 0;
while(i < 4)
{
s += a[i];
i++;
}
sau
39
s = 0;
i = 0;
while(i < 4)
{
s += a[i++];
}
In urmtorul exemplu vom calcula media unui ir de numere reale citite de la
tastatur. Fie n variabila ntreag n care vom citi lungimea irului de numere, i o
variabil n care numrm valorile citite i x o variabil n care citim cte un numr.
Variabila suma va conine suma numerelor deja citite. Programul pseudocod este
urmtorul.
i = 1;
suma = 0;
read n;
while (i <= n)
{
read x;
suma = suma + x;
i = i + 1;
}
media = suma / n;
write media;
Programul corespunztor este urmtorul
// calculul mediei unui sir de numere reale citite de la tastatura
# include <iostream>
using namespace std;
int main()
{
int n, i = 1;
double suma = 0, media, x;
cout << "cate numere ? ";
cin >> n;
// calculul sumelor partiale
while(i <= n)
{
cin >> x;
suma = suma + x;
i = i + 1;
}
// calculul mediei
media = suma / n;
cout << "media este : " << media << endl;
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
40
2.8 Operatorul do-while
Operatorul do-while este tot un operator repetitiv. Acest operator are forma
do
S
while (expresie);
Instruciunea S se execut atta timp ct expresia este diferit de zero (are valoarea
adevrat). Instruciunea S din diagrama sintactic poate fi o secven de instruciuni.
Instruciunea S poate fi o instruciune simpl sau o instruciune compus, scris ntre
acolade, { i }.
Exemplu. Vom calcula valoarea 5! care se definete ca

5
1
! 5
i
i
Vom utiliza o variabil n pus iniial la valoarea 1 i vom executa repetat
instruciunea
n = n * i
pentru i lund valori de la 1 la 5. Programul pseudocod este urmtorul.
n = 1;
i = 1
do
n = n * i;
i = i + 1;
while (i < 6)
Programul corespunztor este urmtorul
# include <iostream>
using namespace std;
/* calculul valorii 5! */
int main()
{
int i, n;
i = 1;
n = 1;
do
{
n = n * i;
i = i + 1;
}
while(i < 6);
41
cout << 5! are valoarea << n << endl;
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
Menionm c, deoarece dorim s executm repetat mai multe instruciuni cu
instruciunea do-while
n = n * i;
i = i + 1;
scriem aceste instruciuni ca o instruciune compus, ntre acolade, { i }.
Putem rescrie partea de calcul din program astfel
int i = 1, n = 1;
do
{
n *= i;
i++;
}
while(i < 6);
sau
int i = 1, n = 1;
do
n *=i++;
while(i < 6);
Reamintim c instruciunea
n *= i++;
este echivalent cu instruciunile
n *= i;
i++;
conform modului de execuie a operatorului postfix ++ : valoarea expresiei este chiar
valoarea variabilei i neincrementate, dup care variabila i este incrementat.
2.9 Operatorul for
Operatorul for permite execuia repetat a unui grup de instruciuni cu modificarea
unei variabile de control dup fiecare iteraie. Operatorul for are forma
for(expresie1; expresie2; expresie3)
S
Operatorul for execut repetat o instruciunea S, att timp ct expresie2 este diferit
de zero. expresie1 are rolul de a iniializa variabila de control. expresie3 are rolul de
a modifica valoarea variabilei de control. Instruciunea S, executat repetat, poate fi o
42
instruciune simpl sau o instruciune compus ce const dintr-o secven de
instruciuni ntre acolade, { i }.
Exemplu. Vom calcula valoarea expresiei x x e
x
+ +2 pentru x cuprins ntre unu i
doi cu pasul 0.2. O prim variant de program pseudocod este urmtorul
for (i = 0; i < 6; i = i + 1)
{
x = 1 + 0.2 * i
y = x x e
x
+ +2
}
Vrem ca rezultatul s fie afiat n dou coloane cu antetul x i y, ca mai jos.
x y
. .
. .
Programul este urmtorul
# include <iostream>
# include <cmath>
# include <iomanip>
using namespace std;
int main()
{
int i;
double x, y;
cout << setw(4) << "x" << '\t' << setw(5) << "y" << endl;
for(i = 0; i < 6; i = i + 1)
{
x = 1 + 0.2 * i;
y = exp(x) + 2 * x + sqrt(x);
cout << setw(4) << x << '\t' << setw(5) << y << endl;
}
return 0;
}
Pentru a scrie antetul tabelului cu valori am utilizat instruciunea
cout << setw(4) << "x" << '\t' << setw(5) << "y" << endl;
care scrie irurile de caractere x i y pe cte 4, respectiv 5 coloane, separate de
caracterul \t (tab). In program rezultatele sunt scrise de asemenea separate de tab.
Pentru a prescrie numrul de coloane al unui cmp se utilizeaz funcia setw() din
biblioteca <iomanip>. Rezultatul rulrii programului este cel de mai jos.
43
Menionm c instruciunea for se putea scrie astfel
for(i = 0; i < 6; i++)
sau
for(i = 0; i < 6; ++i)
Un alt mod de a calcula valorile expresiei de mai sus este de a utiliza instruciunea
for(x = 1; x <= 2; x = x + 0.2)
care modific pe x de la 1 la 2 cu pasul 0.2. Programul este urmtorul
# include <iostream>
# include <cmath>
# include <iomanip>
using namespace std;
int main()
{
double x, y;
cout << setw(4) << "x" << '\t' << setw(5) << "y" << endl;
for(x = 1; x <= 2; x = x + 0.2)
{
y = exp(x) + 2 * x + sqrt(x);
cout << setw(4) << x << '\t' << setw(5) << y << endl;
}
return 0;
}
Exemplul urmtor calculeaz suma componentelor pare i impare ale unui vector x cu
ase elemente. Programul pseudocod este urmtorul
s1 = 0;
s2 = 0;
for( i = 0; i < 6; i=i+1)
if (i % 2 = = 0)
s1 = s1 +
i
x
else
s2 = s2 +
i
x
Elementul
i
x
este adunat la suma componentelor pare s1 sau impare s2 dup cum
expresia i % 2 are valoarea zero sau nu.
Programul este urmtorul
#include <iostream>
using namespace std;
/* calculul sumei componentelor pare si impare ale unui vector */
int main()
{
float s1 = 0, s2 = 0;
int i;
float x[10] = {1, -12, 23.2, 0.44, 3.4, -2.3};
for(i = 0; i < 6; i = i + 1)
if(i % 2 = = 0)
s1 = s1 + x[i];
44
else
s2 = s2 + x[i];
cout << suma elementelor pare este << s1 << endl
<< suma elementelor impare este << s2 << endl;
return 0;
}
Vom ncheia acest paragraf cu un program care s calculeze suma a doi vectori cu
cte trei componente reale fiecare, iniializai la definirea lor n program.
/* calculul sumei a doi vectori */
# include <iostream.h>
int main()
{
float x[3] = {1.1e+1, -2.57, 13.2};
float y[3] = {-2.12, 13.5, 3.41}, float z[3];
for(int i = 0; i < 3; i++)
z[i] = x[i] + y[i];
for(int i = 0; i < 3; i++)
cout << z[i] << \t;
cout << \n;
return 0;
}
In final, menionm instruciunile break i continue. Instruciunea break produce
ieirea imediat din instruciunile for, while, do-while sau switch. Instruciunea
continue trece la urmtoarea iteraie a instruciunii for, while sau do-while.
Exemplu. Vom citi n numere reale de la tastatur i vom calcula media celor pozitive.
La fiecare iteraie a instruciunii for, vom citi cte un numr i vom testa dac este
negativ. Dac da, vom trece la urmtoarea iteraie cu instruciunea continue, n caz
contrar vom prelucra numrul citit.

#include <iostream>
using namespace std;
int main()
{
int n, m = 0, cnt;
float x, sum = 0, media;
cout <<"media numerelor pozitive" << endl;
cout << "cate numere ? ";
cin >> n;
for(cnt = 1; cnt <= n; ++cnt)
{
cout << "dati un numar : ";
cin >> x;
if(x < 0)
continue;
sum = sum + x;
m = m + 1;
}
45
media = sum / m;
cout << "media = " << media << endl;
return 0;
}
Rezultatul rulrii programului este prezentat mai jos.
2.10 Operatorul ,
Operatorul , are urmtoarea form
expresie1, expresie2
Rezultatul operatorului este expresie2, rezultatul evalurii expresie1 se neglijaz.
Operatorul , se poate utiliza oriunde n mod normal se utilizeaz o singur expresie,
dar sunt necesare dou expresii. Un exemplu este instruciunea for, cnd este necesar
s iniializm dou expresii, exp1 i exp2.
for(exp1, exp2; condiie; exp3)
Exemplu. Vom testa dac un cuvnt este palindrom (este acelai cuvnt citit n ambele
sensuri). In program vom citi un ir de caractere ntr-un vector de caractere str. Fie n
numrul de caractere citite. Vom compara literele din prima jumtate a cuvntului cu
cele din a doua jumtate, utiliznd dou variabile, una ce crete de la zero la (n - 1) /
2 , iar alta ce scade de la (n 1). Vom iniializa cele dou variabile n instruciunea for
cu operatorul ,. Pentru a calcula lungimea unui ir de caractere vom utilize funcia
strlen() cu prototipul
int strlen(char[]);
din biblioteca <cstring> . Programul este urmtorul:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char str[80];
int cntup, cntdn, n, nst;
bool pn = true;
cout << "introduceti un cuvant " << endl;
cin >> str;
n = strlen(str);
nst = (n - 1) / 2;
// initializarea a doua variabile cu operatorul ,
for(cntup = 0, cntdn = n - 1; cntup <= nst; cntup++, cntdn--)
if(str[cntup] != str[cntdn])
pn = false;
if(pn)
46
cout << str << " este palindrom" << endl;
else
cout << str << " nu este palindrom" << endl;
return 0;
}
Rezultatul rulrii programului este prezentat mai jos.
47
3 Funcii
Limbajele de programare au funcii predefinite ce corespund funciile matematice
uzuale : sin, cos, exp, log, log10, etc.
In plus, limbajele de programare permit definirea de funcii care s realizeze anumite
calcule. Atunci cnd un grup de instruciuni se utilizeaz n mai multe locuri din
program, aceste instruciuni se plaseaz ntr-o funcie care este apelat unde este
necesar. In acest fel programele mari pot fi formate din module. Descompunerea
unui program n module are avantaje. Funciile pot fi grupate n biblioteci i utilizate
n diverse programe. Funciile pot fi testate separat i programele sunt mai clare.
Un program const din una sau mai multe funcii. Una dintre funcii are numele main
i execuia programului ncepe cu aceast funcie.
3.1 Funcii standard
Limbajul are multe funcii standard, matematice, de prelucrare a caracterelor, etc. Mai
nainte am prezentat cele mai utile funcii matematice. Vom prezenta acum cteva
funcii de prelucrare a caracterelor. Funcia strlen() cu prototipul
int strlen(char x[]);
d lungimea unui ir de caractere. Prototipul acestei funcii se afl n biblioteca
<cstdlib>. Funcia isdigit() cu prototipul
int isdigit(int c);
are o valoare diferit de zero dac c este o cifr, 0, 1, , 9 i zero n caz contrar.
Funcia isalpha() cu prototipul
int isalpha(int c);
are o valoare diferit de zero dac c este o liter, a, , z, A, Z i zero n caz
contrar. Prototipurile acestor funcii se afl n biblioteca header <cctype>.
Vom exemplifica utilizarea acestor funcii cu un program ce citete un ir de caractere
de la tastatur i numr cifrele din ir. Programul este urmtorul
#include <cstdlib>
#include <iostream>
using namespace std;
int main()
{
char a[100];
cout << "introduceti un sir" << endl;
cin >> a;
int n = strlen(a);
int k = 0, i;
for(int i = 0; i < n; i++)
if(isdigit(a[i]))
k++;
cout << "in sir sunt " << k << " cifre" << endl;
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
48
Funciile strlen() i isdigit() au cte un parametru i calculeaz o valoare. Apelarea lor
se face scriind numele funciei urmat n paranteze de argumentul funciei ntr-o
expresie. Funcia strlen() este apelat n membrul drept al unei instruciuni de
atribuire, funcia isdigit() este apelat n expresia testat de instruciunea if. Apelarea
funciilor i transmiterea valorii calculate de funcie n punctual din program unde este
apelat este prezentat schematic mai jos.
3.2 Definirea funciilor
O funcie calculeaz o valoare pe baza valorilor argumentelor sale, furnizate de un
program care apeleaz funcia. Orice funcie are un nume i parametri sau argumente.
Definiia unei funcii este
tip numefuncie (lista de parametri)
{
corpul funciei
}
Prima linie conine :
tip este tipul valorii calculate de funcie (se mai numete tipul funciei),
numefuncie este numele funciei ales de programator,
lista de parametri (argumente ale funciei) are forma :
tip1 arg1, tip2 arg2, , tipn argn
unde tip1, tip2, , tipn reprezint tipurile parametrilor arg1, arg2, , argn.
Parametrii din definiia funciei se numesc parametri formali.
Corpul funciei este format dintr-o secven de instruciuni ntre acolade, { i }, ce
descriu calculele efectuate de funcie. Valoarea calculat de funcie este transmis n
punctul de apelare a funciei cu instruciunea return ce are forma
return expresie;
Tipul acestei expresii trebuie s fie acelai cu tipul funciei. Instruciunea return
termin totodat i execuia funciei.
Exemplu. S definim o funcie care s calculeze suma a dou numere reale de tip
double.
Numele funciei va fi suma, parametrii ei vor fi dou variabile de tip double, x i y,
valoarea calculat de funcie va fi de tip double. In corpul funciei vom defini o
variabil de tip double, z, n care vom calcula rezultatul.
49
/* functie ce calculeaza suma a doua numere reale */
double suma (double x, double y)
{
double z ;
z = x + y ;
return z ;
}
Parametri x i y din definiia funciei suma sunt parametri de intrare, ei conin valori
ce sunt utilizate de funcie n calcule.
Variabilele definite ntr-o funcie exist doar n timpul execuiei funciei. Din aceast
cauz, ele se numesc variabile locale. Variabila z din funcia de mai sus este local.
Variabilele nu pot fi utilizate n afara funciei.
Apelarea unei funcii se face scriind numele funciei urmat de lista de parametrii
inclus n paranteze, ca termen ntr-o expresie. Parametrii din list sunt separai
de virgule. Parametrii de apelare a funciei se numesc parametri actuali sau
argumente. Parametrii de intrare actuali ai unei funcii pot fi orice constante, variabile
sau expresii.
Funciile sunt recursive, adic o funcie se poate apela pe ea nsi.
Vom utiliza funcia definit mai sus, n cadrul funciei main pentru calculul sumei a
dou numere reale, citite de la tastatur. Vom defini dou variabile de tip double, a i
b, ce vor conine valorile citite de la tastatur i o variabil c de tip double, ce va
conine rezultatul. a, b i c sunt variabile locale ale funciei main.
int main()
{
double a, b ;
cout << " a = " ; cin >> a ;
cout << " b = " ; cin >> b ;
double c ;
c = suma(a, b) ;
cout << " a + b = " << c << endl ;
return 0 ;
}
Rezultatul rulrii programului este sel de mai jos.
Funcia suma este utilizat n membrul drept al unei instruciuni de atribuire, deoarece
calculeaz o valoare asociat numelui. Ea este apelat n instruciunea
c = suma(a, b);
Reamintim c parametrii x i y din definiia funciei sunt parametrii de intrare. In
consecin, putem apela funcia suma cu parametrii orice constante, variabile sau
expresii, de exemplu
c = suma(1.73, -2.22);
50
sau
c = suma(1.73 * 2.5 + a, a b + 2);
Menionm c numele parametrilor actuali (din instruciunea de apelare a funciei) pot
fi diferite de cele ale parametrilor formali din definiia funciei.
Pasarea parametrilor ctre funcii se face prin intermediul unei stive. La apelarea
funciei, se aloc spaiu ntr-o stiv pentru parametrii funciei i pentru variabilele
locale ale funciei. In spaiul alocat pentru parametrii funciei se pun valorile acestor
parametri. Funcia poate utiliza valorile acestor parametrii n calcule. Valoarea
calculat de funcie se transmite n punctul de apelare de ctre instruciunea return.
Menionm c este posibil ca o funcie s nu calculeze nici o valoare. In acest caz
tipul ei este void, iar instruciunea return are forma
return;
Menionm c, n general, o funcie poate calcula mai multe valori care s fie
transmise n programul apelant, asociate unor parametri. In acest caz o parte din
parametrii funciei sunt parametri de intrare i ei conin valorile ce vor fi prelucrate de
funcie, ceilali parametri vor conine valorile calculate de funcie ,ce sunt transmise n
programul apelant i vor fi numii parametri de ieire. Modul de definire a
parametrilor de ieire va fi artat ulterior. Parametrii actuali de ieire sunt
variabile.
3.3 Prototipuri de funcii
La ntlnirea unei instruciuni n care se apeleaz o funcie, compilatorul trebuie s
cunoasc prototipul funciei adic numrul i tipurile parametrilor i tipul rezultatului
(tipul valorii calculate de funcie). Compilatorul utilizeaz numrul i tipurile
parametrilor pentru a verifica dac funcia este apelat corect. Tipul rezultatului este
utilizat pentru a converti rezultatul funciei dac funcia este un termen al unei
expresii. In cazul n care funcia este definit n program nainte a fi apelat,
compilatorul cunoate informaiile necesare din linia de definiie a funciei. Acesta
este cazul programului de mai sus. Este posibil ca ntr-un program s definim funcii
i dup ce ele au fost utilizate. In acest caz compilatorul nu cunoate prototipul
funciei n momentul apelrii ei i este obligatoriu s definim prototipul funciei
nainte de a o utiliza, astfel nct compilatorul poate verifica dac apelarea funciei
este corect (tipul i numrul parametrilor, etc.).. Prototipul unei funcii are
urmtoarea definiie
tip nume(lista de parametri);
In prototip putem s identificm doar tipurile parametrilor.
In cazul funciei suma definit anterior prototipul este
double suma(double, double);
sau
double suma(double x, double y) ;
De remarcat c prototipul unei funcii este chiar linia de definiiei a funciei
urmat de caracterul ;.
Prototipurile funciilor matematice standard sunt definite n bibliotecile
standard. De exemplu, biblioteca <iostream> conine prototipurile funciilor intrare /
ieire pentru fiierele standard ale sistemului (tastatura i monitorul), biblioteca
<cmath> conine prototipurile funciilor matematice, etc. Aceste biblioteci sunt
semnalate compilatorului cu directiva # include.
Exemplu. Vom defini o funcia max() care s calculeze maximul a dou numere de tip
double. Definiia funcie max va fi scris dup definiia funciei main(). In acest caz
trebuie s definim prototipul funciei max() nainte de definiia funciei main().
51
#include <iostream>
using namespace std;
// prototipul functiei max(). Functia max() este apelata
// in functia main(), dar este definite ulterior
double max (double, double) ;
// definitia functiei main()
int main()
{
double a, b, c ;
cout << " a = " ; cin >> a ;
cout << " b = " ; cin >> b ;
c = max(a, b) ;
cout << " max(a, b) = " << c << endl ;
return 0 ;
}
// definitia functiei max()
double max (double x, double y)
{
if( x > y)
return x ;
else
return y ;
}
Rezultatul rulrii programului este cel de mai jos.
De remarcat c, o funcie, poate avea mai multe instruciuni return.
3.4 Compilarea separat a funciilor
Funciile definite de programator pot fi scrise n fiiere separate. Aceste fiiere vor fi
compilate separat. Avantajul compilrii separate a funciilor este acela c ele pot fi
testate separat, nainte de a fi utilizate. Funciile definite n fiiere separate sunt
semnalate compilatorului, n fiierele n care sunt utilizate cu directive include, la fel
ca i funciile standard. Forma directivei include este
#include nume fisier
Numele fiierului este scris aici ntre ghilimele. De regul, aceste fiiere au extensia h.
Programul anterior este rescris cu funcia max() definit n fiierul max.h. Cele dou
fiiere sunt prezentate mai jos.
52
Fiierul main.cpp
#include <iostream>
using namespace std;
#include "max.h"
int main(int argc, char *argv[])
{
double a, b, c ;
cout << " a = " ; cin >> a ;
cout << " b = " ; cin >> b ;
c = max(a, b) ;
cout << " max(a, b) = " << c << endl ;
return 0;
}
Fiierul max.h
// definitia functiei max()
double max (double x, double y)
{
if( x > y)
return x ;
else
return y ;
}
3.5 Funcii cu parametri tablouri
Funciile pot avea ca parametri tablouri, vectori, matrice, etc. Pentru a defini un
parametru formal ca vector, scriem numele vectorului urmat de paranteze drepte. La
apelarea unei funcii cu parametri vectori, scriem numele vectorului, fr paranteze
sau indici, ca parametru actual. Prin definiie, atunci cnd un parametru este un
tablou, n stiv se pune adresa tabloului. In consecin, parametrul formal tablou este
un parametru de ieire. Dac elementele tabloului sunt modificate n funcie,
modificarea apare i n programul ce a apelat funcia.
Exemplu. Vom scrie o funcie care s calculeze suma componentelor unui vector a cu
elemente numere reale de tip float. Parametrii funciei vor fi vectorul a i dimensiunea
sa. Valoarea calculat va fi ataat numelui funciei. Vom presupune c, la apelarea
funciei elementele vectorului sunt iniializate. Dup cum am spus mai sus, parametrul
formal vector are forma
float a[]
Definiia funciei va fi precedat de un comentariu ce descrie parametrii funciei, (de
intrare, de ieire), condiii asupra parametrilor de intrare, valoarea calculat de funcie,
etc.
Definiia funciei este urmtoarea
/* funcie ce calculeaza suma componentelor unui vector
float suma(float a[], int n);
Parametri de intrare
53
a vector
n dimensiunea vectorului a
Iesire
suma suma componentelor vectorului a
Preconditie :
elementele vectorului a sunt initializate
*/
float suma(float a[], int n)
{
int i;
float s = 0;
// calculeaza suma componentelor
for (i = 0; i < n; i = i++)
s = s + a[i];
return s;
}
O funcie, odat scris, trebuie testat. Un program simplu ce testeaz funcia de mai
sus este urmtorul.
/* testarea functiei suma */
int main()
{
float x[5] = {11.3, -2.67, 0.34, -2.5, 14};
float z;
// calculeaza suma componentelor
z = suma(x, 5);
// scrie componentele vectorului
cout << suma componentelor vectorului << endl;
for(i = 0, i < 5; i++)
cout << x[i] << \t;
cout << endl;
// scrie rezultatul
cout << este << z << endl;
return 0;
}
Funcia este apelat cu instruciunea
z = suma(x, 5);
Dup cum am spus mai sus, cnd un parametru al unei funcii este tablou, la apelarea
funciei scriem doar numele tabloului, fr indici sau paranteze drepte.
Componentele vectorului sunt afiate pe ecran separate de caracterul tab pe un rnd
iar rezultatul pe rndul urmtor. In exemplul anterior definiia funciei este scris
nainte de utilizarea ei n funcia main. Reamintim c, este posibil de a scrie definiia
unei funcii dup funcia main(). In acest caz, nainte de definiia funciei main()
trebuie s scriem prototipul funciei, cum s-a artat mai sus.
Exemplu. Cutarea binar ntr-o list ordonat cresctor. Fie un vector x cu n
elemente reale ordonate cresctor. Vrem s testm dac valoarea z se afl printre
componentele vectorului. Fie indicii ls i ld domeniului de cutare n vector. Iniial ls
54
= 0 i ld =n-1. Metoda cutrii binare const n testarea elementului de la mijloc al
vectorului cu indicele i=(ls+ld)/2 i restrngerea domeniului de cutare dac valoarea
z nu a fost gsit. Domeniul de cutare este restrns astfel:
dac x[i] < z atunci ls = i + 1
dac x[i] > z atunci ld = i 1
La fel ca la funcia precedent, definiia funciei este precedat de un comentariu ce
descie funcia, parametrii, condiiile asupra parametrilor, etc.
Funcia ce implementeaz acest algoritm este urmtoarea
/*
Cautarea binara
int find (double x[], int n, double z)
Parametri de intrare :
x - vector cu elemente sortate crescator
n - dimensiunea lui x
z - valoarea cautata
find = indicele elementului z in lista daca exista,
= -1 daca z nu exista in lista.
Preconditie :
x[0] <= x[1] <= ... <= x[n - 1]
*/
int find (double x[], int n, double z)
{
int ls, ld, i;
ls = 0;
ld = n - 1;
while(ls <= ld)
{
i = (ls + ld) / 2;
if(x[i] == z)
return i;
if(x[i] < z)
ls = i +1;
else
ld = i - 1;
}
return -1;
}
Un program de testare a funciei este urmtorul. Reamintim c, la apelarea funciei,
parametrul vector este scris ca numele tabloului, fr indici sau paranteze drepte.
int main()
{
double a[6] = {-2.35, 1.77, 3.14, 4.2, 5.12, 7.09};
double z;
int k;
z = 4.2;
55
k = find(a, 6, z);
if(k < 6)
cout << "elementul " << z << " are rangul " << k << endl;
else
cout << "elementul " << z << " nu este in lista" << endl;
return 0;
}
Tabela de mai jos prezint iteraiile algoritmului pentru z = 4.2.
iteraia ls ld i x[i]
1 0 5 2 3.14
2 3 5 4 5.12
3 3 3 3 4.2
Rezultatul rulrii programului este cel de mai jos.
Reamintim c primul element din vector are indicele zero.
Vom ncheia acest paragraf cu un program ce definete funcii pentru lucrul cu
matrice:
funcie ce citete o matrice de la tastatur,
o funcie ce scrie elementele unei matrice pe ecran,
o funcie ce calculeaz suma a dou matrice.
Matricele pot avea oricte linii i de coloane, ce vor fi prescrise n program cu dou
directive define. Fiecare funcie este precedat de un comentariu ce descrie parametrii
i operaia realizat de funcie.
#include <iostream>
#include <iomanip>
# define NLIN 2
# define NCOL 2
using namespace std;
/*
funcie ce citeste elementele unei matrice
void rdmat(double a[NLIN][NCOL])
Parametrii :
NLIN numarul de linii
NCOL numarul de coloane
Paramertii de iesire:
a matrice cu NLIN linii si NCOL coloane
Elementele matricei se introduc pe linii.
*/
56
void rdmat(double a[NLIN][NCOL])
{
int i, j;
for(i = 0; i < NLIN; i++)
for(j = 0; j < NCOL; j++)
cin >> a[i][j];
return;
}
/*
functie ce afisaza elementele unei matrice pe linii
Parametrii de intrare:
NLIN numarul de linii
NCOL numarul de coloane
a matrice cu NLIN linii si NCOL coloane
*/
void wrmat(double a[NLIN][NCOL])
{
int i, j;
for(i = 0; i < NLIN; i++){
for(j = 0; j < NCOL; j++)
cout << setw(6) << a[i][j] << " ";
cout << endl;
}
return;
}
/*
functie ce aduna doua matrice cu elemente tip double
Parametrii de intrare:
a matrice de intrare cu NLIN linii i NCOL coloane
b matrice de intrare cu NLIN linii i NCOL coloane
Parametrii de iesire
c matricea suma cu NLIN linii i NCOL coloane
Preconditie
Matricele a si b sunt initializate.
*/
void addmat(double a[NLIN][NCOL], double b[NLIN][NCOL],
double c[NLIN][NCOL])
{
int i, j;
for(i = 0; i < NLIN; i++)
for(j = 0; j < NCOL; j++)
c[i][j] = a[i][j] + b[i][j];
return;
}
/*
program pentru testarea functiilor
*/
57
int main(int argc, char *argv[])
{
double x[NLIN][NCOL], y[NLIN][NCOL], z[NLIN][NCOL];
// citeste elementele matricelor x si y
cout << "introduceti prima matrice pe linii" << endl;
rdmat(x);
cout << "introduceti a doua matrice pe linii" << endl;
rdmat(y);
addmat(x, y, z);
cout << "matricea suma" << endl;
wrmat(z);
return 0;
}
Rezultatul rulrii programului este prezentat mai jos.
3.6 Suprancrcarea funciilor
Intr-un program putem defini mai multe funcii cu acelai nume dar cu
parametri diferii sau cu un numr de parametri diferit (prototipuri diferite).
Acest lucru se numete suprancrcarea funciilor.
Vom exemplifica suprancrcarea funciilor definind dou funcii cu acelai nume,
min, ce calculeaz minimul a dou, respective trei numere ntregi. Variabilele ce
conin aceti ntregi vor fi parametri de intrare pentru funcii.
# include <iostream>
using namespace std;
// calculul minimului a doua numere intregi
int min(int x, int y)
{
return (x < y? x: y);
}
// calculul minimului a trei numere intregi
int min(int a, int b, int c)
{
int x = a < b? a: b;
if(x < c)
return x;
else
return c;
58
}
int main()
{
int a = 29, b = 47, c = -32;
cout << "min " << a << "," << b << " este " << min(a, b) << endl;
cout << "min " << a << "," << b << ", " << c << " este "
<< min(a, b, c) << endl;
return 0;
}
Rezultatul programului este cel de mai jos.
Vom exemplifica utilizarea prototipurilor definind cele dou funcii cu numele min ce
calculeaz minimul a dou, respectiv trei numere reale dup funcia main. Vom
declara mai nti prototipurile celor dou funcii i vom defini funcia main.
# include <iostream>
using namespace std;
// defineste prototipurile celor doua functii min()
double min(double, double);
double min(double, double, double);
// functia main()
int main()
{
double a = 68.29, b = -77.3, c = 32.5;
cout << "min " << a << "," << b << " este " << min(a, b) << endl;
cout << "min " << a << "," << b << ", " << c << " este "
<< min(a, b, c) << endl;
return 0;
}
Vom defini acum cele dou funcii.
// calculul minimului a doua numere reale
double min(double x, double y)
{
return (x < y? x: y);
}
// calculul minimului a trei numere reale
59
double min(double a, double b, double c)
{
double x = a < b? a: b;
return (x < c? x : c);
}
Menionm c prototipurile celor dou funcii puteau fi scrise respectiv
double min(double a, double b);
double min(double a, double b, double c);
3.7 Transmiterea parametrilor ctre funcii
La apelarea unei funcii, parametrii actuali i variabilele locale ale funciei sunt
memorate ntr-o stiv. Exist dou moduri de a transmite parametrii ctre funcii: prin
valoare i prin referin (adres). In cazul transmiterii unui parametru prin valoare, n
stiv se pune chiar valoarea parametrului, n cazul transmiterii prin adres n stiv se
pune adresa parametrului.
Cazul parametrilor transmii prin valoare. Dac n corpul funciei modificm
aceti parametri, valoarea lor se modific doar n stiv i nu n programul
apelant. In consecin, parametrii transmii prin valoare sunt parametri de
intrare (nu pot fi parametri de ieire ai funciei),
Cazul parametrilor transmii prin adres. Dac n corpul funciei modificm
aceti parametri, valoarea lor se modific n programul apelant (n stiv este
adresa acestor parametri). In consecin, pentru ca un parametru al unei
funcii s fie parametru de ieire, el trebuie transmis prin adres
Vom rezuma proprietile celor dou moduri de transmitere a parametrilor ctre
funcii, n tabelul de mai jos.
In definiia funciei
Parametri transmii prin valoare Parametri transmii prin adres
Sunt parametri de intrare pentru funcie Sunt parametri de ieire pentru funcie
Parametrul este o copie a argumentului Parametrul este adresa argumentului
Funcia nu poate modifica parametrul Funcia poate modifica parametrul
La apelarea funciei
Parametri transmii prin valoare Parametri transmii prin adres
Argumentul este o constant, variabil
sau expresie
Argumentul este o variabil
In general o funcie poate calcula mai multe valori. Una dintre valori este transmis la
punctul de apelare de instruciunea return. Celelalte valori vor fi asociate unor
parametri de ieire, care vor fi obigatoriu transmii prin adres.
Definirea parametrilor tip referin
Exist dou moduri de a defini parametri transmii prin adres:
utilizarea parametrilor tip referin,
utilizare parametrilor tip pointer.
60
Referinele i variabilele tip pointer vor fi prezentate pe larg n capitolul urmtor.
Vom prezenta acum doar parametrii tip referin.
Fie un parametru de un tip T al unei funcii. Referina la un astfel de parametru are
tipul T&.
De exemplu, parametrul formal int x, este transmis funciei prin valoare, parametrul
formal int& x este transmis prin adres.
Dac un parametru al funciei este tip referin, la apelarea funciei se va pune n stiv
adresa acestui parametru, i atunci cnd acest parametru este modificat n corpul
funciei el este modificat direct n programul apelant (este parametru de ieire).
Pentru a vedea care este diferena ntre cele dou moduri de transmitere a parametrilor
considerm o funciei care modific valoarile parametrilor si. Primul parametru va fi
transmis prin valoare iar cellalt prin adres.
// functie ce modifica valorile parametrilor
// primul parametru este transmis prin valoare, al doilea prin adresa
# include <iostream>
using namespace std;
void f(int x, int& y)
{
x = 52;
y = 65;
return;
}
int main()
{
int a = 20, b = 30;
cout << a = << a << , b = << b << endl;
f(a, b);
cout << a = << a << , b = << b << endl;
f(2*a + 3, b);
cout << a = << a << , b = << b << endl;
return 0;
}
Rezultate afiate sunt cele de mai jos.
Menionm c primul parametru se modific doar n stiv i nu n programul apelant,
doarece nu este transmis prin referin.
Valorile variabilelor a i b nainte de prima apelare a funciei sunt
61
La prima apelare a funciei stiva este
Dup prima execuie a funciei valorile variabilelor a i b n program sunt
Menionm c valoarea variabilei a nu se modific, deoarece primul parametru al
funciei este transmis prin valoare.
Exemplu. S construim o funciei care s permute valoarea a dou variabile de tip
ntreg. Funcia va avea doi parametri care la apelare au valorile variabilelor ce trebuie
permutate, iar la ieirea din funcie trebuie s aibe valorile permutate.
/* functie ce permute valoarea a doua variabile */
void perm(int& a, int& b)
{
int c;
c = a;
a = b;
b = c;
return;
}
O funcie main() ce testeaz funcia scris este urmtoarea.
int main()
{
int x = 7, y = 12;
cout << valorile initiale x = << x << y = << y << endl;
perm(x, y);
cout << valorile permutate x = << x << y = << y << endl;
}
Testarea acestei funcii produce rezultatele de mai jos.
In stiv se pun adresele variabilor x i y deoarece parametrii funciei sunt de tip
referin. Menionm c apelarea funciei se face utiliznd pentru parametrii referin
nite variabile din programul apelant (nu constante sau expresii), n cazul nostru
perm(x, y)
Vom recapitula acum diferenele ntre parametrii pasai prin valoare i cei pasai prin
adres (referin).
62
un parametru transmis prin valoare este un parametru de intrare. Valoarea lui
actual este rezultatul evalurii unei constante, variabile sau expresii n
programul apelant.
un parametru tip referin este un parametru de ieire. Argumentul transmis
este o variabil din programul apelant.
Menionm c n cazul n care un parametru este un tablou, n stiv se pune
adresa primului element al tabloului. In consecin, parametri formali tablouri
pot fi parametri de ieire, modificarea unui element al tabloului n funcie
produce modificarea lui n programul ce a apelat funcia.
Exemplu. Vom defini o funcie ce calculeaz suma a doi vectori x i y de numere
reale de dimensiune n. Vectorul sum va fi z. Tipul funciei este void deoarece toate
valorile calculate de funcie sunt asociate unor parametrii de ieire.
/*
Calculul sumei a doi vectori
void sumvect(double x[], double y[], double z[], int n) ;
Parametrii de intrare :
x vector
y vector
n dimensiunea vectorilor x, y, z
Parametrii de iesire :
z vector, z = x + y
Preconditii :
Parametrii de intrare sunt initializati
*/
void sumvect(double x[], double y[], double z[], int n)
{
int i;
for(i = 0; i < n; i++)
z[i] = x[i] + y[i];
return;
}
Un program ce testeaz funcia de mai sus este urmtorul
int main()
{
double a[3] = {1.29, -3.15, 6.92}, b[3] = {0.73, 5.25, -3.21};
double c[3];
sumvect(a, b, c, 3);
cout << "vectorul suma" << endl;
for(int i = 0; i < 3; i++)
cout << c[i] << " ";
cout << endl;
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
63
Vom ncheia acest paragraf definind o funcie care s calculeze media i dispersia
unui ir de numere n
x x x , ,
2 1 . Valoarea medie a elementelor irului este

n
i
i
x
n
m
1
1
iar dispersia

n
i
i
m x
n
d
1
2
) (
1
1
Tipul funciei va fi void. Media i dispersia vor fi asociate unor parametri de ieire ai
funciei. Prototipul funciei va fi
void md(float x[], int n, float& m, float& d);
unde x este vectorul de numere de dimensiune n pentru care calculm media m i
dispersia d. Deoarece valorile calculate, m i d sunt asociate unor parametri, funcia
are tipul void.
#include <iostream>
using namespace std;
/*
Calculul mediei si dispersiei componentelor unui vector
void md(float x[], int n, float& m, float& d);
Parametri de intrare
x vector
n dimensiunea vectorului x
Parametri de iesire
m media componentelor lui x
d dispersia componentelor lui x
Preconditii
Parametrii de intrare sunt initializati
*/
void md(float x[], int n, float& m, float& d)
{
float s = 0;
int i;
// calculeaza media
for(i = 0; i < n; i++)
s = s + x[i];
m = s / n;
// calculeaza dispersia
d = 0;
for(i = 0; i < n; i++)
d = d + (x[i] m) * (x[i] m);
d = d / (n 1);
return;
64
}
Un program ce testeaz funcia de mai sus este urmtorul.
int main()
{
float a[4] = {1.2e-1, -2.34, 1.5, 3.33};
float media, dispersia;
md(a, 4, media, dispersia);
cout << media = << media << dispersia = << dispersia << endl;
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
3.8 Recursivitatea
Funciile limbajelor C i C++ sunt recursive, adic o funcie se poate apela pe ea
nsi. Vom exemplifica acest lucru cu o funcie care s calculeze valoarea n! n
variant recursiv i nerecursiv.
Varianta nerecursiv Varianta recursiv

n
i
i n
1
!

'

>

1 )! 1 ( *
1 1
!
n n n
n
n
// calculul factorialului
int fact(int n)
{
int s = 1;
for(int i = 1; i <= n; ++n)
s = s * i;
return i;
}
// calculul factorialului
int fact(int n)
{
int s;
if(n = = 1)
s = 1;
else
s = n * fact(n 1);
return s;
}
Vom prezenta stiva la apelarea variantei recursive pentru n = 3. Reamintim c
parametrul n i variabila local s sunt memorai n stiv. Dup apelul
fact(3)
stiva este
n=3 s=?
Deoarece n este diferit de unu, se execut instruciunea
s = n * fact(n 1)
adic se apeleaz nc o dat funcia, fact(2). Stiva de
65
n=3 s=? n=2 s=?
Se apeleaz nc o dat funcia, fact(1), i stiva devine
n=3 s=? n=2 s=? N=1 S=1
Dup aceast ultim apelare se ajunge la instruciunea return, dup care variabilele
corespunznd ultimei apelri a funciei se sterg din stiv. Stiva devine
n=3 s=? n=2 s=2
Din nou se ajunge la instruciunea return, variabilele corespunznd acestei apelri se
strerg din stiv
n=3 s=6

Dup care se obine rezultatul final, valoarea 6.
3.9 Funcii generice
In limbajul C++ putem s definim funcii generice n care putem defini tipuri generale
pentru parametri i valoarea returnat de funcie. Definirea unei funcii generice se
face cu instruciunea
template <typename identificator, typename identificator >
declaraie de funcie
S definim de exemplu o funcie generic pentru calculul maximului a dou variabile
/* functie generica ce calculeaza maximul a doua variabile */
template <typename T>
T maxval(T a, T b)
{
return (a > b ? a : b);
}
Apelarea unei funcii generice se face astfel
nume_funcie <tip, tip, >(parametri);
De exemplu, putem calcula maximul a dou numere ntregi sau reale astfel.
int main()
{
// maximul a doua numere intregi
int a = 15, x = 20, c;
c = maxval<int>(a, x);
cout << maximul dintre << a << si << x << este << c <<
endl;
// maximul a doua numere reale
float fa = 3.43, fb = -9.3;
cout << maximul dintre << fa << si << fb << este
<< maxval<float>(fa, fb) << endl;
return;
}
66
Rezultatul rulrii programului este cel de mai jos.
Exerciiu. S se defineasc o clas generic ce permut dou variabile de acelai tip.
3.10Funcii C standard de manipulare a caracterelor
Funciile ce manipuleaz caractere tip ASCII sunt un exemplu de funcii standard ale
limbajului C. Prototipurile lor se afl n biblioteca <cctype>.
Funcie Descriere
int isalnum (int c); Test dac un caracter este alfanumeric
int isalpha (int c); Test dac un caracter este alfabetic
int isdigit (int c); Test dac un caracter este o cifr zecimal
int isxdigit(int c); Test dac un caracter este o cifr hexazecimal
int islower (int c); Test dac un caracter este liter mic
int isupper (int c); Test dac un caracter este liter mare
int isspace (int c); Test dac un caracter este spaiu ( , \n, \t)
Funciile au un rezultat diferit de zero dac argumentul este conform descrierii
funciei. Urmtoarele funcii convertesc literele mari n litere mici i invers.
Funcie Descriere
int tolower(int c); convertete n litere mici
int toupper(int c); convertete n litere mari
Exemple de utilizare a acestor funcii sunt prezentate n tabelul de mai jos.
tolower(A) a
tolower (a) a
tolower (*) *
O funcie util la prelucrarea irurilor este strlen() care d lungimea unui ir de
caractere, fr caracterul \0 terminal. Prototipul acestei funcii este
int strlen(char[]);
Prototipul ei se gsete n biblioteca <cstring>.
Funcia
int strcmp(const char s1[], const char s2[]);
compar cele dou iruri, caracter cu caracter, pn la primul caracter diferit.
Rezultatul este un numr < 0, = 0, sau > 0, dup cum sunt caracterele diferite
comparate. Exemple de utilizare a funciei strcmp sunt prezentate n tabelul de mai jos
strcmp(abc, bcd) < 0 "abc" < "bcd" deoarece a < b
strcmp(xyz, xyz) = 0 irurile sunt egale
strcmp(abcd, abc) > 0 irul abcd este mai lung
67
Vom scrie o funcie care s numere literele mici, literele mari i cifrele dintr-un ir
citit de la tastatur. Programul este urmtorul.
# include <iostream>
# include <cstring>
# include <cctype>
using namespace std;
// calculul numarului de litere mici, litere mari si cifre dintr-un sir
int main()
{
char x[50];
int i, n, cnt;
cout << introduceti un sir;
cin >> x;
// calculeaza lungimea sirului
n = strlen(x);
// numara literele mici din sir
cnt = 0;
for(i = 0; i < n; i++)
if(islower(x[i]))
cnt = cnt + 1;
cout << sirul contine : << cnt << litere mici << endl;
// numara literele mari din sir
cnt = 0;
for(i = 0; i < n; i++)
if(isupper(x[i]))
cnt++;
cout << sirul contine : << cnt << litere mari << endl;
// numara cifrele din sir
cnt = 0;
for(i = 0; i < n; i++)
if(isdigit(x[i]))
cnt = cnt + 1;
cout << sirul contine : << cnt << cifre << endl;
return 0;
}
Rezultatul rulrii programului este urmtorul.
Exerciiu. S se scrie un program care s converteasc literele mici ale unui ir citit de
la tastatur n litere mari.
Alte funcii ce prelucreaz iruri de caractere sunt
int atoi(char s[]);
68
double atof(char s[]);
care convertesc un ir de caractere ntr-un numr ntreg i respectiv real. Prototipurile
acestor funcii se afl n biblioteca <cstdlib>. Un exemplu de utilizare a acestor
funcii poate fi urmtorul. Fie dou iruri ce conin numere. Vom converti aceste
iruri n numere i vom efectua produsul lor.
# include <cstdlib>
# include <iostream>
using namespace std;
int main()
{
char s1[] = -123;
char s2[] = 1.22e-1;
int x;
double y, z;
// scrie sirurile
cout << sirul s1 : << s1 << endl
<< sirul s2 : << s2 << endl;
// converteste sirurile in numere
x = atoi(s1);
y = atof(s2);
z = x * y;
// scrie numerele si produsul lor
cout << x = << x << y = << y << endl;
cout << x * y = << z << endl;
return 0 ;
}
Rezultatul rulrii programului este cel de mai jos.
69
4 Pointeri i referine
Compilatorul aloc oricrei variabile definite n program o zon de memorie egal cu
numrul de octei corespunznd tipului variabilei. In cazul unui tablou se aloc
memorie fiecrui component al tabloului. Fie de exemplu instruciunea
int a, b, x[2], c;
Compilatorul aloc zone de memorie variabilelor ca mai jos
Compilatorul creaz o tabel cu numele variabilelor i adresele lor n memorie, de
exemplu
a 1000
b 1004
x 1008
c 1016
Menionm c unitatea central a calculatoarelor are un registru acumulator utilizat n
calcule. O instruciune de atribuire de forma
a = b ;
este tradus de compilator astfel : se ncarc n registrul acumulator valoarea de la
adresa variabilei b (n cazul nostru adresa 1004) i se memoreaz coninutul
acumulatorului la adresa variabilei a (n cazul nostru adresa 1000). O instruciune de
atribuire de forma
a = b + c;
este tradus de compilator astfel: se ncarc n registrul acumulator valoarea de la
adresa variabilei b (n cazul nostru adresa 1004) se adun la registru valoarea de la
adresa variabilei c (n cazul nostru adresa 1016), i se memoreaz coninutul
registrului acumulator la adresa variabilei a (n cazul nostru adresa 1000). In
programul generat de compilator nu exist nume de variabile, ci doar adrese.
Limbajele C i C++ permit definirea unor variabile ce conin adrese ale altor variabile.
Acestea au tipul pointer i referin. Dup cum vom vedea, aceste variabile se
utilizeaz la transmiterea parametrilor funciilor prin adres; parametrii transmii prin
adres pot fi parametri de ieire ai funciilor. Pointerii sunt utilizai i la prelucrarea
tablourilor.
4.1 Pointeri
Un pointer este o variabil ce conine adresa unei alte variabile. De exemplu, dac n
este o variabil de tip int, ce are valoarea 3, iar pn este o variabil de tipul pointer la
int, ce conine adresa lui n, putem reprezenta cele dou variabile astfel
70
4.1.1 Declararea variabilelor tip pointerilor
O variabil de tip pointer se definete cu instruciunea
tip * nume;
De exemplu
int * pn;
definete o variabil tip pointer la int ce poate conine adresa unei variabile de tip int.
Instruciunea
int u, *pv;
definete o variabil u de tip int i o variabil pv de tip pointer la int.
Pentru a calcula adresa unei variabile se utilizeaz operatorul &. Dac x este o
variabil oarecare, expresia &x este adresa lui x. Variabilele tip pointer pot fi
iniializate doar cu adrese. De exemplu, putem scrie
int n;
int * pn; // pn este de tipul pointer la int
pn = &n; // initializeaza pn cu adresa lui n
Variabilele de tip pointer pot fi iniializate la declararea lor. Putem scrie de exemplu
int n, *pn = &n;
Pentru a obine valoarea variabilei indicate de un pointer se utilizeaz operatorul *
(numit i operator de adresare indirect).
Fie de exemplu instruciunile
int k, n= 14;
int * pn, *pk;
Imaginea memoriei este urmtoarea
Tabela cu adrese creat de compilator poate fi
k 2000
n 2004
pn 2008
pk 2012
Instruciunile
k = n;
i
pn = &n;
k = *pn;
sunt echivalente, k primete valoarea 14. (Variabila pn a fost iniializat n prealabil
cu adresa lui n). Imaginea memoriei dup execuia ultimelor dou instruciuni este
14 14 adresa lui n (2004)
k n pn pk
71
Reamintim modul de execuie al instruciunii
k = n;
valoarea de la adresa 2004 (adresa lui n) se memoreaz la adresa 2000 (adresa lui k).
Instruciunea
k = *pn ;
se execut astfel : valoarea de la adresa 2008 (adresa lui pn) este adresa operandului,
n cazul nostru 2004, vezi tabela de mai sus. Valoarea de la adresa 2004 se
memoreaz la adresa 2000 (adresa lui k).
Instruciunile
k = n;
i
pk = &k;
*pk = n;
sunt echivalente. In final, instruciunile
k = n;
i
pk = &k;
pn = &n;
*pk = *pn;
sunt echivalente;
Orice variabil tip pointer trebuie iniializat nainte de a fi utilizat. De
exemplu, urmtoarea secven de instruciuni nu este corect :
int *pn;
*pn = 5;
deoarece variabila pn nu a fost iniializat, ea nu conine adresa unei variabile de
tip int. O secven corect este
int *pn;
int x;
pn = &x;
*pn = 5;
In acest caz variabila pn a fost iniializat cu adresa unei variabile de tip ntreg.
Variabilele tip pointer pot fi utilizate n expresii aritmetice n locul variabilelor
aritmetice a cror adres o conin. De exemplu, secvena de instruciuni
int u, v, w;
u = 3;
v = 2 * (u + 5);
w = 2 * ( 3 + u + 5);
poate fi scris cu variabile tip pointer ca
int u, v, w;
int * pu;
u = 3;
pu = &u;
v = 2 * (*pu + 5);
w = 2 * (3 + *pu + 5)
Limbajul C nu are referine. In consecin, singurul mod de a declara parametri
de ieire ai unei funcii n limbajul C, este ca acetia s fie de tip pointer.
Exemplu. Vom scrie o funcie care s permute valorile a dou variabile ce vor fi
parametri de ieire ai funciei. Aceti parametri vor fi variabile tip pointer.
72
// functie ce permuta valorile a doua variabile
void perm(int* a, int* b)
{
int c;
c = *a;
*a = *b;
*b = c;
}
Utilizarea acestei funcii se face astfel :
int main()
{
int x = 3, y = -4;
// scrie variabilele inainte de permutare
cout << valori initiale : << x = << x << y = << y << endl;
perm(&x, &y);
// scrie variabilele dupa permutare
cout << valori permutate : << x = << x << y = << y << endl;
return 0;
}
Rularea programului produce rezultatele de mai jos.
La apelarea funciei perm(), stiva este urmtoarea:
In consecin, instruciunile din funcie
*a = *b;
*b = c;
modific valorile parametrilor (variabilele x i y) n funcia main.
Operatorii * i & sunt unari i asociativi la dreapta. Operatorii * i & au aceeai
prioritate cu operatorii ++ -- + - ! ~ sizeof (tip), vezi Anexa 2. Operatorii * i &
sunt inveri.
Exemplu. Fie instruciunile
int a, b;
a = 7;
Instruciunile
b = a;
i
b = *&a;
sunt echivalente.
73
Exemplu. In programul de mai jos definim dou variabile de tip int, a i b i dou
variabile de tip pointer la tipul int, pa i pb. Iniializm variabila pa cu adresa
variabilei a i afim adresa variabilei a i valoarea variabilei pa, ele trebuie s
coincid. Iniializm variabila pb cu adresa variabilei b i apoi dm o valoare
variabilei b. Afim variabila b i valoarea variabilei a crei adres este memorat n
pb. Cele dou valori trebuie s coincid.
#include <iostream>
using namespace std;
int main()
{
int a, b;
// definim variabile tip pointer
int *pa, *pb;
// initializam variabilele tip pointer
pa = &a;
pb = &b;
// se scrie adresa variabilei a si valoarea variabilei pa
cout << adresa variabilei a : << &a << , << pa << endl;
// se scrie valoarea variabilei b si valoarea variabilei cu adresa in pb
b = 15;
cout << valoarea variabilei b : << b << , << *pb << endl;
return 0 ;
}
Rezultatul programului este cel de mai jos.
Prima instruciune cout afiaz de dou ori aceeai adres. A doua instruciune cout
afiaz de dou ori aceeai valoare, 15.
Menionm c numele unui tablou este, prin definiie, un pointer constant la
primul element al tabloului. Fie de exemplu instruciunile
float x[7], * pf, z;
Un pointer la tabloul x are valoarea &x[0] sau x . Putem deci scrie
pf = &x[0];
sau, echivalent,
pf = x;
Dac scriem
pf = &x[3];
pf va conine adresa celui de al patrulea element al tabloului x. Instruciunile
z = x[3];
i
z = *pf;
sunt echivalente. Fie pc o variabil de tip pointer la char. Ea poate primi ca valoare
adresa unui vector de tip char (ir de caractere). Fie instruciunile
char *pc, y[7] ;
74
Putem scrie
pc = y ;
sau putem iniializa pe pc cu adresa unui ir constant
pc = abcd ;
Putem s definim de exemplu un pointer i s-l iniializm n aceeai instruciune
astfel
char * ax = aceg;
Legtura ntre tablouri i variabile tip pointer va fi prezentat pe larg n paragrafele
urmtoare.
Exemplu. S afim adresele elementelor unui vector de numere ntregi.
# include <iostream>
using namespace std;
int main()
{
int x[5];
for(int i = 0; i < 5; i++)
cout << x[ << i << ] adresa : << &x[i] << endl;
return 0;
}
Rezultatul programului este cel de mai jos. Adresele se modific cu 4 octei. De ce ?
4.2 Referine
O referin (sau adres) este un alt nume pentru o variabil. Fie T tipul unei
variabile i fie instruciunea ce definete o variabil
T nume_variabil;
Instruciunea de definire a unei referine este
T& nume_referin = nume_variabil
unde
nume_referin este numele variabilei referin (adres).
Variabila nume_variabil trebuie s fie declarat nainte i s aibe tipul T. De
exemplu instruciunile
int x;
int& rx = x;
declar pe rx ca fiind o referin a lui x (este obligatoriu ca variabila x de tip ntreg a
fost declarat anterior). Secvena anterioar se poate scrie
int x, &rx = x;
Numele x i rx sunt dou nume diferite pentru aceeai variabil. Ele au totdeauna
aceeai valoare. Pentru a verifica acest lucru vom considera urmtorul exemplu n
care scriem valoarea unei variabile i a referinei corespunztoare.
75
int main()
{
float f = 12.8;
float& fr = f;
cout << f = << f << fr = << fr << endl;
fr = fr + 25.3;
cout << f = << f << fr = << fr << endl;
f = f 3.23;
cout << f = << f << fr = << fr << endl;
return 0;
}
Rezultatele rulrii programului sunt cele de mai jos. Dup fiecare instruciune de
scriere, valorile f i fr vor fi aceleai.
Dup cum am vzut n paragraful anterior, dac un parametru formal al unei funcii
este de tip referin, el poate fi un parametru de ieire.
O referin nu este o variabil separat. Variabila i referina au aceeai adres.
Pentru a verifica acest lucru, n urmtorul program vom afia adresa unei variabile i a
referinei la aceast variabil. Vom defini o variabil de tip double dbl, dou variabile
tip referin dbref i dbref2 la dbl i o alt variabil tip referin dbref3 ce va fi
iniializat cu valoarea lui dbref.
int main()
{
double dbl = 23.44;
double& dbref = dbl;
double& dbref2 = dbl;
// scrie adresele variabilelor dbl si dblref
cout << "adresa lui dbl = " << &dbl << endl
<< "adresa lui dbref = " << &dbref << endl;
// scrie adresele variabilelor dbl si dbref2
cout << "adresa lui dbl = " << &dbl << endl
<< "adresa lui dbref2 = " << &dbref2 << endl;
double& dbref3 = dbref;
// scrie adresele variabilelor dbref si dbref3
cout << "adresa lui dbref = " << &dbref << endl
<< "adresa lui dbref3 = " << &dbref3 << endl;
return 0;
}
In toate cazurile se tiprete aceeai valoare dup cum se vede mai jos.
76
Vom ncheia acest paragraf definind o funcie care implementeaz cutarea binar.
Algoritmul a fost prezentat anterior. Funcia va avea ca parametri de intrare vectorul
x, cu elementele sortate cresctor, dimensiunea n a acestui vector i valoarea z care
este cutat printre elementele lui x. Indicele elementului n list este parametrul de
ieire k. Funcia va avea tipul void.
/*
Cautarea binara
void find(double x[], int n, double z, int& k);
Parametri de intrare :
x - vector cu elemente sortate crescator
n - dimensiunea lui x
z - valoarea cautata
Parametri de iesire :
k - indicele elementului z in lista.
Preconditie :
x[0] <= x[1] <= ... <= x[n - 1]
*/
void find(double x[], int n, double z, int& k)
{
int ls, ld;
ls = 0;
ld = n - 1;
while(ls <= ld)
{
k = (ls + ld) / 2;
if(x[k] == z)
return;
if(x[k] < z)
ls = k +1;
else
ld = k - 1;
}
k = n;
return;
}
Un program ce testeaz funcia este urmtorul
int main()
{
double a[6] = {-2.35, 1.77, 3.14, 4.2, 5.12, 7.09};
double z;
int k;
77
z = 3.14;
find(a, 6, z, k);
if(k < 6)
cout << "elementul " << z << " are rangul " << k << endl;
else
cout << "elementul " << z << " nu este in lista" << endl;
return 0;
}
Recapitulm n tabelul de mai jos prototipuri posibile pentru funcia find i modul de
apelare a funciei.
Prototip Apelare
int find(double x[], int n, double z); k = find(a, n, z);
void find(double x[], int n, double z, int& k) ; find(a, n, z, k);
4.3 Pointeri la funcii
O funcie are un punct de intrare care este linia ei de definiie. Acest punct de intrare
este o adres de memorie care poate fi atribuit unei variabile tip pointer i care poate
fi utilizat la apelarea funciei. In programul care apeleaz funcia trebuie s definim o
variabil pointer de tipul funciei respective. Considerm ablonul definiiei unei
funcii
Tip nume(lista de parametri);
O variabil de tip pointer la aceast funcie are definiia
Tip (*ident) (lista de parametri);
unde Tip i lista de parametri din variabila pointer corespund cu tip i lista de
parametri din ablonul definiia funciei, iar ident este numele variabilei pointer.
Exemplu. Fie o funcie f care calculeaz suma a dou numere ntregi x, y. Definiia
funciei este urmtoarea
int f(int x, int y)
{
return x + y;
}
Sablonul funciei este
int f(int, int);
In ablon trebuie s specificm tipul parametrilor, ca mai sus. In ablon putem
specifica i numele parametrilor. Numele parametrilor din ablon pot fi diferite de
cele din definiia funciei. De exemplu, ablonul funciei anterioare putea fi declarat
ca
int f(int a, int b);
O variabil de tip pointer la aceast funcie este
int (*ident)(int , int);
unde ident este numele variabilei tip pointer. Apelarea unei funcii folosind o variabil
de tip pointer se face astfel:
se atribuie variabilei pointer ca valoare numele funciei,
se aplic operatorul () asupra adresei coninut n variabila tip pointer, ca n
exemplul de mai jos.
78
Vom apela acum funcia f definit mai sus direct i folosind o variabil tip pointer.
int main()
{
int a = 5, b = 7, sm;
// apelarea directa a funciei
sm = f(a, b);
cout << suma numerelor << a << si << b << este sm << endl;
// se defineste variabila ptr, pointer la functia f
int (*ptr)(int, int);
// se initializeaza variabila ptr
prt = f;
// se apeleaza functia f prin pointer
sm = (*ptr)(a, b);
cout << suma numerelor << a << si << b << este sm << endl;
return 0;
}
In consecin, apelarea unei funcii se poate face n dou feluri:
se scrie numele funciei, urmat n paranteze de parametri actuali, ca termen
ntr-o expresie (se aplicnd operatorul () asupra numelui funciei),
se definete o variabil de tip pointer la funcie ; se atribuie acestei variabile ca
valoare adresa punctului de intrare n funcie (adresa punctului de intrare este
chiar numele funciei) ; apelarea se face scriind variabila de tip pointer, urmat
n paranteze de parametrii funciei, ca termen ntr-o expresie (aplicnd
operatorul () asupra adresei coninut n variabila tip pointer).
4.4 Interpretarea instruciunilor ce conin pointeri
O instruciune de declarare a unui tip pointer la funcie poate conine urmtorii
operatori, scrii aici n ordinea prioritilor :
1. [], ()
2. *, const
3. tipuri de date
Operatorii [] i () sunt asociativi la stnga. Operatorii * i const sunt asociativi la
dreapta. Instruciunea poate conine i un identificator, care este numele variabilei al
crei tip este definit de ablon. Interpretarea abloanelor se face considernd
operatorii n ordinea prioritii lor, [] reprezint un tablou, () reprezint o funcie, *
reprezint un pointer, etc. Fiecare operator se nlocuiete cu o expresie :
1. () funcie care returneaz,
2. [] tablou de,
3. * - pointer la,
4. const constant,
5. tip tip.
Se ncepe cu identificatorul din ablon.
Exemplu. Fie ablonul
float *f();
Interpretarea lui se face astfel:
float *f() f este
float * () funcie care returneaz
79
float * pointer la o valoare
float tip float
f este o funcie ce returneaz un pointer de tip float.
Exemplu. Fie ablonul
float (*pf) ();
Interpretarea lui se face astfel:
pf este pointer la o funcie ce returneaz o valoare de tip float. Operatorii ()
consecutivi din linia a doua s-au citit de la stnga la dreapta.
Exemplu. Sablonul
int (*r) (int, int);
se interpreteaz ca mai sus :
r este un pointer la o funcie cu doi parametri de tip int, int i care returneaz o valoare
de tip int.
Exemplu. Fie urmtoarea instruciune
const char * pc = abcd;
Reamintim c irul de caractere abcd este un vector cu 5 componente tip caracter,
a, b, c, d i \0 (irurile sunt terminate prin zero). Prin aceast instruciune
compilatorul genereaz un vector cu 5 componente tip caracter i atribuie adresa
acestui vector variabilei tip pointer pc. Interpretarea tipului variabilei pc se face astfel:
const char * pc pc este
const char * pointer la
const char constant
char char
Aceast instruciune declar un pointer la un vector constant de caractere (am inut
cont c operatorii * i const se citesc de la dreapta la stnga). In consecin, nu putem
scrie
pc[3] = c;
deoarece irul de caractere este constant, dar putem scrie
pc = ghij;
adic pointerul poate fi iniializat cu o alt valoare.
Exemplu. Fie acum instruciunea
char * const cp = abcd;
Interpretarea ei se face astfel:
char * const cp cp este
char * const constant
char * pointer la
char char
Instruciunea declar un pointer constant la un vector de caractere. In consecin,
putem modifica vectorul, de exemplu putem scrie
cp[3] = c;
float (*pf)() pf este
float (*) () pointer la
float () funcie care returneaz o valoare
float tip float
80
dar nu putem scrie
cp = ghij;
deoarece pointerul este o constant.
Exemplu. Considerm ablonul
char (*(*f())[])();
Interpretarea lui se face astfel:
char (*(*f())[])() f este
char (*(*())[])() funcie ce returneaz
char (*(*)[])() pointer la
char (*[])() vector de
char (*)() pointeri la
char () funcie ce returneaza o valoare
char tip char
f este o funcie ce returneaz un pointer la un vector de pointeri la o funcie ce
returneaz o valoare de tip char.
4.5 Pointeri i tablouri unidimensionale
Prin definiie, o variabil tip tablou conine adresa primului element al tabloului
(elementul cu indicele zero al tabloului). Variabila tip tablou este un pointer
constant la primul element al tabloului. Fie de exemplu instruciunea
char buffer[20];
Variabila buffer conine adresa primului element al tabloului (adresa elementului
buffer[0]). In consecin, aceast valoare poate fi atribuit unei variabile tip pointer la
tipul elementelor tabloului. Fie instruciunile :
char buffer[20] ;
char * px;
px = buffer;
variabila px conine adresa variabilei buffer[0] i, n consecin,
*px
este valoarea variabilei buffer[0].
La execuia unui program, numele unui tablou este convertit la un pointer la primul
element al tabloului.
Prin definiie, n cazul unui tablou x, scrierile :
x[i]
i
*(x + i)
sunt echivalente. Ele reprezint valoarea variabilei x[i].
La fel, scrierile
&x[i]
i
x + i
sunt echivalente. Ele reprezint adresa variabilei x[i].
Vom rescrie funcia ce permut dou variabile ntregi ca mai jos. Funcia va avea ca
parametri doi vectori cu cte o component.
// functie ce permute valorile a doua variabile intregi
void perm(int a[], int b[])
{
81
int c;
c = a[0];
a[0] = b[0];
b[0] = c;
return;
}
Funcia main() ce apeleaz funcia perm() este urmtoarea.
int main()
{
int x[1] = {3}, y[1] = {-4};
// scrie variabilele inainte de permutare
cout << " valori initiale : " << "x = " << x[0] << " y = " << y[0] <<
endl;
perm(x, y);
// scrie variabilele dupa permutare
cout <<" valori permutate : " << "x = "<< x[0]<<" y = "<<y[0] <<
endl;
return 0;
}
Tabelul de mai jos arat cele dou variante ale funciei ce permut dou variabile, cea
de la nceputul capitolului, cu pointeri i cea de mai sus, cu vectori.
void perm(int* a, int* b)
{
int c ;
c = *a ;
*a = *b ;
*b = c ;
return;
}
void perm(int a[], int b[])
{
int c;
c = a[0];
a[0] = b[0];
b[0] = c;
return;
}
Deoarece instruciunile :
*a
i
a[0]
sunt echivalente, cele dou funcii sunt identice.
Exemplu. Fie x un vector cu 5 componente tip float i un vector z cu 3 componente
ntregi. Se cere s afim componentele vectorilor. Vom face acest lucru utiliznd
elemente de vectoriului x[i] i pointeri *(z + i). Un program posibil este urmtorul.
#include <iostream>
using namespace std;
int main ()
{
float x[5] = {1.23, 6.89, -8.5e2, 0, 9.01};
int z[3] = {-11, 2, 4};
int i;
82
// scrie componentele vectorului x
for(i = 0; i < 5; i++)
cout << \t << x[i];
cout << endl;
// scrie componentele vectorului z
for(i = 0; i < 3; i++)
cout << \t << *(z + i);
cout << endl;
return 0 ;
}
Rezultatul rulrii programului este cel de mai jos
Programul poate fi rescris astfel. Definim o variabil px de tip pointer la tipul float ce
va conine pe rnd adresele componentelor x vectorului i o variabil pz de tip pointer
la tipul int pentru vectorul z. Variabilele vor fi initializate cu adresele vectorilor.
# include <iostream>
using namespace std;
int main()
{
float x[5] = {1.23, 6.89, -8.5e2, 0, 9.01};
int z[3] = {-11, 2, 4};
int i;
float * px;
px = x;
// scrie componentele vectorului x
for(i = 0; i < 5; i++)
cout << \t << *(px + i) ;
cout << endl;
int * pz;
pz = z;
// scrie componentele vectorului z
for(i = 0; i < 3; i++)
cout << \t << pz[i];
cout << endl;
return 0;
}
Programul de mai sus are rolul de a arta echivalena ntre pointeri i tablouri.
Operaiile cu variabilele tip pointer sunt adunarea i scderea unor valori ntregi. La
adunarea sau scderea unei valori ntregi dintr-o variabil tip pointer, la variabil se
adun sau se scade valoarea respectiv nmulit cu dimensiunea n octei a tipului
variabilei (unu pentru tipul char, patru pentru tipul int sau float, etc.) astfel nct
variabila tip pointer conine adresa unui alt element de tablou. Fie din nou
instruciunile :
83
char buffer[20];
char * px;
px = buffer;
Expresia px este adresa elementului buffer[0], iar *px este chiar valoarea elementului
buffer[0]. Expresia px + 1 este adresa variabilei buffer[1], iar *(px + 1) este chiar
valoarea componentei buffer[1]. In general, px + i este adresa variabilei buffer[i] iar
*(px + i) este chiar valoarea componentei buffer[i]. Pentru a aduna sau scdea o
unitate dintr-o variabil de tip pointer se pot folosi operatorii ++ i --.
Putem s rescriem programul precedent astfel :
# include <iostream>
using namespace std;
int main()
{
float x[5] = {1.23, 6.89, -8.5e2, 0, 9.01};
int i;
float * px;
px = x;
// scrie componentele vectorului x
for(i = 0; i < 5; i++)
{
cout << \t << *px;
px = px + 1;
}
cout << endl;
return 0;
}
Echivalent, instruciunea for n care scriem poate fi
for(i = 0; i < 5; i++)
{
cout << \t << *px++;
}
Pentru a vedea c ultima form este corect, reamintim modul de execuie a
operatorului postfix ++. Instruciunea
*px++
este echivalent cu instruciunile
*px;
px++;
In expresie se utilizeaz valoarea neincrementat a variabilei, dup care variabila este
incrementat. In consecin, se utilizeaz expresia *px dup care variabila px este
incrementat. Vom incheia acest paragraf cu un program care s scrie adresele
componentelor unui vector utiliznd o variabil tip pointer
# include <iostream>
using namespace std;
int main()
{
84
float x[5] = {1.23, 6.89, -8.5e2, 0, 9.01};
int i;
float * px;
px = x;
// scrie adresele componentele vectorului x
cout << adresele componentelor vectorului << endl;
for(i = 0; i < 5; i++)
{
cout << x[ << i << ]\t << px << endl;
px = px + 1;
}
return 0;
}
Rezultatul rulrii programului este cel de mai jos. Dup cum se observ, adresele
cresc cu 4 octei. De ce ?.
4.6 iruri tip C
irurile tip C sunt vectori de caractere ASCII la care ultimul caracter este \0.
Bibliotecile standard ale limbajelor C i C++ au numeroase funcii pentru lucrul cu
iruri tip C i caractere ASCII. Cteva dintre aceste funcii, ale cror prototipuri se
afl n biblioteca <cstring>, au fost prezentate mai nainte i sunt repetate aici.
Funcia
char * strcpy(char * s1, const char * s2);
copiaz irul s2 n s1, inclusiv caracterul \0. Funcia returneaz adresa irului s1.
Parametrul s2 este declarat de tip const, adic funcia nu modific irul s2.
Funcia
int strcmp(const char * s1, const char * s2);
compar cele dou iruri, caracter cu caracter, pn la primul caracter diferit.
Rezultatul este un numr < 0, = 0, sau > 0, dup cum sunt caracterele diferite
comparate.
Funcia
size_t strlen(const char * s);
calculeaz lungimea irului s (numrul de caractere ce preced \0). Tipul size_t este
tipul unsigned int.
Funcia
char * strchr(const char * s, int c);
caut prima apariie a caracterul c (convertit la char) n irul s. Funcia returneaz un
pointer la caracterul gsit sau NULL n caz contrar. Valoarea NULL este predefinit
n limbajele C i C++.
Vom exemplifica acum utilizarea funciilor de manipulare a caracterelor ASCII
tiprind caracterele alfabetice, alfanumerice, cifrele, literele mici i mari ale codului
ASCII.
85
Aceste funcii au fost prezentate anterior i prototipurile lor din biblioteca <cctype>
sunt repetate aici.
Funcii de manipulare a caracterelor ASCII
Funcie Descriere
int isalnum (int c); Test dac un caracter este alfanumeric
int isalpha (int c); Test dac un caracter este alfabetic
int isdigit (int c); Test dac un caracter este o cifr zecimal
int isxdigit(int c); Test dac un caracter este o cifr hexazecimal
int islower (int c); Test dac un caracter este liter mic
int isspace (int c); Test dac un caracter este spaiu ( , \n, \t)
int isupper (int c); Test dac un caracter este liter mare
Vom utiliza constanta predefinit UCHAR_MAX din biblioteca <climits> care d
valoarea maxim a unui obiect de tipul unsigned char (aceast valoare este 255). Vom
construi o funcie care genereaz toate caracterele codului ASCII (toate numerele de
la 0 la 255) i vom tipri n fiecare caz caracterele pentru care funciile de mai sus
returneaz o valoare pozitiv (valoarea adevrat). Funcia pe care o vom construi va
avea ca parametru un pointer de tipul funciilor de mai sus. Prototipul acestor funcii
este
int nume(int);
iar un pointer la o asemenea funcie are tipul
int (* fn)(int);
Caracterele vor fi generate cu o instruciune for a crei variabil de control are tipul
unsigned char. Definiia funciei este urmtoarea
#include <cstdlib>
#include <climits>
#include <iostream>
using namespace std;
/*
Parametri de intrare
nume numele functiei, sir de caractere
fn pointer la functie
*/
void prtcars(const char * nume, int (*fn)(int))
{
unsigned char c;
// scrie numele functiei
cout << nume << : ;
/* genereaza toate caracterele si scrie pe cele pentru
care functia are valoarea adevarat */
for(c = 0; c < UCHAR_MAX; ++c)
if((*fn)(c))
cout << c;
cout << endl;
return;
}
Urmtorul program testeaz aceast funcie.
86
int main()
{
prtcars(isdigit, &isdigit);
prtcars(islower, &islower);
prtcars(isupper, &isupper);
prtcars(isalpha, &isalpha);
prtcars(isalnum, &isalnum);
prtcars(isxdigit, &isxdigit);
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
Vom exemplifica utilizarea pointerilor la tablouri unidimensionale construind o
funcie care copiaz un ir n altul (ca i funcia standard strcpy). Prototipul ei va fi
void copy(char * s1, char * s2);
unde irul s2 este sursa iar irul s1 este destinaia.
O prim variant este
void copy(char * s1, char * s2)
{
int len = strlen(s2);
for(i = 0; i < len + 1; i++)
s1[i] = s2[i];
return;
}
O alt variant este
void copy(char * s1, char * s2)
{
int i;
for(i = 0; (s1[i] = s2[i]) != \0; i++)
;
return;
}
Condiia care se testeaz pentru execuia instruciunii for este
(s1[i]=s2[i]) != \0;
Ea este executat astfel. Se execut instruciunea de atribuire
s1[i] = s2[i]
87
dup care rezultatul s1[i] este comparat cu valoarea \0, care este caracterul de
terminare al irului s2. Reamintim c operatorul de atribuire are ca rezultat valoarea
atribuit, n cazul nostru s1[i].
O alt variant utilizeaz pointeri n locul elementelor de tablouri i faptul c irurile
tip C sunt terminate prin zero.
void copy(char * s1, char * s2)
{
while(*s1 = *s2)
{
s1++;
s2++;
}
return;
}
Expresia testat de ctre instruciunea while este
*s1 = *s2
Rezultatul evalurii expresiei este valoarea *s1 (un caracter copiat n irul s1).
Instruciunea while se execut pn cnd aceast valoare este 0 (pn cnd caracterul
\0 al irului s2 este copiat n s1).
In final putem scrie varianta urmtoare.
void copy(char * s1, char * s2)
{
while(*s1++ = *s2++)
;
return;
}
care este o scriere condensat a variantei anterioare.
4.7 Pointeri i tablouri multidimensionale
Tablourile se definesc conform urmroarei diagrame sintactice
Elementele tablourilor sunt memorate pe linii. De exemplu, tabloul
int x[2][3];
este compus din elementele :
x[0][0], x[0][1], x[0][2], x[1][0], x[1][1], x[1][2]
El este considerat ca un vector cu 2 elemente, x[0] i x[1], fiecare element fiind un
vector cu trei elemente de tip int. Operatorul [] selecteaz un element al unui
tablou (este operator de selecie). El este un operator binar, operandul stng
88
fiind un tablou, operandul drept fiind un indice. De exemplu, x[0] selecteaz
primul element din x care este vectorul
x[0][0], x[0][1], x[0][2]
Aplicnd operatorul de selecie asupra lui x[0], selectm un element al acestuia, de
exemplu x[0][1]. Reamintim c operatorul de selecie este asociativ la stnga. Indicii
unui element de tablou pot fi orice expresii ntregi pozitive.
Numele unui tablou este o variabil de tip pointer ce conine adresa primului element
al matricei. In cazul matricei de mai sus x conine adresa elementului x[0][0].
Elementele tabloului pot fi selectate folosind operatorul *.
Fie de exemplu tabloul
double a[3];
Dup cum am spus anterior, prin definiie, expresiile
a[i]
i
*(a + i)
sunt echivalente.
Aplicm aceast regul pentru tabloul de mai sus
int x[2][3];
Expresia
x[i][j]
este echivalent cu
(x[i])[j]
care, conform celor de mai sus, este echivalent cu
*((x[i]) + j)
care este echivalent cu expresia
*(*(x + i) + j)
Reamintim c
x[i]
selecteaz un element al tabloului x, aici o linie, deci, echivalent
*(x + i)
selecteaz o linie a tabloului x.
Vom prezenta un exemplu de utilizare a pointerilor la tablouri cu dou dimensiuni.
Fie o matrice x cu dou linii i trei coloane, cu elemente de tip ntreg. Vom afia
pentru nceput adresele celor dou linii ale matricei, cu trei programe echivalente.
Dup cum am spus mai sus, cele dou linii ale matricei sunt vectori cu trei
componente, iar adresele lor sunt x[0] i x[1], sau, echivalent, *(x + 0) i *(x + 1).
Prima variant a programului este cea de mai jos.
#include <iostream>
using namespace std;
int main()
{
int x[2][3];
int i;
// afisarea adreselor liniilor matricei x
for(i = 0; i < 2; i++)
cout << "adresa lui x[" << i << "] = " << x[i] << endl;
return 0;
89
}
Rezultatul rulrii programului este cel de mai jos.
Dup cum se observ, adresa lui x[1] este mai mare cu 12 octei (0xc) dect adresa lui
x[0]. De ce?
A doua variant afiaz adresele liniilor matricei x utiliznd expresia echivalent a lui
x[i], care este *(x + i).
#include <iostream>
using namespace std;
int main()
{
int x[2][3];
int i;
// afisarea adreselor liniilor matricei x
for(i = 0; i < 2; i++)
cout << "adresa lui x[" << i << "] = " << *(x + i) << endl;
return 0;
}
A treia variant a programului este urmtoarea. Reamintim c linia matricei este un
vector cu elemente ntregi. Definim o variabil y de tip pointer la ntreg
int * y;
In program, ea va primi ca valoare adresa liniei matricei x (adresa unui vector cu
elemente ntregi).
#include <iostream>
using namespace std;
int main()
{
int x[2][3];
int i;
int * y;
for(i = 0; i < 2; i++)
{
y = x[i];
cout << "adresa lui x[" << i << "] = " << y << endl;
}
return 0;
}
90
Menionm c, n locul instruciunii
y = x[i] ;
se putea scrie
y = *(x + i) ;
Vom afia acum adresele elementelor matricei x cu dou programe echivalente.
Adresele elementelor primei linii sunt x[0] + 0, x[0] + 1, x[0] + 2. Adresele
elementelor limiei a doua sunt x[1] + 0, x[1] + 1, x[1] + 2. In general, adresa
elementului x[i][j] al unei matrice x este
x[i] + j
Prima variant a programului este urmtoarea
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int x[2][3];
int i, j;
// afisarea adreselor elementelor matricei x
for(i = 0; i < 2; i++)
{
for(j = 0; j < 3; j++)
{
cout << "adresa lui x[" << i << "][" << j << "] = " << x[i] + j << endl;
}
}
return 0;
}
Rezultatul rulrii programului este cel de mai jos. Dup cum se observ, adresele
cresc cu patru octei. De ce ?
O alt variant a programului este cea de mai jos. In aceast variant, expresia x[i] + j
este nlocuit cu expresia *(x + i) + j.
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int x[2][3];
int i, j;
91
// afisarea adreselor elementelor matricei x
for(i = 0; i < 2; i++)
{
for(j = 0; j < 3; j++)
{
cout << "adresa lui x[" << i << "][" << j << "] = " << *(x + i) + j << endl;
}
}
return 0;
}
In final prezentm un program ce afiaz componentele matricei x. Elementul x[i][j]
al matricei x este, conform regulilor de mai sus,
*(*(x + i) + j)
Elementele matricei sunt afiate pe cte trei coloane, fiecare element este urmat de
dou spaii. Pentru a prescrie dimensiunea cmpului utilizm n instruciunea cout
funcia setw(4).
#include <iostream>
#include <iomanip>
using namespace std;
int main(int argc, char *argv[])
{
int x[2][3] = {{1, 2, 3}, {-2, -4, -6}};
int i, j;
// afisarea elementelor matricei x
for(i = 0; i < 2; i++)
{
for(j = 0; j < 3; j++)
cout << setw(4) << *(*(x + i) + j) << " ";
cout << endl;
}
return 0;
}
Rezultatul programului este afiat mai jos.
4.8 Parametrii funciei main. Parametrii liniei de comand
Prototipul funciei main() utilizat pn acum este
int main();
Funcia main poate avea i urmtorul prototip
int main(int argc, char * argv[]);
Considerm al doilea parametru din aceast definiie
92
char * argv[]
El este interpretat astfel
char * argv [] argv este
char * [] vector de
char * pointeri la
char char
argv reprezin un vector de pointeri la caracter, iar argc este dimensiunea acesui
vector. Pointerii sunt adresele unor iruri de caractere ce corespund argumentelor
liniei de comand. Primul ir de caractere este chiar numele programului. Ca exemplu
fie un program ce tiprete argumentele liniei de comand.
int main(int argc, char * argv[])
{
int i;
for(i = 0; i < argc; ++i)
cout << argv[i] << endl;
return 0;
}
Un mod de a furniza parametri liniei de comand este de a rula programul ntr-o
fereastr DOS, de la linia de comand
aplicatie.exe parametru1 parametru2 parametrun
Alt mod este de a introduce aceti parametri ntr-o caset de dialog a mediul de
programare.
4.9 Alocarea dinamic a memoriei
Alocarea memoriei unei variabile scalare sau tablou se face astfel :
de ctre compilator, la declararea unei variabile de un tip oarecare
cu funcia malloc()
cu operatorul new
Alocarea memoriei unei variabile cu funcia malloc() sau operatorul new se face la
execuia programului.
In programele n care alocm memorie cu funcia malloc() sau cu operatorul new
trebuie s definim o variabil pointer de un tip corespunztor ce va conine adresa
memoriei alocate.
Alocarea de memorie se poate face cu funcia malloc() cu prototipul
void * malloc(int size);
unde size este numrul de octei de alocat. Tipul funciei este void*, adic un pointer
de tip nespecificat, i el trebuie convertit n pointer la tipul alocat. Eliberarea
memoriei alocate se face cu funcia
void free(p);
unde p este o variabil tip pointer ce conine adresa zonei de memorie ce va fi
eliberate. Prototipul acestor funcii se afl n biblioteca <cstdlib>.
Exemplu. Vom aloca un vector cu 10 componente ntregi, l vom iniializa i l vom
scrie pe ecran. In program definim o variabil v de tip pointer la ntreg ce va conine
adresa memoriei alocate de funcia malloc(). Dup alocare, vectorul poate fi utilizat
93
pentru calcule. La sfritul programului, memoria alocat trebuie eliberat cu funcia
free().
# include <iostream>
# include <cstdlib>
using namespace std;
int main()
{
int j;
int * v = (int *) malloc(10 * sizeof(int));
for(j = 0; j < 10; j++)
{
// *(v + j) = 2 * j;
v[j] = 2 * j;
}
for(j = 0; j < 10; j++)
{
cout << *(v + j) << ;
// cout << v[j] << ;
}
cout << endl;
free(v); // elibereaza memoria
return 0;
}
Instruciunea
int * v = (int *) malloc(10 * sizeof(int));
aloc un vector cu 10 componente de tipul int. Ea are acelai efect cu instruciunea
int v[10];
dar vectorul v[10] este alocat de compilator i nu poate fi ters, n timp ce vectorul
v[10], alocat cu funcia malloc, poate fi ters. Instruciunea convertete pointerul
furnizat de funcia malloc() la tipul (int *).
Rezultatul rulrii programului este cel de mai jos.
In continuare vom arta cum se aloc memorie pentru o matrice. Pentru a determina
tipul variabilei pointer ce va conine memoria alocat cu funcia malloc(), vom analiza
cazul unei matrice x cu elemente ntregi cu dou linii i trei coloane. Definiia acestei
matrice este
int x[2][3] ;
Matricea x este format din doi vectori, x[0] i x[1], ce corespund celor dou linii ale
matricei. Vectorul x[0] de exemplu, conine elementele x[0][0], x[0][1], x[0][2]. Tipul
vectorilor x[0] i x[1] este, aa cum am spus mai sus
int *
Matricea x const deci dintr-un vector cu dou componente al cror tip este int *, deci
tipul variabilei x va fi
int **
94
Prezentm mai jos un program n care am definit matricea
int x[2][3] = {{1, 2, 3}, {-4, -5, -6}};
Vom afia adresele liniilor matricei, adresele elementelor matricei i elementele
matricei utiliznd o variabil tip pinter.
Definim un vector y cu dou elemente de tipul int * ce va fi iniializat cu adresele
celor dou linii ale matricei x, x[0] i x[1] ;
int * y[2];
y[0] = x[0];
y[1] = x[1];
Definim n final o variabil z de tip pointer ce va fi iniializat cu adresa vectorului y.
Tipul variabilei z va fi int **
int ** z ;
z = y;
In continuare prezentm secvene din program n care utilizm variabila z pentru a
afia adresele liniilor matricei, adresele elementelor matricei i valorile elementelor
matricei x.
Vom afia adresele liniilor matricei x cu cele dou expresii echivalente, z[i] i *(z + i)
// afisaza adresele liniilor matricei x
cout << "adresele liniilor matricei" << endl;
for(i = 0; i < 2; i++)
{
cout << "adresa lui x[" << i << "] : " << z[i] << endl;
}
// afisaza adresele liniilor matricei x
cout << "adresele liniilor matricei" << endl;
for(i = 0; i < 2; i++)
{
cout << "adresa lui x[" << i << "] : " << *(z + i) << endl;
}
Afim apoi adresele elementelor matricei x cu cele dou expresii echivalente, z[i] + j
i *(z + i) + j
// afisaza adresele elementelor matricei
cout << "adresele elementelor matricei" << endl;
for(i = 0; i < 2; i++)
{
for(j = 0; j < 3; j++)
cout << "adresa lui x[" << i << "][" << j << "] : "
<< z[i] + j << endl;
}
// afisaza adresele elementelor matricei
cout << "adresele elementelor matricei" << endl;
95
for(i = 0; i < 2; i++)
{
for(j = 0; j < 3; j++)
cout << "adresa lui x[" << i << "][" << j << "] : "
<< *(z + i) + j << endl;
}
In final, afim elementele matricei x pe linii, cu cele dou expresii echivalente, z[i][j]
i *(*(z + i) + j
// afisaza elementele matricei x pe linii
cout << "elementele matricei" << endl;
for(i = 0; i < 2; i++)
{
for(j = 0; j < 3; j++)
cout << setw(3) << z[i][j] << " ";
cout << endl;
}
// afisaza elementele matricei x pe linii
cout << "elementele matricei" << endl;
for(i = 0; i < 2; i++)
{
for(j = 0; j < 3; j++)
cout << setw(3) << *(*(z + i) + j) << " ";
cout << endl;
}
Programul complet este cel de mai jos
#include <iostream>
#include <iomanip>
using namespace std;
int main(int argc, char *argv[])
{
int x[2][3] = {{1, 2, 3}, {-4, -5, -6}};
int * y[2];
int ** z;

z = y;

y[0] = x[0];
y[1] = x[1];

int i, j;
// afisaza adresele liniilor matricei x
cout << "adresele liniilor matricei" << endl;
for(i = 0; i < 2; i++)
{
96
cout << "adresa lui x[" << i << "] : " << z[i] << endl;
}
// afisaza adresele liniilor matricei x
cout << "adresele liniilor matricei" << endl;
for(i = 0; i < 2; i++)
{
cout << "adresa lui x[" << i << "] : " << *(z + i) << endl;
}
// afisaza adresele elementelor matricei x
cout << "adresele elementelor matricei" << endl;
for(i = 0; i < 2; i++)
{
for(j = 0; j < 3; j++)
cout << "adresa lui x[" << i << "][" << j << "] : "
<< z[i] + j << endl;
}
// afisaza adresele elementelor matricei x
cout << "adresele elementelor matricei" << endl;
for(i = 0; i < 2; i++)
{
for(j = 0; j < 3; j++)
cout << "adresa lui x[" << i << "][" << j << "] : "
<< *(z + i) + j << endl;
}
// afisaza elementele matricei x pe linii
cout << "elementele matricei" << endl;
for(i = 0; i < 2; i++)
{
for(j = 0; j < 3; j++)
cout << setw(3) << z[i][j] << " ";
cout << endl;
}
// afisaza elementele matricei x pe linii
cout << "elementele matricei" << endl;
for(i = 0; i < 2; i++)
{
for(j = 0; j < 3; j++)
cout << setw(3) << *(*(z + i) + j) << " ";
cout << endl;
}
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
97
Exemplu. Vom aloca memorie pentru o matrice cu elemente ntregi cu nlin linii i
ncol coloane, unde nlin i ncol se vor citi de la tastatur. Alocarea se face astfel. Dup
cum am spus mai sus, o matrice este compus din vectori corespunztori liniilor.
Fiecare linie a matricei este un vector cu componente de tip int, deci tipul vectorului
liniei este int*. Se aloc mai nti un vector de dimensiune nlin ce va conine elemente
de tip int*. Variabila z ce conine adresa acestui vector are tipul int **. Apoi, fiecare
element al acestui vector, primete ca valoare adresa unui vector de ncol ntregi. In
final se atribuie valori componentelor matricei
z[i][j] = i * j ;
Programul este urmtorul
# include <iostream>
# include <cstdlib>
using namespace std;
int main()
{
int i, j;
int nlin, ncol;
cout << "introduceti # de coloane "; cin >> ncol;
cout << "introduceti # de linii "; cin >> nlin;
// aloca un vector de dimensiune nlin de pointeri de tip int *
int ** z = (int **) malloc(nlin * sizeof(int *));
// aloca pentru fiecare linie un vector de ncol intregi
for(i = 0; i < nlin; i++)
z[i] = (int*) malloc(ncol * sizeof(int));
// atribuie valori componentelor matricei
for(i = 0; i < nlin; i++)
for(j = 0; j < ncol; j++)
98
z[i][j] = i * j;
for(i = 0; i < nlin; i++)
{
for(j = 0; j < ncol; j++)
cout << z[i][j] << '\t';
cout << endl;
}
return 0;
}
Prima funcie malloc() aloc memorie pentru un vector cu nlin elemente de tipul int*.
A doua funcie malloc() aloc memorie pentru un vector cu ncol elemente de tipul int.
Rezultatul rulrii programului este artat mai jos.
Limbajul C++ permite alocarea memoriei necesar unei variabile cu operatorul new
cu formele
new tip
pentru alocarea de memorie pentru un scalar i
new tip[expresie ntreag]
pentru alocarea de memorie pentru un vector cu un numr de componente dat de
expresie ntreag.
De exemplu urmtoarele instruciuni aloc memorie prntu o variabil scalar
double * ptr;
ptr = new double;
*ptr = 1.7;
Operatorul new aloc memoria corespunztoare tipului de variabil i are ca rezultat
adresa zonei de memorie alocat. Primele dou instruciuni puteau fi scrise
double *ptr = new double;
Memoria alocat cu operatorul new poate fi eliberat cu operatorul delete cu formele
delete prt;
pentru eliberarea memoriei allocate unei variabile scalare i
delete [] ptr;
pentru eliberarea memoriei alocate unui vector. Variabila ptr conine adresa memoriei
alocat mai nainte cu new.
Operatorii new i delete sunt utili la operaii cu vectori.
Exemplu. Instruciunea
float *pf = new float[10];
aloc un vector de 10 componente de tip float, iat variabila pf conine adresa
vectorului. Un vector alocat cu new poate fi ters cu operatorul delete
delete [] pf;
Exemplu. Vom aloca un vector cu 10 componente ntregi, l vom iniializa i vom
afia pe ecran componentele lui.
int main()
99
{
int * v = new int[10];
int j;
for(j = 0; j < 10; j++)
{
*(v + j) = j;
// v[j] = j;
}
for(j = 0; j < 10; j++)
{
cout << v[j] << ;
// cout << *(v + j) << ;
}
cout << endl;
delete [] v;
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
Instruciunea
int * v = new int[10];
are acelai efect cu instruciunea
int x[10];
dar vectorul v[10] alocat cu new poate fi ters, vectorul v[10] alocat de compilator nu
poate fi ters.
Exemplu. Vom aloca o matrice cu nlin linii i ncol coloane, cu elemente ntregi, unde
nlin i ncol se vor citi de la tastatur. Pentru tipul variabilelor utilizate n program vezi
exemplu anterior. Elementele matricei vor primi aceleai valori ca n exemplul
anterior.
# include <iostream>
# include <cstdlib>
using namespace std;
int main()
{
int i, j;
int ** v;
int nlin, ncol;
cout << "introduceti # de coloane "; cin >> ncol;
cout << "introduceti # de linii "; cin >> nlin;
v = new int * [nlin];
for(i = 0; i < nlin; i++)
v[i] = new int[ncol];
100
for(i = 0; i < nlin; i++)
for(j = 0; j < ncol; j++)
v[i][j] = i * j;
for(i = 0; i < nlin; i++)
{
for(j = 0; j < ncol; j++)
cout << v[i][j] << '\t';
cout << endl;
}
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
Instruciunea
v = new int * [nlin];
aloc memorie pentru un vector cu nlin elemente de tipul int*. La fel ca mai nainte
variabila tip pointer v are tipul int**.
101
5 Fiiere tip C
In limbajele C i C++ fiierele sunt considerate ca un ir ordonat de octei. Exist
dou tipuri de fiiere, text i binare.
un fiier tip text este un ir ordonat de caractere grupate n linii. Fiecare linie
const din zero sau mai multe caractere, urmate de un caracter \n.
un fiier binar este un ir ordonat de octei.
Menionm c, fiecare fiier pe disc are o etichet ce conine numele fiierului, adresa
de nceput i adresa de sfrit a fiierului.
In program, fiecare fiier este asociat unui obiect numit stream. Un stream este
asociat unui fiier prin operaia de deschidere a fiierului.
Pentru prelucrare, un fiier se deschide n citire. La deschiderea unui fiier n citire,
sistemul de operare caut pe disc fiierul cu numele specificat i memoreaz adresele
de nceput i de sfrit ale fiierului n obiectul stream asociat.
Cnd se creaz un fiier el se deschide n scriere. La deschiderea unui fiier n scriere,
se creaz o etichet corespunztoare acestui fiier i se completez numele fiierului i
adresa de nceput n obiectul stream asociat.
Un stream este disociat de un fiier prin operaia de nchidere a fiierului. La
nchiderea unui fiier n creare se completeaz eticheta de pe disc a fiierului cu
adresa ultimului octet al fiierului.
Fiierele au un indicator de poziie ce d adresa urmtorului octet de citit sau scris.
Acest indicator este iniial pus la zero i este actualizat de operaiile de citire sau
scriere.
Un fiier poate avea o zon de memorie asociat (buffer) n care se citesc date din
fiier sau din care se scriu date n fiier.
Limbajele C i C++ au tipul de structur FILE ce poate nregistra toate informaiile
necesare pentru controlul unul stream, inclusiv:
numele fiierului,
indicatorul de poziie al fiierului,
indicator de eroare poziionat dac a aprut o eroare intrare/ieire,
indicatorul de sfrit de fiier, eof, (end of file), poziionat la valoare true dac
n timpul operaiei de citire s-a ajuns la sfritul fiierului.
Prototipurile funciilor intrare / ieire pentru fiierele tip C sunt memorate n
fiiere header i trebuie semnalate compilatorului cu directive include.
Prototipurile funciilor ce efectueaz operaii intrare/ieire n limbajul C se afl
n biblioteca <stdio.h>. Pentru limbajul C++ numele fiierului header este
redefinit ca <cstdio>. Reamintim cele dou forme ale directivei include:
n cazul programelor C, directiva include conine numele fiierului antet
(header), inclusiv extensia h. Forma directivei include este
#include <stdio.h>
n cazul programelor C++, directiva include conine doar mumele
fiierului antet (header). Forma directivei include este
#include <cstdio>
In exemplele urmtoare vom utiliza stilul C.
Funciile importante pentru prelucrarea fiierelor sunt urmtoarele.
FILE* fopen(const char * filename, const char * mode);
Aceast funcie deschide un fiier. Ea creaz o structur tip FILE cu informaii despre
fiier i are ca rezultat adresa ei. Parametrii acestei funcii sunt
102
1. filename - un pointer la irul de caractere ce d numele fiierului.
2. mode - un pointer la un ir de caractere ce d modul de deschidere.
Parametrul mode poate avea urmtoarele valori:
r fiier text deschis n citire
w - fiier text deschis n scriere
rb fiier binar deschis n citire
wb - fiier binar deschis n scriere
int fclose(FILE * stream); Funcia nchide un fiier. Ea returneaz valoarea
zero dac operaia a avut succes.
int feof(FILE * stream); Funcia returneaz o valoare diferit de zero dac s-a
detectat sfritul unui fiier n timpul operaiei de citire precedente.
int remove(char * filename); terge fiierul cu numele filename. Funcia
returneaz o valoare diferit de zero dac operaia avut succes.
La lansarea n execuie a unui program exist trei streamuri standard tip text
deschise:
stdin fiierul standard de intrare asociat tastaturii
stdout - fiierul standard de ieire asociat ecranului
stderr - fiierul standard de ieire pentru scrierea mesajelor de eroare
Exemplu. Schema prelucrrii unui fiier text n citire este urmtoarea
FILE * fp;
fp = fopen(numefisier, r);
// prelucreaza fisierul
fclose(fp);
Menionm c la citirea secvenial a unui fiier, dup fiecare operaie de citire
trebuie s testm dac s-a ajuns la sfritul fiierului. La ntlnirea sfritului de
fiier indicatorul de sfrit de fiier este poziionat la o valoare diferit de zero
iar funciile de citire returneaz o valoare specific (constanta EOF, predefinit
n biblioteca <stdio.h>). Citirea secvenial a unui fiier se face cu instruciunea
while ce va testa indicatorul de sfrit de fiier cu funcia feof(), sau dac funcia
de citire a returnat valoarea EOF.
In cazul citirii datelor de la tastatur, (din fiierul stdin), sfritul de fiier este
indicat prin Ctrl+Z. Dup aceasta se apas tasta return.
Fiecare aplicaie are un director curent asociat. Atunci cnd parametrul
filename din instruciunea fopen() conine doar numele fiierului, fiierul se afl
n directorul curent. Pentru a prelucra fiiere n alte directoare, trebuie ca
parametrul filename s conin i calea, absolut sau relativ spre fiier.
5.1 Fiiere tip text
In cazul fiierelor tip text avem dou tipuri de funcii pentru operaiile de intrare /
ieire:
funcii pentru intrri / ieiri cu format, la care operaiile de citire / scriere se
fac sub controlul unui format,
funcii care citesc / scriu caractere.
103
5.1.1 Funcii intrare / ieire cu format
Aceste funcii scriu / citesc valori n / din fiiere pe disc, fiierele standard sau fiiere
tip ir de caractere (fiiere memorate n vectori tip char). Pentru scriere, aceste funcii
sunt:
int fprintf(FILE * stream, const char * format, argumente);
int printf( const char * format, argumente);
int sprintf(char * s, const char * format, argumente);
Funciile au ca rezultat numrul de octei scrii. In cazul unei erori intrare / ieire
funciile au ca rezultat un numr negativ.
Pentru citire, funciile sunt
int fscanf(FILE * stream, const char * format, argumente);
int scanf( const char * format, argumente);
int sscanf(char * s, const char * format, argumente);
Funciile au ca rezultat numrul de valori citite. In cazul unei erori intrare / ieire
funciile au ca rezultat un numr negativ.
funciile de scriere / citire pentru fiiere pe disc sunt fprintf i fscanf,
funciile de scriere / citire pentru fiierele standard stdout / stdin sunt printf i
scanf,
funciile de scriere / citire pentru fiierele tip ir de caractere sunt sprintf i
sscanf. In cazul fiierelor ir de caractere, parametrul s este un ir tip C n care
se scriu sau din care se citesc valorile variabilelor.
Menionm c, n cazul instruciunilor scanf, argumentele sunt parametri de
ieire, deci de tip pointer.
Parametrul format este un ir de caractere compus din specificatori de conversie
definii de % i alte caractere. Specificatorii de conversie sunt :
%d ntreg cu semn n baza 10
%i ntreg cu semn
%o ntreg n baza 8
%u ntreg n baza 10 far semn
%x ntreg n baza 16 cu semn
%c caracter
%s ir de caractere
%f numr real tip float
%lf numr real tip double
%e numr real cu exponent
%le- numr real tip double cu exponent
%p pointer
Dup % poate urma un numr ntreg care d lungimea minim a cmpului n cazul
instruciunii printf i lungimea maxim a cmpului n cazul instruciunii scanf. La
scrierea numerelor cu specificatorul %f putem specifica i numrul de cifre ale prii
subunitare. De exemplu specificatorul %7f descrie un numr real ce ocup 7 poziii,
iar specificatorul %7.3f descrie un numr real ce ocup 7 poziii din care 3 sunt pentru
partea subunitar.
104
Exemplu. S citim un numr hexazecimal de la tastatur i s-l scriem n format
zecimal i hexazecimal pe ecran.
#include<stdio.h>
int main()
{
int i;
printf(introduceti un numar hexazecimal\n);
scanf(%x, &i);
printf(\n numarul zecimal : %d\n numarul hexazecimal : %x\n, i, i);
}
Rezultatul programului este cel de mai jos.
Reamintim c, parametrii funciei scanf sunt de tip pointer (sunt parametri de ieire).
In consecin, la apelarea funciei scanf n program utilizm adresa variabilei i
scanf(%x, &i);
In cazul instruciunilor printf specificatorii de conversie dau formatul de scriere a
varibilelor, n timp ce restul caracterelor sunt scrise n fiier. De exemplu,
instruciunea
printf(\n numarul zecimal : %d\n numarul hexazecimal : %x\n, i, i);
are ca rezultat scrierea caracterului \n, (trecerea la un nou linie), a irului numarul
zecimal i a valorii variabilei i, etc.
Exemplu. Vom scrie un program care calculeaz valoarea unei expresii
x x
x x
ln
) sin( 2 ) 2 cos( 1
+
+ +
pentru valori ale lui x cuprinse ntre 1 i 2 cu pasul 0.2. Valorile expresiei vor fi scrise
pe ecran i ntr-un fiier cu numele rez.txt. Specificatorii de format vor fi %4.1f pentru
variabila x i %6.2f pentru expresie. Valoarea lui x va ocupa 4 caractere, cu un
caracter pentru partea subunitar, cea a lui z ocup 6 caractere, dou pentru partea
subunitar. Valorile vor fi separate de un caracter tab, \t. Formatul se va ncheia cu
un caracter \n.
#include <stdio.h>
#include <math.h>
int main ()
{
FILE * fp;
fp = fopen("rez.txt", "w");
int i;
float x, z;
// scrie antetul pe ecran si in fisier
printf(" x \t f(x) \n");
105
fprintf(fp, " x \t f(x) \n");
x = 1.0;
// calculeaza valorile expresiei si scrie aceste valori in fisiere
for(i = 0; i < 6; i++)
{
z = (1 + cos(2 * x) + 2 * sin(x)) / (x + log(fabs(x)));
printf(" %4.1f \t %6.2f \n", x, z);
fprintf(fp, " %4.1f \t %6.2f \n", x, z);
x = x + 0.2;
}
fclose(fp);
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
In programul anterior puteam defini un ir de caractere cu specificatorii de format
char * format = %4.1f \t %6.2f \n;
i instruciunile de scriere devin
printf(format, x, z);
fprintf(fp, format, x, z);
Exemplu. Consideram un vector cu 5 componente numere reale. Vom afia
componentele vectorului sub forma
Element Valoare
x[0] ..
x[1] ..
# include <stdio.h>
int main()
{
double x[5] = {1.23, -23, 0.98, 4.12, 5.1};
int i;
printf(Element\tValoare);
// scrie componentele vectorului
for(i = 0; i < 5; i++)
printf(x[%d] \t\t%d\t, i, x[i]);
return 0;
}
5.1.2 Funcii intrare / ieire tip caracter
Funcia
int fgetc(FILE * stream);
106
citete un caracter din fiierul de intrare i avanseaz indicatorul de poziionare al
fiierului cu valoarea unu. Dac se ntlnete sfritul de fiier, funcia returneaz
valoarea EOF care este o constant predefinit n biblioteca <stdio.h>.
Funcia
int getchar();
citete un caracter din streamul stdin. Ea este echivalent cu funcia fgetc(stdin);
Funcia
int fputc(int c, FILE * stream);
scrie caracterul c n streamul specificat de stream. Funcia returneaz caracterul scris
sau constanta EOF n caz de eroare.
Funcia
int putchar(int c);
scrie caracterul c in streamul stdout.
Funcia
int ungetc(int c, FILE * stream);
pune caracterul c n streamul de intrare.
Urmtoarele funcii citesc sau scriu linii din fiiere tip text.
Funcia
char * fgets(char * s, int n, FILE * stream);
citete cel mult n 1 caractere n vectorul s. Ea se oprete dac ntlnete caracterul
\n sau sfritul de fiier. Caracterul \n este introdus n irul citit. Dup ultimul
caracter citit se adaug caracterul \0 n vectorul s. Funcia returneaz adresa
vectorului s. La ntlnirea sfritului de fiier sau la o eroare funcia returneaz
valoarea NULL.
Funcia
int fputs(const char * s, FILE * stream);
scrie irul de caractere s (terminat cu \0) n fluxul stream. Caracterul \0 nu este
scris.
Funcia
int puts(char * s);
scrie irul de caractere s (terminat cu \0) n fluxul stdout. Caracterul \0 nu este
scris. Funcia scrie i caracterul \n dup ce a scris irul s.
Reamintim c funcia fputs nu scrie caracterul \n n fiier, n timp ce funcia puts
scrie caracterul \n n fiierul stdout dup ir. In consecin, pentru a afia cte un ir
de caractere pe rnd, la scrierea n fiierul stdout cu funcia fputs vom scrie
fputs(x, stdout);
fputs(\n, stdout);
Schema principial de citire a unui fiier secvenial este urmtoarea. Presupunem c
utilizm o funcie read(file) ce citete cte un bloc de date din fiier. Operaia de citire
poziioneaz indicatorul de sfrit de fiier la o valoare diferit de zero dac n cursul
operaiei de citire s-a detectat sfrtul fiierului i acest lucru este detectat cu funcia
feof().
read(file)
while(! feof(file))
{
// prelucreaza blocul citit
read(file)
}
107
Exemplu. Vom exemplifica utilizarea acestor funcii cu un program care s calculeze
dimensiunea n octei a unui fiier. Programul va citi numele unui fiier de la tastatur,
i va deschide fiierul n citire. Funcia fopen are ca rezultat valoarea NULL dac
operaia nu a avut succes. Apoi se va citi cte un caracter pan la ntlnirea sfritului
de fiier i se vor numra octeii citii. Citirea secvenial a fiierului se va face cu
instruciunea while.
/* calculul dimensiunii unui fisier */
#include <stdio.h>
int main()
{
char name[64];
FILE* file;
char car;
int nb = 0;
printf("introduceti numele fisierului\n");
scanf("%s", name);
// deschide fisierul in citire
file = fopen(name, "r");
// test daca fisierul exista
if(file == NULL)
{
printf("nume de fisier eronat\n");
return 0;
}
// citeste cate un caracter pn la sfarsitul fisierului
// citeste un caracter
car = fgetc(file);
while(car != EOF)
{
// numara caracterul citit
nb = nb + 1;
// citeste un caracter
car = fgetc(file);
}
fclose(file);
printf("fisierul %s contine %d octeti\n", name, nb);
return 0;
}
Rezultatul rulrii proghramului este cel de mai jos.
Un alt mod de a rezolva aceast problem va fi artat ulterior.
108
Exemplu. Vom face un program care s copieze un fiier existent n altul. Fie un fiier
n directorul curent. Vom copia acest fiier ntr-un alt fiier tot n directorul curent.
Numele celor dou fiiere se vor citi de la tastatur. Vom deschide cele dou fiiere i
vom testa dac operaia a avut success, utiliznd faptul c funcia fopen are ca rezultat
valoarea NULL dac operaia nu a avut succes. Apoi se citete repetat cte un caracter
din primul fiier i se scrie n al doilea, pn la ntlnirea sfritului primului fiier.
Citirea secvenial a primului fiier se va face cu instruciunea while.
# include <stdio.h>
int main ()
{
FILE * fin, * fout;
char nume1[64], nume2[64];
// citeste numele primului fisier
printf(introduceti numele fisierului ce va fi copiat\n);
scanf(%s, nume1);
fin = fopen(nume1, "r");
if(fin == NULL)
{
printf("fisierul %s nu exista\n", nume1);
return 0;
}
// citeste numele noului fisier
printf(introduceti numele noului fisier\n);
scanf(%s, nume2);
fout = fopen(nume2, "w");
if(fout == NULL)
{
printf("fisierul %s nu se poate crea", nume2);
return 0;
}
// copiaza fisierul
int c;
c = fgetc(fin);
while(c != EOF)
{
fputc(c, fout);
c = fgetc(fin);
}
fclose(fin);
fclose(fout);
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
109
Instruciunile ce citesc i scriu din fiiere pot fi rescrise ca
int c;
while((c = fgetc(fin)) != EOF)
fputc(c, fout);
5.2 Fiiere text tip ir de caractere
Limbajul ofer posibilitatea de a lucra cu fiiere tip text memorate ntr-un ir tip C.
Instruciunile de scriere / citire sunt
int sprintf(char * s, const char * format, argumente);
int sscanf(char * s, const char * format, argumente);
Parametrul s este irul de caractere tip C n care se scriu sau din care se citesc datele.
Parametrul format este un ir de caractere compus din specificatori de conversie
definii de % i alte caractere. Asemenea fiiere sunt utile la conversii ale valorilor
numerice n iruri de caractere i invers.
Exemplu. Fie doi vectori tip char ce conin irurile 104 i 1.23e-1. Vom converti
aceste iruri n dou variabile tip int i double, vom face suma lor i o vom scrie pe
ecran.
#include <stdio.h>
int main()
{
char x[] = "104";
char y[] = "1.23e-1";
int i;
double z, r;
sscanf(x, "%d", &i);
sscanf(y, "%lf", &z);
printf("i = %d \n", i);
printf("y = %lf \n", z);
r = z + i;
printf("i + y = %lf\n", r);
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
110
Reamintim c la citirea unei variabile tip double se utilizeaz specificatorul de
conversie %lf.
Exemplu. Fie variabilele
int x = 10;
double d = -2.34;
char c[] = "abc";
Vom scrie valorile acestor variabile, separate de spaii, ntr-un fiier tip ir de
caractere
char s[100] ;
Vom apoi citi valorile din vectorul s i vom iniializa alte variabile
int x1;
double d1;
char c1[10];
i vom scrie valorile lor pe ecran.
# include <stdio.h>
int main()
{
char s[100];
int x = 10;
double d = -2.34;
char c[] = "abc";
// scrie pe ecran variabilele initiale
printf("x = %d d = %f c = %s\n", x, d, c);
// scrie variabilele initiale in fisierul tip sir
sprintf(s, "%d %f %s", x, d, c);
// scrie pe ecran fisierul tip sir
printf("%s\n", s);
int x1;
double d1;
char c1[10];
// citeste valorile variabilelor din fisierul tip sir
sscanf(s, "%d %lf %s", &x1, &d1, c1);
// scrie valorile variabilelor pe ecran
printf("x = %d d = %f c = %s\n", x1, d1, c1);
return 0;
}
Pentru citirea variabilei d1 de tip double am utilizat specificatorul de conversie %lf.
Menionm c parametrii funciei sscanf sunt de tip pointer (sunt parametri de ieire).
In consecin, la apelarea funciei sscanf n program utilizm adresele variabilelor x1
i d1
sscanf(s, "%d %lf %s", &x1, &d1, c1);
Valorile scrise pe ecran cu cele trei instruciuni printf() sunt cele de mai jos.
111
5.3 Fiiere binare
Pentru scrierea i citirea de date din fiiere binare exist funciile fread i fwrite.
Aceste funcii pot citi sau scrie unul sau mai multe blocuri de date.
Funcia
size_t fread(void * ptr, size_t size, size_t nmb, FILE * stream);
citete n vectorul ptr cel mult nmb blocuri de dimensiune size din fiierul stream.
Funcia returneaz numrul efectiv de blocuri citite. Indicatorul de poziie al fiierului
este avansat cu numrul de octei citii. In cazul ntlnirii sfaritului de fiier, funcia
returneaz valoarea 0.
Funcia
size_t fwrite(const void * ptr, size_t size, size_t nmb, FILE * stream);
scrie n vectorul ptr cel mult nmb blocuri de dimensiune size n fiierul stream.
Funcia returneaz numrul efectiv de blocuri scrise. Indicatorul de poziie al
fiierului este avansat cu numrul de octei scrii.
Pentru citirea elementelor n ordine aleatoare exist posibilitatea de a modifica
indicatorul de poziie al fiierului cu funcia
int fseek (FILE * stream, long int offset, int whence);
Noua valoare a indicatorului fiierului este obinut adugnd valoarea offset la
poziia specificat de whence care poate fi
SEEK_SET nceputul fiierului
SEEK_CUR poziia curent a indicatorului
SEEK_END sfritul fiierului
Dup o instruciune fseek, urmtoarea instruciune poate fi o operaie de citire sau
scriere.
Funcia
long ftell(FILE* stream);
are ca rezultat valoarea indicatorului de poziie al fiierului.
Exemplu. Vom calcula lungimea unui fiier text modificnd indicatorul fiierului
astfel nct noua lui poziie s fie sfritul fiierului. Lungimea fiierului va fi
valoarea indicatorului de poziie.
#include <stdio.h>
// fisiere text C. Calculul lungimii fiserului
// prin modificarea indicatorului de pozitie.
int main()
{
char name[256];
FILE* file;
int nb = 0;
printf("introduceti numele fisierului\n");
scanf("%s", name);
// deschide fisierul in citire
file = fopen(name, "r");
if(file == NULL)
{
112
printf("nume de fisier eronat\n");
return 0;
}
// modifica indicatorul de pozitie la sfarsitul fisierului
fseek(file, 0, SEEK_END);
// citeste valoarea indicatorului de pozitie
nb = ftell(file);
fclose(file);
printf("fisierul %s contine %d octeti\n", name, nb);
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
Fiierul citit este chiar fiierul surs ce conine programul, main.c.
Exemplu. Vom crea un fiier binar pe care l citim apoi secvenial. Vom scrie n fiier
10 blocuri de cte 15 octei fiecare. Blocurile vor consta din iruri de cte 14 caractere
plus \0, primul bloc caractere 0, al doilea bloc caractere 1, etc. Citirea secvenial
se va face cu instruciunea while. Dup fiecare citire testm rezultatul funciei fread.
Un rezultat zero al acestei funcii semnific ntlnirea sfritului de fiier. Menionm
c putem genera caracterele 0, 1, etc., cu o expresie de forma
0 + i
unde i ia valorile 0, 1, 2,
Programul este urmtorul.
#include <stdio.h>
int main()
{
FILE * fil;
int i, j;
char x[15];
// deschide fisierul in creare
fil = fopen(fil.txt, wb);
if(fil == NULL)
{
printf(fisierul nu se poate crea\n);
return 0;
}
for(i = 0; i < 10; i++)
{
// creaza un bloc
for(j = 0; j < 14; ++j)
x[j] = 0 + i ;
x[14] = 0;
// scrie blocul in fisier
113
fwrite(x, 15, 1, fil);
}
// inchide fisierul
fclose(fil);
// deschide fisierul in citire
fil = fopen(fil.txt, rb);
if(fil == NULL)
{
printf(fisierul nu se poate deschide\n);
return 0;
}
int xct;
// citeste un sir
xct = fread(x, 15, 1, fil);
while(xct != 0)
{
// scrie sirul pe ecran (in streamul stdout)
printf(%s\n, x);
// citeste un sir
xct = fread(x, 15, 1, fil);
}
// inchide fisierul
fclose(fil);
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
Exemplu. Vom crea un fiier binar n care vom scrie 15 blocuri de cte 10 caractere i
apoi vom citi blocurile pare. Blocurile vor conine iruri de caractere de forma
abcde
bcdef
cdefg
generate cu o expresie de forma
a + i + j
unde i i j iau valorile 0, 1, 2,
#include <stdio.h>
int main()
{
FILE * fil;
114
int i, j;
char x[10];
// deschide fisierul in creare
fil = fopen(fil, wb);
if(fil == NULL)
{
printf("fisierul nu se poate crea\n");
return 0;
}
for(i = 0; i < 15; i++)
{
// creaza un bloc
for(j = 0; j < 9; ++j)
x[j] = a + i + j;
x[9] = 0;
// scrie blocul in fisier
fwrite(x, 10, 1, fil);
// scrie sirul pe ecran (in fluxul stdout)
puts(x);
}
// inchide fisierul
fclose(fil);
// deschide fisierul in citire
fil = fopen(fil, rb);
if(fil == NULL)
{
printf("fisierul nu se poate citi\n");
return 0;
}
printf("fisierul citit\n");
// citeste sirurile pare
for(i = 0; i < 15; i += 2)
{
// pozitioneaza indicatorul fisierului in raport cu inceputul fisierului
fseek(fil, (long)(i * 10), SEEK_SET);
// citeste un sir
fread(x, 10, 1, fil);
// scrie sirul pe ecran (in fluxul stdout)
fputs(x, stdout);
fputs(\n, stdout);
}
// inchide fisierul
fclose(fil);
return 0;
}
Menionm c puteam avansa indicatorul fiierului la sfritul ciclului for cu 10 octei
n raport cu poziia curent ca mai jos
// avanseaza indicatorul fisierului cu 10 in raport cu pozitia curenta
fseek(fil, (long)(10), SEEK_CUR);
115
n loc de a-l poziiona n raport cu nceputul fiierului.
Rezultatul rulrii programului este cel de mai jos.
116
6 Structuri tip C i uniuni
6.1 Structuri
O structur este un tip de date definit de utilizator. O structur este o colecie de date
de tipuri diferite. Datele dintr-o structur vor fi numite componente sau cmpuri.
Definirea unei structuri se face cu instruciunea
struct nume {lista de declaraii de tip };
unde nume este noul tip de date.
De exemplu, urmtoarea structur poate defini tipul numere complexe
struct complex {
float real;
float imag;
};
Menionm c o structur poate conine componente de orice tip, chiar i alte
structuri.
Putem defini apoi variabile corespunznd acestui nou tip cu o instruciune de forma
struct nume list de variabile;
De exemplu, ntr-un program putem defini numerele complexe a i b astfel
struct complex a, b;
Este posibil s combinm cele dou instruciuni n una singur
struct complex {
float real;
float imag;
} a, b;
Instruciunea de definire a unei structuri i a variabilelor corespunznd acestui tip are
forma general
struct nume {liste de declaraii de tip } list de variabile;
O structur poate fi iniializat la declarare. Putem scrie
struct complex n = {1.1, -2.34};
Adresarea unui element al unei structuri se face cu operatorul . cu forma
nume.membru
Operatorul . are aceeai prioritate ca i operatorii () i [], vezi Anexa 2.
Putem da valori variabilei a definite anterior astfel :
a.real = 1.0;
a.imag = -1.2 + sin(0.3);
Putem utiliza valorile componentelor unei structuri n expresii :
float x;
x = a.real * a.imag;
Este posibil s atribuim o structur alteia, de exemplu :
struct complex a = {0.0, 1.0}, b;
b = a;
Exemplu. Vom defini o structur ce conine date despre o persoan, numele,
prenumele i vrsta. iniializm structura i scriem datele pe ecran.
117
#include <stdio.h>
#include <string.h>
struct person {
char nume[64];
char prenume[64];
int varsta;
};
int main()
{
struct person p1, p2;
strcpy(p1.nume, "popescu");
strcpy(p1.prenume, "ioan");
p1.varsta = 50;
p2 = p1;
printf("nume : %s\n", p2.nume);
printf("prenume : %s\n", p2.prenume);
printf("varsta : %d\n", p2.varsta);
return 0;
}
Rezultatul rulrii programului este prezentat mai jos.
Pentru a defini funcii ce au ca argumente sau rezultat structuri n limbajul C,
definim un nou tip de date corespunznd structurii cu instruciunea typedef.
Reamintim c, forma instruciunii typedef este
typedef tip-existent tip-nou
Pentru exemplificare vom defini (cu instruciunea typedef) un tip numit vector ce va fi
o structur ce conine dou numere reale.
# include <stdio.h>
typedef struct
{
double cmpa;
double cmpb;
} vector;
Vom construi o funcie care s adune doi vectori. Funcia va avea ca parametri dou
structuri i ca rezultat o structur. Vom declara variabile de acest tip n funcia main i
n funcia ce adun vectorii.
vector addcmp(vector x, vector y)
{
vector c;
118
c.cmpa = x.cmpa + y.cmpa;
c.cmpb = x.cmpb + y.cmpb;
return c;
}
int main()
{
vector cx, cy, cz;
cx.cmpa = 1;
cx.cmpb = 1;
cy.cmpa = 0;
cy.cmpb = 1;
cz = addcmp(cx, cy);
printf(suma este (%f , %f) \n, cz.cmpa ,cz.cmpb);
return 0;
}
La fel ca i n cazul variabilelor putem defini variabile tip pointer la o structur, ce vor
conine adresa unei structuri. Instruciunea de definire a unui pointer la o structur are
formele
struct nume * identificator;
unde nume este numele structurii sau
numetip * identificator;
dac am definit un tip de structur numetip cu instruciunea typedef. In ambele cazuri
identificator este numele variabilei tip pointer.
De exemplu,
struct complex * pc;
definete un pointer de tip struct complex. Variabila tip pointer poate fi iniializat ca
orice variabil tip pointer, folosind operatorul de calcul al adresei &
pc = &a;
In cazul unui pointer p la o structur, un cmp al structurii este adresat astfel
(*p).membru
deoarece operatorul . are preceden mai mare dect operatorul *.
Prin definiie, aceast scriere se prescurteaz ca
p->membru
Operatorii . i -> au aceeai prioritate ca operatorii () i [], vezi Anexa 2.
Exemplu. Fie instruciunile
complex y;
struct complex * py;
py = &y;
Putem iniializa structura y, utiliznd pointerul py
py->real = -23.4;
py->imag = 1.2;
Putem iniializa direct componentele structurii
y.imag = 1.24;
y.real = 0.23;
Putem utiliza valorile variabileleor definite de structura y.
float fm = pc->imag;
Sunt corecte i scrierile
(*pc).real = cos(1.23);
119
double d = (*pc).imag + (*pc).real;
Exemplu. Vom defini un tip de structur numcmp ce descrie numerele complexe cu
instruciunea typedef. Vom iniializa o variabil de acest tip i vom scrie valorile ei pe
ecran folosind un pointer la structur. Rezultatul va fi scris sub forma (real, imag).
# include <stdio.h>
typedef struct
{
float real;
float imag;
} numcmp;
int main ()
{
numcmp cr = {1.1, -1.2};
numcmp * pv;
pv = &cr;
printf("(%f , %f)\n", pv->real, pv->imag);
}
Vom prezenta un exemplu de utilizare a operatorilor de incrementare ++ n cazul
pointerilor la structuri. Fie structura
struct strx {
int c;
float d;
};
Fie o variabil tip strx i o variabil tip pointer la structura strx;
struct strx a;
struct strx * b;
Vom iniializa pe b cu adresa lui a.
b = &a;
i elementul c al structurii la valoarea zero.
b->c = 0;
Putem incrementa pe c astfel:
b->c = b-> + 1;
b->c += 1;
(*b).c += 1;
++(*b).c;
++b->c;
Operatorul ++ are o prioritate mai mic dect -> i . astfel nct ultimele expresii sunt
echivalente cu
++((*b).c);
++(b->c);
6.2 Uniuni
Uniunile conin membri ale cror tipuri individuale pot diferi unul de altul dar toi
membrii unei uniuni ocup aceeai zon de memorie. Reamintim c, n cazul
structurilor, fiecare membru ocup o zon proprie de memorie. Uniunile sunt utile n
aplicaii cu multe variabile ale cror valori nu sunt necesare simultan. Instruciunea de
definire a unei uniuni este
120
union nume {lista de declaraii de tip };
unde nume este noul tip de date. Menionm c o structur poate conine componente
de orice tip, chiar i alte structuri.
Putem defini apoi variabile corespunznd acestui nou tip cu o instruciune
union nume list de variabile;
Exemplu.
union id {
int marime;
char culoare[21];
};
Variabilele tip id se declar ca
union id v1, v2;
Putem scrie direct ca i n cazul structurilor
union id {
int marime;
char culoare[21];
} v1, v2;
O varibil tip id poate conine o mrime sau o culoare, dar nu ambele simultan.
Un membru individual al uniunii se adreseaz prin operatorii . i -> ca i n cazul
structurilor. Exemplu.
// atribuie o valoare marimii
v1.marime = 12;
printf(marime %d \n, v1.marime);
// atribuie o valoare culorii
strcpy(v1.culoare, alb);
printf(culoare %s \n, v1.culoare);
// afisaza dimensiunea uniunii
printf(dimensiunea uniunii id : %d \n, sizeof(id));
121
Partea II. Programarea orientat obiect
7 Clase
Pentru a rezolva o problem trebuie s crem un model al problemei. Procesul de
modelare se numeste abstractizare. In acest proces trebuie s definim :
datele afectate
operaiile identificate de problem.
Abstractizarea este structurarea problemei n entiti definind datele i operaiile
asociate acestor entiti. Tipurile de date abstracte pe care le definim au urmtoarele
proprieti :
definesc o structura a datelor
datele sunt accesibile prin operaii bine definite. Setul de operaii definite se
numete interfa. Operaiile interfeei sunt singurul mecanism de acces la
structura de date.
Definiiile pe care le vom utiliza sunt urmtoarele :
Clasa este o reprezentare a unui tip de date abstracte. Ea asigur detaliile de
implementare pentru structura de date i pentru operaii. Clasa definete
variabile (numite i cmpuri sau atribute sau proprieti) i funcii (numite
i metode) care implementeaz structura de date i operaiile tipului abstract.
Instanele clasei se numesc obiecte. Clasa definete deci proprietile i
comportarea unei mulimi de obiecte. Intr-o clas exist o parte de definire a
datelor i operaiilor i o parte de implementare. Partea de definire se numete
interfa.
Obiect. Un obiect este o instan a unei clase (a unui tip abstract). El este unic
identificat prin nume i definete o stare reprezentat de valorile atributelor la
un moment dat. Comportarea unui obiect este definit de metodele ce se pot
aplica asupra lui.
Mesaje. Un program este o multime de obiecte create, distruse i care
interacioneaz. Interaciunea este bazat pe mesaje trimise de la un obiect la
altul cernd destinatarului s aplice o metod asupra lui (apelarea unei functii).
Un mesaj este o cerere ctre un obiect ca el s invoce una din metodele lui.
Mesajul conine :
- numele metodei,
- argumentele metodei.
Metoda. O metoda este asociat unei clase. Un obiect invoca o metod ca
reacie la primirea unui mesaj.
Clasa este un tip de date definit de utilizator. Clasa definete variabile i funcii ce
prelucreaz aceste variabile.
Exist o notaie pentru tipurile de date abstracte pe care le definim
Nume clas
Date
Operaii
In programe crem variabile de tipul unor clase care se numesc obiecte. Vom spune
c obiectele sunt instane sau realizri ale unor clase. Obiectele unei clase sunt create
i iniializate de funcii membre ale clasei special definite pentru acest scop numite
constructori. Obiectele sunt distruse cnd nu mai sunt necesare de funcii membre ale
122
clasei numite destructori. Valorile proprietilor dau starea obiectului la un moment
dat.
Datele i funciile membre ale clasei pot fi publice, private sau protejate. Membri
publici ai clasei pot fi utilizai de orice funcie din program. Membri privai ai clasei
pot fi utilizai doar de funciile membre ale clasei. Membri protejai vor fi prezentai
ulterior. Implicit, toate datele i funciile unei clase sunt private.
Principiile programrii orientate obiect sunt urmtoarele
Primul principiu al programrii orientate obiect este ncapsularea datelor.
Acesta cere combinarea datelor i metodelor ntr-o singur structur de date.
Acest principiu asigurar ascunderea structurii de date cu ajutorul unei
interfee pentru adresarea datelor. Exemplu. Numere complexe. Un numr
complex este o pereche ordonat de numere reale. Pentru a nmuli dou
numere complexe trebuie s adresm structura i s adunm produse ale prile
reale si cele imaginare. Definind o operaie pentru nmulirea numerelor
complexe ncapsulm detaliile i nmulim dou numere complexe fr s ne
intereseze cum se face operaia n detaliu.
Motenirea. Acest principiu cere definirea unei clase generale ce conine
caracteristicile comune ale mai multor elemente. Apoi aceast clas este
motenit de alte clase particulare, fiecare adaug doar elementele proprii.
Clasa care este motenit se numete clas de baz sau superclas, iar clasele
care motenesc se numesc clase derivate sau subclase.
Polimorfismul. Avem funcii cu acelai nume n clasa de baz i n clasele
derivate. Funciile din clasele derivate redefinesc operaiile necesare claselor
derivate. Cnd apelm funcia respectiv se apeleaz versiunea
corespunztoare tipului obiectului.
7.1 Definirea unei clase
7.1.1 Definirea unei clase
Diagrama sintactic a definiiei unei clase este
Clasele sunt definite utiliznd cuvntul cheie class. identificator este numele clasei.
Specificatorii de acces sunt public, protected i private, iar membru este o declaraie
de funcie membru sau dat a clasei. Implicit toi membri clasei sunt privai.
In exemplele urmtoare vom adopta urmtoarea regul : numele claselor vor ncepe
cu litere mari, iar numele cmpurilor i metodelor cu litere mici.
Ca exemplu vom defini o clas care reprezint funcia liniar
f(x) = mx + n
pentru care vom calcula valoarea funciei ntr-un punct, funcia invers i integrala
definit. Clasa va avea o funcie print() ce afiaz parametrii m i n ai obiectului.
Reprezentarea acestei clase este cea de mai jos.
Line
123
double m;
double n;
Line (double, double);
void assign();
void value(double);
double intgrl(double, double);
void print();
void invert();
Definiia clasei este urmtoarea
/*
clasa Line descrie functia f(x) = m * x + n
*/
class Line
{
private:
double m, n;
public:
void assign(double, double);
double value(double);
double intgrl(double, double);
void print();
Line(double, double);
void invert();
};
Numele clasei este Line. Definiia clasei este inclus ntre acolade { i }, urmate de ;.
Datele, (cmpurile), membre ale clasei sunt m i n i ele vor memora constantele m i
n din funcia descris de clas. Ele sunt de tip double i sunt declarate private. In acest
fel ele vor fi accesibile doar funciilor membre ale clasei. Interzicerea accesului din
afara clasei este un principiu al programrii orientate obiect numit ncapsularea
informaiilor. Funciile membre ale clasei, (metodele) sunt assign(), ce atribuie valori
variabilelor m i n, value(), ce d valoarea funciei ntr-un punct, invert(), ce
inverseaz funcia i print(), ce scrie variabilele m i n i intgrl() ce calculeaz
integrala definit a funciei. Funcia Line() este constructor. Ea creaz obiecte i
iniializeaz variabilele acestora. Toate funciile sunt declarate publice i vor putea fi
utilizate de obiecte n afara clasei. Funciile member, (metodele), pot fi definite n
interiorul clasei sau n afara ei. Funciile definite n interiorul clasei sunt funcii inline
, compilatorul genereaz direct textul lor n program, i nu un apel la funcie.
In limbajul C++ avem posibilitatea de a grupa anumite nume n spaii de nume.
Prin definiie, datele i funciile unei clase constituie un spaiu de nume ce are
numele clasei. Operatorul de rezoluie :: arat c un nume de dat sau de funcie
aparine unui spaiu de nume. Operatorul de rezoluie :: se utilizeaz pentru a
defini o funcie membru a clasei n afara clasei.
Vom defini metodele clasei Line n afara definiiei clasei, ca mai jos :
// atribuirea de valori variabilelor m si n
void Line::assign(double a, double b)
{
124
m = a;
n = b;
}
// calculul valorii functiei in punctul x
double Line::value(double x)
{
return m * x + n;
}
// calculul integralei definite
double Line::intgrl(double a, double b)
{
return m * (b * b - a * a) / 2 + n * (b - a);
}
// scrierea parametrilor pe ecran
void Line::print()
{
cout << "functia f(x) = m * x + n, "
<< " m = " << m << " n = " << n << endl;
}
// constructor cu parametri
Line::Line(double a, double b)
{
m = a;
n = b;
}
// calculul functiei inverse
void Line::invert()
{
double temp;
temp = 1.0 / m;
m = temp;
n = - n * temp;
}
Apelul unei funcii a clasei de ctre un obiect se face conform urmtoarei diagrame
sintactice
Utilizarea unui cmp al un obiect se face conform urmtoarei diagrame sintactice
125
Declararea unui obiect se face n acelai fel cu declararea tipurilor standard.
Reamintim c un obiect este o instan a unei clase. Diagrama sintactic pentru
definirea obiectelor este cea de mai jos
La declararea unui obiect se apeleaz un constructor. Orice obiect are propriile
variabile.
Vom exemplifica utilizarea clasei definind funcia liniar x + 1i calculnd valoarea ei
n punctual 0.5, integrala de la 0 la 1 i inversa ei.
int main()
{
// creaza un obiect de tipul Line
Line a(1, 1);
a.print();
cout << "f(0.5) = " << a.value(0.5) << endl;
cout << "intgrala f(x) de la 0 la 1 = " << a.intgrl(0, 1) << endl;
cout << "functia inversa \n";
a.invert();
a.print();
return 0;
}
Pe ecran se vor afia urmtoarele
In funcia main(), x este declarat ca un obiect de tipul Line cu numele a (o instan a
clasei Line) cu instruciunea
Line a(1, 1);
El are cele dou data membre, m i n. Obiectul este creat prin apelarea constructorului
Line(double a, double b)
care iniializeaz cmpurile m i n la valorile 1 i 1.
126
Obiectul poate apela funciile membre assign(), invert() i print(), etc., care au fost
declarate publice n definiia clasei.
Acesta este un principiu al programrii orientate obiect. Nu utilizm variabile i
funcii globale, ci fiecare obiect are propriile lui date.
Menionm c n funcia main() nu putem scrie instruciunea
cout << a.m << << a.n << endl;
deoarece variabilele clasei, m i n, sunt declarate private. Ele pot fi utilizate doar de
funciile clasei i nu de obiecte de tipul clasei. Pentru a putea utiliza datele clasei de
ctre obiecte n funcia main(), ca mai sus, ele ar trebui declarate publice.
Menionm c n limbajul C++ putem defini clase i cu cuvntul cheie struct (spre
deosebire de limbajul C, unde cuvntul cheie struct definete structuri). In cazul unei
clase definite cu struct toi membrii clasei sunt doar variabile i sunt declarai implicit
ca publici.
Menionm c putem scrie definiia unei clase ntr-un fiier header i definiia funciei
main() ntr-un fiier separat care s includ definiiile claselor. De exemplu, putem
scrie definiia clasei Line n fiierul header Line.h ca mai jos.
/*
clasa Line descrie functia f(x) = m * x + n
*/
class Line
{
private:
double m, n;
public:
void print();
Line(double a, double b) : m(a), n(b) {};
Line() : m(0), n(0) {};
};
void Line::print()
{
cout << "functia f(x) = m * x + n, "
<< " m = " << m << " n = " << n << endl;
}
Scriem apoi definiia funciei main() n alt fiier surs n care includem fiierul Line.h.
In cazul fiierelor header definite de utilizator, n directiva include numele fiierului
header se scrie ntre ghilimele, ca exemplul de mai jos.
#include <iostream>
using namespace std;
#include "Line.h"
int main()
{
// creaza un vector cu obiecte de tipul Line
Line v[2];
127
v[0] = Line(1, -1);
v[1] = Line(2, -2);
int i;
for(i = 0; i < 2; i++)
v[i].print();
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
7.1.2 Pointerul this
Fie o instruciune de definire a unor obiecte de tipul Line
Line x(1, 1), y(2.5, -1) ;
Considerm instruciunile n care un obiect apeleaz o funcie membru a clasei, de
exemplu
x.assign(3, 4);
y.assign(-1, 5);
Adresarea funciilor clasei de ctre obiecte se face n felul urmtor. Fiecare obiect are
o variabil implicit numit this care este un pointer de tipul clasei ce conine adresa
obiectului. Funciile clasei au un parametru implicit, un pointer de tipul clasei. In
acest fel aceste funcii pot adresa variabilele obiectului (n cazul nostru ale obiectelor
x i y). Atunci cnd un obiect apeleaz o funcie a clasei, parametrul implicit al
funciei primete ca valoare pointerul this. Pointerul this poate fi utilizat n orice
funcie membr a clasei pentru a apela variabile sau alte funcii membre. Ca exemplu
vom rescrie funcia invert() ca s utilizeze pointerul this la apelarea variabilelor m i
n.
void Line::invert()
{
double temp;
temp = 1.0 / this->m;
m = temp;
n = - this->n * temp;
}
7.1.3 Spaii de nume
In limbajul C++ putem defini spaii de nume. Un spaiu de nume ne permite s
grupm o mulime de clase, obiecte i funcii globale sub un nume. Definiia unei
clase creaz automat un spaiu cu numele clasei ce cuprinde toate variabilele i
funciile membre ale clasei. Declararea unui spaiu de nume se face astfel
namespace identificator
{
// declaraii de clase, funcii, obiecte
}
128
De exemplu, putem defini urmtorul spaiu de nume
namespace general
{
int a, b;
}
Pentru a adresa variabilele i funciile definite ntr-un spaiu n funciile din
afara spaiului se utilizeaz operatorul de rezoluie :: Operatorul de rezoluie
are cea mai mare prioritate, vezi Anexa 2.
De exemplu, pentru a utiliza variabila a din spaiul anterior scriem
general::a
Directiva using namespace asociaz un spaiu de nume cu un anumit nivel al
programului, astfel nct obiectele i funciile din acel spaiu sunt accesibile direct ca
i cnd ar fi fost definite ca globale. Aceast directiv are forma
using namespace identificator;
Toate clasele, obiectele i funciile din bibliotecile C++ standard sunt definite n
spaiul std.
De exemplu, obiectul cout corespunztor streamului de ieire standard poate fi utilizat
astfel:
Folosind directiva using namespace
# include <iostream>
using namespace std;

cout << endl;


Utiliznd numele spaiului
# include <iostream>

std::cout << std::endl;


Putem utiliza directiva using pentru a declara doar anumite simboluri din
spaiul de nume
#include <iostream>
using std::cout;
using std::endl;
..
cout << endl;
7.2 Constructori i destructori
7.2.1 Constructori
In general, obiectele trebuie s iniializeze variabilele lor la declararea obiectului.
Pentru aceasta se definesc funcii constructor ale clasei. Un constructor este o
funcie membru a clasei apelat automat atunci cnd obiectul este declarat.
Constructorul are acelai nume cu al clasei i nu are nici un tip.
Clasa precedent avea un constructor
Line (int, int);
Deoarece constructorii au, n general, rolul de a iniializa variabilele obiectului,
limbajul are o sintax special numit list de iniializatori. Constructorul anterior se
poate scrie
129
Line::Line(int a, int b)
: m(a), n(b)
{
}
Clasele au n general urmtoarele tipuri de constructori, identificai de definiia
lor :
X(); // constructorul implicit
X(const X&); // constructorul copiere
unde X numele clasei.
Constructorul implicit nu are parametri. El este apelat ori de cte ori declarm
un obiect cu instruciunea
X obiect;
Dac nu definim niciun constructor, compilatorul definiete un constructor
implicit.
Constructorul copiere este apelat atunci cnd vrem s crem un obiect care s
aibe aceiai parametrii ca un alt obiect. De exemplu instruciunea
X a(b);
declar un obiect a de tipul X i i atribuie ca valoare obiectul b. Dac nu definim
un constructor copiere, el este definit de compilator. Menionm cuvntul cheie
const din definiia constructorului copiere. El interzice modificarea
argumentului n timpul copierii.
In consecin, orice clas are cel puin doi constructori.
Orice clas include un operator implicit de atribuire = care are ca parametru un
obiect de tipul clasei.
Exemplu. Fie din nou clasa Line n care definim un constructor copiere, un
constructor fr parametri, i un constructor cu parametri.
# include <iostream>
using namespace std;
/*
clasa Line descrie functia f(x) = m * x + n
*/
class Line
{
private:
double m, n;
public:
void assign(double, double);
double value(double);
double intgrl(double, double);
void print();
Line(double, double);
void invert();
Line();
Line(const Line&);
};
130
Vom prezenta doar definiiile constructorilor, definiiile celorlalte funcii sunt cele
anterioare.
// constructor tip copiere
Line::Line(const Line& x)
{
m = x.m;
n = x.n;
}
// constructor implicit
Line::Line()
{
m = 0;
n = 0;
}
Vom rescrie definiia clasei utiliznd lista de iniializatori n definiiile constructorilor.
/*
clasa Line descrie functia f(x) = m * x + n
*/
class Line
{
private:
double m, n;
public:
void assign(double, double);
double value(double);
double intgrl(double, double);
void print();
Line(double a, double b) : m(a), n(b) {};
void invert();
Line() : m(0), n(0) {};
Line(const Line& x) : m(x.m), n(x.n) {};
};
Un program care testeaz definiia clasei Line este cel de mai jos n care crem un
obiect x, apelm constructorul copiere pentru a crea un alt obiect y, i iniializm un
obiect z cu operatorul =.
int main()
{
Line x(12, 25);
Line z;
Line y(x); // se apeleaza constructorul copiere
x.print();
y.print();
z = x;
z.print();
}
131
Constructorul copiere este apelat ori de cte ori :
un obiect este copiat,
un obiect este transmis prin valoare unei funcii (obiectul este copiat n stiv),
un obiect este returnat ca valoare de o funcie.
Exemplu. Presupunem clasa Line definit anterior. Fie o funcie global f care are ca
parametru un obiect de tip Line i ca rezultat un obiect de tip Line, care este inversul
obiectului ce este parametrul funciei. Definitia funciei f() este urmtoarea
Line f(Line r)
{
Line s = r;
s.invert();
return s; // se apeleaza constructorul copiere
}
int main()
{
Line x(11, 22);
Line y(x); // se apeleaza constructorul copiere
Line z;
// scrie numarul x
x.print();
z = f(y); // se apeleaza constructorul copiere
// scrie numrul z
z.print();
return 0;
}
Constructorul copiere este apelat
1) atunci cnd se declar obiectul
Line y(x);
2) cnd se apeleaz funcia
z = f(y);
Parametrul funciei f (r n definiia funciei) este transmis prin valoare, deci n stiv se
pune o copie a obiectului creat cu constructorul copiere.
3) cnd se execut instruciunea
return s;
obiectul s se copiaz n stiv utiliznd constructorul copiere.
Menionm c definiia funciei f putea fi
Line f(const Line r);
deoarece funcia nu modific parametrul r.
Putem defini tablouri de obiecte n mod obinuit, de exemplu
Line x[20];
Pentru aceasta, clasa trebuie s defineasc un constructor fr parametri.
Tabloul definit poate fi prelucrat, de exemplu putem avea instruciunile
Line a(1, 2);
x[5] = a;
Exemplu. Vom crea un vector cu dou componente de tipul Line i vom afia
parametri m i n ai obiectelor.
132
# include <iostream>
using namespace std;
class Line
{
private:
double m, n;
public:
void print();
Line(double a, double b) : m(a), n(b) {};
Line() : m(0), n(0) {};
};
void Line::print()
{
cout << "functia f(x) = m * x + n, "
<< " m = " << m << " n = " << n << endl;
}
int main()
{
// creaza un vector cu obiecte de tipul Line
Line v[2];
v[0] = Line(1, -1);
v[1] = Line(2, -2);
int i;
for(i = 0; i < 2; i++)
v[i].print();
return 0;
}
Menionm c am definit un constructor fr parametri, Line(), care este apelat la
definirea vectorului de obiecte tip Line
Line v[2];
n funcia main().
7.2.2 Destructori
Destructorul unei clase este apelat automat cnd un obiect este distrus. Fiecare clas
are un singur destructor. Destructorul nu are tip i nici parametri. Diagrama sintactic
a destructorului este urmtoarea
~ nume_clasa(){/* corpul destructorului*/}
Dac el nu este definit explicit, compilatorul genereaz unul. Un obiect este creat ntr-
o funcie sau ntr-un bloc dintr-o funcie i este distrus la ieirea din funcie sau din
bloc. Blocul este orice ir de instruciuni ntre acolade, { i } din interiorul unei
funcii.
Pentru a vedea cum sunt apelai constructorii i destructorul, fie urmtoarea clas n
care constructorul i destructorul scriu un mesaj.
class Test
{
public:
133
Test() {cout << obiectul este creat << endl;}
~Test() {cout << obiectul este distrus << endl;}
};
Fie dou blocuri de instruciuni n funcia main. In fiecare bloc crem cte un obiect.
int main()
{
{
cout << intrare blocul 1 << endl;
Test x;
cout << iesire blocul 1 << endl;
}
{
cout << intrare blocul 2 << endl;
Test y;
cout << iesire blocul 2 << endl;
}
}
Mesajele scrise vor fi:
Menionm c toate variabilele locale unei funcii sau unui bloc sunt create intr-o stiv
la intrarea n funcie sau bloc i sunt terse din stiv la ieirea din funcie sau bloc.
7.3 Funcii prietene
In general avem nevoie s utilizm i s modificm datele (cmpurile) unui obiect n
timpul execuiei programului. Dac datele sunt declarate private, nu putem face acest
lucru direct. Exist dou moduri de a rezolva aceast problem.
In prima metod se definesc funcii care s modifice i s furnizeze valorile datelor
unui obiect. In cazul clasei Line putem defini funcii membre ale clasei care
furnizeaz parametrii m i n :
double getm();
double getn();
i funcii care modific aceti parametric :
void setm(double);
void setn(double);
Aceste funcii se numesc funcii de acces i sunt de regul publice.
Definiiile funciilor getm() i setm() pot fi:
134
double Line::getm()
{
return m;
}
void Line::setm(double x)
{
m = x;
}
Exemplu. Vom defini o funcie global care s adune dou funcii liniare. Prototipul
funciei va fi
Line sum(const Line x, const Line y);
Parametrii x i y sunt cele dou funcii liniare ce sunt adunate. Deoarece obiectele nu
vor fi modificate, ele au fost declarate const.
Considerm dou funcii liniare,
1 1 1
) ( n x m x f + i
2 2 2
) ( n x m x f + . Suma lor va fi
funcia ) ( ) ( ) (
2 1 2 1
n n x m m x f + + + . In implementarea funciei nu putem folosi
direct variabilele m i n, deoarece ele sunt declarate private n definiia funciei. Vom
utiliza funciile getm() i getn() pentru a obine valoarea lor. Implementarea funciei
este urmtoarea
Line sum(Line x, Line y)
{
double a = x.getm();
double b = x.getn();
double c = y.getm();
double d = y.getn();
Line temp(a + c, b + d);
return temp;
}
O alt soluie este urmtoarea. Pentru ca o funcie extern s aibe acces la membri
privai ai clasei, ea trebuie declarat n definiia clasei ca funcie prieten, friend.
Diagrama sintactic a definiiei unei funcii prietene este
friend tip nume_funcie ( parametri);
Noua definiie a clasei Line este urmtoarea.
class Line
{
public:
Line (double, double);
Line (const Line & x);
Line ();
void assign(double, double);
double value(double);
double intgrl(double, double);
void print();
void invert();
friend Line sum(const Line x, const Line y);
private:
135
double m;
double n;
};
In aceast definiie funcia sum a fost declarat prieten, deci poate utiliza variabilele
private ale clasei. Implementarea funciei sum este urmtoarea
Line sum(const Line x, const Line y)
{
Line temp(x.m + y.m, x.n + y.n);
return temp;
}
Un program care testeaz funcia sum este cel de mai jos.
int main()
{
Line a(1.5, 2.3);
a.print();
Line b(2.2, -1.5);
b.print();
Line c;
c = sum(a, b);
c.print();
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
7.4 Determinarea tipului unei expresii
Limbajul C++ are operatorul typeid ce permite determinarea tipului unei expresii.
Forma operatorului este
typeid(expresie)
Operatorul typeid are ca rezultat o referin la un obiect constant de tipul type_info.
Clasa type_info este o clas predefinit a limbajului, definit n fiierul antet
<typeinfo>. Clasa definete metoda
const char * name();
care are ca rezultat un ir de caractere cu numele tipului expresiei i operatorii == i !
= cu care putem compara tipurile a dou expresii.
Exemplu. Vom determina tipul expresiilor aritmetice i booleene i tipul unui pointer
i al unei referine cu programul de mai jos.
#include <iostream>
136
#include <typeinfo>
using namespace std;
int main(int argc, char *argv[])
{
int a, b;
char c;
double x, y;
bool bl;
float f1, f2;
int * ptra;
int& ra = a;

cout << typeid(a + b).name() << endl;
cout << typeid(x + y).name() << endl;
cout << typeid(f1 + f2).name() << endl;
cout << typeid(c).name() << endl;
cout << typeid(bl).name() << endl;
cout << typeid(ptra).name() << endl;
cout << typeid(ra).name() << endl;
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
In program se include biblioteca <typeinfo> ce definete clasa type_info . Expresia
typeid(a + b)
are ca rezultat o referin la un obiect constant de tipul type_info. In consecin,
expresia
typeid(a + b).name()
apeleaz metoda name() a acestui obiect, care are ca rezultat un ir de caractere cu
numele tipului expresiei, i pentru int, d pentru double, etc.
Operatorul typeid poate avea ca parametru un obiect de un tip oarecare.
Exemplu. Fie clasa Line definit mai sus. Programul urmtor determin tipul unui
obiect de tipul Line i al unui poiner la un obiect de tip Line. Definiia clasei Line nu
este artat.
#include <iostream>
#include <typeinfo>
using namespace std;
137
int main(int argc, char *argv[])
{
Line a(1, 2);
Line * ptrln = new Line(-1, 2);
cout << typeid(a).name() << endl;
cout << typeid(ptrln).name() << endl;
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
Programul afiaz tipul unui obiect Line i tipul unei variabile pointer de tip Line.
138
8 Siruri tip C++
8.1 Clasa string
Limbajul C++ definete clasa string pentru lucrul cu iruri. Spre deosebire de irurile
tip C care sunt terminate printr-un octet cu valoarea zero, obiectele acestei clase au un
cmp ce conine lungimea irului. Clasa string este definit n fiierul header
<string>. Clasa are urmtorii constructori:
constructorul implicit care creaz un ir vid
string();
constructor copiere cu argument ir tip C sau ir tip string
string(const string&);
string(const char *);
Operatorul = are ca argument drept un ir tip C sau ir tip string.
Exemple de definiri de obiecte tip string
string x = "abcd";
string y(x);
string z = x;
string x1("abc");
Clasa implementeaz operatorii + i += (concatenarea irurilor).
Exemple.
string a = x + xyz;
a += abc;
Clasa definete operatori de comparare ai irurilor, <, <=, >, >= , = = i != ce au ca
rezultat valorile true sau false.
Operatorii << i >> scriu i citesc iruri tip string.
Exemple.
if(x < x1)
cout << x1;
else
cout << x;
Funcii membre importante ale clasei sunt :
int length(); d lungimea irului tip string,
int size(); d lungimea irului tip string,
const char * c_str(); - convertete irul ntr-un ir tip C,
bool empty(); - are valoarea true dac irul este vid.
Exemplu. S copiem un ir C++ ntr-un ir tip C.
char c[100];
string str(abcd);
strcpy(c, str.c_str());
Clasa are operatorul de selecie [] ce poate selecta un caracter din ir sau poate atribui
o valoare unui caracter din ir. Indicele primului caracter din ir este 0.
Exemplu. S scriem un ir, caracter cu caracter.
string s = abcd;
for(j = 0; j < s.length(); j++)
cout << s[j];
Vom prezenta acum funcii de cutare de subiruri i de modificare a irurilor.
Fie un obiect tip string.
funcia find() cu prototipul
139
int find(char * substring);
d indicele primei apariii a irului substring n irul respectiv. Dac irul substring nu
exist n ir funcia are ca rezultat lungimea irului.
Exemple. Fie irul
string str = abcdefg;
Instruciunea
cout << str.find(cd) << endl;
afiaz valoarea 2. (indicele caracterului c este 2). Instruciunea
cout << str.find(xyz) << endl;
afiaz valoarea 7 (lungimea irului).
funcia erase() cu prototipul
erase(int index, int size)
terge size caractere ncepnd cu caracterul cu indicele index.
Exemplu. Fie irul
string str = ABCD*FGHIJK;
Instruciunea
str.erase(4, 2);
terge dou caractere ncepnd cu caracterul * ce are indicele 4. Noul ir este
ABCDGHIJK
funcia replace() nlocuiete un subir cu altul. Ea are prototipurile :
replace(int index, int size, char * sir);
replace(int index, int size, string sir);
i nlocuiete subirul de lungime size ce ncepe cu caracterul index cu subirul sir.
Exemple. Fie irul
string str = ABCDGHIJK;
Instruciunea
str.replace(5, 2, xyz);
nlocuiete subirul HI cu subirul xyz. Noul ir este
ABCDGxyzJK
Fie irul
string s2 = abc;
Instruciunea
str.replace(5, 3, s2);
nlocuiete subirul xyz cu irul abc. Noul ir este
ABCDGabcJK
funcia substr() cu prototipul
string substr(int index, int size);
creaz un ir tip string din subirul de lungime size ce ncepe cu caracterul index.
Exemplu. Fie instruciunile
string x = abcxyz;
string z = x.substr(3, 2);
A doua instruciune creaz irul tip string z
xy
funcia insert() cu prototipul
insert( int index, string str) ;
insereaz irul str ncepnd cu indexul index.
funcia append() adaug un ir la sfritul irului curent. Ea are prototipurile:
append(const string& str);
append(const char* str);
append(const string& str, int index, int size);
140
Primele dou funcii adaug irul str la sfritul irului. A treia funcie adaug la
sfritul irului caracterele irul str de lungime size ncepnd cu indicele index.
Trebuie s avem ndeplinit condiia
index <= size
Exemplu. Fie un obiect tip string ce conine irul "abc". Se va aduga la sfritul lui
irul "xyz". Fie apoi un obiect tip string ce conine irul "xyz". Se va aduga la
sfritul lui irul "abc", ncepnd odat de la indicele 1 i alt dat de la indicele 2.
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
string a("abc");
a.append("xyz");
cout << a << endl;
string b = "xyz";
b.append("abc", 1, 3);
cout << b << endl;
b = "xyz";
b.append("abc", 2, 3);
cout << b << endl;
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
Adugnd irul abc ncepnd cu indicele 1 se obine irul xyzbc, adugnd irul
abc ncepnd cu indicele 2 se obine irul xyzc.
Exemplu. Fir irurile
string x = abcd, y = xyz;
Instruciunea
x.insert(1, y) ;
modific irul x la axyzbcd ;
Pentru citirea unui ir de caractere dintr-un fiier ntr-un obiect tip string, este definit
funcia global getline cu prototipurile :
getline(stream, string& str, char delim);
getline(stream, string& str);
Funcia citete caractere din stream n obiectul str pn la ntlnirea caracterului delim
(prima variant) sau pn la ntlnirea caracterului \n (a doua variant). In acest fel
este posibil citirea unei linii dintr-un fiier tip text.
Exemplu. Instruciunile
string s;
141
getline(cin, str);
produc citirea unei linii de caractere din fiierul de intrare cin.
Un program ce exemplific utilizarea funciei insert este cel de mai jos care insereaz
repetat un ir inaintea unui ir dat.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str1 = "abcdg";
string str2 = "xy";
cout << str1 << endl;
str1.insert(0, str2);
cout << str1 << endl;
str1.insert(2, str2);
cout << str1 << endl;
str1.insert(2, "123");
cout << str1 << endl;
return 0;
}
Rezultatul rulrii programului este cel de mai jos.
142
9 Suprancrcarea operatorilor
Operatorii limbajului C++ sunt predefinii pentru tipurile fundamentale: int, double,
char, etc. Cnd definim o clas nou, crem un nou tip. Operatorii limbajului pot fi
definii i pentru tipurile nou create. Aceast operaie se numete suprancrcarea
operatorilor (operator overloading). Pentru a suprancarca un operator definim o
functie de forma
tip operator semn (parametri) {/* corpul funciei */}
unde semn este operatorul dorit +,-, *, / , [], (), <<, >>, =, etc. Operatorii
suprancrcai au aceeai prioritate ca cei originali i acelai numr de parametri.
Menionm c orice operator suprancrcat poate fi definit ca funcie membr a clasei
sau ca funcie global.
Exemplu. S suprancrcm operatorul + pentru clasa Line, care s adune dou funcii
liniare. Operatorul ce va fi definit ca o funcie global este urmtorul.
Line operator+( Line x, Line y)
{
double a = x.getm();
double b = x.getn();
double c = y.getm();
double d = y.getn();
Line temp(a + c, b + d);
return temp;
}
A se compara aceast funcie cu funcia sum definit anterior. Funcia are doi
parametri, funciile de adunat, deoarece este o funcie global. Putem utiliza funcia
definit astfel
int main()
{
Line x(2, 3), y(3, -5), z;
z = x + y;
z.print();
return 0;
}
Putem defini operatorul ca funcie prieten a clasei. In definiia clasei vom scrie
instruciunea
friend Line operator+ (Line, Line);
In acest caz definiia funciei este
Line operator+( Line x, Line y)
{
Line temp(x.m + y.m, x.n + y.n);
return temp;
}
143
Al doilea mod de a defini operatorul + este ca funcie membr a clasei. O funcie
membr a clasei este apelat de un obiect. Fie a, b, c obiecte de tip Line. Putem scrie
c = a.operator+(b);
sau, echivalent
c = a + b;
De accea, atunci cnd operatorul este o funcie membr a clasei, funcia
corespunztoare are un singur parametru, operandul drept, i este apelat de operandul
stng. Definiia clasei Line cu operatorul + este
class Line
{
public:
Line (int, int);
Line (const Line & x);
Line ();
void print();
void invert();
Line operator+( Line); // functia are un singur parametru
private:
double m;
double n;
};
Implementarea funciei este
Line Line::operator+( Line x)
{
Line temp(m + x.m, n + x.n);
return temp;
}
Exemplu. Fie instruciunea
Line a(1, 3), b(4, -3), c;
Instruciunile
c = a + b;
i
c = a.operator+(b);
sunt echivalente.
9.1 Suprancrcarea operatorului de atribuire
Considerm clasa definit anterior n care definim constructorul implicit,
constructorul copiere i operatorul de atribuire. Menionm c operatorul de atribuire
este automat definit pentru orice clas. Suprancrcarea lui aici este doar un exerciiu.
O definiie incorect a operatorului de atribuire este urmtoarea
# include <iostream>
using namespace std;
class Line
{
144
private:
double m, n;
public:
Line ();
Line (const Line &);
void operator = (const Line &);
};
O implementare a definiiei incorecte a operatorului de atribuire suprancrcat este
urmtoarea
void Line::operator = (const Line & r)
{
m = r.m;
n = r.n;
}
Ea copiaz obiectul r n obiectul ce apeleaz operatorul. Fie de exemplu instruciunea
Line x, y, z;
Cu aceast definiie putem scrie
x = z;
y = z;
dar nu putem scrie
x = y = z;
deoarece rezultatul funciei este void.
Pentru a vedea care este definiia corect a operatorului de atribuire considerm
instruciunea
int x, y, z = 2;
Limbajul permite o instruciune de atribuire multipl de forma
x = y = z = 2;
Operatorul = este asociativ la dreapta i are ca rezultat valoarea atribuit operandului
stng. Prima dat se execut instruciunea
z = 2;
apoi
y = z;
etc. Simboliznd operatorul = cu o funcie f cu dou argumente, putem scrie
instruciunea de atribuire multipl de mai sus
f(x, f(y, f(z, 2)));
In consecin, operatorul de atribuire = trebuie s aibe ca rezultat o referin de acelai
tip cu valoarea pe care o atribuie operandului stng (tipul operandului stng). In acest
fel operatorul este asociativ la dreapta. Definiia corect a operatorului de atribuire
al clasei Line este
Line & operator = (const Line & );
Definiia clasei va fi
class Line
{
private:
double m, n;
public:
145
Line o();
Line o(const Line o&);
Line & operator = (const Line &);
};
Prototipul operatorului de atribuire al unei clase T este
T& operator = (const T&);
Operatorul are ca rezultat o referin la obiectul ce apeleaz operatorul. Pentru aceasta
se utilizeaz pointerul this. Implementarea corect a operatorului de atribuire
suprancrcat este urmtoarea.
Line & Line::operator = (const Line & r)
{
// obiectul ce a apelat operatorul primeste valoarea obiectului r
m = r.m;
n = r.n;
// rezultatul funciei este referinta obiectului ce a apelat operatorul
return *this;
}
Putem scrie acum instruciunile
Line x, y, z(2, 3);
x = y = z;
9.2 Suprancrcarea operatorilor aritmetici
Limbajul ne d posibilitatea de a defini funcii care s efectueze operaiile standard
+,-, etc., pentru operanzi ce sunt obiecte ale unor clase (operator overloading). Un
operator poate fi definit ca o funcie global sau ca o funcie membru a clasei. Vom
exemplifica suprancrcarea operatorului + pentru o clas ce descrie numere
complexe. Clasa va defini dou varibile de tip float, real i imag, pentru partea real i
cea imaginar a numrului complex i doi constructori, constructorul implicit fr
parametri i un constructor care s iniializeze variabilele real i imag. O reprezentare
a clasei este cea de mai jos.
Complex
float real;
float imag;
Complex ();
Complex (float, float);
Vom exemplifica pentru nceput suprancrcarea operatorului + pentru clasa Complex
n cazul n cazul n care operatorul este o funcie global. Funcia are numele
operator+ i doi parametri de tip Complex, numerele complexe ce se adun. Tipul
funciei este Complex. Definiia funciei este
Complex operator+(Complex, Complex);
Definiia clasei Complex este cea de mai jos.
class Complex
{
private:
float real;
146
float imag;
public:
Complex();
Complex (float, float);
};
Problema scrierii funciei este aceea c datele clasei Complex sunt declarate private i
nu pot fi utilizate direct de funcie, care este global. La fel ca ntr-un capitol anterior,
o soluie este de a scrie dou funcii de acces membre ale clasei, de exemplu :
float getreal();
float getimag();
care au ca rezultat variabilele real i imag ale clasei. Aceast soluie rmne ca
exerciiu. O alt soluie este urmtoarea. Pentru ca o funcie extern s aibe acces la
membrii privai ai clasei, ea trebuie declarat n definiia clasei ca funcie
prieten, friend. Definiia unei funcii prietene este
friend tip nume_funcie ( parametri);
In consecin, definiia clasei Complex va fi
class Complex
{
private:
float real;
float imag;
public:
Complex();
Complex (float, float);
friend Complex operator+(Complex &, Complex &);
};
Definiia funciei va fi cea de mai jos.
Complex operator+(Complex& x, Complex& y)
{
Complex temp;
temp.real = x.real + y.real;
temp.imag = x.imag + y.imag;
return temp;
}
Trebuie ca n definiia clasei s includem un constructor implicit, fr parametri
Complex();
Constructorul implicit este apelat la declararea obiectului temp
Complex temp;
n funcia operator+. Constructorul implicit nu mai este generat automat de compilator
deoarece am definit un constructor.
Vom exemplifica acum suprancrcarea operatorului + pentru clasa Complex n cazul
n care operatorul este definit ca o funcie membr a clasei. Numele funciei este
operator+. O funcie membru a clasei este apelat de un obiect. In consecin, vom
scrie
c = a.operator+(b);
147
sau, echivalent
c = a + b;
De accea, atunci cnd operatorul este o funcie membr a clasei, funcia
corespunztoare are un singur parametru, operandul drept, i este apelat de operandul
stng. Fie definiia clasei Complex n care definim i funcia operator+ ca funcie
membr
class Complex
{
private:
float real;
float imag;
public:
Complex();
Complex (float, float);
Complex operator+ (Complex);
};
Implementarea constructorilor este
Complex::Complex(float x, float y)
{
real = x;
imag = y;
}
Complex::Complex()
{
real = 0;
imag = 0;
}
Implementarea operatorul + este urmtoarea
Complex Complex::operator+(Complex p)
{
Complex temp;
temp.real = real + p.real;
temp.imag = imag + p.imag;
return temp;
}
Exerciiu. S se scrie implementarea operatorilor de scdere, -, nmulire, * i
mprire, / a dou numere complexe.
9.3 Suprancrcarea operatorilor << i >>
Operatorul << este numit operator de inserie, el insereaza caractere ntr-un stream.
Operatorul >> este numit operator de extracie, el extrage caractere dintr-un stream.
Toate funciile de inserie au forma
148
ostream& operator << (ostream& stream, tip obiect)
{
// corpul functiei
return stream;
}
Primul parametru este o referin la streamul de ieire. Al doilea este obiectul ce
trebuie inserat. Ultima instruciune este
return stream;
Exemplu. Suprancrcarea operatorului de inserie << pentru clasa Complex. In
definiia clasei definim funcia
friend ostream& operator << (ostream& stream, Complex x);
Implementarea funciei este
ostream& operator << (ostream& stream, Complex x)
{
stream << "(" << x.real << "," << x.imag << ")";
return stream;
}
Exemplu. Operatorul de extracie >> pentru clasa Complex este suprancrcat astfel
friend istream& operator >> (istream& stream, Complex& x);
Implementarea lui este urmtoarea
istream& operator >> (istream& stream, Complex& x)
{
stream >> x.real >> x.imag;
return stream;
}
Cnd un operator este membru al unei clase, operandul stng (transmis prin this) este
cel care apeleaza operatorul. Operatorii << i >> pe care i-am definit nu pot fi membri
ai clasei deoarece operandul stng ostream, respectiv istream, nu sunt un membri ai
clasei. In consecin, aceti operatori vor fi funcii externe. Reamintim c, pentru ca
o funcie extern s aibe acces la membrii privai ai clasei, ea trebuie declarat n
definiia clasei ca funcie prieten friend. Definiia unei funcii prietene este, cum s-
a arat mai nainte
friend tip nume_funcie ( parametri);
Cu aceasta, definiia clasei Complex este
class Complex
{
private:
float real;
float imag;
public:
Complex();
Complex (float, float);
Complex operator+ (Complex);
friend ostream& operator << (ostream&, Complex&);
149
friend istream& operator >> (istream&, Complex&);
};
Definiia funciilor mrmbre ale clasei este cea de mai sus.
Putem utiliza operatorii definii astfel
int main()
{
Complex a(1.0, 1.0);
Complex b(0.0, 1.0);
Complex c;
c = a + b;
// echivalent putem scrie
// c = a.operator+(b);
cout << a = << a << endl;
cout << b = << b << endl;
cout << c = << c << endl;
return 0;
}
Rezultatul programului este cel de mai jos.
Reamintim c, trebuie ca n definiia clasei s includem un constructor implicit, fr
parametri, de exemplu cu definiia
Complex() {real = 0; imag = 0;}
Constructorul implicit nu mai este generat automat de compilator deoarece am definit
un constructor. Constructorul implicit este apelat la declararea obiectului temp
Complex temp;
n funcia operator+ i a obiectului c n funcia main().
Complex c;
Acest constructor iniializeaz variabilele obiectului la valoarea 0.
Reamintim c orice clas include un operator implicit de atribuire = care are ca
parametru un obiect de tipul clasei.
150
10 Motenirea
10.1 Pointeri la obiecte. Operatorii new i delete
O clas, odat definit, este un tip de date valid. Putem defini variabile pointer de
tipul clasei la fel cu pointeri la orice tip. O variabil tip pointer la o clas poate fi
iniializat cu adresa unui obiect de tipul clasei, iar datele i funciile acelui obiect pot
apelate utiliznd pointerul.
Instruciunea de definire a unui pointer la o clas este
tip * identificator;
unde tip este numele clasei, iar identificator este numele variabilei tip pointer.
Variabila tip pointer poate fi iniializat, ca orice variabil tip pointer, folosind
operatorul de calcul al adresei &.
Fie p un pointer la un obiect. Un cmp al obiectului este adresat astfel
(*p).membru
Prin definiie, aceast scriere se prescurteaz
p->membru
O funcie membr a clasei se apeleaz astfel
(*p).funcie(parametri);
Prin definiie, aceast scriere se prescurteaz astfel
p->funcie(parametri);
Operatorii . i -> au aceeai prioritate ca operatorii () i [].
Exemplu. Vom considera din nou definiia clasei Line care reprezint funcia liniar
f(x) = mx + n
Clasa definete variabilele m i n, un constructor ce iniializeaz variabilele i dou
funcii, value(), ce calculeaz valoarea funciei ntr-un punct i print(), ce scrie pe
ecran valorile variabilelor.
Line
double m;
double n;
Line (double, double);
void value(double);
void print();
Definiia clasei Line este urmtoarea
/*
clasa Line descrie functia f(x) = m * x + n
*/
class Line
{
private:
double m, n;
public:
double value(double x) {return (m * x + n) ;}
void print(){
cout << "functia f(x) = m * x + n, " <<
" m = " << m << " n = " << n << endl;
151
}
Line(double x, double y) {m = x; n = y;};
};
Vom apela funciile clasei Line direct i prin pointer.
int main()
{
Line d(1, 0);
double a = 1.5;
// defineste un pointer la obiect
Line * pl;
pl = &d;
// apeleaza functiile prin pointer
pl->print();
cout << "f(" << a << ")= " << pl->value(a) << endl;
// apeleaza functiile direct
d.print();
cout << "f(" << a << ")= " << d.value(a) << endl;
return 0;
}
Datele afiate pe ecran vor fi
functia f(x) = m * x + n, m = 1, n = 0
f(1.5) = 1.5
f(1.5) = 1.5
Exist trei moduri de a crea obiecte :
obiecte globale declarate la nivelul programului, n afara oricrei funcii. Ele
sunt create la nceputul execuiei programului i distruse la sfritul execuiei,
obiecte locale, declarate n funcii sau n blocuri din funcii, ntre { i } Ele
sunt create la intrarea n bloc i distruse la ieirea din bloc,
obiecte create n memorie cu operatorul new. Ele trebuie distruse cu
operatorul delete cnd nu mai sunt necesare. Ele sunt create ntr-o zon
special de memorie denumit heap.
Operatorul new creaz un obiect n memorie apelnd constructorul i furnizeaz
adresa obiectului nou creat, adic un pointer. Forma operatorului new este
ptr = new tip (list de parametri);
tip este numele unei clase, iar ptr este variabil tip pointer de tipul clasei. Operatorul
delete are forma
delete ptr;
unde ptr este variabila tip pointer cu adresa obiectului.
Exemplu. Vom considera aceeai clas Line, vom crea un obiect corespunznd
funciei
f(x) = x
cu operatorul new i vom calcula f(1.5). Funcia main() corespunztoare este cea de
mai jos.
int main()
{
// defineste un pointer la obiect
Line * pl;
152
// creaza un obiect cu operatorul new
pl = new Line (1, 0);
double a = 1.5;
// apeleaza functiile prin pointer
pl->print();
cout << "f(" << a << ")= " << pl->value(a) << endl;
// distruge obiectul
delete pl;
return 0;
}
In programul de mai sus puteam scrie
Line *pl = new Line(1, 0) ;
Putem crea vectori de obiecte cu operatorul new. Pentru aceasta, clasa trebuie s aib
un constructor fr parametri. De exemplu, putem crea un vector cu zece obiecte de
tip Line
Line * vect;
vect = new Line[10];
Acest vector se terge cu operatorul delete cu forma
delete [] vect;
Exemplu. Vom crea vectori cu 2 componente cu obiecte tip Line i vom afia pe ecran
parametrii obiectelor create. Fie pentru nceput definiia clasei Line.
# include <iostream>
using namespace std;
class Line
{
private:
double m, n;
public:
void print();
Line(double a, double b) : m(a), n(b) {};
Line() : m(0), n(0) {};
};
void Line::print()
{
cout << "functia f(x) = m * x + n, "
<< " m = " << m << " n = " << n << endl;
}
Pentru nceput definim un vector de pointeri, pv[2] de tipul Line :
Line * pv[2] ;
Componentele vectorului pv sunt iniializate cu adresele unor obiecte create cu
operatorul new
pv[0] = new Line(-1, 1) ;
pv[1] = new Line(-2, 2) ;
Apelarea funciei print() se face conform definiiei de mai sus. De exemplu, adresa
primului obiect, indicat de componentul pv[0] al vectorului pv, este *pv[0], deci
funcia print() se apeleaz
(*pv[0]).print();
153
sau, echivalent
pv[0]->print();
Definim apoi o variabil pointer de tip Line, pvx. Ea este iniializat cu adresa unui
vector ce conine obiecte de tipul Line :
Line * pvx = new Line[2];
Menionm c, n acest caz, este apelat constructorul fr parametri al clasei. In acest
vector memorm nite obiecte de tip Line :
pvx[0] = Line(1, -1) ;
pvx[1] = Line(2, -2) ;
Apelarea funciei print() se face astfel. Obiectul din al doilea component alvectorului
pvx este pvx[1] sau *(pvx + 1), deci funcia print() se apeleaz
(pvx[1]).print();
sau
(*(pvx + 1)).print();
sau, conform celor dintr-un capitol anterior
(pvx + 1)->print();
Obiectul pvx este ters n final cu instruciunea
delete []
Programul este urmtorul
int main()
{
int i;
Line * pv[2];
pv[0] = new Line(-1, 1);
pv[1] = new Line(-2, 2);
// scrie obiectele
for(i = 0; i < 2; i++)
(*pv[i]).print();
// pv[i]->print();
Line * pvx = new Line[2];
pvx[0] = Line(1, -1);
pvx[1] = Line(2, -2);
// scrie obiectele
for(i = 0; i < 2; i++)
(*(pvx + i)).print();
// (pvx[i]).print();
// (pvx + i)->print();
delete [] pvx;
return 0;
}
Rezultatul apelrii programului este cel de mai jos.
154
10.2 Motenirea
Motenirea este un concept al programrii cu obiecte. Motenirea permite s
crem clase care sunt derivate din alte clase existente. Clasa care este motenit
se numete clas de baz sau superclas, iar clasele care motenesc se numesc
clase derivate sau subclase. Clasa derivat motenete membrii clasei de baz,
funcii i variabile. In acest fel, putem construi programe complexe din obiecte
simple. Clasa de baz conine caracteristicile comune ale mai multor elemente.
Clasele care motenesc sunt clase particulare ce adaug doar elementele proprii.
Cu ajutorul motenirii reutilizm clase deja construite.
10.2.1 Definirea unei clase derivate
Forma definiiei unei clase derivate este
class nume_clasa_derivata : acces nume_clasa_baza
{
// definitia clasei derivate
};
In aceast definiie, cuvntul cheie acces poate fi public, protected sau private. In
primele exemple, vom utiliza acces public, care are semnificaia c, membrii publici
ai clasei de baz, funcii i variabile, sunt membrii publici i n clasa derivat.
Exemplu. Vom defini o clas numit Baza ce definete dou variabile tip double a i
b, un constructor cu parametri ce iniializeaz variabilele a i b i o funcie print() ce
afiaz valorile variabilelor a i b sub forma (a, b).
Baza
double a;
double b;
Baza (double, double);
void print();
Definiia clasei Baza este urmtoarea
# include <iostream>
# include <cmath>
using namespace std;
class Baza
{
protected:
double a, b;
public:
Baza(double x, double y) {a = x; b = y;}
void print() {cout << "(" << a << "," << b << ")" << endl;}
};
Variabilele clasei Baza au specificatorul de acces protected. Semnificaia lui este
aceea c variabilele a i b pot fi utilizate n clasele derivate.
Vom defini dou clase ce descriu triunghiuri i respectiv numere complexe, ce
motenesc clasa Baza, conform diagramei de mai jos.
155
Baza
double a;
double b;
Baza (double,
double);
void print();
Triunghi
double aria() ;
void print() ;
Triunghi(double, double) ;
In clasa Triunghi, a va fi baza, iar b nlimea. Clasa Triunghi definete o funcie
aria() ce calculeaz aria triunghiului, o funcie print() ce scrie valorile bazei i
nlimii i un constructor cu parametri. Definiia acestei clase este cea de mai jos.
class Triunghi : public Baza
{
public:
double aria() {return a * b / 2;}
void print(){cout << "(baza, inaltimea) = "; Baza::print(); }
Triunghi(double x, double y) : Baza(x, y) {}
};
Funcia print() a clasei Triunghi apeleaz funcia print() a clasei de baz pentru a scrie
valorile a i b. Apelarea funciei print() din clasa de baz se face cu operatorul de
rezoluie ::
Baza ::print() ;
deoarece simpla apelare cu instruciune print() ar fi nsemnat apelare recursiv a
funciei print() din clasa Triunghi. Constructorul clasei Triunghi apeleaz
constructorul clasei Baza pentru a iniializa variabilele a i b.
In clasa Complex, a i b vor fi partea real i partea imaginar a numrului complex.
Clasa Complex definete o funcie abs() ce calculeaz modulul numrului complex, o
funcie print() ce scrie numrul complex i un constructor cu parametri.
class Complex : public Baza
{
public:
double abs() {return sqrt(a * a + b * b);}
void print() {cout << "(u, v) = "; Baza::print();}
Complex(double x, double y) : Baza(x, y) {}
};
Complex
double abs() ;
void print() ;
Complex(double, double) ;
156
Pentru a scrie numrul complex, funcia print() a clasei Complex apeleaz funcia
print() a clasei de baz cu operatorul de rezoluie ca mai sus. Constructorul clasei
Complex apeleaz constructorul clasei Baza pentru a iniializa variabilele a i b.
Pentru a utiliza clasele derivate de mai sus, crem un triunghi i i calculm aria, apoi
definim un numr complex i i calculm modulul.
int main()
{
Triunghi trg(2.5, 1);
Complex c(1, 1);
trg.print();
cout << "aria = " << trg.aria() << endl;
c.print();
cout << "|(u, v)| = " <<c.abs() << endl;
return 0;
}
Rezultate afiate sunt cele de mai jos.
Reamintim c am definit variabilele clasei de baz h i b de tipul protected.
Datele i funciile declarate protected n clasa de baz pot fi utilizate n clasele
derivate, dar nu pot fi utilizate de obiecte.
De exemplu, nu putem scrie n funcia main() instruciunea
cout << trg.a << endl;
Din acest motiv, pentru a afia valorile variabilelor a i b am definit funcia print().
Datele i funciile declarate private n clasa de baz nu pot fi utilizate n clasele
derivate sau de obiecte de tipul claselor derivate.
10.2.2 Specificatorii de acces
Vom prezenta acum semnificaia cuvntului cheie acces din definiia clasei derivate.
In definiia unei clase, specificatorii de acces sunt : public, private i protected.
Semnificaia lor este urmtoarea :
membrii privai ai clasei pot fi utilizai doar n interiorul clasei,
menbrii protejai ai clasei pot fi utilizai i n clasele derivate,
membrii publici ai clasei pot fi utilizai i n afara clasei, n clasele derivate i
n obiectele de tipul clasei sau al claselor derivate.
Clasa derivat motenete membrii publici i pretejai ai clasei de baz.
Membrii publici i protejai ai clasei de baz apar ca i cum ar fi declarai n
clasa derivat.
Fie definiia unei clase numit Baza
class Baza
{
157
public:
int x;
protected:
int y;
private :
int v ;
} ;
Variabila x poate fi utilizat n clasa Baza, n clasele derivate i n obiecte de tipul
clasei Baza sau derivate. Variabila y poate fi utilizat n clasa Baza i in clasele
derivate, dar nu n obiecte de tipul clasei Baza sau clase derivate. Variabila v poate fi
utilizat doar n interiorul clasei Baza.
Considerm acum specificatorul de acces din definiia clasei derivate
public spune c toi membrii publici i protejai ai clasei de baz sunt motenii
n clasa derivat ca membrii publici sau protejai,
protected spune c toi membrii publici i protejai ai clasei de baz sunt
motenii n clasa derivat ca membrii protejai,
private spune c toi membrii publici i protejai ai clasei de baz sunt
motenii n clasa derivat ca membrii privai.
Specificatorul de acces din definiia clasei derivate d nivelul minim de acces pentru
membrii motenii din clasa de baz. La utilizarea specificatorului de acces public,
clasa derivat motenete toi membrii clasei de baz cu nivelul de acces avut n clasa
de baz.
Putem sumariza acum specificatorul de acces al variabilelor unui obiect n funcie de
specificatorii lor n clasa de baz i specificatorul din definiia clasei derivate.
specificatorul de acces n
definiia clasei derivate
specificatorul de acces al variabilei n
clasa de baz
public protected private
public public protected acces interzis
protected protected protected acces interzis
private private private acces interzis
Putem sumariza acum accesul la variabilele unui obiect n funcie de specificatorii lor.
specificatorul de acces al variabilei
din tabelul de mai sus
public protected private
membri ai aceleiai clase da da da
membri claselor derivate da da nu
nemembri da nu nu
Fie o clas derivat din Baza cu specificatorul de acces public
class DerivPublic : public Baza
{
/* declaratii din clasa Deriv */
public:
int w;
158
};
In acest caz variabilele x i y au n clasa Deriv specificatorul de acces definit n clasa
Baza, respectiv public pentru x i protected pentru y. Ele pot fi utilizate de funciile
definite n clasa Deriv, dar numai variabila x poate fi utilizat de obiectele de tipul
Deriv, deoarece doar variabilele cu specificatorul de acces public pot fi utilizate de
obiectele de tipul clasei. De exemplu, n funcia main() putem avea instruciunile
int main()
{
DerivPublic b;
cout << b.x;
}
dar nu putem avea instruciunea
cout << b.y;
Variabila x poate fi utilizat de obiecte de tipul Deriv deoarece este definit de tipul
public n clasa de baz, dar variabila y nu poate fi utilizat de obiecte de tipul Deriv
deoarece este declarat protected n clasa de baz. In tabelul de mai jos se arat
variabilele obiectului b, publice, protejate i private.
Considerm clasa derivat din Baza definit cu specificatorul de acces protected
class DerivProtected : protected Baza
{
/* declaratii din clasa Deriv */
public:
int w;
} ;
In acest caz variabilele x i y