Documente Academic
Documente Profesional
Documente Cultură
1.1
Tehnici de programare
1.2
Convenii lexicale
continue
default
delete
do
double
else
enum
extern
float
for
friend
goto
if
inline
int
long
new
operator
private
protected
public
register
return
short
signed
sizeof
static
struct
switch
template
this
throw
try
typedef
union
unsigned
virtual
void
volatile
while
O constant real (cu virgul flotant) este alctuit dintr-o parte ntreag,
punctul zecimal, o parte fracionar i opional, un exponent ntreg cu semn precedat
de caracterul e sau E. Pot lipsi partea ntreag sau partea fracionar, dar nu
amndou. Tipul constantei flotante este double, dac nu conine un sufix care s
specifice explicit tipul (f sau F, pentru float; l sau L pentru long double).
O constant ir de caractere este o secven de caractere cuprins ntre
ghilimele duble i este de tipul vector de caractere. O constant ir de caractere are
clasa de memorare static i se iniializeaz cu caracterele date, la care se adaug
caracterul \0 (care are valoarea zero).
Este de asemenea posibil s fie definite constante simbolice (constante cu
nume). Acestea sunt prezentate n subseciunea urmtoare.
1.3
Declaraii, definiii
struct S;
typedef int Int;
//
//
//
//
corect,
corect,
corect,
eroare,
redeclarare
redeclarare
definiie
redefinire
Domeniul de definiie (scope) al unui nume este zona din program n care
numele este cunoscut i poate fi folosit. Dat fiind c un nume este fcut cunoscut
printr-o declaraie, domeniile numelor se difereniaz n funcie de locul n care este
introdus declaraia n program. Exist patru categorii de domenii: local, funcie, clas
i fiier.
Domeniul local: un nume declarat ntr-un bloc (o secven de instruciuni
cuprins ntre dou acolade) este local blocului i poate fi folosit numai n acel bloc,
ncepnd din locul declaraiei i pn la sfritul blocului i n toate blocurile incluse
dup punctul de declaraie. Argumentele formale ale unei funcii sunt tratate ca i cnd
ar fi declarate n blocul exterior al funciei respective.
Domeniul funcie: un nume declarat ntr-o funcie poate fi folosit n funcia
respectiv, ncepnd din punctul de declaraie i pn la sfritul blocului n care se
afl declaraia. Domeniul funcie poate fi considerat un caz particular de domeniu
local.
Domeniul clas: Un nume al unui membru al unei clase este local clasei
respective. Posibilitile de utilizare al acestor tipuri de nume vor fi prezentate ulterior.
Domeniul fiier: Un nume declarat n afara oricrui bloc sau clas are ca
domeniu fiierul n care a fost declarat i poate fi utilizat din punctul declaraiei pn
la sfritul fiierului. Numele cu domeniu fiier se numesc nume globale.
Domeniul de vizibilitate. Un nume este vizibil n ntregul su domeniu de
definiie dac nu este redefinit ntr-un bloc inclus n domeniul respectiv. Dac ntr-un
bloc interior domeniului unui nume se redefinete (sau se redeclar) acelai nume,
atunci numele iniial (din blocul exterior) este parial ascuns, i anume n tot domeniul
redeclarrii. De exemplu:
void fv1(){
int i = 10;
// definitie variabila i
{
// in acest bloc variabila i din blocul exterior
// este ascunsa datorit redefinirii
int i = 100;
cout << i << endl; // afiseaza 100
}
cout << i << endl;
// afiseaza 10
}
10
produce mesajele:
a = 1
a = 2
a = 3
b
b
b
= 2
= 2
= 2
c = 3
c = 5
c = 7
O variabil (obiect) global sau static, care nu este iniializat explicit, este
iniializat automat cu 0. n afara acestui mod de creare a obiectelor, se mai pot crea
obiecte n memoria liber (heap), a cror durat de via este controlat explicit
folosind funcii sau operatori de alocare. Acest mod de creare a obiectelor este
prezentat n subseciunea 2.4.
Categorii de memorare. Exist patru specificatori de categorii de memorare
a obiectelor: auto, static, register, extern.
11
1.4
Tipuri
Fiecare nume ntr-un program C++ are un tip asociat lui, care determin ce
operaii se pot aplica entitii la care se refer acest nume.
Un nume folosit pentru a specifica tipul unui alt nume ntr-o declaraie este un
nume de tip. Singurele operaii care se pot aplica unui nume de tip sunt: sizeof,
(care determin cantitatea de memorie necesar memorrii unui obiect de acel tip) i
new (operaia de alocare n memoria liber a unui obiect de tipul respectiv).
1.4.1
Tipuri fundamentale
char
short int
1 octet
2 octei
12
int
long
2 sau 4 octei
4 sau 8 octei
float
double
long double
4 octei
8 octei
12 sau 16 octei
Aceste tipuri sunt denumite mpreun tipuri aritmetice. Pentru tipurile ntreg,
exist variante de declaraie cu semn (signed) i fr semn (unsigned).
1.4.2
Tipuri derivate
13
// variabila c1
// p memoreaz adresa lui c1
// dereferentiere, c2 = a;
Operatorul & este operatorul adres, care se utilizeaz pentru a obine adresa
unei variabile.
Tipul void* este folosit pentru a indica adresa unui obiect de tip necunoscut.
Asupra pointerilor sunt admise unele operaii aritmetice. De exemplu, se
consider un vector de caractere dintre care ultimul este caracterul 0 (se mai numete
ir de caractere terminat cu nul). Pentru calculul numrului de caractere se pot folosi
operaii cu pointeri astfel:
int strlen(char* p){
int i = 0;
while (*p++) i++;
return i;
}
14
//
//
//
//
15
16
// prototip functie f2
// definitie functie f3
void fp(){
double r1 = f1(7, 8.9);
double r2 = f2(7, 8.9);
char str[] = "abcde";
double r3 = f3(7, str);
// eroare,
// identificator nedeclarat
// corect, fol. prototipul
// eroare de tip argument
double f1(int
/*..*/
double t =
return t;
}
double f2(int
/*...*/
double t =
return t;
}
a, double f) {
a + f;
a, double f) {
a*f;
17
din declaraia funciei, n ordinea din declaraie. Argumentele unei funcii se pot
transfera n dou moduri: apelul prin valoare i apelul prin referin.
n apelul prin valoare se copiaz valoarea argumentului real n argumentul
formal corespunztor al funciei. n acest caz, modificrile efectuate asupra
argumentului funciei nu modific argumentul real.
n apelul prin referin este accesat direct variabila din argumentul real
transmis funciei, care poate fi deci modificat. Ca exemplificare, se definete o
funcie swap() care realizeaz intershimbul ntre valorile a dou variabile. Dac nu
se folosesc referine, argumentele de apel ale funciei trebuie s fie pointeri la
variabilele respective. Pointerii, ca argumente de apel, nu vor fi modificai, dar
variabilele indicate de acetia pot fi modificate. Funcia swap() cu argumente
pointeri arat astfel:
void swap(int* x, int* y){
int t;
t = *x;
// dereferentiere
*x = *y;
*y = t;
}
18
struct data{
int zi;
int luna;
int an;
} g_data;
void setdata(int zi, int luna=9, int an =1999){
g_data.zi = zi;
g_data.luna = luna;
g_data.an = an;
}
void main(){
setdata(15);
// 15 9 1999
setdata(21,7);
// 21 7 1999
setdata(20,1,2000);
// 21 1 2000
}
pf = func1;
float z = (*pf)(3, 1.2f);
cout << z << endl;
pf = func2;
z = (*pf)(3, 1.2f);
cout << z << endl;
Dei din acest exemplu simplu nu reiese care ar putea fi avantajul folosirii
apelului prin pointer a unei funcii, exist totui situaii cnd apelul prin pointeri este
foarte avantajos. De exemplu, poate s fie nlocuit o instruciune switch care
selecteaz dintre mai multe apeluri de funcii, cu un vector de pointeri la funcii care
se pot apela prin pointerii corespunztori.
19
// apeleaza abs(int)
// apeleaza abs(double)
Acceptarea mai multor versiuni ale unei funcii cu acelai nume este
condiionat de posibilitatea selectrii fr ambiguitate a uneia dintre acestea dup
tipul sau numrul argumentelor. Nu este admis ca funciile s difere doar prin tipul
returnat.
Dou funcii declarate cu acelai nume se refer la aceeai funcie dac sunt n
acelai domeniu i au numr i tipuri identice de argumente. O funcie declarat local
nu este n acelai domeniu cu o funcie cu domeniul la nivel de fiier. De exemplu:
int f(char*);
void g(){
extern f(int);
f(abcd); // eroare, f(int) ascunde f(char*)
//deci nu exista f(char*) n acest domeniu
}
20
//
//
//
//
//
selecteaza
selecteaza
selecteaza
selecteaza
selecteaza
power(long, int)
power(int, int)
power(double, int)
power(double, double)
power(double, double)
Dac prin astfel de conversii nu se poate stabili cea mai bun potrivire a
argumentelor, atunci sunt ncercate i conversii pentru tipuri definite de utilizatori.
Apelul este acceptat numai dac selecia unei versiuni a funciei (pe baza criteriului de
cea mai bun potrivire a argumentelor) este unic. Conversiile ntre date de tipuri
definite de utilizatori sunt prezentate n seciunea 4, dedicat suprancrcrii
operatorilor.
1.4.2.5 Constante simbolice
O constant simbolic (sau constant cu nume) este un nume a crui valoare
nu poate fi modificat n cursul programului. n C++ exist trei modaliti de a defini
constante simbolice:
Orice valoare, de orice tip care poate primi un nume, poate fi folosit ca o
constant simbolic prin adugarea cuvntului-cheie const n declaraia
acesteia.
Orice nume de funcie sau de tablou este o constant simbolic.
O enumeraie definete o mulime de constante ntregi.
De exemplu, urmtoarele declaraii introduc constante simbolice prin folosirea
cuvntului-cheie const:
const int val = 100;
const double d[] = {1.2, 2.8, 9.5};
// eroare
// eroare
21
22
good,
bad,
fail
};
void fe (states st ){
if (st != good){
//.
}
}
Un nume declarat de tipul unei enumeraii poate lua orice valoare particular
cuprins n enumeraie.
n sfrit, este posibil iniializarea elementelor unei enumeraii:
enum states{
good = 0x00,
bad = 0x01,
fail = 0x10
};
23
este i o definiie a clasei X, care introduce un tip nou de date. Prin aceast definiie se
asociaz numele X cu entitatea definit n corpul clasei. Dup definirea unui astfel de
tip de date, se pot declara (defini) obiecte de tipul respectiv, la fel ca i variabilele
(obiecte) de tipuri predefinite:
X obx1;
1.5
Expresii i operatori
24
i comutativitate se aplic pentru acei operatori care sunt n mod real asociativi sau
comutativi.
O expresie care se refer la un obiect sau funcie este denumit valoare stnga
(left value, prescurtat lvalue). Aceast denumire provine din faptul c o astfel de
valoare poate fi folosit ca membru stng al unei expresii de asignare: E1 = E2.
Operandul E1 trebuie s fie expresie lvalue. n expresii, unii operatori produc expresii
lvalue, alii necesit expresii lvalue. O expresie lvalue este modificabil dac nu este
numele unei funcii, numele unui tablou, sau constant.
25
unde tip_data este un tip de date predefinit sau definit de utilizator (clas), p este
pointerul (adresa de nceput) a zonei alocate n memoria liber, returnat la execuia
operatorului new, iar initializare este o expresie care depinde de tipul datei i
permite iniializarea zonei de memorie alocate. Dac alocarea nu este posibil,
pointerul returnat este NULL.
Forma de utilizare a operatorului new pentru alocarea unui vector de date
(tablou unidimensional) de dimensiune dim, este urmtoarea:
tip_data* p = new tip_data[dim];
Prima form se utilizeaz pentru eliberarea unei zone de memorie ocupat de o singur
dat (obiect), nu de un vector. Pointerul p trebuie s fie un pointer la o zon de
memorie alocat anterior printr-un operator new. Operatorul delete trebuie s fie
folosit doar cu un pointer valid, alocat numai cu new i care nu a fost modificat sau nu
a mai fost eliberat zona de memorie mai nainte (cu un alt operator delete sau prin
apelul unei funcii free()). Folosirea operatorului delete cu un pointer invalid
este o operaie cu rezultat nedefinit, cel mai adesea producnd erori de execuie grave.
Cea de-a doua form a operatorului delete[] se folosete pentru eliberarea
unei zone de memorie ocupat de un vector de date. Pentru tipurile de date predefinite
ale limbajului, se poate folosi i prima form pentru eliberarea unui vector, dar, n
cazul obiectelor de tipuri definite de utilizator, acest lucru nu mai este valabil. Aceast
situaie va fi detaliat n seciunea urmtoare.
Cteva exemple de utilizare a operatorilor new i delete:
int *pi = new int(3);
double *pd = new double;
char *pc1 = new char[12];
char *pc2 = new char[20];
delete pi;
delete pd;
//
//
//
//
26
delete pc1;
delete []pc2;
n legtur cu cele dou metode de alocare dinamic, prin operatorii newdelete i prin funciile de bibliotec malloc-free, fr s fie o regul precis, se
recomand evitarea combinrii lor, deoarece nu exist garania compatibilitii ntre
ele.
1.5.2
Precedena operatorilor
n tabelul urmtor sunt prezentai concis operatorii din limbajul C++ grupai
n ordinea precedenei lor. n fiecare compartiment sunt trecui operatorii cu aceeai
preceden. Un operator dat are o preceden mai ridicat dect un altul dintr-un
compartiment aflat mai jos n tabel. Operatorii se aplic n ordinea precedenei lor. De
exemplu, a+b*c nseamn a+(b*c), deoarece nmulirea (*) are o preceden mai
ridicat dect adunarea (+).
Operatori C++
::
operator rezoluie
nume_clas::membru
::
nume global
::nume
selecie membru
obiect.membru
->
selecie membru
pointer->membru
[]
indexare
pointer[expr]
()
apel funcie
expr (lista_expr)
()
conversie explicit
tip(list_expr)
sizeof
dimensiune obiect
sizeof expr
sizeof
dimensiune tip
sizeof (tip)
++
post incrementare
lvalue++
++
pre incrementare
++lvalue
--
post decrementare
lvalue--
--
pre decrementare
--lvalue
complement
~expr
negaie
!expr
minus unar
-expr
plus unar
+expr
&
adres
&lvalue
27
derefereniere
*expr
new
alocare
new tip
delete
eliberare(dezalocare)
delete pointer
delete[]
eliberare tablou
delete[]pointer
()
conversie cast
(tip)expr
.*
selecie membru
obiect.*pointer_la_membru
->*
selecie membru
pointer->*pointer_la_membru
nmulire
expr * expr
mprire
expr / expr
modulo
expr % expr
adunare
expr + expr
scdere
expr - expr
<<
>>
<
mai mic
<=
>
mai mare
>=
expr >=expr
==
egal
expr == expr
!=
diferit
expr != expr
&
expr ^ expr
OR orientat pe bii
expr | expr
&&
||
OR logic (SAU)
expr || expr
?:
expresie condi.
asignare simpl
lvalue = expr
*=
nmulire i asignare
expr *= expr
/=
mprire i asignare
expr /= expr
%=
modulo i asignare
expr %= expr
+=
adunare i asignare
expr += expr
-=
scdere i asignare
expr -= expr
28
<<=
>>=
&=
AND i asignare
|=
OR i asignare
expr |= expr
^=
XOR i asignare
expr ^= expr
throw
lansare excepie
throw expresie
virgul(secveniere)
expr, expr
1.6
Conversii standard
Unii operatori pot provoca conversia valorii unui operand de la un tip la altul,
n funcie de tipul operanzilor. Conversiile standard executate pentru tipurile
predefinite n C++ sunt identice cu cele din limbajul C i de aceea vor fi descrise
foarte succint. Astfel de conversii intervin n urmtoarele situaii:
Conversia unor operanzi de tipuri diferite ntr-o expresie aritmetic.
Conversia unui argument de apel al unei funcii la tipul argumentului
formal corespunztor.
Conversia valorii returnate de o funcie din tipul folosit n instruciunea
return n tipul din declaraia funciei.
n toate aceste situaii se respect cteva reguli de conversie care sunt descrise
n continuare.
1.6.1
Conversiile aritmetice
29
1.6.2
Conversia pointerilor
1.7
Orice program C++ care nu este foarte simplu este alctuit din mai multe
uniti de compilare, numite convenional fiiere.
Din punct de vedere al limbajului C++, un fiier reprezint un domeniu de
definiie (domeniul fiier), care este domeniul pentru funciile globale de tip static
i inline i pentru variabilele globale de tip static. Un fiier este, de asemenea,
o unitate de memorare n sistemul de fiiere i o unitate de compilare (un modul).
30
Dezvoltarea unui program ntr-un singur fiier este practic imposibil, deoarece
sunt apelate funcii din biblioteci i funcii ale sistemului de operare care sunt
memorate n mai multe fiiere. Chiar i partea de program scris de utilizator este
inconvenabil s fie toat cuprins ntr-un singur fiier, datorit dificultii de
organizare i de evideniere a diferitelor pri ale programului. Mai mult, dac
programul este curins ntr-o singur unitate de compilare, orice modificare trebuie
urmat de recompilarea ntregului fiier.
n organizarea pe mai multe fiiere a unui program, este necesar ca
programatorul s prevad declaraii care s permit analiza de ctre compilator a
fiecrei uniti de compilare luat izolat dar, n acelai timp, i utilizarea unitar a
numelor i a tipurilor definite. Orice sistem de programare permite o astfel de
organizare i legare a unitilor compilate separat, n principal prin programul de
linkare (linker).
1.7.1
Linkarea modulelor
Dac nu este specificat altfel, un nume care nu este local (definit ntr-o funcie
sau clas) trebuie s se refere la aceeai entitate n oricare din unitile de compilare
(fiiere) ale programului, adic trebuie s existe o singur funcie, valoare, tip sau
obiect nelocal cu acelai nume. De exemplu, se consider fiierele:
// fisier1.cpp
int x = 0;
void f() {/* corpul functiei*/}
// fisier2.cpp
extern int x;
void f();
int g() {
x = f();
}
1.7.2
31
Fiiere antet
#include antet2.h
#define BOOL int
struct point {double x, y;};
const double epsilon = 0.1;
enum state{good, false};
inline char get(char*p)
{return *p++;}
template<class T>
class V{/* */};
extern int x;
class X;
extern int func(char c);
/* comentariu */
*/};
32
Exerciii
E1.1 S se rescrie funciile strlen(), care returneaz lungimea unui ir,
strcmy(), care compar dou iruri i strcpy() care copiaz un ir n alt ir. S
se stabileasc ce fel de tipuri de argumente sunt necesare, dup aceea s se compare cu
versiunea standard declarat n <string.h>.
E1.2 Se consider urmtoarea operaie de copiere a dou iruri de caractere
terminate cu nul:
int len = strlen(q);
for (int i = 0; i<=len; i++) p[i] = q[i];