Sunteți pe pagina 1din 115

BAZELE PROGRAMRII

LIMBAJUL C/C + +
I.1. Prezentarea limbajului C: vocabular, tipuri de
date, constante, variabile, operatori i expresii
Un program este un text ce specific aciuni care vor fi executate de un
procesor. Scrierea unui program se face ntr-un limbaj de programare.
Un limbaj de programare are vocabular i reguli de sintax.
Vocabularul este format din uniti lexicale: cele mai simple elemente cu
semnificaie lingvistic.
Sintaxa: ansamblu de reguli pe baza crora se combin elementele
vocabularului (unitile lexicale) pentru a obine fraze corecte (instruciuni,
secvene de instruciuni, declarare de variabile etc).
Elementele vocabularului sunt alctuite din caractere.
Orice caracter este reprezentat n calculator n codul ASCII (American
Standard Code for Information Interchange), printr-un numr natural unic, cuprins
ntre 0 i 255 .
Caracterele sunt simboluri grupate n litere, cifre i semne speciale, astfel:
- literele mari ale alfabetului englez cu codurile 65,...,90: A, B, ..., X, Y, Z
- literele mici ale alfabetului englez cu codurile 97,...,122: a, b, ..., x, y, z
- cifrele bazei zece, care au codurile in 48,...,57: 0, 1, 2, ... ,9
- liniua de subliniere _
- semne de punctuaie i semne speciale : , . : ? ( ) [ ] { } < > ! | \ / ~ # & ^
+-*%
Unitile lexicale ale limbajului C/C++ sunt: identificatori, cuvinte cheie,
constante, iruri, operatori i separatori. La scrierea lor se folosesc reguli precise
date de sintaxa limbajului prin utilizarea setului de caractere al codului ASCII.

I.1.1. Identificatori i cuvinte cheie


Un identificator reprezint o succesiune de litere (litera mic este tratat ca
distinct de litera mare), cifre, liniue de subliniere, primul caracter din secven
fiind obligatoriu o liter sau o liniu de subliniere.
Identificatorii sunt nume simbolice date de utilizator constantelor,
variabilelor, tipurilor de date, funciilor etc, pentru a descrie datele de prelucrat (de
exemplu nume de variabile) i procesele de prelucrare (de exemplu nume de
funcii). n general numai primele 32 de caractere se consider semnificative n C.

Ca identificatori se prefer folosirea unor nume sau simboluri care s


sugereze semnificaia mrimilor pe care le desemneaz, contribuind la creterea
claritii programului.
Cuvintele cheie (keywords) sunt cuvinte rezervate pentru limbaj n sine, au
neles predefinit i nu pot avea alt utilizare. Aceste cuvinte se scriu cu litere mici.
ANSI (American National Standards Institute) C are 32 de cuvinte cheie:
auto
struct
long
enum
char
union

const
unsigned
signed
goto
do
while

double
break
switch
register
extern

float
continue
void
sizeof
if

int
else
case
typedef
return

short
for
default
volatile
static

I.1.2. Comentariu
n redactarea programelor se folosesc o serie de texte care dau explicaii cu
privire la program, la prile sale la variabilele utilizate etc. Aceste texte explicative
se adreseaz utilizatorilor; se numesc comentarii i sunt ignorate de compilator.
n limbajul C un comentariu ncepe prin /* i se termin prin */.
n C++ un comentariu care ncape pe un rnd poate fi scris dup //.

I.1.3. Tipuri de date, constante, variabile


Tipul unei date determin:
- spaiul de memorie ocupat;
- modul de reprezentare intern;
- domeniul de valori;
- timpul de via asociat datei;
- operatori utilizai i restricii n folosirea acestora.
Limbajul C lucreaz cu valori care pot fi stocate n constante sau variabile.
Constantele stocheaz valori nemodificabile pe parcursul execuiei
programului.
Variabilele sunt mrimi care i modific valoarea n timpul execuiei
programului.
Tipurile de date utilizate de limbajul C se clasific astfel:
- tipuri fundamentale
- caracter
- ntregi
- reale
- tip void
- tipuri derivate
- tablouri
- pointeri
- structuri
- uniuni
- enumerri

- tip definit de utilizator


Tipurile fundamentale se mai numesc scalare, predefinite, simple sau de
baz.

I.1.4. Tipuri de date standard


Datele reprezint informaii care fac obiectul prelucrrilor. Fiecare dat este
memorat ntr-un anumit format. Pe de alt parte, interpretarea valorilor memorate
se face diferit, n funcie de semnificaia datelor respective. Prin urmare, este
important att modul de memorare a datelor (formatul fizic de reprezentare) prin
care se stabilete domeniul valorilor datelor, ct i semnificaia lor prin care se
stabilesc operaiile care se pot efectua cu aceste date. Aceste caracteristici ale unei
date sunt precizate prin tipul su.
Tipurile de date standard (predefinite) ale limbajului C sunt:
Lungime n
Specificator Abreviaia
Domeniu de valori
bii
Caracter reprezentat prin cod ASCII
signed char
char
8
sau ntreg binar din intervalul 128
... 127.
Caracter reprezentat prin cod ASCII
unsigned char
8
sau ntreg binar fr semn din
intervalul 0 ... 255.
dependent
ntreg binar reprezentat n cod
signed int
int
de calculator
complementar fa de 2
16 sau 32
ntreg binar reprezentat n cod
short int
short
16
complementar fa de 2, din
intervalul -32768 ... 32767.
ntreg binar reprezentat n cod
complementar fa de 2 din
long int
long
32
intervalul
-2147483648 ... 2147483647
dependent
unsigned int
unsigned
de calculator ntreg binar fr semn
16 sau 32
ntreg binar fr semn din intervalul
unsigned short
unsigned
16
int
short
0 ... 65535.
ntreg binar fr semn din intervalul
unsigned
unsigned long int
32
long
0 ... 4294967295
Numr reprezentat n virgul mobil
1bit pentru semn, 7b exponent, 24b
float
32
mantisa, precizie 7 zecimale.
Domeniu [3.4E-38, 3.4E38]
Numr reprezentat n virgul mobil
long float
double
64
1 bit ptr. semn, 11b exponent, 52b

mantisa, precizie 15 zecimale.


Domeniu [1.7E-308, 1.7E308]
Numr reprezentat n virgul mobil
long double
80
precizie 19 zecimale.
Domeniu [3.4E-4932, 1.1E4932]
Pe lng aceste tipuri de date, limbajul C mai dispune de tipul pointer i
tipul void. Tipul void indic absena oricrei valori.
Pointerii se utilizeaz pentru a face referire la date cunoscute prin adresele
lor. Un pointer este o variabil care are ca valori adrese.
Tipul pointer are formatul:
<tip>* <nume>;

ceea ce nseamn c <nume> este un pointer ctre o zon de memorie ce


conine o dat de tipul <tip>.

I.1.5. Constante
O constant este o valoare fix care apare literalmente n codul surs al unui
program. Tipul i valoarea constantei sunt determinate de modul n care constanta
este scris. Constantele pot fi de mai multe tipuri: ntreg, flotant(real), caracter, ir
de caractere. Aceste constante sunt folosite, de exemplu, pentru a iniializarea
variabilelor.

Constante ntregi
O constant ntreag este un numr ntreg reprezentat n cod complementar
fa de 2 pe 16 bii sau pe 32 bii dac nu ncape pe 16 bii. Exemple: 7, -3, 0.
n cazul n care dorim ca o constant ntreag din intervalul -32768 ...
+32767 s fie reprezentat pe 32 bii (implicit astfel de constante se reprezint pe
16 bii), vom termina constanta respectiv prin L sau l, adic i impunem tipul long.
Exemplu -10L.
Dac, la o constant ntreag, adugm sufixul U sau u, atunci form tipul
constantei la unsigned int sau unsigned long. Dac adugm sufixul UL sau ul sau
Ul sau uL constanta va fi de tipul unsigned long.
O constant ntreag, precedat de un zero nesemnificativ se consider scris
n sistemul de numeraie cu baza 8.
O constant ntreag care ncepe cu 0X sau 0x se consider scris n
sistemul de numeraie cu baza 16 (cifrele hexazecimale sunt 0...9, a...f sau
A...F). n rest se consider c baza de numeraie este 10.
Exemple:
Constanta
1234
02322
0x4D2

Tip
int
int /* octal */
Int /* hexazecimal */

Constanta
123456789L
1234U
123456789UL

Tip
long
unsigned int
unsigned long int

Constante flotante
Atunci cnd ncercm s reprezentm n memoria calculatorului un numr
real, cutm de fapt cel mai apropiat numr real reprezentabil n calculator i
aproximm numrul iniial cu acesta din urm. Ca rezultat, putem efectua calcule
complexe cu o precizie rezonabil.
Constantele reale sunt reprezentate n virgul mobil prin notaia clasic cu
mantis i exponent.
Sintaxa: partea ntreag . partea fracionar {E|e} exponentul
Pot lipsi fie partea ntreag, fie partea fracionar, dar nu ambele.
Pot lipsi punctul zecimal cu partea fracionar sau litera E cu exponentul dar
nu ambele. Semnul + este opional pentru numerele nenegative.
Exemple:
3.1415921
4.3E20
-.2e+15
2e-5

-12.

.34
-.125
/* pentru numrul 4.3*1020 */
/* pentru numrul 0.2*1015 */
/* pentru numrul 2*10-5 */

n mod implicit, o constant real este reprezentat intern n format double.


Tipul constantei poate fi influenat prin adugarea unui sufix de f (sau F) sau l(sau
L). Sufixul f (saui F) foreaz constanta la tipul float, sufixul l (sau L) foreaz
constanta la tipul long duble.
Constanta
12.34
12.3e-4
12.34F
12.34L

tip
double
double
float
long double

Constante caracter
O constant caracter reprezint un caracter i are ca valoare codul ASCII al
caracterului respectiv. O constant caracter grafic se poate scrie incluznd
caracterul respectiv ntre caractere apostrof.
Exemple:
literele mari au codurile ASCII n intervalul [65,90]
'A' > 65, ... , 'Z' > 90.
literele mici au codurile ASCII n intervalul [97,122]
'a' > 97, ... ,'z' > 122
cifrele au codurile ASCII n intervalul [48,57]
'0' > 48, ... ,'9' > 57
constanta '*' are valoarea 77
Caracterele negrafice cu excepia caracterului DEL (care are codul 127), au
coduri ASCII mai mici dect 32. O parte dintre aceste caractere formeaz categoria
caracterelor de control i au notaii speciale de tipul \caracter.

De exemplu codul ASCII de valoare zero definete caracterul NULL. Acesta


este un caracter impropriu i spre deosebire de alte caractere el nu poate fi generat
de la tastatur i nu are efect nici la ieire. n C este folosit ca terminator pentru
iruri de caractere i are notaia \0.
Setul de caractere de control:
Valoare
cod
Reprezentare Rol
ASCII
0
\0
Caracterul NULL (zero binar)
7
\a
Alarm (bell)
8
\b
Spaiu napoi (backspace); BS
9
\t
Tabulator orizontal; TAB
10
\n
Salt la linie nou (new line)
11
\v
Tabulator vertical
12
\f
Salt de pagin la imprimant (formfeed); FF
13
\r
Deplasarea cursorului n coloana 1 pe aceeai linie; CR
O constant caracter cu notaie special, se va scrie incluznd notaia ntre
caractere apostrof. Exemple: '\n', '\t', '\r'
Constanta apostrof se reprezint prin '\''.
Constanta backslash se reprezint prin '\\'.
Construcia '\ddd', unde d este o cifr octal, reprezint caracterul al
crui cod ASCII are valoarea egal cu numrul octal ddd. n particular caracterul
impropriu NULL se poate reprezenta prin constanta caracter '\0'.
Caracterul DEL al crui cod ASCII are valoarea 127 se reprezint prin
'\177'. Caracterul spaiu al crui cod ASCII are valoarea 32 se poate reprezenta
prin ' ' sau '\40'.
Construcia '\xdd', unde d reprezint o cifr hexazecimal reprezint
caracterul al crui cod ASCII are valoarea egal cu numrul zecimal dd.
Exemplu: '\x20' reprezint caracterul spaiu.
Dac \ este urmat de un alt caracter dect cele artate, atunci \ este ignorat
de compilator.
Caracterele spaiu (cod ASCII 32), tab (cod ASCII 9) i linie nou (cod
ASCII 10) formeaz categoria de separatori spaii albe. n afar de locurile unde
sunt necesare spaiile albe pentru separarea identificatorilor, a cuvintelor cheie etc.
aceste spaii albe sunt ignorate de compilator i pot fi folosite oriunde n program.

Constante ir de caractere
O constant ir de caractere este o succesiune de zero sau mai multe
caractere delimitate prin ghilimele. Ghilimelele nu fac parte din irul de caractere.
Dac dorim s folosim caractere negrafice n compunerea unui ir de caractere,
atunci putem folosi convenia de utilizare a caracterului \. Dac dorim s
reprezentm chiar caracterul ghilimele, atunci vom scrie \", de asemenea pentru
backslash scriem \\.

Exemple:
"123"
"1\"2"
-reprezint succesiunea 1"2
"a\\b"
-reprezint succesiunea a\b
"c:\\tc\\bgi"
-reprezint succesiunea c:\tc\bgi
Un ir de caractere poate fi continuat de pe un rnd pe altul, dac nainte de
a aciona tasta <enter> se va tasta \.
Constanta ir de caractere se reprezint printr-o succesiune de octei n care
se pstreaz codurile ASCII ale caracterelor irului, iar ultimul octet conine
totdeauna caracterul NULL pentru a marca sfritul irului. De aici rezult c, de
exemplu, 'A' i "A" sunt construcii diferite. Prima reprezint o constant caracter
care se pstreaz pe un singur octet n memorie. A doua, reprezint un ir de
caractere i se pstreaz pe doi octei, primul octet conine valoarea codului
ASCII al lui A, iar cel de-al doilea conine caracterul NULL, adic valoarea 0.

I.1.6. Variabile
Prin variabil nelegem o zon temporar de stocare a datelor a crei
valoare se poate schimba n timpul execuiei programului. Unei variabile i se
asociaz un nume prin intermediul cruia putem avea acces la valoarea ei i un tip
de date care stabilete valorile pe care le poate lua variabila. Corespondena ntre
numele i tipul unei variabile se realizeaz printr-o construcie special numit
declaraie. Toate variabilele utilizate ntr-un program trebuie declarate naintea
utilizrii lor.
O declaraie de variabil are urmtoarea sintax:
< tip > < lista de variabile >
unde lista conine unul sau mai multe nume de variabile desprite prin
virgule.
Exemple:
int i,j,X;
unsigned long k;
float a,b;
char c;

Sunt situaii n care variabilele trebuie s fie grupate din punct de vedere
logic. Tablourile reprezint grupuri unidimensionale sau multidimensionale de
variabile de acelai tip. Declaraia de tablou conine tipul comun al elementelor
sale, numele tabloului i numrul de elemente pentru fiecare dimensiune incluse
ntre paranteze drepte.
<tip> <lista de elemente>;

Elementele se separ prin virgule.


Un element din lista de tip tablou are formatul:
nume[dim1][dim2]...[dimn]

unde dim1,dim2,...,dimn sunt expresii constante care au valori ntregi.


Exemple:
int v[10];
float a[100][3];

La elementele unui tablou ne referim prin variabile cu indici. O astfel de


variabil se compune din numele tabloului urmat de unul sau mai muli indici,
fiecare indice fiind inclus ntre paranteze drepte. Indicii au limita inferioar zero.
Exemple: Tablourile v i a declarate mai sus se compun din variabilele
v[0], v[1], ... , v[9]

respectiv,
a[0][0],
a[1][0],

a[0][1],
a[1][1],

a[0][2],
a[1][2],

...
a[99][0]

a[99][1],

a[99][2].

Tablourile unidimensionale de tip caracter se utilizeaz pentru a pstra iruri


de caractere. Exemplu:
char tab[4];

tab poate pstra un ir de maxim 3 caractere, al patrulea octet fiind necesar


pentru caracterul NULL - marcatorul sfrituli irului.
Numele unui tablou are ca valoare adresa primului su element.

I.1.7. Operatori i expresii


Operatorii sunt simboluri care specific operaiile ce se aplic unor variabile
sau constante numite operanzi.
O expresie este o construcie aritmetic sau algebric care definete un
calcul prin aplicarea unor operatori asupra unor termeni care pot fi: constante,
variabile, funcii.
Expresiile se evalueaz pe baza unui set de reguli care precizeaz prioritatea
i modul de asociere a operatorilor precum i conversiile aplicate operanzilor:
prioritatea determin ordinea de efectuare a operaiilor ntr-o expresie cu
diveri operatori.
modul de asociere indic ordinea de efectuare a operaiilor ntr-o secven
de operaii care au aceeai prioritate.
n tabela de mai jos se indic operatorii C++ n ordinea descresctoare a
prioritii lor. Operatorii din aceeai categorie au aceeai prioritate. Operatorii de
aceeai prioritate sunt prelucrati n ordinea de la stnga la dreapta sau la dreapta la
stnga n direcia indicat de sageat.
Categoria de operatori
Primari:
Apel de funcie
Indice de tablou
Operator rezoluie
Referin la membru de structur
Referin indirect la membru
structur
Unari:
Stabilirea tipului

Operatori

Prioritate

Mod de
asociere

()
[]
::
.
->

15

(tip)

14

Categoria de operatori
Dimensiune n octei
Alocare memorie
Dezalocare memorie
Adres
Coninut adres
Semn
Negaie
Incrementare, decrementare
Dereferenierea
pointerilor
membrii claselor
Multiplicativi
Aditivi
Deplasare
Relaionali
Egalitate
I la nivel de bit
SAU EXCLUSIV la nivel de bit
SAU la nivel de bit
I logic
SAU logic
Condiional
Atribuire
Operatorul virgul

Operatori
sizeof
new
delete
&
*
+ !
~
++ -spre .*
->*
* / %
+ << >>
< <= > >=
= = !=
&
^
|
&&
||
?:
=
+= -= *= /=
%= &= |= ^=
<<= >>=
,

Prioritate

Mod de
asociere

13

12
11
10
9
8
7
6
5
4
3
2

1
0

Operatori aritmetici
Operatorii + i unari se aplic unui singur operand i se folosesc la
stabilrea semnului operandului: pozitiv sau negativ.
Operatorul * reprezint operatorul de nmulire al operanzilor la care se
aplic.
Operatorul / reprezint operatorul de mprire. Dac ambii operanzi sunt
ntregi (char, int, unsigned, long), se realizeaz o mprire ntreag, adic ne
furnizeaz ctul mpririi.
Operatorul % are ca rezultat restul mpririi dintre doi operanzi ntregi.
Operatorii binari + i reprezint operaiile obinuite de adunare i scdere.
Exemple:
int a, b;
float x, y;
Dac a=3 i b=7 atunci b/a are valoarea 2 iar b%a are valoarea 1.
Dac x=9 i y=2 atunci x/y are valoarea 4.5.
Expresia x*y are sens, aici este operatorul unar.

Operatori de incrementare / decrementare


Sunt operatori unari. Operandul asupra cruia se aplic trebuie s fie o
variabil ntreag sau flotant. Operatorul de incrementare se noteaz prin ++, i
mrete valoarea operandului cu 1, iar cel de decrementare se noteaz cu --, i
micoreaz valoarea operandului cu 1.
Operatorii pot fi folosii prefixai:
++operand
--operand

sau postfixai:
operand++
operand--

n cazul n care sunt folosii postfixai, ei produc ca rezultat valoarea


operandului i apoi incrementeaz/decrementeaz operandul. Cnd se folosesc
prefixai se incrementeaz/decrementeaz operandul dup care produc ca rezultat
valoarea incrementat/decrementat.
Exemple:
Expresie
Efect
j=i++
j=i; i=i+1;
y=--x
x=x-1; y=x;
x=v[3]-x=v[3]; v[3]=v[3]-1;
x=++v[++j]
j=j+1; v[j]=v[j]+1; x=v[j];
y=++i-j
i=i+1; y=i-j;
y=i++-j
y=i-j; i=i+1;
y=(i-j)++
construcie eronat

Operatori relaionali
Operatorii relaionali sunt <, <=, >, >=, ==, !=.
Rezultatul aplicrii unui operator relaional este 1 sau 0 dup cum operanzii
se afl n relaia definit de operatorul respectiv sau nu.
De exemplu, dac a=5 i b=6 atunci expresia a<=b are valoarea 1, iar
expresia a+1>b are valoarea 0.
Operatorul == (egal) furnizeaz 1 dac operanzii sunt egali i zero n caz
contrar. Operatorul != (diferit) furnizeaz 1 dac operanzii nu sunt egali i zero n
caz contrar.
Exemple:
Dac x=2 i y =-1 atunci expresia x==y are valoarea 0, expresia x!=y are
valoarea 1, expresia x+y==1 are valoarea 1.

Operatori logici
!
negaie logic,operator unar.
&& I logic.
||
SAU logic.

10

n limbajul C nu exist valori logice speciale. Valoarea fals este reprezentat


prin 0. Orice valoare diferit de 0 reprezint valoarea adevrat. Operatorii logici
admit operanzi de orice tip scalar. Rezultatul evalurii unei expresii logice este de
tip ntreg: zero pentu fals i 1 pentru adevrat.
Dac la evaluarea unei expresii logice se ajunge ntr-un punct n care se
cunoate valoarea ntregii expresii, atunci restul expresiei nu se mai evalueaz.
Exemple:
Dac a i b sunt ambii diferii de zero expresia a&&b are valoarea 1, altfel 0.
Dac a este negativ, expresia !(a<0) are valoarea 0, altfel 1.
Expresia !a&&b||a&&!b realizeaz SAU EXCLUSIV. Dac a=0 i b=1,
deoarece !a&&b are valoarea 1 i deci rezultatul ntregii expresii este 1,
subexpresia a&&!b nu se mai evalueaz.

Operatori logici pe bii


Constituie una din extensiile limbajului C spre limbajele de asamblare. Se
aplic operanzilor de tip ntreg, execuia fcndu-se bit cu bit, cu ajutorul celor
patru operaii logice i dou operaii de deplasare la stnga i la dreapta.
Se utilizeaz urmtoarele simboluri:
& pentru I
| pentru SAU
^ pentru SAU EXCLUSIV
~ pentru NEGARE(complement fa de unu, schimb fiecare bit 1 al
operandului n 0 i fiecare bit 0 n 1)
<< pentru deplasare stnga
>> pentru deplasare dreapta
Cu excepia operatorului negare care este unar, ceilali sunt operatori
binari.
Operaiile logice pentru o pereche oarecare de bii x i y se prezint astfel:
x
y
x&y
x|y
x^ y
~x
0
0
0
0
0
1
0
1
0
1
1
1
1
0
0
1
1
0
1
1
1
1
0
0
Exemple:Numerele x=5, y=36 se reprezint n binar astfel:
x=00000101,
y=00100100
00000101
00100100
x&y= ------------00000100
00000101
00100100
x^y= -------------

00000101
00100100
x | y = -----------00100101

00000101
~ x= -------------

11

00100001
11111010
Operatorul & se poate utiliza la anulri de bii, de exemplu:
a & 0x00ff are ca valoare, valoarea octetului mai puin semnificativ al
valorii variabilei a (primii 8 bii sunt nlocuii cu 0, iar urmtorii 8 bii coincid cu
cei ai lui a).
Operatorul | se poate utiliza la la setri de bii, de exemplu:
a | 0x00ff primii 8 bii ai rezultatului coincid cu cei ai lui a, iar
urmtorii 8 sunt 1.
Operatorul <<, operator binar, realizeaz deplasarea la stnga a valorii
primului operand cu un numr de poziii binare egal cu valoarea celui de-al doilea
operand al su, biii liberi din dreapta se completeaz cu zero. Aceast operaie este
echivalent cu o nmulire cu puteri ale lui 2.
Exemplu.
x=7 n baza 2 se scrie 0000 0000 0000 0111
x <<2 va produce 0000 0000 0001 1100 deplasarea cu o poziie spre stnga
i adugarea unui zero. Valoarea sa este 28 adica 7*22
Operatorul >>, operator binar, realizeaz deplasarea la dreapta a valorii
primului operand cu un numr de poziii binare egal cu valoarea celui de-al doilea
operand al su. Aceast operaie este echivalent cu o mprire cu puteri ale lui 2.
In cazul deplasarii spre dreapta, biii liberi din stnga se completeaz
automat cu zero numai dac numrul este nenegativ. Dac numrul este negativ,
din necesitatea de a conserva semnul (reprezentat n bitul cel mai semnificativ cu
1), biii liberi din stnga se completeaz cu 1.
Exemple:
19>>3 are ca rezultat numrul binar 0000 0000 0000 0010 egal cu 2 adic
19/23.
x=-9 se reprezint n binar n cod complementar fa de 2. Acesta se obine
adunnd la complementul fa de unu al numrului, valoarea 1.
Deci 9 se obine ca ~ 9+1.
9 se reprezint prin:
0000 0000 0000 1001
~ 9 se repretint prin:
1111 1111 1111 0110
~ 9 +1 se reprezint prin:
1111 1111 1111 0111
atunci 9 se reprezint prin: 1111 1111 1111 0111
x>>2 va produce:
1111 1111 1111 1101

Operatori de atribuire
Operatorul = se utilizeaz n construcii de forma v = expresie.
Aceast construcie se numete expresie de atribuire i este un caz particular
de expresie. Tipul ei coincide cu tipul lui v, iar valoarea ei este chiar valoarea
atribuit lui v. Rezult c o expresie de forma:
v1 = (v = expresie)

este legal.
Deoarece operatorii de atribuire se evalueaz de la dreapta la stnga expresia
de mai sus se poate scrie fr paranteze.
n general, putem realiza atribuiri multiple de forma

12

vn=vn-1=...=v1=expresie.

n cazul unei expresii de atribuire, dac expresia din dreapta semnului egal
are un tip diferit de cel al variabilei v, atunci nti se convertete valoarea ei spre
tipul variabilei v i pe urm se realizeaz atribuirea.
Pentru operaia de atribuire putem folosi operatorii de atribuire combinat:
op=

Unde prin op se nelege unul din operatorii binari aritmetici sau logici pe
bii, adic: *, /, %, +, -, &, |, ^, <<, >>.
Expresia:
v op= expresie

este echivalent cu
v = v op (expresie)

Se pot realiza maximum zece combinaii:


+= ,-=, *=, /=, %=, & =, |=, ^=, <<=, >>=

Exemple:
Expresia:
x=x+5 este echivalent cu x+=5.
Expresia x=x^y este echivalent cu x^=y.
Expresia x=x<<y este echivalent cu x<<=y.
Expresia:
x/=y+3 este echivalent cu x=x/(y+3).
Expresia:
tab[i*j+1]=tab[i*j+1]*z
este echivalent cu
tab[i*j+1]*=z.
Expresia C=C*n/k, cu C, n i k de tip ntreg, nu produce acelai
rezultat cu C*=n/k, de exemplu pentru C=20, n=5, k=2 prima expresie furnizeaz
rezultatul 50, iar a doua 40 (C*=n/k este echivalent cu C=C*(n/k)).

Operatorul de conversie explicit


Dac dorim s form tipul unui operand sau al unei expresii putem folosi o
construcie de forma (tip)operand. Prin aceasta, valoarea operandului se
convertete spre tipul indicat n paranteze.
n C++, dac tip este format dintr-un singur cuvnt, se poate folosi i
construcia: tip(operand)
Exemple:
int x,y;
double z;
x=10; y=4;
z=x/y; /* z primete valoarea 2.0 deoarece mprirea, fcndu-se ntre operanzi de tip
ntreg,
este o mprire ntreag*/
z=(double)x/(double)y; // rezultatul va fi z=2.5.

Construcia: (float)(x+y) este echivalent n C++ cu float(x+y).


Construcia: unsigned char(x) este eronat deoarece tipul conversiei
este format din dou cuvinte.

13

Operatori condiionali
Operatorii condiionali se utilizeaz n evaluri de expresii care prezint
alternative. Ei sunt ?:.
O astfel de expresie are formatul:
exp1 ? exp2 : exp3

i are urmtoarea interpretare: dac exp1 este diferit de zero, atunci


valoarea i tipul expresiei condiionale sunt date de valoarea i tipul expresiei
exp2 altfel de valoarea i tipul lui exp3.
Exemplu:
y?x/y:x*x

Maximul dintre dou numere se poate determina astfel:


max=a>b?a:b;

Operatorul virgul
Exist cazuri n care este util s grupm mai multe expresii ntr-una singur,
expresii care s se evalueze succesiv. n acest scop se folosete operatorul virgul
care separ secvena de expresii, acestea grupndu-se ntr-o singur expresie.
Expresia:
exp1, exp2, ... , expn

va avea ca valoare i tip valoarea i tipul lui expn, deci cu a ultimei expresii.
Exemple:
k=(x=10, y=2*i-5, z=3*j, x+y+z);

Se execut pe rnd cele trei atribuiri, apoi se efectueaz suma x+y+z care se
atribuie lui k.
++i, --j

i se mrete cu o unitate, j se micoreaz cu o unitate, valoarea i tipul


ntregii expresii coincid cu valoarea i tipul lui j.

Operatorul dimensiune (sizeof)


Lungimea n octei a unei date se poate afla cu o construcie de forma
sizeof(data)

unde data este numele unei variabile, al unui tablou, al unui tip etc.
Exemple:
int i;
float x;
char c;
double d;
int tab[10];
sizeof(i)
sizeof(x)
sizeof(float)
sizeof(c)
sizeof(tab)
sizeof(tab[i])

-furnizeaz valoarea 2
-furnizeaz valoarea 4
-furnizeaz valoarea 4
-furnizeaz valoarea 1
-furnizeaz valoarea 20
-furnizeaz valoarea 2

14

Operatori parantez
Operatorul parantez rotund () se utilizeaz pentru a impune o alt
ordine n efectuarea operaiilor. O expresie inclus ntre paranteze rotunde
formeaz un operand.
Parantezele rotunde se utilizeaz i la apelul funciilor.
Parantezele ptrate [] includ expresii care reprezint indici. Ele formeaz
operatorul de indexare.

Operatori de adres
Operatorul & returneaz adresa unei variabile. Astfel, dac x este o
variabil, &x va fi adresa variabilei x.
Operatorul * returneaz valoarea de la o anumit adres. Astfel, dac p este
pointer la tipul char, *p va fi caracterul referit de p.

Regula conversiilor implicite


Dac operanzii unui operator binar nu sunt de acelai tip, sunt necesare
conversii care se execut automat astfel:
1. Fiecare operand de tip char, unsigned char sau short se convertete
spre tipul int i orice operand de tip float se convertete spre tipul double.
2. Dac unul dintre operanzi este de tip long double, atunci i cellalt se
convertete la tipul long double i rezultatul va fi de tip long double.
3. Dac unul dintre operanzi este de tip double, atunci i cellalt se
convertete la tipul double i rezultatul va fi de tip double.
4. Dac unul dintre operanzi este de tip unsigned long, atunci i cellalt
se convertete la tipul unsigned long i rezultatul va fi de tip unsigned long.
5. Dac unul dintre operanzi este de tip long, atunci i cellalt se
convertete la tipul long i rezultatul va fi de tip long.
6. Dac unul dintre operanzi este de tip unsigned, atunci i cellalt se
convertete la tipul unsigned i rezultatul va fi de tip unsigned.

I.2. Structura programelor C


Prin program nelegem un text ce specific aciuni ce vor fi executate de un
procesor. Limajul C este un limbaj procedural ceea ce nseamn c structura
programelor scrise n C se bazeaz pe subprograme.
Un subprogram este o secven de declaraii i instruciuni care formeaz o
structur unitar, ce rezolv o problem de complexitate redus, putnd fi innclus
ntr-un program sau stocat n biblioteci, compilat separat i utilizat ori de cte ori
este nevoie.
Aciunile sunt descrise cu ajutorul instruciunilor.
In limbajul C subprogramele sunt realizate sub form de funcii.

15

Un program C se compune din una sau mai multe funcii. Fiecare funcie are
un nume. Orice program scris n limbajul C, indiferent de complexitate, trebuie s
conin o funcie, numit funcie principal, al crui nume este main.
Aceast funcie preia controlul de la sistemul de operare n momentul n care
programul este lansat n execuie i l red la terminarea execuiei.
Execuia unui program C nseamn execuia instruciunilor din funcia
main.
Structura unei funcii este urmtoarea:
<tip> <nume>( <lista parametrilor formali>) //antet
{
<declaraii i instruciuni> //corpul funciei
}

Structura general a unui program C este urmtoarea:


<directive preprocesor>
<declaratii globale>
<tip> <functie1> (<list parametri>)
{
<declaraii locale si instruciuni>
}
...
<tip> <functien> (<list parametri>)
{
<declaraii locale si instruciuni>
}
<tip> main (<list parametri>)
{
<declaraii locale si instruciuni>
}

Un program C parcurge urmtoarele etape:


editarea fiierului surs, care const n scrierea programului folosind
regulile de sintax ale editorului de texte corespunztor;
- compilarea fiierului surs, un program specializat numit compilator,
transform instruciunile programului surs n instruciuni main. Dac nu
detecteaz erori sintactice, el va genera un fiier numit fiier obiect, care
are numele fiierului surs i extensia .obj.
- editarea legturilor, un program specializat numit linkeditor, asambleaz
mai multe module obiect i genereaz programul executabil sub forma unui
fiier cu extensia .exe. Pot s apar erori generate de incompatibilitatea
modulelor obiect asamblate.
- lansarea n execuie programul se afl sub form executabil i poate fi
lansat n execuie. n aceast etap pot s apar erori fie datorit datelor
eronate introduse n calculator, fie conceperii greite a programului.
-

16

n limbajul C exist dou categorii de funcii:


funcii care produc (returneaz) un rezultat direct ce poate fi utilizat n
diverse expresii. Tipul acestui rezultat se definete prin <tip> din antetul funciei.
Dac <tip> este absent, se presupune c funcia returneaz o valoare de tip int.
funcii care nu produc un rezultat direct. Pentru aceste funcii se va folosi
cuvntul cheie void n calitate de tip. El semnific lipsa valorii returnate la
revenirea din funcie.
O funcie poate avea zero sau mai muli parametri separai prin virgule.
Dac o funcie are lista parametrilor formali vid, antetul su se reduce la:
<tip> <nume>()

Absena parametrilor formali poate fi indicat explicit folosind cuvntul


cheie void. Astfel, antetul de mai sus poate fi scris i sub forma:
<tip> <nume>(void)

Exemple:
int g(float x, long n)
{
...
}
void f(void)
{
...
}
void main()
{...}

I.2.1. Preprocesare
Un program C poate suporta anumite prelucrri nainte de compilare. O
astfel de prelucrare se numete preprocesare. Ea se realizeaz printr-un program
special numit preprocesor. Preprocesorul este apelat automat nainte de a ncepe
compilarea.
Prin intermediul preprocesorului se pot realiza:
includeri de fiiere standard i utilizator;
definirea de macrodefiniii;
compilare condiionat.

I.2.2. Includeri de fiiere


Fiierele se includ cu ajutorul construciei #include folosindu-se formatele:
#include<specificator_de_fiier>
#include "specificator_de_fiier"

Preprocesorul localizeaz fiierul i nlocuie construcia include cu textul


fiierului localizat. n felul acesta compilatorul C nu va mai ntlni linia
#include, ci textul fiierului inclus de preprocesor.

17

Prima variant se folosete pentru ncorporarea fiierelor standard ce se


gsesc n bibliotecile ataate mediului de programare. A doua variant se folosete
uzual pentru ncorporarea fiierelor create de utilizator; dac nu este specificat
calea atunci fiierul este cutat n directorul curent i n bibliotecile ataate
mediului de programare.
Includerile de fiiere se fac, de obicei, la nceputul fiierului surs. Textul
unui fiier inclus poate s conin construcia #include n vederea includerii altor
fiiere.
Exemple:
#include<iostream.h>
#include"geo.cpp"

I.2.3. Macrodefiniii
O alt construcie tratat de preprocesor este construcia define cu
formatul:
#define <nume> <succesiune de caractere>

Folosind aceast construcie, preprocesorul substituie <nume> cu


<succesiune de caractere> peste tot n textul surs care urmeaz, exceptnd
cazul n care <nume> apare ntr-un ir de caractere sau ntr-un comentariu. Dac
succesiunea de caractere nu ncape pe un rnd ea poate fi continuat terminnd
rndul cu "\".
Se recomand ca <nume> s se scrie cu litere mari; <succesiune de
caractere> poate conine alte macrodefiniii care trebuie s fie n prealabil definite.
O macrodefiniie este definit din punctul construciei #define i pn la
sfritul fiierului surs respectiv sau pn la redefinirea ei sau pn la anihilarea ei
prin intermediul construciei: #undef <nume>
Exemple:
#define PI 3.14159
#define DIM 100
#define A 123
#define B A+120
...
x=3*B // se substituie prin x=3*123+120
#define A 123
#define B (A+120)
...
x=3*B // se substituie prin x=3*(123+120)

Macrodefiniii cu argumente
Directiva #define poate fi folosit i n sintaxa:
#define <nume>(<list de parametri>) <corp macrodefinie>

ntre <nume> i "(" nu exist spaii.

18

Exemplu:
#define MAX(a,b) ((a)>(b)?(a):(b))
...
x=max(k+5,m)

I.2.4. Compilare condiionat


Compilarea condiionat se realizeaz folosind construciile:
1.
#if expresieConstant //dac expresie este diferit de zero
text
#endif

2.
#if expresieConstant
text1
#else
text2
#endif

3.
#ifdef identificator //dac identificator a aprut ntr-o directiv #define
text
#endif

4.
#ifdef identificator // dac identificator a aprut ntr-o directiv #define
text1
#else
text2
#endif

5.
#ifndef identificator //dac identificator nu a aprut ntr-o directiv #define
text
#endif

6.
#ifndef identificator //dac identificator nu a aprut ntr-o directiv #define
text1
#else
text2
#endif

Pentru toate directivele if liniile care urmeaz pn la o directiv #endif


sau #else sunt supuse preprocesrii dac condiia testat este satisfcut i sunt
ignorate dac condiia nu este satisfcut. Liniile dintre #else i #endif sunt
supuse preprocesrii dac condiia testat de directiva #if nu este satisfcut.
Exemplu:
#ifndef tipData
#define tipData long
#endif
tipData x;

19

I.3. Operaii de intrare-ieire


Operaiile de intrare/ieire asigur instrumentul necesar pentru comunicarea
dintre utilizator i calculator. LIMBAJUL C/C++ asigur posibilitatea de a folosi
orice echipamente periferice: consola (tastatura i ecranul), imprimanta, uniti de
magnetice diverse etc.
Pentru uniformizarea modului de lucru cu dispozitivele de intrare/ieire, se
introduce un nivel intermediar ntre program i echipamentul periferic folosit.
Forma intermediar a informaiilor corespunde unui echipament "logic" i se
numete "flux" sau "ir" de informaii (stream, n limba englez) i nu depinde de
echipamentul periferic folosit. Un flux de informaii const dintr-o succesiune
ordonat de octei i poate s fie privit ca un tablou unidimensional de caractere de
lungime neprecizat. Citirea sau scrierea la un echipament periferic const n
citirea datelor dintr-un flux, sau scrierea datelor ntr-un flux.

I.3.1. Operaii de intrare / ieire, utiliznd consola, n


C++
Limbajul C++ nu dispune de instruciuni specifice pentru operaiile de
intrare/ieire. Acestea se efectueaz cu ajutorul unor funcii de bibliotec ce
folosesc conceptele generale ale limbajului C++: programare orientat pe obiecte,
cu ierarhii de clase, moteniri multiple, suprancrcarea operatorilor.
Fiierul iostream.h, care trebuie inclus n orice program pentru a apela
operaiile de I/E specifice C++, conine cele mai importante funcii de lucru cu
tastatura i ecranul.
De asemenea n acest fiier sunt definite fluxurile:
cin folosit pentru intrare, dispoziiv implicit tastatura (console input);
cout folosit pentru ieire, dispoziiv implicit ecranul (console output);
cerr folosit pentru afiarea erorilor, dispoziiv implicit ecranul;
clog
folosit pentru afiarea erorilor, dispozitiv implicit ecranul; clog
reprezint versiunea cu tampon a lui cerr.
Deoarece conceptele programrii orientate pe obiecte nu au fost prezentate,
vom explica numai modul de utilizare a funciilor de I/E.
Vom accepta c n fiierul iostream.h sunt definite noi tipuri de date
printre care istream i ostream. Obiectele de tipul istream sunt dispozitive
logice de intrare (cin este un astfel de obiect).
Obiectele de tipul ostream reprezint dispozitive logice de ieire (cout,
cerr, clog sunt astfel de obiecte).
Se prevd dou nivele de interfa ntre programator i dipozitivele logice
de intrare/ieire, prin dou seturi de funcii:
a) funcii pentru operaii de I/E la nivel nalt
b) funcii pentru operaii la nivel de caracter.

20

I.3.2. Funcii pentru operaii de I/E la nivel nalt


Pentru operaiile de I/E la nivel nalt, au fost suprancrcai operatorii ">>"
pentru fluxul cin i "<<" pentru fluxul cout, cerr, clog.
Operatorul ">>", redefinit, se numete operator de extracie sau extractor.
Aceast denumire provine de la faptul c la citire se extrag date dintr-un stream.
Operatorul "<<", redefinit, se numete operator de inserie sau insertor.
Aceast denumire provine de la faptul c un operator de ieire insereaz informaia
n stream.
Ambii operatori posed proprietatea de asociativitate la stnga i returneaz
o referin la streamul asociat ca prim operand (cin pentru ">>", respectiv cout,
cerr sau clog pentru "<<"), deci ei pot fi nlnuii.
Exemplu:
#include<iostream.h>
void main()
{ float v,t,d;
cout<<Distanta parcursa(Km)=; cin>>d;
cout<<Numar de ore =;
cin>>t;
v=d/t;
cout<<Viteza medie este de <<v<< km/h;
// nlnuirea operatorului <<
}

Nu se accept nlnuiri mixte ("<<" cu ">>").


Faptul ca operatorii returneaz o referin ctre stream, permite s se poat
testa starea streamului ca n exemplul urmtor:
#include <iostream.h>
void main()
{ int n;
if(cin>>n) cout<<"citire cu succes";
else cout<<"esec la citire"; // s-a tastat un ir nenumeric
}

Tipurile de date predefinite acceptate implicit de un stream de intrare sunt:


char, short, int, long toate cu sau fr unsigned, float double i ir de caractere.
A extrage o valoare numeric dintr-un ir nseamn:
ignorarea tuturor caracterelor de tip spaiu;
un test dac primul caracter nespaiu este cifr, semn sau punct zecimal
(pentru tipurile flotante). n caz c aceast condiie este ndeplinit se va continua
cu urmtorul pas, altfel se va semnaliza eroare i nu se vor mai putea efectua
operaii de intrare pn ce nu se trateaz respectiva eroare;
se extrag toate caracterele consecutive, pn la ntlnirea unuia invalid
pentru respectivul tip de dat;
n cele din urm, se va efectua conversia irului extras la tipul de dat
respectiv.
n cazul tipului de dat char, o secven de genul:
char c;
cin>>c;

atribuie variabilei c, primul caracter nespaiu aflat n streamul de intrare.

21

Dac se dorete extragerea unui ir de caractere, se vor citi toate caracterele


ntlnite consecutiv n streamul de intrare, ncepnd cu primul caracter nespaiu din
stream, pn se va ajunge la un caracter spaiu. Stringului astfel obinut i se va
aduga la sfrit caracterul NULL (\0).
S presupunem c, la o operaie de citire, primul caracter nespaiu din
streamul de intrare va fi invalid pentru tipul de dat citit. n acest caz valoarea
variabilei destinaie va rmne neschimbat. n plus se va seta un indicator,
indicatorul "fail" (eec) al streamului de intrare, fapt ce va duce la imposibilitatea
de a mai citi din acest stream pn la resetarea indicatorului.
Indicatorul de eroare se anuleaz cu ajutorul metodei (funciei) clear().
Sintaxa de apel pentru streamul cin este:
cin.clear();

Metoda fail(), returneaz o valoare non-zero (true) dac streamul de citire se


afl n stare de eroare i 0 dac citirea s-a efectuat cu succes.
Sintaxa de apel pentru streamul cin este:
cin.fail()

Metoda eof(), returneaz o valoare 1 (true) dac s-a atins sfritul


streamului din care citim i 0 n caz contrar.
Sintaxa de apel pentru streamul cin este:
cin.eof()

Tipurile de date predefinite pe care le accept implicit un stream de ieire


sunt: char, short, int, long cu sau fr unsigned, float,
double, long double, pointeri la aceste tipuri i tipul void*.
Pointerul la caracter (char*) este utilizat la tiprirea irurilor de caractere
iar void* la cea a variabilelor de tip pointer (afiarea se face n hexa).
Exemple:
1.
#include <iostream.h>
void main()
{ char c;
long n;
float x;
double t;
cin>>c; cout<<"c="<<c<<\n; // cout<<'\n' are ca efect saltul la linie nou.
cin>>n; cout<<"n="<<n<<'\n';
cin>>x; cout<<"x="<<x<<'\n';
cin>>t; cout<<"t="<<t<<'\n';
}

2.
#include <iostream.h>
void main()
{ char s[20];
cin>>s; cout<<s;
}

Deoarece numele unui tablou are ca valoare adresa primului su element,


nseamn c, n exemplul de mai sus, s este de fapt un pointer (constant) ctre
caractere.

22

3.
#include <iostream.h>
void main()
{ char* a="xyzw";
cout<<"sirul a="<<a<<" adresa sirului a="<<(void*)a;
}

I.3.3. Manipulatori de intrare / ieire


Pentru situaia n care nu dorim ca citirea dintr-un stream sau scrierea ntr-un
stream s se fac n formatele implicite din C++, sunt prevzute i posibiliti de a
controla formatele de intrare i de ieire prin comenzi incluse n construciile de
intrare/ieire.
Aceste comenzi se numesc manipulatori de I/E.
Pentru a putea folosi manipulatorii care au parametri (de exemplu setw())
trebuie s includem fiierul iomanip.h. Acest lucru nu este necesar dac utilizm
manipulatori fr parametri. Manipulatorii pot apare n lanul de operaii de I/E.
Lista manipulatorilor de I/E este urmtoarea:
Manipulator
dec
oct
hex
setbase(int baza)
setw(int w)
setprecision(int p)
setfill(int ch)
setiosflags(long f)
resetiosflags(long f)
flush
endl
ends
ws

Intrare/
ieire
formateaz datele numerice n zecimal valabil E
pn la resetare
formateaz datele numerice n octal, valabil E
pn la resetare
formateaz datele numerice n hexazecimal, E
valabil pn la resetare
stabilete baza de numeraie la baza (8,10,16), E
valabil pn la resetare
stabilete la w numrul de poziii pe care se va E
afia urmtoarea dat de scris.
stabilete numrul de cifre aflat dup punctul E
zecimal. comanda este valabil pn la
reapelare.
stabilete caracterul de umplere, implicit spaiu, E
valabil pn la resetare
activeaz indicatorii de format specificai n I/E
variabila f.
dezactiveaz indicatorii de format specificai n I/E
variabila f.
elibereaz un stream
E
scrie un caracter "newline" i elibereaz E
streamul
Scrie un caracter null
E
ignor caracterele de tip spaiu
I
Scop

23

Exemplu:
#include<iostream.h>
#include<iomanip.h>
void main()
{ cout<<hex<<100<<endl;
cout<<dec <<setfill('*')<<setw(5)<<100<<endl;
}

I.3.4. Indicatori de format


Fiecare stream din C++ are asociat un numr de indicatori de format flags.
Ei sunt codificai ntr-o variabil de tip long.
Urmtoarele constante definesc aceti indicatori de format:
Constanta
Valoare Rol
ios::skipws
0x0001 Ignor caracterele de tip spaiu de la intrare
ios::left
0x0002 aliniere la stnga n ieire
ios::right
0x0004 aliniere la dreapta n ieire
ios::internal
0x0008 semn aliniat ex: 55 >
55
ios::dec
0x0010 conversie n baza 10
ios::oct
0x0020 conversie n baza 8
ios::hex
0x0040 conversie n hexazecimal
ios::showbase 0x0080 se va tipri i baza (0 - octal, 0x -hexa)
afieaz i zerourile nesemnificative de dup
ios::showpoint 0x0100
punctul zecimal
Pentru "literele" din baza 16 se vor utiliza
ios::uppercase 0x0200
majuscule
ios::showpos 0x0400 ntregii pozitivi sunt prefixati de "+"
Pentru date flotante se folosete notaia stiinific
ios::scientific 0x0800
( 1.234e2 )
ios::fixed
0x1000 utilizeaz notaia normal ( 123.45 )
streamul se golete (afieaz) dup fiecare
ios::unitbuf
0x2000
inserare
Stream-urile predefinite de ieire se vor goli dup
ios::stdio
0x4000
fiecare inserare
Prin aplicarea operatorului de tip or "|" putem poziiona mai muli indicatori.
De exemplu:
cout<<setiosflags(ios::left|ios::showpoint);

realizeaz alinierea la stnga i afiarea zerourilor nesemnificative de dup


punctul zecimal.
Pentru stream-urile standard, avem urmtoarele valori implicite:
pentru cin: 0x0001
pentru cout: 0x2001
pentru cerr: 0x2001 pentru clog: 0x0001
Pentru a afla strile curente ale indicatorilor, se folosete funcia flags().

24

Funcia se apeleaz utiliznd formatul: <stream>.flags() i returneaz


o valoare de tip long ce conine, codificat, indicatorii de stare ai streamului
asociat.
Exemplu: Indicatorii streamului cin se pot afia astfel:
cout<<hex<<cin.flags();

I.3.5. Funcii pentru operaii la nivel de caracter


Funciile uzuale la nivel de caracter, asociate unui stream sunt:
1) stream& put(char c)

insereaz un caracter n streamul de ieire i returneaz streamul de ieire;


Exemplu de apel:
char x;
...
cout.put(x);
2) int get(void)

extrage urmtorul caracter din streamul de intrare (chiar spaiu) i l


returneaz (se returneaz EOF(-1) cnd se ajunge la sfritul intrrii);
Exemplu de apel:
char x;
x=cin.get();

Exemplu de utilizare:
Urmtorul program copiaz caracterele din streamul de intrare cin (pn la
ntlnirea caracterului CTRL Z) n streamul de ieire cout.
#include <iostream.h>
void main()
{ char c;
while((c=cin.get())!=EOF) cout.put(c);
}
3) istream& get(unsigned char&)
4) istream& get( signed char& )

Ambele funcii extrag urmtorul caracter din streamul de intrare n variabila


dat ca argument i returneaz streamul de intrare.
Exemplu de apel:
char x;
cin.get(x);
5) istream& get (unsigned char *c, int n, char='\n');
6) istream& get ( signed char *c, int n, char='\n');

Ambele funcii extrag un ir de caractere din streamul de intrare n variabila


tablou "c". Numrul maxim de caractere al irului este dat de al doilea argument (se
extrag maxim n1 caractere).

25

Al treilea argument indic aa-zisul caracter de sfrit. Caracterul de sfrit


nu va fi citit i nici nu va fi eliminat din stream.
Exemple de apel:
char c[10];
cin.get(c,10);
//se extrag 9 caractere sau pn la ntlnirea caracterului de sfrit implicit '\n'
cin.get(c,10,',');
//se extrag 9 caractere sau pn la ntlnirea caracterului "," care nu va fi extras din ir
7) istream& getline(unsigned char *c, int n, char='\n');
8) istream& getline(signed char *c, int n, char='\n');

Sunt echivalente cu get dar extrag (fr a fi depus n c), eventual, i


delimitatorul dac este ntlnit nainte de a citi toate cele n1 caractere propriu-zise
ale irului.
Exemple de apel:
char c[10];
cin.getline(c,5);

- se extrag i se depun n c, 4 caractere sau pn la ntlnirea caracterului


'\n' (<enter>), care va fi extras din stream.
cin.getline(c,5,'.');

- se extrag 4 caractere sau pn la ntlnirea caracterului '.' care va fi extras


din stream.
9) istream& ignore(int n=1, int =EOF);

Neglijeaz un numr maxim de caractere, dat de primul argument (valoare


implicit 1) sau pn la ntlnirea delimitatorului dat de al doilea argument.
Returneaz o referin ctre streamul de intrare.
Exemple de apel:
cin.ignore(80,'#'); // ignor urmtoarele 80 de caractere sau pn ntlnete "#"
cin.ignore();
//ignor urmtorul caracter.

Exemplu de utilizare combinat a metodelor eof(), fail(), ignore():


#include <iostream.h>
void main()
{int x,i;
i = 0;
while (1) // ciclu infinit; se iese din el la tastarea combinatiei CTRL+Z
{i++;
cout<<"x"<<i<<"="; cin >> x;
if(cin.eof()) break; //s-a atins sfarsitul streamului (CTRL+Z)
if (cin.fail()) //esec la citire
{ cout <<"eroare"<<endl; i--;
cin.clear(); // resetam indicatorul de eroare
cin.ignore(80,'\n'); /* eliminam din stream caracterele
care au generat eoarea */
}
}
}

26

10) int gcount();

Returneaz

numrul de caractere citite din stream la ultima operaie de

citire.
Exemplu de apel:
void main()
{ int x; char y[25];
cin>>x>>y;
cout<<cin.gcount();
}

Dac tastm:

1234 abc<enter> rezultatul va fi 3.

11) int peek();

- ntoarce caracterul urmtor fr s-l extrag din stream


12) istream& putback(char c);

- insereaz caracterul c n stream (ca prim caracter de citit)


#include <iostream.h>
void main()
{ char c;
c=cin.get();
// citete primul caracter din stream
cout<<c<<endl; // afieaz caracterul citit
cin.putback('x'); // insereaz 'x' n stream
c=cin.get();
// citete caracterul inserat
cout<<c<<endl;
}
13) istream& read(char * c, int n);

- citete n caractere din stream n tabloul c. Niciun caracter de


delimitare nu ntrerupe citirea.
Exemplu:
#include <iostream.h>
void main()
{ char c[10];
cin.read(c,5); //citete 5 caractere la care adaug caracterul '\0'
cout<<c<<endl;
}
14) ostream& write(char *c, int n);

- insereaz n caractere din irul c n streamul de ieire asociat

I.3.6. Gestiunea ecranului n mod text


Biblioteca standard a limbajului C /C++ conine funcii pentru gestiunea
ecranului. Acesta poate fi gestionat n dou moduri: mod text sau mod grafic.
Funciile standard de gestiune a ecranului n mod text au prototipurile n
fiierul conio.h.

27

n mod curent ecranul este format din 25 linii i 80 coloane. Colul stnga
sus al ecranului are coordonatele (1,1). Colul dreapta jos al ecranului are n mod
curent coordonatele (80,25).
Prezentm cteva funcii, uzuale, pentru gestiunea ecranului:
15) void window(int x1,int y1,int x2,int y2);

- Definete o fereastr pe ecran, unde (x1,y1) reprezint colul stnga sus al


ferestrei, (x2,y2) reprezint colul dreapta jos al ferestrei.
Funciile de gestiune ale ecranului acioneaz numai asupra ferestrei active.
Dac parametrii de apel sunt eronai, funcia nu are efect.
Exemplu:
#include <iostream.h>
#include <conio.h>
void main()
{ clrscr();
window(40,10,60,20);
cout<<"xxx";
cout<<wherey()<<wherex();
}
16) void clrscr(void);

- terge fereastra activ i poziioneaz cursorul n colul stnga sus al


ferestrei active, adic n poziia de coordonate (1,1).
17) int wherex(void);

- returneaz numrul coloanei pe care se afl cursorul


18) int wherey(void);

- returneaz numrul liniei pe care se afl cursorul


19) void gotoxy(int x,int y);

- mut cursorul n punctul de coordonate (x,y) relative la fereastra activ.


n fiierul conio.h exist i funcii de lucru cu tastatura, printre care:
20) int getche();
21) int getch();

- realizeaz citirea de la intrarea standard a caracterului curent i returneaz


codul ASCII al caracterului citit. Aceste funcii au acces direct la caracter de ndat
ce acesta a fost tastat. getche() efectueaz citirea cu ecou, pe cnd getch() o
efectueaz fr ecou.
22) int kbhit(void);

- funcia ntoarce o valoare diferit de 0 dac a fost apsat o tast.

28

I.4. Instruciuni C/C++


Descrierea aciunilor ce vor fi executate de calculator se face cu ajutorul
instruciuilor.

I.4.1. Instruciunea de atribuire


Se obine scriind punct i virgul dup o expresie de atribuire sau dup o
expresie n care se aplic la o variabil unul din operatorii de incrementare sau
decrementare. Deci o instruciune de atribuire are una din urmtoarele formate:
<expresie de atribuire>;
<variabila>++;
++<variabila>;
<variabila>--;
--<variabila>;

I.4.2. Instruciunea compus (blocul)


Instruciunea compus este o succesiune de instruciuni incluse ntre
acolade, succesiune care eventual poate conine declaraii. Sintaxa:
{
<declaraii i instruciuni>
}

Dac sunt prezente, declaraiile definesc variabile care sunt valabile numai
n instruciunea compus respectiv. Dup paranteza nchis a unei instruciuni
compuse nu se pune ";"
Structura unei funcii poate fi considerat ca fiind:
<antetul funciei>
<instruciune compus>

I.4.3. Instruciunea if
Instruciunea if implementeaz structura alternativ.
Ea are unul din formatele:
Formatul 1:
if(<expresie>)
<instruciune1>
else
<instruciune2>

Dac <expresie> este diferit de zero se execut <instruciune1>, altfel se


execut <instruciune2>.

29

Formatul 2:
if(<expresie>) <instruciune>

Dac <expresie> este diferit de zero se execut <instruciune>, altfel


instruciunea if nu are niciun efect.
O selecie multipl se poate programa cu mai multe instruciuni if else n
cascad.
Sintaxa:
if ( <expresie1> ) <instruciune1> ;
else if ( <expresie2> ) <instruciune2> ;
...
else if ( <expresien> ) <instruciunen> ;
else <instruciunen+1> ;

Trebuie inut seama de faptul c else este asociat celui mai apropiat if.
Pentru a determina un alt mod de asociere se pot utiliza delimitatorii de bloc.

if ( <expresie1> )
{ if ( <expresie2 > ) <instruciune1 > }
else <instruciune2 >

n acest mod else se asociaz primului if i nu celui deal doilea care este
mai apropiat.
Exemplu de utilizare a instruciunii if:
Programul urmtor calculeaz valoarea funciei
4 x 2 2 x 1,

f ( x) 50 ,
2 x 2 8 x 1,

dac x 0
dac x 0
dac x 0

ntr-un punct x introdus de la tastatur.


#include<iostream.h>
#include<conio.h>
void main()
{ float x,f;
cout<<"x="; cin>>x; // Citirea lui x
// Evaluarea functiei:
if(x<0) f=4*x*x+2*x-1;
else if(x==0) f=50;
else
f=2*x*x+8*x+1;
cout<<"f("<<x<<")="<<f<<endl;

// Afisarea rezultatului

30

I.4.4. Instruciunea while


Instruciunea while implementeaz structura repetitiv cu test iniial i are
sintaxa:
while(<expresie>)
<instruciune>

Se execut <instruciune> ct timp <expresie> este adevrat.


Exemple de utilizare a instruciunii while:
1) Fie x un vector cu n elemente flotante ce se introduc de la tastatur.
Urmtorul program inverseaz ordinea elementelor n vector.
#include<iostream.h>
void main()
{float x[100],aux;
int n,i,j;
// Citirea vectorului:
cout<<"n="; cin>>n;
i=0;
while(i<n)
{ cout<<"x"<<i<<"="; cin>>x[i];
i++;
}
// Inversarea elementelor:
i=0; j=n-1;
while(i<j)
{aux=x[i]; x[i]=x[j];
i++;
j--;
}

x[j]=aux;

// Afisarea vectorului:
cout<<" vectorul inversat este:";
i=0;
while(i<n)
{ cout<<x[i]<<" ";
i++;
}
}

31

2) S se calculeze valoarea numrului utiliznd formula lui Madhava din


k

Sangamagrama(anul 1400)

12

k 0

1

3
2k 1

#include<iostream.h>
#include<iomanip.h>
#include <math.h> // pentru fabsl =valoarea absoluta
long double Pi()
{ long double eps=1.0e-20;
long double pi=1.0, pia=0,t=1;
/* pi=valoarea la pasul curent, k;
pia=valoarea de la pasul anterior;
t=(-1/3)^k ;
*/
unsigned long k=1;
while(fabsl(pi-pia)>eps)
{ pia=pi;
t*=-1.0/3.0;
pi+=t/(2*k+1);
k++;
}
// cout<<k<<endl;
return sqrt(12)*pi;
}
void main()
{ cout<<endl<<setw(22)<<setprecision(20)<<Pi()<<endl;}

I.4.5. Instruciunea for


Instruciunea for, ca i instruciunea while se utilizeaz pentru
implementarea structurii repetitive cu test iniial. Uzual, instruciunea for se
folosete pentru implementarea ciclui cu contor.
Formatul ei este:
for( <exp1>; <exp2>; <exp3> )
<instruciune>

unde
<exp1> se numete expresie de iniializare i se evalueaz o singur dat,
naintea primei iteraii, realiznd iniializarea ciclului. Uzual, ea atribuie o valoare
iniial variabilei de control a ciclului. Valoarea sau expresia de iniializare poate
lipsi in situaia n care iniializarea ciclului este fcut n afara sa, sau poate conine
mai multe expresii de iniializare separate prin operatorul virgul.
<exp2> se numete expresie de testare i se execut naintea fiecrei iteraii,
reprezentnd condiia de continuare aciclului. Ciclul se termin cnd aceast
expresie devine fals. Dac <exp2> lipsete, se consider c expresia de test este
adevrat tot timpul, iar ciclul se execut fr ntrerupere.

32

<exp3> specific reiniializrile ce se efectueaz dup fiecare iteraie;


<instruciune> formeaz corpul ciclului, care se execut repetat.
Expresiile <exp1>,<exp2>,<exp3> pot fi i vide. Totui caracterele ";"
vor fi totdeauna prezente.
Instruciunea for este echivalent cu:
<exp1>;
while(<exp2>)
{ <instruciune>
<exp3>;
}

Reciproc, orice instruciune while:


while(<exp>) <instruciune>

este echivalent cu
for( ; <exp> ; ) <instruciune>

Instruciunea:
for(;;) <instruciune>

definete un ciclu "infinit" din care se iese prin alte mijloace dect cele
obinuite.
Exemple de utilizare a instruciunii for:
(a) k k
x
k!
k 0
n

Programul urmtor calculeaz suma S


#include<iostream.h>
void main()
{ long double T,S;
float a,x;
int n,k;
cout<<"n="; cin>>n;
cout<<"a="; cin>>a;
cout<<"x="; cin>>x;
T=1;
S=1;
for(k=1;k<=n;k++)
{ T*=-a*x/k;
S+=T;
}
cout<<"S="<<S<<endl;
}

33

2) Fie x1, x2,, xn ,numere ntregi ce se introduc de la tastatur. S se


determine suma numerelor pozitive i suma ptratelor numerelor negative.
#include<iostream.h>
void main()
{ int n,x,S1,S2,i;
S1=0;
S2=0;
cout<<"n="; cin>>n;
for(i=1;i<=n;i++)
{ cout<<"x"<<i<<"="; cin>>x;
if(x>=0)S1+=x;
else S2+=x*x;
}
cout<<"Suma numerelor pozitive="<<S1<<endl;
cout<<"Suma patratelor numerelor negative="<<S2<<endl;
}

3) Fie a0, a1,, an-1 i x0, x1,, xn-1, numere reale ce se introduc de la tastatur
n 1

n vectorii a i x. Programul urmtor calculeaz suma S ai xi


i 0

#include<iostream.h>
void main()
{float a[100],x[100],S;
int n,i;
cout<<"n="; cin>>n;
for(i=0;i<n;i++) { cout<<"a"<<i<<"="; cin>>a[i]; }
for(i=0;i<n;i++) { cout<<"x"<<i<<"="; cin>>x[i]; }
S=0;
for(i=0;i<n;i++)
S=S+a[i]*x[i];
cout<<"S="<<S;
}

Putem avea mai multe cicluri for consecutive, ca de exemplu:


p=1;
for(i=1; i<=m; i++)
for(j=1; j<=n; j++)
for(k=1; k<=p; k++)
p*=i+j+k;

34

I.4.6. Instruciunea do while


Aceast instruciune are formatul:
do
<instruciune>
while(<expresie>);

i implementeaz structura repetitiv cu test final.


Efect: Execut n mod repetat <instruciune> (simpl sau compus) ct timp
<expresie> este adevrat (diferit de zero).
Exemplu de utilizare a instruciunii do while:
Programul urmtor calculeaz suma unor produse de perechi de numere
introduse de la tastatur ct timp suma rezultat este mai mica dect 1000.
#include<iostream.h>
void main()
{long x,y,S;
S=0;
do
{ cout<<"x,y=";
cin>>x>>y; //se vor tasta dou numere ntregi separate prin spaiu
S+=x*y;
}
while (S<1000);
cout<<"S="<<S<<endl;
}

I.4.7. Instruciunea break


Formatul acestei instruciuni este:
break;

Ea produce ieirea forat din instruciunile repetitive while, do while


i for sau dintr-o instruciune switch. Instruciunea break permite ieirea
dintr-un singur ciclu, nu i din eventualele cicluri care ar conine ciclul n care s-a
executat instruciunea break.
Un exemplu de utilizare frecvent, il constituie ieirea dintr-un ciclu infinit
de forma:
for(;;)
{ ...
if(...) break;
...
}

35

Instruciunea break provoac eroare dac apare n afara instruciunilor


while, for, do while i switch.
Exemple de utilizare a instruciunii break:
1) Urmtorul program implementeaz jocul Ghicete numrul!.
#include<iostream.h>
#include<conio.h>
void main()
{float a, b;
cout<<"Propuneti un numar: ";cin>>a; // nr. ce trebuie ghicit
clrscr(); // stergerea ecranului
cout<<"Ghiciti numarul: "; cin>>b;
while(1) // ciclu infinit
{ if(a==b) {cout<<"Ai ghicit nr!"; break;}
if(a<b) cout<<"Numar prea mare"<<endl;
else
cout<<"Numar prea mic"<<endl;
cout<<"Incercati alt numar:"; cin>>b;
}
getch();
}

2) Urmtorul program afieaz poziia pe care se afl un numr x n vectorul


neordonat (a0, a1,..., an-1).
#include<iostream.h>
void main()
{long a[100],x,poz;
int n,i;
// Citirea vectorului:
cout<<"n=";
cin>>n;
cout<<Tastati elementele vectorului:;
for(i=0;i<n;i++) cin>>a[i];
// Citirea lui x:
cout<<"x=";
cin>>x;
// Determinarea pozitiei lui x in vector:
poz=-1;
for(i=0;i<n;i++) if(x==a[i]){poz=i; break;}
if(poz>=0) cout<<x<<"se afla in vector pe pozitia "
<<poz<<endl;
else
cout<<x<<"nu se afla in vector "<<endl;
}

36

3) Urmtorul program verific dac un vector format din n elemente numere


reale, este ordonat cresctor.
In program se folosete variabila semafor pentru a indica dac vectorul este
ordonat cresctor (semafor==1) sau nu (semafor==0).
#include<iostream.h>
void main()
{float a[100];
int n,i;
cout<<"n="; cin>>n;
cout<<"Tastati "<<n<<"numere separate prin spatiu:"<<endl;
for(i=0;i<n;i++)cin>>a[i]; //citirea elementelor vectorului
int semafor;
semafor=1;
for(i=1;i<n;i++)
if(a[i]<a[i-1]){semafor=0;break; /*vectorul nu este ordonat crescator*/ }
if(semafor==1)
cout<<"vectorul este ordonat crescator"<<endl;
else
cout<<"vectorul nu este ordonat crescator"<<endl;
}

I.4.8. Instruciunea continue


Are formatul:
continue;

Se utilizeaz n corpul unui ciclu i are urmtorul efect:


n ciclurile while i do while ea realizeaz saltul la evaluarea
expresiei care decide asupra continurii ciclului;
0251659264251660288 n ciclul for ea realizeaz saltul la pasul de
while( expr)
{
..
if() continue;
...
}

do
{ ..
if() continue;
..
}
while(expr);

for(expr1; expr2; expr3)


{
.
if() continue;
.
}

37

reiniializare.
Astfel, programul
#include<iostream.h>
void main()
{ int i;
for (i = 0; i < 5; i++)
{ if (i == 3) continue;
printf("i = %d\n",i);
}
cout<<"valoarea lui i la iesirea din ciclul for este <<i;
}

Va afisa urmatoarele rezultate


i=0
i=1
i=2
i=4
valoarea lui i la iesirea din ciclul for este 5
Exemplu de utilizare a instruciunilor continue i break:
Se introduc de la tastatur numere ntregi (pozitive i negative) ct timp suma
numerelor pozitive este mai mic dect 1000. Programul afieaz ptratul
numerelor pozitive.
#include<iostream.h>
#include<conio.h>
void main()
{ long S,x;
S=0;
for(;;) // ciclu infinit
{ cout<<"x="; cin>>x;
if(x<=0) continue; /* salt la partea de reiniializare a instruciunii for
(n cazul de fa expresia de reiniializare este
vid)*/
S+=x;
if(S>=1000) break; // ieire din for
cout<<"x*x="<<x*x<<endl;
}
}

I.4.9. Instruciunea switch


Implementeaz structura de selecie multipl. Sintaxa acestei instruciuni
este:
switch(<expresie>)
{ case <c1>: <sir1>
case <c2>: <sir2>
...
case <cn>: <sirn>
default : <sir>

38

unde
<c1>,<c2>,...,<cn> sunt expresii constante de tip ntreg,
<expresie> este o expresie de tip ntreg (orice tip ntreg),
<sir1>,...,<sirn> sunt iruri de instruciuni (un astfel de ir poate fi i vid).
Efect:
1) Se evalueaz <expresie>.
2) Se compar valoarea expresiei <expresie>, succesiv, cu valorile
<c1>,<c2>,...,<cn>.

3) Dac valoarea <expresie> coincide cu <ck>, se execut secvena de


instruciuni <sirk>, <sirk+1>,...,<sirn>,<sir>.
Dac n aceast secven se ntlnete instruciunea break, atunci aceasta
are ca efect ieirea din instruciunea switch.
4) n cazul n care valoarea expresiei nu coincide cu niciuna din
constantele <c1>,<c2>,...,<cn> se execut secvena de instruciuni definit de
<sir>. Alternativa default nu este obligatorie, n lipsa ei, dac valoarea
<expresie> nu coincide cu niciuna din constantele <c1>,<c2>,...,<cn>
instruciunea switch nu are niciun efect.
Exemplu de utilizare a instruciunii switch:
Programul urmtor calculeaz funcia

sin x, k 1

cos x, k 2

f(x,k) tg x,
k3
ctg x, k 4

5 2 sin x 3 cos x , k {1,2,3,4}


unde x este dat n grade.
#include<math.h>
#include<conio.h>
#include<iostream.h>
void main()
{ int k;
float x,f;
float r; // pentru conversia lui x n radiani
cout<<"k="; cin>>k;
cout<<"x="; cin>>x;
r=x*3.141592/180;
switch(k)
{ case 1: f=sin(r);
break;
case 2: f=cos(r);
break;

39

case 3: f=tan(r);
break;
case 4: f=1/tan(r);
break;
default: f=sqrt(5+2*sin(r)+3*cos(r));
}
cout<<"f("<<k<<","<<x<<")="<<f<<endl;
}

I.4.10. Instruciunea vid


Pentru instruciunea vid nu exist cuvnt rezervat, prezena ei este marcat
prin caracterul punct i virgul i nu are niciun efect asupra variabilelor, starea
acestora rmnnd neschimbat; Instruciunea vid este necesar n anumite
situaii de programare. De exemplu, poate fi util pentru un ciclu fr instruciuni
n corpul su:
i=0;
while(x[i++]=y[i]); /* copiaz elementele vectorului y n vectorul x pn la
ntlnirea primului element zero din y */

I.4.11. Instruciunea goto


Prin etichet nelegem un nume urmat de dou puncte (:)
<nume>:
Etichetele sunt locale funciei i prefixeaz instruciuni. Instruciunea goto
are formatul
goto <nume>;

Ea realizeaz saltul la instruciunea prefixat de <nume>:


Se recomand folosirea instruciunii goto cnd dorim s ieim dintr-un ciclu
inclus n mai multe cicluri.

I.4.12. Apelul unei funcii


O funcie de forma:
void <nume funcie>(<lista parametrilor formali>)
{ ... }

care nu produce o valoare direct, se apeleaz printr-o instruciune de apel


cu urmtorul format:
<nume funcie>(<lista parametrilor efectivi>);

O funcie de forma
<tip returnat> <nume funcie>(<lista parametrilor formali>)
{ ... }

unde <tip returnat> este diferit de void (prin urmare returneaz


valori directe), poate fi apelat fie printr-o instruciune de apel, cnd nu dorim s
utilizm valoarea returnat, fie sub forma unui operand al unei expresii cnd
utilizm valoarea returnat. In exemplul urmtor funcia int getch(void)

40

(returneaz codul ASCII al caracterului citit de la tastatur), este apelat n ambele


variante.
#include<conio.h>
#include<iostream.h>
void main()
{char c;
cout<<tastati un caracter;
c=getch();
//citete caracterul tastat i l memoreaz n c (folosim valoarea
returnat)
cout<<c<<endl;
getch();
// citete caracterul tastat fr memorare (nu folosim valoarea
returnat)
}

I.4.13. Instruciunea return


Revenirea dintr-o funcie se poate face n dou moduri:
la ntlnirea instruciunii return;
dup execuia ultimei sale instruciuni, adic a instruciunii ce precede
acolada nchis ce termin corpul funciei respective. n aceast situaie funcia nu
returneaz nicio valoare.
Instruciunea return are dou formate:
return;

caz n care funcia nu returneaz un rezultat direct(tipul funciei este void),


sau
return <expresie>

caz n care funcia returneaz valoarea expresiei <expresie> (convertit,


dac este cazul, la tipul funciei).
Exemplu:
In urmtorul program funcia int prim(long n) returneaz 1 dac
argumentul este numr prim i 0 n caz contrar.
#include<iostream.h>
#include<math.h> //pentru funcia sqrt() - radical de ordin 2
int prim(long n) // verifica daca n 1 este prim
{ if(n==1) return 0; //1 nu este prim
if(n==2||n==3) return 1; // 2 si 3 sunt nr. prime
if(n%2==0) return 0; // n nu este prim pentru ca se divide cu 2
long r=sqrt(n);
for( long d=3; d<=r; d+=2)
if(n%d==0) return 0;
return 1;
}
void main()
{ long n;

41

cout<<n=; cin>>n;
if(prim(n))cout<<n<< este numar prim <<endl;
else
cout<<n<< nu este numar prim <<endl;
}

I.5. Sfera de influen a variabilelor


n funcie de locul de declarare, variabilele pot fi: globale cnd sunt
declarate n afara funciilor i locale cnd sunt declarate in interiorul funciilor.
Variabilele globale formeaz nivelul extern. Aceste variabile sunt accesibile
din orice funcie a fiierului surs care urmeaz declaraiei. Variabilele globale se
aloc la compilare i rmn n memoria calculatorului pe tot parcursul executrii
programului, de aceea se mai numesc i permanente.
Variabilele locale formeaz nivelul intern si este format din declaraiile
coninute n interiorul blocurilor formeaz (prin bloc nelegem o instruciune
compus sau corpul unei funcii, adic o succesiune de instruciuni delimitate de
acolade). Aceste variabile pot fi folosite (sunt vizibile) doar n blocul n care au
fost declarate sau ntr-un bloc subordonat acestuia. La nivel inferior putem declara
o variabil avnd aceeai denumire cu a uneia declarate la nivel superior. In acest
caz noua declaraie va fi valabil la acest nivel i la nivelele inferioare
(subordonate), iar n nivelele superioare rmne valabil declaraia iniial.
Variabilele locale pot fi declarate statice (prin utilizarea cuvntului cheie
static), urmnd s fie alocate la compilare is ramn n memoria
calculatorului pe tot parcursul executrii programului. Variabilele locale nestatice
sunt create i li se aloc spaiu n memoria calculatorului numai n momentul n
care se execut blocul de program n care este declarat variabila. La ncheierea
execuiei blocului respectiv, variabila dispare i spaiul de memorie va fi alocat
altor blocuri. Dac se revine ulterior n blocul iniial, variabila va fi realocat i
poate s primeasc alt adres. Variabilele de acest fel se numesc variabile cu
alocare automat a adresei (variabile automatice). Alocarea variabilelor din
clasa "auto" se face pe stiva sistemului. Variabilele locale, al cror domeniu de
valabilitate se limiteaz la un bloc sunt n mod implicit variabile automatice, chiar
dac nu se menioneaz n mod explicit acest lucru. De asemenea, parametrii
formali sunt variabile din clasa "auto" i deci se aloc pe stiva sistemului. Dac
dorim ca o variabil local s nu fie alocat pe stiv, deci s nu fie "auto", o
declarm obinuit, dar declaraia va fi precedat de cuvntul "static":
static <tip> <lista de nume>;

Exemplu:
float f()
{ int k;
static int a[5];
// ...
}

Variabila simpl k, precum i variabila tablou a sunt cunoscute i pot fi


referite n interiorul blocului n care au fost declarate. Se mai spune c ele sunt

42

locale. Variabila tablou a, descris prin cuvntul cheie static, i pstreaz aceeai
adres pe toat durata programului, adres pe care o primete la nceputul
executrii programului. Variabilei k i se aloc spaiu pe stiv de fiecare dat cnd
se execut funcia f(), la adrese care pot fi diferite.
Declaraia informativ "extern"
Pentru ca o variabil global s poat fi folosit de funcii situate n alt fiier
surs, sau n cadrul aceluiai fiier n funcii anterioare declarrii variabilei, trebuie
ca acea variabil s fie descris printr-o declaraie "extern" n funciile
respective sau n afara oricrei funcii ale noului fiier. Acum fiierele pot fi
compilate separat i linkeditate mpreun.
Exemplu:
Fiierul F1.CPP
...
int x,y;
...

Fiierul F2.CPP
...
extern int x,y;
int suma(){return x+y;}

Fiierele se pot compila separat.


Pentru obinerea executabilului vom include n fiierul F2.CPP, fiierul
F1.CPP cu ajutorul directivei #include"F1.CPP" sau vom crea un proiect. Pentru
crearea proiectului vom selecta, din meniul turbo C, Open project. Alegem
pentru proiect, de exemplu, numele PR1. Includem fiierele F1.CPP i F2.CPP
utiliznd tasta funcional <Insert>. Compilarea proiectului se face cu Build
all din Compile. tergerea unui fiier din proiect se face prin poziionarea pe
fiierul respectiv cu ajutorul sgeilor i apoi acionarea tastei <Delete>.
Exemplificare:
Program pentru ordonarea cresctoare a unui vector de numere ntregi:
#include<iostream.h>
#include<conio.h>
long x[100];
int n; // variabile globale
void citeste() // funcie pentru citirea vectorului
{ int i; //variabil local
cout<<"n="; cin>>n;
cout<< "Tastati "<<n<<" numere intregi:"
for(i=0;i<n;i++)
{ cout<<"x["<<i+1<<"]="; cin>>x[i];}
}

43

void sorteaza() // funcie pentru ordonarea vectorului


{ int i,j; //variabile locale
for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(x[i]>x[j])
{ long aux; //variabil local
aux=x[i]; x[i]=x[j]; x[j]=aux;
}
}
void afiseaza() // funcie pentru afiarea vectorului
{ int i;
for(i=0;i<n;i++)cout<<x[i]<<" ";
}
void main() // funcia principal
{ clrscr();
citste();
cout<<"X=";
afiseaza(); cout<<endl;
sorteaza();
cout<<"Vectorul sortat: "<<endl;
afiseaza(); cout<<endl;
getch();
}

I.6. Iniializarea variabilelor


Iniializarea variabilelor simple
O variabil simpl se poate iniializa printr-o declaraie de forma:
<tip> <nume> = <expresie>;

sau
static <tip> <nume> = <expresie>;

dac variabila este static.


n cazul variabilelor globale i statice, expresia utilizat trebuie s fie o
expresie constant, care s poat fi evaluat de compilator la ntlnirea ei. Aceasta,
deoarece variabilele globale i statice se iniializeaz prin valori definite la
compilare. Variabilele automatice se iniializeaz la execuie, de fiecare dat cnd
se activeaz funcia n care sunt declarate. Din aceast cauz, expresia utilizat la
iniializare nu mai este necesar s fie o expresie constant. Variabilele automatice
care nu sunt iniializate vor conine valori ntmpltoare i, deoarece ele apar i
dispar odat cu blocul n care au fost declarate, nu i pstreaz valorile de la o
execuie la alta a blocului din care aparin. Spre deosebire de variabilele
automatice, variabilele globale i statice primesc n mod automat valoarea zero la
nceputul executrii programului, dac nu sunt iniializate n mod explicit.
Variabilele statice sunt iniializate numai o singur dat, la nceputul executrii
programului, i i pstreaz valorile de la o execuie la alta a blocului n care au
fost declarate.

44

Exemplul 1:
#include<iostream.h>
void incrementare()
{ int i=1;
static int k=1;
i++;
k++;
cout<<"i="<<i<<", k="<<k<<endl;
}
void main()
{ incrementare();
incrementare();
incrementare();
}

Rezultatul execuiei va fi:


i=2, k=2
i=2, k=3
i=2, k=4

Variabilele interne statice ofer posibilitatea pstrrii n permanen a unor


informaii ce aparin funciei. O astfel de variabil ar putea fi folosit pentru a
memora de cte ori a fost apelat o funcie.
Exemplul 2:
#include <iostream.h>
void f1()
{ static int k; // implicit iniializat cu 0
k++;
cout<<"f1 apelul"<<k<<endl;
}
void f2()
{ static int k; /* Variabil iniializat implicit cu 0. Este variabil intern funciei f2(),
cu alocare static la o adres diferit de adresa variabilei k, intern
funciei f1.*/
k++;
cout<<"f2 apelul"<<k<<endl;
}
void main()
{ f1(); f1(); f2(); f1(); f2(); }

Rezultatul execuiei este:


f1 apelul 1
f1 apelul 2
f2 apelul 1
f1 apelul 3
f2 apelul 2

Iniializarea variabilelor tablou


Un tablou unidimensional se poate iniializa folosind formatul:

45

<tip> <nume> [<dim>]={<e1>,<e2>,...,<en>};

sau
static <tip> <nume> [<dim>]={<e1>,<e2>,...,<en>};

Numrul expresiilor <ei> de iniializare poate fi mai mic dect al numrului


elementelor tabloului. Elementele neiniializate au valoarea iniial 0.
n cazul n care se iniializeaz fiecare element al tabloului, numrul <dim>
al elementelor acestuia nu mai este obligatoriu n declaraia tabloului respectiv.
Deci putem scrie:
<tip> <nume> []={<e1>,<e2>,...,<en>}

Numrul elementelor tabloului fiind considerat egal cu numrul expresiilor.


Pentru un tablou bidimensional vom folosi urmtorul format:

<tip><nume>[<dim1>][<dim2>]={{<e11>,<e12>,...,<e1 m1>},
{<e21>,<e21>,...,<e2 m2>},
...
{<en1>,<en1>,...,<en mn>}
};

sau
static <tip> <nume> [<dim1>][<dim2>]={{<e11>,<e12>,...,<e1 m1>},
{<e21>,<e21>,...,<e2 m2>},
...
{<en1>,<en1>,...,<en mn>}
};

Numerele m1, m2,..., mn, pot fi mai mici dect <dim2> n oricare din
acoladele corespunztoare ale tabloului, de asemenea n poate fi mai mic dect
<dim1>. n aceste situaii restul elementelor tabloului vor fi iniializate cu 0. Dac n
este egal cu <dim1>, atunci <dim1> poate fi omis, dar <dim2> este obligatoriu.
ntr-o modalitate asemntoare se pot iniializa i tablouri cu mai multe
dimensiuni.
Exemplu
int a[2][3]={ {1,2,3},
{4,5,6}
};

Un tablou multidimensional se poate iniializa i astfel:


int t[2][3]={1,2,3,4,5,6};

sau
int t[][3]={1,2,3,4,5,6};

Tablourile de tip caracter pot fi iniializate astfel:


char <nume>[<dim>]=<sir de caractere>;

sau
static char <nume>[<dim>]=<sir de caractere>;

Compilatorul adaug automat caracterul NULL (\0) dup ultimul caracter al


irului utilizat n iniializare. Numrul <dim> poate fi omis.
Deci declaraia:

46

char t[4]={'a','b','c','\0'};

este echivalent cu:


char t[4]="abc";

i cu:
char t[]="abc";

47

I.7. Transferul parametrilor la apelul funciilor


La apelul unei funcii, fiecrui parametru formal i corespunde un parametru
efectiv. In C++ sunt implementate dou metode de transmitere a parametrilor la
funcii:
prin valoare cnd o eventual modificare a parametrului n funcie nu
afecteaz valoarea parametrului efectiv n funcia apelant. n cazul apelului prin
valoare, se transfer funciei apelate valoarea parametrului efectiv care poate fi o
constant, o variabil sau o expresie.
prin referin n care variabila transmis funciei ca parametru efectiv este
afectat de eventualele modificri aduse n funcie. Pentru aceasta funcia apelat
trebuie s dispun de adresa parametrului efectiv pentru ca s-l poat modifica.
Sunt trei modaliti de a realiza transferul prin referin:
- prin utilizarea ca parametru a numelui unui tablou ;
- prin utilizarea ca parametru a unei variabile de tip pointer ;
- prin utilizarea ca parametru a unei variabile de tip referin.
Numele unui tablou are ca valoare chiar adresa primului su element, n
consecin, dac un parametru formal este numele unui tablou atunci la apel se va
transmite funciei adresa de nceput a tabloului ce se utilizeaz efectiv, i prin
urmare i pot fi modificate elementele.
Deoarece compilatorul nu folosete dimensiunea tabloului transmis ca
parametru, ci doar adresa lui de nceput, pentru parametrul formal de tip tablou
putem folosi sintaxa de declarare urmtoare:
<tip> <nume tablou>[]

I.7.1. Probleme rezolvate.


1) Operaii cu matrice
Citirea si afiarea matricelor, suma i produsul a dou matrice
#include<iostream.h>
#include<iomanip.h>
#include<conio.h>
void citire(int a[10][10],int m,int n)
{ int i,j;
for(i=0;i<m;i++)
{ cout<<"Linia "<<i+1<<":";
// tastai n numere separate prin spaiu
for(j=0;j<n;j++) cin>>a[i][j];
}
}

48

void suma(int a[10][10],int b[10][10],int c[10][10],


int m,int n)
{ int i,j;
for(i=0;i<m;i++)
for(j=0;j<n;j++)
c[i][j]=a[i][j]+b[i][j];
}
void produs(int a[10][10],int b[10][10],int c[10][10],
int m,int n,int p)
// a cu m linii si n coloane, b cu n linii si p coloane, c cu m linii si p coloane
{ int i,j,k,s;
for(i=0;i<m;i++)
for(j=0;j<p;j++)
{ s=0;
for(k=0;k<n;k++)
s+=a[i][k]*b[k][j];
c[i][j]=s;
}
}
void afisare(int a[10][10],int m,int n)
{ int i,j;
for(i=0;i<m;i++)
{ for(j=0;j<n;j++)
cout<<setw(5)<<a[i][j];
cout<<endl;
}
}
void main()
{ clrscr();
int x[10][10],y[10][10],z[10][10];
int n;
cout<<"n="; cin>>n; // n linii, n coloane
cout<<"Matricea X:"<<endl;
citire(x,n,n);
cout<<"Matricea Y:"<<endl;
citire(y,n,n);
suma(x,y,z,n,n);
cout<<"Z=X+Y:"<<endl;
afisare(z,n,n);
produs(x,y,z,n,n,n);
cout<<"Z=X*Y:"<<endl;
afisare(z,n,n);
getch();
}

49

2) Parcurgere n spiral
Fie a o matrice cu m linii i n coloane. S se construiasc vectorul b cu m*n
elemente obinute prin parcurgerea matricei n spiral, din colul din stnga-sus
ctre dreapta, pn n centrul matricei.
#include<iostream.h>
#include<iomanip.h> //pentru setw
void citireMatrice(int a[10][10],int m, int n)
{ int i,j;
for(i=0;i<m;i++)
{ cout<<"linia "<<i<<":";
for(j=0;j<n;j++)
cin>>a[i][j];
}
}
void afisareMatrice(int a[10][10],int m,int n)
{ int i,j;
for(i=0;i<m;i++)
{ for(j=0;j<n;j++)
cout<<setw(6)<<a[i][j];
cout<<endl;
}
}
void parcurgereInSpirala(int a[10][10], int m, int n,
int b[], int mn )
{ int k,p,q,r,i,j;
k=0;
p=0; q=m-1; r=n-1; //p,q,r definesc conturul de parcurs (p,p)->(p,q)->(q,r)->(r,p-1)
while(k<m*n)
{ for(j=p;j<=r;j++)b[k++]=a[p][j]; //parcurgere stanga->dreapta
for(i=p+1;i<=q;i++)b[k++]=a[i][r]; //sus ->jos (col. din dreapta)
for(j=r-1;j>=p;j--)b[k++]=a[q][j]; // dreapta->stanga(linia de jos)
for(i=q-1;i>=p+1;i--)b[k++]=a[i][p]; // jos->sus (col din stanga)
p++;q--;r--; //urmatorul contur
}
}
void afisareVector(int b[],int n)
{ for(int i=0;i<n;i++)cout<<b[i]<<" "; }
void main()
{int a[10][10],m,n;
int b[100],mn;
cout<<"nr. linii="; cin >>m;
cout<<"nr. coloane="; cin >>n;
mn=m*n;
citireMatrice(a,m,n);
afisareMatrice(a,m,n);
parcurgereInSpirala(a, m, n, b, mn);
cout<<"Vectorul obtinut prin parcurgerea matricei in spirala:"<<endl;
afisareVector(b,mn);
}

50

3) Problema celor 4 triunghiuri


O matrice ptratic este mprit de cele dou diagonale n patru triunghiuri.
S se determine suma elementelor din cele patru triunghiuri. Elementele de pe
diagonale fac parte din triunghiurile respective.
#include<iostream.h>
long sumaTrSus(long a[20][20],int n)
{ long S=0;
int p,q,k;
p=0;q=n-1;
while(p<=q)
{ for(k=p;k<=q;k++)
S+=a[p][k];
p++;q--;
}
return S;
}
long sumaTrJos(long a[20][20],int n)
{ long S=0;
int p,q,k;
p=0;q=n-1;
while(p<=q)
{ for(k=p;k<=q;k++)
S+=a[q][k];
p++;q--;
}
return S;
}
long sumaTrStanga(long a[20][20],int n)
{ long S=0;
int p,q,k;
p=0;q=n-1;
while(p<=q)
{ for(k=p;k<=q;k++)
S+=a[k][p];
p++;q--;
}
return S;
}
long sumaTrDreapta(long a[20][20],int n)
{ long S=0;
int p,q,k;
p=0;q=n-1;
while(p<=q)
{ for(k=p;k<=q;k++)
S+=a[k][q];
p++;q--;
}
return S;
}

51

void main()
{long a[20][20]={{1,2,3,4,5},
{1,2,3,4,5},
{1,2,3,4,5},
{1,2,3,4,5},
{1,2,3,4,5}};
cout<<sumaTrSus(a,5)<<endl;
cout<<sumaTrStanga(a,5)<<endl;
cout<<sumaTrJos(a,5)<<endl;
cout<<sumaTrDreapta(a,5)<<endl;
}

4) Cutare binar
Algoritmul de cutare binar este un algoritm de cutare folosit pentru a gsi
un element ntr-un vector ordonat. Fie a un vector ordonat cresctor i x un
element ce se caut n vectorul a. Valoarea x este comparat cu valoarea
elementului din mijlocul vectorului a. Dac cele dou valori sunt egale, algoritmul
se termin. Dac valoarea lui x este mai mic dect acea valoare, cutarea se
efectueaz, prin acelai procedeu, pentru elementele de la nceputul vectorului
pn la mijloc, iar dac este mai mare, cutarea se efectueaz de la mijlocul
vectorului pn la sfritul su. ntruct la fiecare pas cardinalul mulimii de
elemente n care se efectueaz cutarea se njumtete, algoritmul are
complexitate logaritmic.
#include<iostream.h>
#include<stdlib.h>
int caut(long a[],int n,long x)
{ int i=0,j=n-1,m;
while(i<=j)
{ m=(i+j)/2;
if(a[m]==x) return m;// x se gaseste pe pozitia m
if(x<a[m])j=m-1;
else i=m+1;
}
return -1; // x nu se gaseste in vectorul a
}
void main()
{
long a[100], x;
int n, poz;
cout<<"n=";
cin>>n;
cout<<"Tastati "<<n<<" elemente in ordine crescatoare, "
<<"separate prin spatiu:"<<endl;
cin>>a[0];

52

for(int i=1;i<n;i++)
{cin>>a[i];
if(a[i]<a[i-1])
{ cout<<"vectorul nu este ordonat crescator"<<endl;
return;
}
}
while(1)
{cout<<"Tastati valoarea lui x "
<<" (sau CTRL+Z pentru sfarsit):";
cin>>x; if(cin.eof()) break;
poz=caut(a,n,x);
if(poz>=0)
cout<<x<<" se gaseste in vectorul a pe pozitia "
<<poz<<endl;
else
cout<<x<<" nu se gaseste in vectorul a"<<endl;
}

5) Exemple de funcii de lucru cu iruri de caractere:


Determinarea numrului de caractere dintr-un ir de caractere:
int lungime(char s[])
{ int k=0;
while(s[k]) k++;
return k;
}

Copierea unui ir de caractere:


void copiaza(char sursa[], char dest[])
{ int i=0;
while(dest[i++]=sursa[i]);
}

Observaie: Biblioteca <string.h> conine funcii pentru determinarea


lungimii i pentru copierea irurilor(strlen respectiv strcpy).
Inversarea caracterelor unui ir de caractere:
void inversare(char s[])
{ int i,j;
char c;
for(i=0,j=lungime(s)-1; i<j; i++,j--)
{ c=s[i]; s[i]=s[j]; s[j]=c; }
}

53

Determinarea primei poziii de unde ncepe un subir ntr-un ir de caractere.


int cauta(char sir[], char subsir[])
{ int k,j,lgSubsir,pozMax;
lgSubsir=lungime(subsir);
pozMax=lungime(sir)-lgSubsir;
for(k=0; k<= pozMax; k++)
{ for ( j=0; j<lgSubsir && subsir[j]==sir[k+j]; j++ );
if(j==lgSubsir) return k;
}
return -1;
}
#include<iostream.h>
void main()
{ char a[25],b[25];
cout<<"Sirul a="; cin>>a;
cout<<"Sirul b="; cin>>b;
cout<<"Sirul a are "<<lungime(a)<<" caractere."<<endl;
cout<<"Sirul b are "<<lungime(b)<<" caractere."<<endl;
cout<<"Subsirul b apare in a ncepnd de la poz. "
<<cauta(a,b)<<endl;
}

6) Se introduce un text de la tastatur. S se afieze frecvena literelor mari i


a literelor mici din textul introdus.
#include <stdio.h> //pentru gets si printf
#include <conio.h> //pentru clrscr
#include <string.h> //pentru strlen
#include <ctype.h> // pentru islower si isupper
void main ( )
{ int i, n, a[26], b[26] ;
char sir[1000],c ;
clrscr( );
printf(" Introduceti sirul:"); gets(sir);
n=strlen(sir);
for(i=0;i<26;i++)
{a[i]=0; b[i]=0;}
for(i=0;i<n;i++)
{c=sir[i];
if(islower(c))a[c-'a']++;
if(isupper(c))b[c-'A']++;
} //a=97, ...,z=122; A=65, ..., Z=90

54

for(i=0;i<26;i++)
{ if(a[i]!=0)printf("Litera %c apare de %d ori \n",
(char)(i+97),a[i]);
if(b[i]!=0)printf("Litera %c apare de %d ori \n",
(char)(i+65),b[i]);
}
}

7) Operaii cu numere naturale mari: suma, diferena aritmetic, compararea


i produsul a dou numere mari; mprirea unui numr mare la un numr ntreg.
Algoritmi clasici.
Vom considera numerele reprezentate n baza 10. Cifrele numerelor mari,
completate cu zerouri nesmnificative, vor fi memorate n vectori cu acelai numr
de elemente. Dimensiunea comun a vectorilor este aleas astfel nct s fie
suficient i pentru memorarea numerelor rezultate in urma operaiilor aplicate
lor.
#include <iostream.h>
#include <conio.h>
#include<string.h>
int dim=100; // dimensiunea comuna a vectorilor(nr maxim de cifre); valoare implicita 100
int suma( int u[],int v[],int w[]) //w=u+v
{int t=0,c; // t - cifra de transport
for(int i=dim-1; i>=0;i--)
{ c=u[i]+v[i]+t;
if(c>=10) { w[i]=c-10; t=1;} else {w[i]=c; t=0;}
}
return 1-t; // 1 adunare cu succes, 0 - depasire
}
int diferenta(int u[],int v[], int w[]) // w=u-v, unde u>v
{int t=0,c;
for(int i=dim-1;i>=0;i--)
{ c=u[i]-v[i]+t;
if(c<0){w[i]=10+c; t=-1;}
else {w[i]=c; t=0;}
}
return 1+t;
}
int comparare(int u[], int v[]) //1 daca u>v, 0 daca u=v, -1 daca u<v
{
for (int i=0;i<dim;i++)
{ if(u[i]<v[i])return -1;
if (u[i]>v[i]) return 1;
}
return 0;
}

55

/* Produsul a doua numere mari se calculeaza inmultind fiecare cifra a inmultitorului cu


fiecare cifra a deinmultitului si adunind rezultatul la ordinul de marime corespunztor. */
int produs(int u[],int v[],int w[]) //w=uv
{int i,j,t=0,s;
for (i=0;i<dim;i++) w[i]=0;
for( j=dim-1;j>=0;j--)
for(i=dim-1;i>=0;i--)
{ int k=i+j+1-dim;
s=u[i]*v[j]+t;
if(k>=0)
{ w[k]+=s;
t=w[k]/10;
w[k]%=10;
}
else if(s!=0)return 0;// esec! dimensiune prea mica
}
return t==0?1:0; //1 succes; 0 esec
}
void impartire(int u[],long q,int w[],long &r) //w=uq+r
{ int i;
long p;
r=0;
for(i=0;i<dim;i++)
{p=r*10+u[i];
w[i]=p/q;
r=p%q;
}
}
void afisare( int u[])
{ int i=0;
while(i<dim-1 && u[i]==0)i++; // salt peste cifrele 0 nesemnificative
while(i<dim){ cout<<u[i]; i++;}
}
int citire(int v[])
{ char s[255];
cin>>s;
int m=strlen(s);
if(m>dim) return 0; //esec; dimensiune insuficienta
int i,j;
for(i=m-1,j=dim-1; i>=0; i--,j--)
{v[j]=s[i]-'0';
if(v[j]<0||v[j]>9) return 0; //esec; caracter nenumeric
}
for( ;j>=0;j--)v[j]=0;
return 1; //citire cu succes
}

56

void main()
{ int u[100], v[100],s[100],d[100],p[100],r[100];
dim=100;
cout<<"u=";
citire(u);
cout<<"v=";
citire(v);
suma(u,v,s);
afisare(u); cout<<"+"; afisare(v);
cout<<"="; afisare(w); cout<<endl;
if(comparare(u,v)>0)diferenta(u,v,d);
else diferenta(v,u,d);
cout<<"|";afisare(u); cout<<"-"; afisare(v);
cout<<"| ="; afisare(d); cout<<endl;
int ok=produs(u,v,p);
afisare(u); cout<<"*"; afisare(v);
cout<<"="; afisare(p);
if(!ok)cout<<"esec! dim prea mica"; cout<<endl;
long q,rest;
cout<<"q="; cin>>q;
impartire(u,q,r,rest);
afisare(u); cout<<":"; cout<<q<<"="; afisare(r);
cout<<" rest "<<rest<<endl;
}

8) Fiind date n numere ntregi a1, a2,..., an nu n mod necesar diferite, exist
totdeauna o submulime a acestei mulimi de numere, cu proprietatea c suma
elementelor sale este divizibil prin n. Urmtorul program determin o astfel de
submulime.
Soluie.
Fie s k a1 a 2 a k , k 1,, n .
Dac ()s k a.. nsk problema este rezolvat, altfel resturile sunt nenule
() k{1,2,...,n} i aparin mulimii {1,...,n-1} () dou sume
cu resturi egale. Fie sk i si, i<k, dou asemenea sume nsk-si.
Dac sk mod n = r, vom memora indicele k n variabila rest[r]. n
situaia n care n rest[r] este deja memorat un indice nu ne rmne dect s
afim soluia.
#include<iostream.h>
int a[101],rest[101],n;
void citeste()
{ cout<<"n="; cin>>n;
cout<<"Tastati "<<n<<" numere:";
int i;

57

for(i=1;i<=n;i++){ cin>>a[i];rest[i]=-1;}
rest[0]=0;
}
void solutie()
{ int s,k,i,r;
s=0;
for(k=1;k<=n;k++)
{s+=a[k];
r=s%n;
if(rest[r]==-1) rest[r]=k;
else { cout<<"Solutie:";
for(i=rest[r]+1; i<=k; i++)
cout<<a[i]<<" ";
cout<<endl;
return;
}
}
}
void main()
{ citeste();
solutie();
}

I.8. Capcane n programare


1) Ce rezultat furnizeaz programiul urmtor?
#include<iostream.h>
void main()
{ float x=1.0;
x=x/10;
cout<<x*10=<<x*10<<endl;
if(x*10==1) cout<< " Adevarat! x*10 == 1 "<< endl;
else
cout<< " Fals! x*10 != 1 "<< endl;
}

Comentariu. Programul afieaz un rezultat neateptat :


x*10=1
Fals! x*10 != 1

Acest rezultat se datoreaz faptului c numarul 0.1 atribuit lui x are


reprezentarea binar 0.00011001100110011...=0.0(0011), deci nu poate fi memorat
exact. Cu toate acestea, prin mecanismul de rotunjire utilizat de funcia cout, x*10
este afiat ca fiind egal cu 1.

58

2) Ce rezultat furnizeaz programiul urmator?


#include<iostream.h>
void interschimba(int x,int y)
{ int aux;
aux=x;
x=y;
y=aux;
}
void main()
{ int a=10,b=20;
interschimba(a,b);
cout<<"a="<<a<<", b="<<b<<endl;
}

Comentariu. Programul afiseaz:


a=10, b=20
deci valoarea variabilei a nu este interschimbat cu a lui b.
Acest lucru se datoreaz faptului c parametrii x i y sunt parametri de
intrare, ceea ce nseamn c se transfer funciei interschimba valoarile
parametrilor efectivi a i b. Modificarea valorilor variabilelor x i y de ctre funcia
interschimba nu are efect asupra coninutului variabilelor a i b din programul
apelant.
3) S se determine numerele de forma abxcy divizibile cu 19; x i y se
introduc de la tastatur.
Soluie.
#include<iostream.h>
void main()
{ long abxcy;
int a,b,x,c,y;
cout<<"x,y="; cin>>x>>y; // tastati doua cifre separate prin spatiu
for(a=1;a<=9;a++)
for(b=0;b<=9;b++)
for(c=0;c<=9;c++)
{ abxcy=10000*a+1000*b+100*x+10*c+y;
if(abxcy%19==0) cout<<abxcy<<" ";
}
cout<<endl;
}

Comentariu. Programul afieaz ciudat i cteva numere negative.


Deoarece 10000 este o constant de tip int i a este tot de tip int rezult c 10000*a
este tot de tip int, dar dac a >=4 atunci 10000*4 >32567 i astfel depim
domeniul numerelor de tip int. Putem corecta programul, de exemplu, forand tipul
constantei 10000 la tipul long sau la tipul unsigned long folosind una din
variantele:
abxcy=10000l*a+1000*b+100*x+10*c+y;
abxcy=long(10000)*a+1000*b+100*x+10*c+y;
abxcy=10000ul*a+1000*b+100*x+10*c+y;

59

abxcy=(unsigned long)10000*a+1000*b+100*x+10*c+y;
k

4) Programul urmtor calculeaz C n , n i k se introduc de la tastatur.


Cnk

n n 1
n k 1 k n i 1

1 2
k
i
i 1

#include<iostream.h>
void main()
{ long C,n,k,i;
// Citirea lui n si k:
cout<<"n="; cin>>n;
cout<<"k="; cin>>k;
// Calculul combinarilor:
C=1; i=1;
while(i<=k)
{ C*=(n-i+1)/i;
i++;
}
// Afisarea rezultatului:
cout<<"C("<<n<<","<<k<<")="<<C<<endl;
}

Comentariu. Pentru n=10, k=3 programul afieaz


C(10,3)=80

Dar rezultatul corect este 120.


Expresia C*=( n-i+1)/i, cu C, n i i de tip ntreg, nu produce acelai
rezultat cu C=C*( n-i+1)/i, de exemplu pentru C=10, n=10, i=2 a doua expresie
furnizeaz rezultatul C=10*9/2=45, iar prima C*=9/2 C*=4 C=40. (C*=(
n-i+1)/i este echivalent cu C=C*(( n-i+1)/i)).
Programul se corecteaz nlocuind secvena:
while(i<=k)
{ C*=(n-i+1)/i;
i++;
}

cu
while(i<=k)
{ C=C*(n-i+1)/i;
i++;
}

I.9. Pointeri
Pointerii se utilizeaz pentru a face referire la date prin adresele lor.
ntr-o variabil de tip pointer putem pstra adresa unei date n loc de a
memora data nsi sau putem pstra adresa unei funcii. Schimbnd adresa
memorat n pointer, putem manipula informaii din diverse locaii de memorie.

60

Ca orice tip de variabil, nainte de a fi utilizat, variabila de tip pointer


trebuie declarat.
Pointerii ofer posibilitatea de a aloca dinamic memoria, ceea ce nseamn
c pe parcursul execuiei unui program se pot aloca i dealoca zone de memorie
asociate lor.
O variabil de tip pointer se declar utiliznd formatul:
<tip>* <nume>;

ceea ce nseamn c <nume> este un pointer ctre o zon de memorie ce


conine o dat de tipul <tip>.
Caracterul "*" poate fi alturat de <tip> sau de <nume> sau poate fi separat
prin caractere spaiu i de <tip> i de <nume>. El indic compilatorului c a fost
declarat o variabil pointer i nu una obinuit.
Construcia <tip>* se spune ca reprezint tipul pointer.
Exemplul 1:
int *p;

Aici se stabilete faptul c p va conine adrese de zone de memorie alocate


datelor de tip int.
Exemplul 2:
float *p, t, *q;

Aici p i q sunt pointeri ctre date de tip float, iar t este o variabil de tip
float.
Utilizarea pointerilor se face cu doi operatori unari:
& - operatorul adresa (de referentiere) - pentru aflarea adresei din memorie
a unei variabile;
* - operatorul de indirectare (de deferentiere) - care furnizeaz valoarea din
zona de memorie spre care pointeaz pointerul operand.
Dac x este o variabil atunci operatorul unar & aplicat lui x, &x, ne
furnizeaz adresa lui x. Dac dorim ca pointerul p s indice pe x, putem utiliza
atribuirea:
p=&x;

Dac p este o variabil de tip pointer atunci operatorul unar * aplicat lui p,
*p, ne furnizeaz variabila a crei adres este memorat n p.
Exemplu:
int a,*adr;
adr=&a; // acum a i *adr reprezint aceeai dat.
a=100; // este echivalent cu: *adr=100;
*adr=200; // este echivalent cu: a=200;

Exist cazuri n care dorim ca un pointer s fie utilizat cu mai multe tipuri de
date. n acest caz, la declararea lui nu dorim s precizm un tip anume. Aceasta se
realizeaz astfel:
void *<nume>;

61

Utilizarea tipului void* implic conversii explicite de tip.


Exemplu:
void *p;
int x;
p=&x; // Atribuire neacceptat deoarece tipul pointerului p este nedeterminat
(int*)p=&x; //Atribuire corect: tipul void* este convertit spre int*
*p=10; // Atribuire neacceptat deoarece tipul pointerului p este nedeterminat
*(int*)p=10; // Atribuire corect: tipul void* este convertit spre int*

Deoarece pointerii reprezint adrese, ei se folosesc la transferul prin


referin al parametrilor.
Exemplu:
#include<iostream.h>
void interschimba(int *x,int *y)
{ int aux=*x;
*x=*y;
*y=aux;
}
void main()
{ int a,b;
cout<<"a="; cin>>a;
cout<<"b="; cin>>b;
interschimba (&a,&b);
cout<<"a="<<a<<" b="<<b<<endl;
}

n funcia interschimba, parametrii formali x, y sunt pointeri la int, astfel


nct la apel, parametrii actuali trebuie s fie adrese ale unor variabile de tip int,
i nu valori ntregi. Orice modificare se va face la adresele transmise ca parametri
actuali.
O variabil pointer poate fi iniializat cu adresa unei variabile, astfel:
int x=10;
int *p=&x; // pointerul p se iniializeaz cu adresa variabilei x

Un pointer la caractere poate fi iniializat ca n exemplul urmtor:


char *q="abc";

// q memoreaz adresa de unde ncepe irul "abc"

Operaii cu pointeri
Asupra pointerilor se pot face urmtoarele operaii: atribuire, comparare,
adunare, scdere, incrementare, decrementare.
Adunarea i scderea unui ntreg dintr-un pointer.
Dac p este un pointer avnd declaraia:
<tip> *p;

62

atunci p+n furnizeaz valoarea lui p mrit cu n*sizeof(<tip>), iar


pn valoarea lui p micorat cu n*sizeof(<tip>).
Asupra pointerilor se pot face operaii de incrementare i decrementare:
p++ i ++p mresc adresa coninut de p cu sizeof(<tip>)
p--, --p micoreaz valoarea pointerului p cu sizeof(<tip>).
Exemple:
char *c;
int *k;
float *f1,*f2;
double *d;
c++;
//c= (adresa memorat n c) + 1
k+=5; // k=(adresa memorat n k) + 5*2
f2=f1-5; // f2=(adresa memorat n f1) 5*4
d-=3; //d=(adresa memorat n d) 3*8
d--;
//d=(adresa memorat n d) 1*8

Operaiile de incrementare i decrementare se pot aplica pointerului nsui


sau obiectului pe care-l puncteaz (memoreaz).
Instruciunea *a++ obine mai nti valoarea pe care o puncteaz a i apoi a
este incrementat pentru a puncta elementul urmtor.
Instruciunea (*a)++ incrementeaz obiectul pe care-l puncteaz a.

Legtura dintre pointeri i tablouri


Numele unui tablou este un pointer i el are ca valoare adresa primului su
element.
Fie
int t[5];
int *p;
p=t; // Atribuire corect!

p va pointa spre primul element al tabloului t. ntre p i t exist o diferen


i anume: valoarea lui p poate fi modificat dar a lui t nu poate fi modificat (t
este un pointer constant), deci este interzis o atribuire de forma t=p;
Un nume de tablou poate fi utilizat ca i cum ar fi un pointer i, reciproc, un
pointer poate fi indexat ca i cum ar fi un tablou.
Dac x este un tablou:
<tip> x[<dim>];

atunci expresia x+n este corect i reprezint un pointer ctre al n-lea


element al tabloului (x+n==&x[n]), deci x[n] este echivalent cu *(x+n).
Dac p este un pointer:
<tip> *p;

atunci *(p+i) este echivalent cu p[i].


O diferen ntre pointer i tablou const n alocarea de memorie. n cazul
tabloului, se rezerv automat spaiul necesar. n cazul pointerilor, spaiul trebuie
creat explicit de utilizator sau trebuie atribuit pointerului o adres a unui spaiu
deja alocat.

63

Fie declaraia
int t[5];

Elementele tabloului t sunt memorate n celule succesive de memorie i


sunt numerotate ncepnd cu zero.
n exemplul nostru vom avea:
t[0], t[1], t[2], t[3], t[4].

Deoarece t[0] este o variabil simpl, adresa sa este &t[0], deci vom avea:
t==&t[0].

Elementele unui tablou multidimensional sunt memorate n ordinea


cresctoare a liniilor.
De exemplu, elementele tabloului descris prin:
int a[2][3];

vor fi memorate n ordinea


a[0][0], a[0][1], a[0][2], a[1][0], a[1][1], a[1][2].

a reprezint adresa primului element din tablou. Tabloul a, avnd dou


linii, este considerat ca un tablou cu dou elemente (tablouri unidimensionale):
elementele a[0] i a[1]. a este adresa elementului a[0], adic avem a==&a[0].
Cum a[0] este i el un tablou, nseamn ca a[0] este adresa primului su element,
deci a[0]==&a[0][0]. Dar, cele dou tablouri, tabloul bidimensional a[][], i
tabloul liniar a[0] ncep de la aceeai adres, astfel c:
a==&a[0]==a[0]==&a[0][0]

Dac privim tabloul a ca o variabil structurat, atunci adresa acestei


variabile se poate afla cu &a, deci avem lanul de egalitai:
&a==a==a[0]==&a[0]==&a[0][0].

Compararea a doi pointeri


Dac doi pointeri pointeaz spre elementele aceluiai tablou, pot fi
comparai folosind operatorii de relaie i egalitate.
Astfel
<tip> t[dim];
<tip> *p,*q;

Dac p pointeaz spre t[i] i q spre t[j], atunci


p<q dac i<j,
p!=q dac ij.
Un pointer mai poate fi comparat cu constanta NULL (zero binar) utiliznd
operatorii == i !=. Astfel stabilim dac o variabil pointer conine sau nu o
adres.
Doi pointeri care pointeaz elementele aceluiai tablou pot fi sczui, astfel
dac p pointeaz pe t[i] i q pe t[i+n], atunci qp are valoarea n.
Observaie. Nu se admite adunarea a doi pointeri.

Tablouri de pointeri
Datele de tip pointer pot fi organizate n tablouri la fel ca i alte tipuri de
date. Pentru a descrie un tablou de pointeri se folosete o construcie de forma:
<tip> *<nume>[<dim>];

64

unde <nume> este un tablou avnd <dim> elemente de tip pointer ce


memoreaz adrese ale unor date de tipul <tip>.
Exemplu:
#include<iostream.h>
int DenumireZi(int m)
{ static char *zi[7]={"luni","marti","miercuri",
"joi","vineri","sambata","duminica"};
if (m<1||m>7) return 0; else {cout<<zi[m-1]; return 1;}
}

Pentru memorarea denumirilor zilelor s-ar fi putut folosi un tablou cu dou


dimensiuni care s pstreze pe fiecare linie cte un ir de caractere corespunztor
numelui zilei.
char nume[7][10]={"luni","marti","miercuri","joi","vineri",
"sambata","duminica"};

Soluia cu pointeri are avantajul c liniile tabloului pot fi de lungimi diferite,


conducnd la o reprezentare eficient a datelor.
n exemplul de mai jos, funcia zi returneaz un pointer ctre un ir de
caractere:
#include<iostream.h>
char* zi(int m)
{ static char *z[7]={"luni", "marti", "miercuri",
"joi","vineri","smbat","duminic"};
if(m<1 || m>7) return 0; //pointer NULL
return z[m-1];
}
void main()
{ int n;
char *pZi;
cin>>n;
pZi=zi(n);
cout<<pZi<<endl;
}

I.9.1. Exemple de funcii de lucru cu iruri de caractere.


Varianta cu pointeri.
1) Determinarea numrului de caractere dintr-un ir de caractere:
int lungime(char *sir)
{
for(int k=0; *sir++; k++);
return k;
}

2) Copierea unui ir de caractere:


void copiaza(char *sursa, char *dest)

65

{ while(*dest++=*sursa++); }
#include<iostream.h>
void main()
{ char a[25],b[25];
cout<<"Sirul a="; cin>>a;
copiaza(a,b);
cout<<"Sirul a are "<<lungime(a)<<" caractere."<<endl;
cout<<"Sirul b este "<<b<<endl;
}

3) Funcie pentru transformarea n majuscule a literelor unui sir de caractere


#include <stdio.h> // pentru puts, gets si printf
#include <conio.h> // pentru clrscr si getche
char* majuscule(char *s)
{ char *p=s;
while(*p){ if(*p>='a'&&*p<='z') *p+='A'-'a';
p++; }
return s;
}
void main ( )
{ char sir[1000] ;
clrscr( );
puts(" Introduceti sirul:"); gets(sir);
puts(majuscule(sir));
getche( );
}

Observaii:
-Incrementarea unui pointer este mai rapid dect indexarea unui tablou.
-Biblioteca <string.h> conine funcii pentru determinarea lungimii unui ir
de caractere,
pentru compararea, localizarea i copierea irurilor, pentru
transformarea caracterelor n majuscule sau minuscule(strlen, strcmp, strchr, strstr,
strcpy, strcat, strupr, strlwr etc.).

I.10. Alocarea dinamic a memoriei


Necesitatea definirii n programe a datelor de tip dinamic, este dat de
utilizarea mai bun a memoriei, lungimea unui program variind n funcie de
volumul datelor cu care se lucreaz.
Limbajele C i C++ i permit utilizatorului s cear n timpul rularii
programului, n funcie de necesiti, s se aloce memorie suplimentar sau s se
renune la ea.
Variabilele dinamice sunt acele variabile crora, n mod explicit, li se aloc
i dealoc memorie i a cror dimensiune se poate modifica pe parcursul execuiei
unui program n funcie de opiunile programatorului.

66

Zona de memorie n care se face alocarea dinamic a variabilelor se numete


heap.
Alocarea dinamic se poate face pentru tipurile de date:
-fundamentale
-structurate: tablouri, liste, arbori etc.
Programele scrise n limbajul C standard, utilizeaz pentru alocarea
dinamic a memoriei o familie de funcii malloc i free, destul de greoaie n
folosire. Ele au fost pstrate n C++ doar pentru meninerea compatibilitii. n
locul lor se folosesc operatorii new i delete.
Operatorul new servete la alocarea dinamic a memoriei. El va returna un
pointer la zona de memorie alocat dinamic. n cazul n care nu exist memorie
suficient, alocarea nu va avea loc. Acest fapt se semnaleaz prin returnarea unui
pointer NULL (zero binar). De aceea se recomand ca, n cazul utilizrii intensive a
alocrii dinamice, dup fiecare utilizare a lui new s se testeze valoarea returnat.
Fie p un pointer ctre un tip de date, adic avnd o declaraie de forma:
<tip> *p;

Operatorul new poate fi folosit utiliznd urmtoarele formate:


p=new <tip>;
p=new <tip>(<expresie>);
p=new <tip>[<dim>];

n varianta 1. operatorul new aloc, dac este posibil, spaiul necesar tipului
<tip>, i returneaz adresa zonei de memorie alocate.
n varianta 2. variabila dinamic creat cu new se iniializeaz cu valoarea
expresiei <expresie>.
Varianta 3. se folosete pentru alocarea a <dim> variabile dinamice de tipul
<tip> (un tablou liniar cu <dim> elemente). Iniializarea tablourilor nu este
posibil.
Exemple:
int *p, *q,*r;
p=new int;
// se aloc memorie pentru un ntreg
q=new int(7); // se aloc memorie pentru un ntreg i se iniializeaz variabila cu 7
r=new long[10]; // se aloc un tablou de 10 ntregi

Dezalocarea zonei de memorie alocat cu new, se face cu ajutorul


operatorului delete, cu sintaxa:
delete <variabila>;

Exemple:
delete p;
delete r;

Prezentm mai jos trei variante de utilizare a unui vector alocat dinamic:
1.
#include <iostream.h>
void main()

67

{ int *a,n;
cout<<"n=";
cin>>n;
a=new int[n]; // alocare vector
for(int i=0;i<n; i++)
{ cout<<"a"<<i<<"="; cin>>*(a+i);}
cout<<"a=(";
for(i=0;i<n; i++)
cout<<*(a+i)<<",";
cout<<"\b)"<<endl;
delete a;
}

2.
#include <iostream.h>
void main()
{ int *a,n;
cout<<"n=";
cin>>n;
a=new int[n]; // alocare vector
for(int i=0;i<n; i++)
{cout<<"a"<<i<<"="; cin>>a[i];}
cout<<"a=(";
for(i=0;i<n; i++)
cout<<a[i]<<",";
cout<<"\b)"<<endl;
delete a;
}

3.
#include <iostream.h>
void main()
{ int *a, n;
cout<<"n="; cin>>n;
a=new int[n]-1; // astfel, elementele vectorului sunt a[1], a[2], ..., a[n]
for(int i=1;i<=n; i++) { cout<<"a"<<i<<"="; cin>>a[i]; }
cout<<"a=(";
for( i=1;i<=n; i++) cout<<a[i]<<",";
cout<<"\b)"<<endl;
a++; // revenire la adresa returnat de new
delete a;
}

I.11. Tipul referin


Pentru a simplifica lucrul cu pointeri, n C++ a fost introdus tipul referin.
Tipul referin implementeaz perfect conceptul de transmitere a parametrilor prin
referin.
O referin este un nume alternativ pentru un obiect.

68

Dac avem tipul de dat T, prin T& sau T & (cu spaiu dup T) sau T & (cu
spaiu dup T i dup &) vom nelege o referin (o trimitere) la un obiect de tipul
T.
Exemplu:
int x=10;
int& r=x; // r i x refer acum acelai obiect
r=20; // echivalent cu x=20;
x=30;
// echivalent cu r=30;

Variabila r de mai sus, este o referin la variabila x de tip int. Acest lucru
nseamn c identificatorii r i x permit accesul la aceeai zon de memorie. Prin
urmare, x i r sunt sinonime. Iniializarea unei referine (trimiteri) n declaraia sa
este obligatorie (dac nu este folosit ca argument al unei funcii), dar aceast
iniializare nu trebuie confundat cu atribuirea; ea definete pur i simplu un alt
nume (un alias) al obiectului cu care a fost iniializat. n exemplul de mai sus r
este un nou nume pentru x. O referin nu mai poate fi modificat dup iniializare.
Ea refer ntotdeauna acelai obiect stabilit prin iniializare s-l desemneze. Pentru
a obine un pointer la obiectul desemnat de referina r, se poate folosi &r.
Referinele sunt utile i cnd sunt folosite ca argumente pentru funcii.
Exemplu:
#include<iostream.h>
void interschimba(int& a,int& b)
{int aux=a; a=b; b=c; }
void main()
{ int x=10,y=20;
interschimba (x,y);
cout<<"x="<<x<<"y="<<y;
}

Semantica transmiterii argumentelor este aceea a iniializrii, la apel


argumentele a i b ale funciei interschimba, devin alte nume pentru variabilele x
i y i de aceea operaiile se fac direct asupra variabilelor x i y.
Dac tipul unei funcii este o referin, atunci acea funcie va ntoarce o
variabil. n astfel de situaii variabila returnat trebuie s fie static sau alocat cu
operatorul new ca mai jos:
Exemple:
int& f()
{ static int x;
...
return x;
}

Funcia f() ntoarce variabila de tipul int cunoscut n interiorul funciei


prin identificatorul x. Au sens, f()++ (incrementeaz variabila returnat) i
&f() (reprezentnd adresa variabilei returnate ).

69

int& g()
{ int& x= *new int; //Am dat un nume variabilei anonime *new int
...
return x;
}
Funcia g() ntoarce variabila de tipul int alocat dinamic.

I.11.1. Probleme rezolvate


1) Intersecia, reuniunea i diferena a dou mulimi
#include<iostream.h>
#include<conio.h>
void citire(int a[],int& n)
{ cout<<"numar de elemente:";cin>>n;
int i;
cout<<"tastati "<<n<<" elemente:";
for(i=0;i<n;i++)cin>>a[i];
}
void afisare(int a[],int n)
{ int i;
cout<<"{";
for(i=0;i<n;i++)cout<<a[i]<<" ";
cout<<"}";
}
void intersectie(int a[],int m,int b[],int n, int c[],int& p)
{ int i,j;
p=0;
for(i=0;i<m;i++)
for(j=0;j<n;j++)
if(a[i]==b[j]) { c[p++]=a[i];break;}
}
void reuniune(int a[],int m,int b[],int n,int c[],int& p)
{ int i,j;
for(i=0;i<m;i++)c[i]=a[i];
p=m;
int semafor; // semafor=1 daca b[j] apartine lui a si semafor =0 daca nu apartine
for(j=0;j<n;j++)
{ semafor =0; // b[j] nu apartine lui a
for(i=0;i<m;i++)
if(b[j]==a[i]) { semafor=1; break;}
if(semafor ==0)c[p++]=b[j];
}
}
void diferenta(int a[],int m,int b[],int n,int c[],int& p)
{ int i,j;
p=0;
int semafor;
for(i=0;i<m;i++)

70

{ semafor =0;
for(j=0;j<n;j++)
if(a[i]==b[j]) { semafor =1;break;}
if(semafor ==0)c[p++]=a[i];
}
}
void main()
{ int u[100],v[100],w[100];
int n1,n2,n3;
cout<<"Multimea U:"<<endl;
citire(u,n1);
cout<<"Multimea V:"<<endl;
citire(v,n2);
int op;
do
{ clrscr();
cout<<"U=";afisare(u,n1);cout<<endl;
cout<<"V=";afisare(v,n2);cout<<endl;
cout<<"1 - intersectie"<<endl;
cout<<"2 - reuniune"<<endl;
cout<<"3 - diferenta"<<endl;
cout<<"4 - STOP"<<endl;
cout<<"Tastati optiunea:";
cin>>op;
switch(op)
{ case 1:intersectie(u,n1,v,n2,w,n3);
cout<<"U intersectat cu V=";
afisare(w,n3); cout<<endl;
break;
case 2:reuniune(u,n1,v,n2,w,n3);
cout<<"U reunit cu V=";
afisare(w,n3);cout<<endl;
break;
case 3:diferenta(u,n1,v,n2,w,n3);
cout<<"U-V="; afisare(w,n3); cout<<endl;
break;
}
getch();
}
while(op!=4);
}

2) Algoritmul extins al lui Euclid.


Algoritmul lui Euclid calculeaz cel mai mare divizor comun a dou
numere ntregi a i b. Cel mai mare divizor comun d este cel mai mare numr
natural care divide pe a i pe b. Algoritmul lui Euclid are la baz urmtoarea
proprietate:
Dac d | a i d | b atunci d | (m a n b) m, n Z .

71

Algoritmul extins al lui Euclid rezolv urmtoarea problem:


Fiind dai doi ntregi a i b care nu sunt simultan 0, s se determine cel mai mare
divizor comun al lor d i doi ntregi m i n astfel nct m a n b d (Identitatea
lui Bzout).
Pentru obinerea identitii m a n b d , se pleac de la relaiile:
1 a 0 b a (1)
0 a 1 b b (2) , dac a 0 i b 0 .
Dac a 0 , relaia (1) se nlocuiete cu 1 a 0 b a (1' ) .
Dac b 0 , relaia (2) se nlocuiete cu 0 a (1) b b (2' ) .
Cum cel mai mare divizor comun al dou numere nu se modific dac din
numrul cel mai mare scdem numrul mai mic, deducem c prin repetarea unui
proces de reducere prin scdere aplicat ntre relaiile (1) i (2) ajungem n situaia
n care una din relaii are membrul drept egal cu zero. Cealalt relaie ne furnizeaz
cel mai mare divizor comun i coeficienii m i n ai identitii lui Bezout.
long euclid(long a,long b,long &m, long &n)
{ long m1,n1;
if(a>=0) { m=1; n=0;} else {m=-1; n=0; a=-a;}
if(b>=0) {m1=0; n1=1;} else {m1=0;n1=-1;b=-b;}
if(a==0) {m=m1; n=n1; return b;}
while(b!=0)
{ if(a>b) { m-=m1; n-=n1; a-=b; }
else { m1-=m; n1-=n; b-=a; }
}
return a;
}

Putem optimiza algoritmul astfel: dac a=bq+r , 0r<b scdem din relaia (1)
relaia (2) multiplicat cu q.
long euclid1(long a,long b,long &m, long &n)
{ long m1=1,n1=0,u,v;
m=0; n=1;
long q=a/b, r=a%b;
while(r)
{ u=m1,v=n1; m1=m,n1=n;
m=u-q*m; n=v-q*n;
a=b; b=r; q=a/b; r=a%b;
}
return b;
}
In limbajul C, a%b r (b, b) , de exemplu pentru a=-65, b=10 avem

a/b=-6, a%b=-5. Algoritmul euclid1 genereaz rezultate corecte i pentru a<0


sau/i b<0.

72

3) S se determine o progresie aritmetic format din k termeni, toi numere


prime1.
Soluie.
Fie 2, 3, 5, , pn-1 irul format din primele n-1 numere prime n ordinea lor
cresctoare. Dac n acest ir nu exist o progresie aritmetic format din k
termeni, generm urmtorul numr prim p n i testm dac acesta este ultimul
termen al progresiei cutate. Raia progresiei aritmetice, dac exist, este egal cu
r pn pn1 sau r pn pn2 , etc. Odat fixat raia r, testm dac numerele
a1 pn (k 1) r, a2 a1 r, ..., ak 1 ak 2 r, ak pn , sunt toate numere
prime. O condiie iniial este ca a1 3 .
Putem optimiza procesul de cutare dac inem cont de proprietatea lui
Cantor Dac a1 , a2 , ..., ak este o progresie aritmetic format din numere prime,
atunci raia ei se divide la produsul numerelor prime mai mici dect k .
Justificarea acestei proprieti se bazeaz pe urmtoarele observaii:
Fie q un numr prim, 1<q<k,
- cel mult a1=q,
- termenii progresiei a2 a1 r, a3 a1 r, ..., aq1 a1 q r prin
mrire la q vor furniza q valori n mulimea {1, 2, , q-1} de unde
rezult c exist 1 i j q cu ai a j (modq) , adic q ( j i) r ;
cum j - i q si q prim q r .
#include<iostream.h>
#include<math.h>
#include<conio.h>
int prim(long m) // returneaza 1 daca m este prim si 0 in caz contrar
{ if(m==1) return 0; // 1 nu este prim
if(m==2||m==3) return 1; // 2 si 3 sunt nr. prime
if(m%2==0) return 0;
long r=sqrt(m);
for( long d=3; d<=r; d+=2)
if(m%d==0) return 0;
return 1;
}
long nrPrimUrmator(long m)// determina cel mai mic nr prim mai mare decat m
{ while(!prim(++m));
return m;
}
void PAP(int k,long &a1,long &ratia)
1

In 1963 matematicianul romn Solomon Marcurs a demonstrat c nu exist o


progresie aritmetic cu numar infinit de termeni, toi numere prime (Automates finis,
progressions arithmetiques et grammaires a un nombre fini d'etats. Comptes
rendus de l'Academie des Sciences, Paris, vol. 256, 1963, nr.
17, p. 3571-3574.).
Pna acum, prin algoritmi euristici sofisticai s-au determinat progresii aritmetice
formate din maxim 26 termeni numere prime.

73

// a1 primul termen al progresiei


{ long pn;// ultimul nr prim testat
int q=2;
int p=2;
p=nrPrimUrmator(p);
while(p<k) {q*=p; p=nrPrimUrmator(p);}
//q=produsul nr. prime mai mici decat k
pn=(k-1)*q; //pn > (k-1)*q
int k1;
while(1)
{ pn=nrPrimUrmator(pn); // urmatorul nr prim
int f=0; // f=factor de multiplicare
while(1)
{ f++;
ratia=f*q; // valoarea posibila a ratiei este multiplu de q
a1=pn-(k-1)*ratia;
// valoarea primului termen al progresiei, care urmeaza sa fie validata
if(a1<3) break;
k1=1;
for(long p=a1;p<pn ; p+=ratia)
{ if(!prim(p)) break;
k1++;
}
if(k1==k) return; // progresia contine k termeni nr prime
}
}
}
void main()
{ long a1, ratia;
clrscr();
int k;
for(k=3;k<=12;k++)
{ PAP(k,a1,ratia);
cout<<"k="<<k<<" solutie: a1="<<a1
<<" ratia="<<ratia<<endl;
cout<<a1;
for(int i=1;i<k;i++)
cout<<", "<<a1+i*ratia;
cout<<endl;
}
}

Programul furnizeaz urmtoarele rezultate:


k=3, a1=3, ratia =2;
k=4, a1=5, ratia =6;
k=5, a1=5, ratia =6;
k=6, a1=7, ratia =30;
k=7, a1=7, ratia =150;
k=8, a1=199, ratia =210;

74

k=9, a1=199, ratia =210;


k=10, a1=199 ratia =210;
k=11, a1=110437 ratia =13860;
k=12, a1=110437 ratia =13860;
4) Programul urmtor determin numrul de progresii aritmetice din
intervalul 2 n, formate din k termeni numere prime consecutive i afieaz
progresiile cu cel puin m termeni.
#include<iostream.h>
#include<math.h>
#include<conio.h>
int nr[10];
int prim(long m)
{ if(m==1) return 0;
if(m==2||m==3) return 1;
if(m%2==0) return 0;
long r=sqrt(m);
for( long d=3; d<=r; d+=2)
if(m%d==0) return 0;
return 1;
}
long nrPrimUrmator(long m)// determina cel mai mic nr prim mai mare decat m
{ while(!prim(++m));
return m;
}
void afisarePAPC(long a1,long ratia,int k)
{ cout<<a1;
for(int i=1;i<k;i++)
cout<<", "<<a1+i*ratia;
cout<<endl;
}
void PAPC(long n,int m)/* Contorizeaza in vectorul nr[], numarul de progresii aritmetice din
intervalul 2...n, formate din k termeni numere prime consecutive si afiseaza progresiile cu cel putin m
termeni */
{
long a1=3, a2=5,r=a2-a1,an;
//a1=primul termen al posibilei progresii de ratie r
int k=2;
while(a2<n)
{for(an=a2+r; prim(an); an+=r)k++; /* determinarea progresiei
a1, a1+r,, a1+(k-1)r */
if(k>=3)nr[k-3]++;
if(k>=m)afisarePAPC(a1,r,k);
a1+=(k-1)*r; //primul termen al urmatoarei, posibile, progresii
a2=nrPrimUrmator(a1); // urmatorul nr prim.
r=a2-a1;
k=2;

75

}
}
void main()
{ clrscr();
long n=1000000;
PAPC(n,5);
cout<<"in intervalul [2, "<<n<<"] exista:"<<endl;
for(int i=0;i<10;i++)
if(nr[i]>0)
cout<<nr[i]<<" progresii formate din "
<<i+3<<" termeni nr. prime consecutive"<<endl;
}

5) Urmtorul exemplu ne arat cum putem reprezenta eficient o matrice


simetric.
O matrice simetric de ordinul n este bine determinat dac pentru fiecare
linie i, i=0,1,...,n1 se cunosc elementele: a[i][0], a[i][1], ..., a[i][i].
#include<iostream.h>
void alocare(int **&a,int n) // a este parametru de ieire
{ int i,j;
a=new int*[n]; // a este un pointer la n pointeri ctre ntregi
for(i=0; i<n; i++)
a[i]=new int[i+1]; // a[i] este un pointer la i+1 ntregi
}
void dezalocare (int **a,int n)
{ int i;
for(i=0; i<n; i++)
delete a[i]; // vectorul pointat de a[i] este ters
delete a; // terge vectorul de pointeri, indicat de a
}
void cit(int **a,int n)
{ int i,j;
for(i=0;i<n;i++)
for(j=0;j<=i;j++)
cin>>a[i][j];
}
void scr(int **a,int n)
{ int i,j;
for(i=0;i<n;i++)
{ for(j=0;j<=i;j++)cout<<a[i][j];
cout<<endl;
}
}

76

void main()
{ int **a,n=4;
alocare(a,n);
cit(a,n);
scr(a,n);
dezalocare(a,n);
}

n varianta urmtoare, funcia alocare va returna adresa la care este alocat


matricea triunghiular:
int** alocare(int n)
{ int **a;
int i,j;
a=new int*[n]; // a este un pointer la n pointeri ctre ntregi
for(i=0; i<n; i++)
a[i]=new int[i+1]; // a[i] este un pointer la i+1 ntregi
return a;
}
void main()
{ int n=4;
int **a=alocare(n);
cit(a,n);
scr(a,n);
dezalocare(a,n);
}

I.12. Constante simbolice


Specificatorul const folosit ntr-o declaraie, definete o constant
simbolic. O constant simbolic n C++ este un nume cruia i se asociaz o
valoare care nu poate fi schimbat. Exist trei tipuri de constante simbolice:
1) Oricrei valori de orice tip i se poate da un nume i poate fi folosit ca o
constant, dac definiia sa este prefixat de cuvntul cheie const;
2) Un set de constante ntregi se poate defini ca o enumerare;
3) Orice nume de vector sau de funcie este o constant.
Comentarii:
Pentru c nu poate fi modificat o constant trebuie s fie iniializat.
Exemple:
const int h=176;
const int v[]={1,2,3,4}; //vector constant

Dac tipul unei constante simbolice nu este precizat, se consider c acea


constant are tipul int. Cnd se folosete un pointer, sunt implicate dou obiecte:
pointerul nsui i obiectul spre care el indic. Dac se prefixeaz declaraia unui
pointer cu const, obiectul i nu pointerul este constant.

77

De exemplu:
const char *p ="abcd"; // p este un pointer la o constant
p[3]='a';
// eroare !
p="efgh";
// p indic spre alt obiect

Pentru a declara c nsui pointerul i nu obiectul spre care el indic este o


constant, se folosete construcia *const.
De exemplu:
char * const p ="abcd"; // p este un pointer constant.
p[1]='x';
// ok! irul nu este constant
p="efgh";
// eroare

Pentru a face ambele obiecte constante, le declarm pe amndou cu


const, astfel:
const char * const p="abcd"; // p este pointer constant la o constant
p[1]='x'; // eroare !
p="efgh"; // eroare !

Adresa unei constante nu poate fi atribuit unui pointer, pentru a nu se


permite ca valoarea obiectului s fie modificat.

I.12.1. Parametri constani pentru securitatea codului


float raport(int num,int den)
{ if(den=0) return num;
return (float)num/den ;
}

Funcia de mai sus conine o eroare de programare pe care compilatorul nu o


detecteaz. ntr-adevr, den = 0 este o atribuire i nu un test de egalitate.
Parametrul den este adus sistematic la valoarea 0. Cum putem preveni astfel de
erori? Putem utiliza modificatorul const pentru parametrii de intrare care nu
trebuie s evolueze n funcie.
float raport(const int num,const int den)
{ if(den=0) return num; // error: Cannon modify a const object
else return (float)num/den ;
}

n acest caz compilatorul indic faptul c a detectat o eroare: un obiect


constant (care nu poate fi modificat) este utilizat n partea stnga a unei atribuiri.

I.13. Tipul enumerare


Acest tip permite folosirea unor nume sugestive pentru valori numerice
ntregi.
O enumerare reprezint o list de constante ntregi, pus n coresponden cu
o list de identificatori.
Constantele ntregi sunt adesea definite mai convenabil cu enum.
Exemplu:

78

enum{ IAN, FEB, MAR, APR, MAI};

definete patru constante ntregi numite enumeratori i le atribuie valori.


Deoarece valorile de enumerare sunt atribuite implicit ncepnd de la zero,
declaraia de mai sus este echivalent cu:
const int IAN=0, FEB=1, MAR=2, APR=3, MAI=4;

Dac o enumerare poart un nume, ca n exemplul de mai jos, acel nume


devine sinonim cu int, nu este un nou tip.
Enumeratorii pot primi valori explicite care nu trebuie s fie distincte
cresctoare sau pozitive.
Exemple:
enum taste {stanga=4,dreapta=6,sus=8,jos=2};
taste t;
...
t=dreapta;
...
enum culori {galben,albastru=5,rosu,verde=-5,alb} CULOARE;

n acest caz avem echivalena cu:


const galben=0, albastru=5, rosu=6, verde=-5, alb=-4;

n acest exemplu CULOARE este o variabil de tip asumat int, deci putem
scrie:
CULOARE=rosu;

sau
CULOARE=6;

sau
CULOARE=100;

I.14. Prototipul unei funcii


n principiu, o funcie poate fi apelat dac este definit n fiierul surs
nainte de a fi apelat. Acest lucru nu este ntotdeauna posibil i n astfel de cazuri
apelul funciei trebuie s fie precedat de prototipul ei.
Prototipul unei funcii are ca scop s informeze compilatorul despre:
tipul valorii returnate de funcie
tipurile parametrilor.
n felul acesta, la apelul unei funcii, compilatorul poate face teste cu privire
la tipul expresiilor parametrilor efectivi precum i unele conversii necesare legate
de valoarea returnat de funcie.
Prototipul unei funcii poate fi evideniat utiliznd formatele:
<tip> <nume funcie>(<lista parametrilor formali>);
<tip> <nume funcie>(<lista tipurilor parametrilor formali>);

Exemple:

79

1. int f1(float x,double a);

sau
int f1(float,double);
2. void f2(int a[],int b[]);

sau
void f2(int [],int []);
3. long f3(int x[4][4]);

sau
long f3(int [][]);
4.
#include <iostream.h>
void f(int [][]);
void main()
{ int a[][2]={0,1,0,2};
f(a);
}
void f(int x[][2])
{ cout<<x[1][1]; }

Exemplul 4 ne arat c, n prototip, pentru parametrii formali de tip tablou


pot lipsi toate dimensiunile, dar n antetul funciei poate lipsi numai prima
dimensiune a tabloului.

I.15. Asignri de nume pentru tipuri de date


Programatorul poate s asocieze oricrui tip de date (predefinit sau
utilizator), un nume utiliznd construcia typedef cu sintaxa:
typedef <tip> <nume>;

Exemple:
1.

typedef unsigned long natural;

Declaraia:
natural a;

este echivalent cu:


unsigned long a ;
2.

typedef char* ptrchr;

Declaraia:
ptrchr s="abc",t="zxc";

este echivalent cu:


char *s="abc",*t="zxc";

3.

Tipul tablou unidimensional cu 10 elemente poate fi declarat astfel:

80

typedef int vector[10];

Declaraia:
vector y={1,2,3,4};

este echivalent cu:


int y[10]={1,2,3,4};

4. Tipul tablou bidimensional poate fi declarat ca n exemplul urmtor:


typedef int matr[10][10];

Declaraia:
matr x={{1,1},{1,2}};

este echivalent cu:


int x[10][10]={{1,1},{1,2}};

I.16. Pointeri care memoreaz adrese de funcii


n declaraia
int f();

identificatorul f este un pointer care indic adresa funciei f. El este un


pointer constant, deci nu poate fi modificat prin instruciuni de program. Putem
declara variabile pointer care s memoreze adrese de funcii n felul urmator:
<tip> (*<identificator pointer>)(<tipurile parametrilor>);

Exemplu:
int (*adrF)();

Conform acestei declaraii, variabila adrF poate s memoreze o adres a


unei funcii care calculeaz un rezultat de tip ntreg i are lista parametrilor formali
vid. S observm c parantezele care delimiteaz *adrF sunt absolut necesare
n declaraia anterioar. n lipsa lor, declaraia int *adrF(); descrie o funcie
care calculeaz un pointer la o valoare de tip int.
Atunci cnd se menioneaz numai numele unei funcii, fr lista
parametrilor asociai i far paranteze se obine adresa de nceput a funciei. Prin
urmare, variabilei pointer din exemplul de mai sus i se poate atribui o valoare
printr-o atribuire de forma:
adrF=f;

unde f este numele unei funcii ce returneaz un ntreg i are lista


parametrilor formali vid.
Este greit s se scrie:
adrF=f();

sau
adrF=&f();

deoarece f() reprezint valoarea returnat de funcia f() iar &f() este adresa
rezultatului furnizat de funcie, dac acest rezultat este o referin. Apelarea
funciei a crei adres este memorat ntr-o variabil pointer se poate face, pentru
exemplul de mai sus, n una din variantele:
a)
b)

adrF()
(*adrF)()

Utiliznd construcia typedef putem s asignm un nume i tipului


pointer la funcii ca n exemplul urmtor:

81

typedef double (*fct)(double);

fct este identificatorul tipului de date pointer la funcii care ntorc o


valoare de tip double i au un argument de tipul double. Acum are sens, de
exemplu:
fct f=sin;

Funcia sort din programul urmtor folosete parametrul ord de tip


pointer la funcii, pentru stabilirea criteriului de ordonare cresctoare sau
descresctoare a elementelor unui vector
#include<iostream.h>
int cresc(int a,int b) {return a<=b;}
int descr(int a,int b) {return a>=b;}
typedef int (*criteriuOrdonare)(int,int);
enum boolean{false,true};
void sort(int x[],int n,criteriuOrdonare ord)
{ boolean sortat=false;
int aux;
while(!sortat)
{ sortat =true;
for(int i=0;i<n-1;i++)
if (!ord(x[i],x[i+1]))
{int aux=x[i]; x[i]=x[i+1]; x[i+1]=aux; sortat=false;}
n--;
}
}
void main()
{ int x[5]={3,5,1,8,7};
cout<<"Ordonare crescatoare:";
sort(x,5,cresc);
for(int i=0;i<5;i++) cout<<x[i]<<" ";
cout<<endl<<"Ordonare descrescatoare:";
sort(x,5,descr);
for(i=0;i<5;i++) cout<<x[i]<<" ";
cout<<endl;
}

I.17. Argumente implicite pentru funcii


C++ ofer posibilitatea declarrii funciilor cu valori implicite pentru unele
argumente. La apelarea unei astfel de funcii, se pot omite parametrii efectivi
pentru acei parametri formali care au declarate valori implicite. Un argument
implicit poate fi iniializat numai cu o expresie constant. Se pot specifica oricte
argumente cu valori implicite. Argumentele implicite trebuie s fie ultimele n lista
de argumente. Nu sunt permise alternri ntre argumente normale i argumente cu
valori implicite. C++ permite specificarea argumentelor implicite fie n definiia

82

funciei fie n prototip, dar nu n ambele. La apelare, lista parametrilor efectivi,


corespunde primilor parametri formali.
Exemplu:
#include<iostream.h>
void conv(long n,int baza=2)/* afiseaz numrul n in baza de numeraie specificat
prin parametrul baza( cu valoarea implicit 2) */
{ if (n<baza)
{ if(n<10) cout<<n; else cout<<"("<<n<<")"; return; }
conv(n/baza,baza); // Apel recursiv. ( vezi I.21. Recursivitatea n limbajul C)
int c=n%baza;
if(c<10) cout<<c; else cout<<"("<<c<<")";
}
void main()
{ cout<<endl;
int n=19;
cout<<n<<"="; conv(n);cout<<" (baza 2)"<<endl;
cout<<n<<"="; conv(n,8); cout<<" (baza 8)"<<endl;
}

Apelul conv(n) folosete baza 2(implicit), iar apelul conv(n,8) folosete


baza 8.

I.18. Funcii suprancrcate


C++ permite existena mai multor funcii cu acelai nume dar cu argumente
diferite ca numr sau tip.
Astfel de funcii se numesc suprancrcate. Compilatorul va determina
funcia apelat prin examinarea tipului argumentelor i ncercarea de a face
corespondena cu argumentele efective. Compilatorul nu verific tipul valorii
returnate de funcie. Deci, dou funcii suprancrcate nu pot diferi doar prin
valoarea returnat. De asemenea, nu pot avea acelai nume funciile cu argumente
ce difer doar prin faptul c unele sunt de tip referin iar celelalte nu sau unele
sunt statice iar celelalte nu.
#include<iostream.h>
long produs(int a[],int n)
{ long P=1;
for(int i=0;i<n;i++) P*=a[i];
return P;
}
long produs(long a[],int n)
{ long P=1;
for(int i=0;i<n;i++) P*=a[i];
return P;
}

83

double produs(float a[],int n)


{ long P=1;
for(int i=0;i<n;i++) P*=a[i];
return P;
}
double produs(double a[],int n)
{ long P=1;
for(int i=0;i<n;i++) P*=a[i];
return P;
}
void main()
{ int a[3]={1,2,3};
float b[4]={2.,3.,4.,5.};
cout<<produs(a,3)<<endl;
cout<<produs(b,4)<<endl;
}

I.19. Funcii inline


Dac o funcie este declarat inline compilatorul va genera codul
corespunztor funciei n poziia apelului, n loc de a genera secvena de apel.
Semantica apelului rmne neschimbat. Atributul inline trebuie folosit numai
pentru funciile de dimensiuni foarte mici, pentru care regia de apel este
semnificativ n raport cu timpul de execuie al funciei propriu-zise. Inline este
o cerere adresat compilatorului care poate s nu fie onorat, caz n care se
genereaz secvena obinuit de apel (de exemplu dac n program se utilizeaz
pointeri ctre funcia respectiv).
O funcie inline se declar astfel:
inline <tip> <nume funcie>(<lista argumentelor>)
{ <corp functie> }

Observaie. O funcie inline nu poate s conin instruciuni repetitive.

I.20. Structuri i uniuni


O structur reprezint o colecie de date de tipuri diferite.
Tipul unei astfel de date se spune c este definit de utilizator i se numete
tip structurat.
n C++ o structur se poate declara utiliznd sintaxa:
struct <identificator structur>
{<lista de declaraii>} <list de variabile>;
<list de variabile> poate s lipseasc.

Exemplu:
struct complex{float re,im;} c1,c2,c3[10];

Variabilele c1 i c2 sunt structuri cu cte dou cmpuri de tip float, iar c3


este un tablou de asemenea structuri.

84

n C++ putem declara variabile de tip structurat prin:


<identificator structura> <lista de variabile>;

Exemplu:
complex z1,z2,*p;

Fie declaraia:
complex x,y,*p;

Cmpurile componente ale unui date structurate pot fi referite n dou feluri:
direct, prin numele structurii urmat de "." i de numele cmpului
Exemple:
x.re, x.im, y.re, y.im
indirect, prin adresa structurii urmat de > i de numele cmpului
Exemple:
p>re, p>im

Aceast scriere este forma simplificat a scrierii (*p).re, (*p).im


Operatorul ">" are aceeai prioritate ca i ".". Ambii operatori sunt de
prioritate maxim.
Componentele unei date structurate pot fi ele nsele date structurate.
Elementele unei date de tip structurat pot fi iniializate astfel: n declaraie,
dup numele variabilei structurate se scrie "=", iar dup acesta, ntre acolade se
iniializeaz componentele structurii.
Exemple:
complex x={1,0},y={2,1};
struct student
{ char nume[20];
int note[10];
};
student s1={ "Popa Dan",{10,10,10,9,10}};

I.20.1. Probleme rezolvate


1) n urmtorul program este definit structura student i se exemplific
utilizarea ei.
#include<iostream.h>#include<iomanip.h>struct student
{ char nume[20];
char adresa[40];
long telefon;
};
void main()
{student s[100]; // vector cu componente structurate
int n;
cout<<"n="; cin>>n;
for(int i=0;i<n; i++)
{ cin.get();
// extragerea caracterului <enter> din stream
cout<<"student "<<i<<":"<<endl;
cout<<" nume:";

85

cin.getline(s[i].nume,30); // citete nume


cout<<" adresa:";
cin.getline(s[i].adresa,40); //citete adresa
cout<<" telefon:"; cin>>s[i].telefon;
}
cout<<" Lista studentilor"<<endl;
cout<<setiosflags(ios::left); // aliniere la stnga for(i=0;i<n; i++) {
cout<<setw(20)<<s[i].nume<< setw(30)<<s[i].adresa
<<s[i].telefon<<endl;
}
}

2) Calculul ariei unui poligon cu n laturi, n3, cnd se cunosc coordonatele


rectangulare ale vrfurilor poligonului (xi,yi), i=1, 2, ..., n utiliznd formula:
A=| (x1+x2)(y1-y2)+(x2+x3)(y2-y3)+...+ (xn+x1)(yn-y1) |/2,
i determinarea coordonatelor centrului de greutate al poligonului.
#include <iostream.h>
#include <iomanip.h>
#include <math.h>
struct punct {float x,y;};
int cit( punct P[])
{ int n;
cout<<"Nr. puncte="; cin>>n;
for(int i=0;i<n; i++)
{ cout<<"P"<<i+1<<"(x y)="; cin>>P[i].x>>P[i].y; }
return n;
}
float arie( punct P[],int n)
{ float s=(P[n-1].x+P[0].x)*(P[n-1].y-P[0].y);
for(int i=0;i<n-1;i++)
s+=(P[i].x+P[i+1].x)*(P[i].y-P[i+1].y);
return fabs(s)/2;
}
punct centruGr(punct P[],int n)
// ne arat c o funcie poate returna o dat structurat
{ punct G={0,0};
for(int i=0;i<n;i++)
{ G.x+=P[i].x; G.y+=P[i].y; }
G.x/=n; G.y/=n;
return G;
}
void main()
{ punct P[100];

86

int n =cit(P);
float S=arie(P,n);
punct C=centruGr(P,n);
cout<<setprecision(4);
cout<<"Aria poligonului="<<S<<endl;
cout<<"Centru de greutate este C("<<C.x<<","
<<C.y<<")"<<endl;
}

3) Transfer rapid de tablouri:


#include<iostream.h>
const dim=10;
int a[dim]={1,2,3,4,5,6,7,8,9,10},b[dim];
void main()
{ struct vector { int v[dim];};
*(vector*)b = *(vector*)a; // execuia transferului
cout<<"b=";
for(int i=0;i<dim;i++) cout<<b[i]<<" ";
cout<<endl;
}

4) Funcie care transfer blocuri de date:


void transfer(void *dest,void *sursa,int n)
{ const dimBloc=256;
struct bloc { char a[dimBloc];};
bloc* d=(bloc*)dest;
bloc* s=(bloc*)sursa;
while (n>=dimBloc)
{ *d++=*s++; n-=dimBloc; }
char* p1=(char*)d;
char* p2=(char*)s;
while (n--) *p1++=*p2++;
}
#include<iostream.h>
void main()
{ const dim=600;
int a[dim],b[dim];
for(int i=0;i<dim;i++) a[i]=i;
transfer(b,a,sizeof(a));
for (i=0;i<dim;i++) cout<<b[i]<<" ";
cout<<endl;
}

87

O uniune este o structur de date care permite folosirea n comun a aceleiai


zone de memorie, de dou sau mai multe variabile diferite, la momente de timp
diferite.
Forma general a unei uniuni:
union nume_uniune
{
tip1 nume_cmp1;
tip2 nume_cmp2;
...
tipn nume_cmpn;
} lista_variabile_uniune;

Se observ c forma general de declarare a unei uniuni este asemntoare


cu cea a unei structuri i ceea ce s-a spus la structuri este valabil i la uniuni.
Operatorul sizeof aplicat tipului de date union, adic sizeof (union
nume_uniune) va furniza lungimea uniunii(lungimea celui mai mare membru al
uniunii).
Deosebirea fundamental dintre o uniune i o structur const n modul n
care cmpurile folosesc memoria.
La structur, zonele de memorie rezervate cmpurilor sunt diferite pentru
cmpuri diferite.
La uniune, toate cmpurile din uniune mpart aceeai zon de memorie.
Aceasta nseamn c numai valoarea unuia din cmpuri poate fi memorat la un
moment dat n zona de memorie rezervat variabilei uniune.
Exemplu:
union h
{
int i;
float t;
}x;

Datele din variabila x vor fi privite ca ntregi dac selectm x.i sau reale
dac selectm x.t.
Cmpurile i i t se refer la aceeai adres:
n x.i se memoreaz sizeof(int) octei la aceast adres;
n x.t se memoreaz sizeof(float) octei care ncep la aceast adres.

I.21. Recursivitatea n limbajul C


Spunem despre o funcie C c este recursiv dac se autoapeleaz. Funcia
recursiv se poate reapela fie direct, fie indirect prin apelul altor funcii.
Funciile recursive se definesc prin punerea n eviden a dou seturi de
instruciuni i anume:

88

un set care descrie modul n care funcioneaz funcia pentru anumite


valori (iniiale) ale unora dintre argumente;
un set care descrie procesul recursiv de calcul.
Valorile unei funcii recursive se calculeaz din aproape n aproape, pe baza
valorilor cunoscute ale funciei pentru anumite argumente iniiale. Pentru a calcula
noile valori ale unei funcii recursive, trebuie memorate valorile deja calculate, care
sunt strict necesare. Acest fapt face ca implementarea n program a calculului unor
funcii recursive s necesite un consum mai mare de memorie, rezultnd timpi mai
mari de execuie.
Recursivitatea poate fi transformat n iteraie.
In general, forma iterativ a unei funcii este mai eficient dect cea
recursiv n ceea ce privete timpul de execuie i memoria consumat.
n alegerea cii (interativ sau recursiv) de rezolvare a unei probleme,
trebuie considerai o serie de factori: uurina programrii, testrii i ntreinerii
programului, eficiena, complexitatea etc.
Dac o problem are o complexitate redus este preferat varianta iterativ.
Forma recursiv este preferat acolo unde transformarea recursivitii n
iteraie cere un efort de programare deosebit, algoritmul pierzndu-i claritatea,
testarea i ntreinerea devenind astfel foarte dificile.
La fiecare apel al funciei recursive, parametrii i variabilele ei locale
automatice se aloc pe stiv ntr-o zon nou, independent. De asemenea n stiv
se trece adresa de revenire n subprogramul chemtor, adic adresa instruciunii
urmtoare apelului. La revenire, se realizeaz curarea stivei, adic zona de pe
stiv afectat la apel parametrilor i variabilelor automatice, se elibereaz.
Observaii:
n general, recursivitatea permite o scriere mai compact i mai clar a
programelor care conin procese de calcul recursiv.
De obicei, recursivitatea nu conduce nici la economie de memorie i nici la
execuia mai rapid a programelor. n mod frecvent sunt variante nerecursive mai
rapide dect variantele recursive i conduc adesea i la economie de memorie.
Apelurile recursive pot conduce la depirea stivei.

I.21.1. Pobleme rezolvate:


1. Funcia factorial: fact : NN

1 dac n 0,
fact(n)
n fact(n 1) dac n 1
#include <stdio.h>
int fact(int n)
{ if(n==0) return 1;
return n*fact(n-1);
}

89

void main()
{ int n;
clrscr();
printf (n = ) ; scanf (%d, &n) ;
printf ( %d!=%d,n, fact(n));
}

Apelul lui fact(4) declaneaz un lan de apeluri ale lui fact pentru 3, 2, 1,0
dup care urmeaz revenirea din apeluri i evaluarea lui fact pentru 0,1,2,3,4.

fact(4)
4 fact(3)
3 fact(2)
2 fact(1)
1 fact(0)
1

Starea stivei in timpul execuiei succesive a autoapelrii:


0

Stiva
Vida

Apel
fact(4)

Apel
fact(3)

Apel
fact(2)

Apel
fact(1)

Apel
fact(0)

Pentru fiecare din aceste apeluri, n stiv se vor depune parametrii actuali:
4,3,2,1,0. Strile stivei dup ieirea din autoapel sunt urmatoarele:

0
1

90

fact(0)
=
1

fact(1)
=
1*1

fact(2)
=
1*1*2

fact(3)
=1*1*
2*3

fact(4)
=1*1*
2*3*4

Stiva
vida

Rezolvarea fiecrui autoapel nseamn deplasarea pe un nivel inferior.


2. Funcia lui Fibonacci:

fib : N N ,

1, n 0 sau n 1,
fib(n)
fib(n 1) fib(n 2), n 2
Error! Reference source not found.
long fib(int n)
{ if (n==0||n==1) return 1;
return fib(n-1) + fib(n- 2);
}

Varianta iterativa:
long fib(int n)
{ long f1=1,f2=1,f;
if(n==0||n==1)return 1;
for(k=2;k<=n;k++)
{ f=f2+f1; f1=f2; f2=f; }
return f;
}

3. Funcia lui Ackermann: ac : N x N N

dac m 0
n 1,

ac(m, n) ac(m 1,1), dac n 0


ac(m 1, ac(m, n 1)), dac m 0, n 0

int ac(int m, int n)


{ if(m==0)return n+1;
if(n==0) return ac(m-1,1);
return ac(m-1,ac(m,n-1));
}

4) Fie v un vector cu n elemente de tip long. Elaborai funcii C recursive


pentru
citirea, afiarea, determinarea sumei i determinarea minimului
elementelor vectorului.
Rezolvare:
#include<iostream.h>

91

long suma(long v[],int n)


{ if(n==0) return 0;
return v[n-1]+suma(v,n-1);
}
long min(long v[],int n)
{ if(n==1) return v[0];
long min2=min(v,n-1);
return min2<=v[n-1]?min2:v[n-1];
}
void citire(long v[],int n)
{ if(n==0)return;
citire(v,n-1);
cin>>v[n-1];
}
void afisare(long v[],int n)
{ if(n==0) return;
afisare(v,n-1);
cout<<v[n-1]<<" ";
}
void main()
{ long v[100];
int n;
cout<<"n=";
cin>>n;
cout<<"Tastati "<<n<<" elemente";
citire(v,n);
cout<<"Vectorul citit este:";
afisare(v,n);
cout<<endl;
long S=suma(v,n);
cout<<"Suma elementelor vectorului este "<<S<<endl;
cout<<"Elementul minim este "<<min(v,n)<<endl;
}

5) Calculul determinanilor
Programul urmtor calculeaz valoarea determinantului unei matrice
ptratic de ordinul n,

92

a 00
a10

a 01
a11

a n 1 0

a n 1 1

det( A)

... a 0 n 1
... a1n 1
,
....
... a n 1 n 1

prin utilizarea urmatoarei formule de

recuren(dezvoltarea dup prima linie):


a 00 ,
n 1

a 00 a11 a 01 a10 ,
n2
det( A)
n 1 (1) j a M , n 2
0j
0j

j 0

unde M 0 j este minorul lui a0 j (determinantul obinut din cel iniial, prin
suprimarea liniei 0, coloana j).
Dac det(A)0 putem calcula inversa matricei A dup formula
A 1

1
A* ,
det( A)

Matricea A* (bi j ), i, j 0,1,..., n 1 se numete adjuncta matricei A, unde


bi j (1) i j M j i iar M j i este minorul corespunztor elementului a j i al matricei

Programul conine i o funcie pentru determinarea adjunctei A* .


#include<iostream.h>
#include<iomanip.h>
#include<math.h>
#include <conio.h>
float ** alocare(int n)
// alocare dinamica pentru o matrice patratica de ordin n
{ float **m=new float*[n];
for(int i=0;i<n;i++)m[i]=new float[n];
return m;
}
void dezalocare(float **a,int n)
// eliberarea memoriei alocat dinamic pentru matricea patratica de ordin n
{ for(int i=0;i<n;i++) delete a[i];
delete a;
}
float ** minor(float **A,int n,int l,int k)
// Crearea matricei minorului corespunzator elementului A[l][k]
{ float **m=alocare(n-1);
int i,j,ii,jj;
jj=0;
for (j = 0 ; j < n ; j++)
{ if(j==k) continue;
ii=0;
for (i = 0; i < n; i++)
{ if(i==l) continue;

93

A.

m[ii][jj] = A[i][j];
ii++;
}
jj++;
}
return m;
}
float det(float **A, int n)
{ int i, j, p,k;
float d;
if (n==1)return A[0][0];
if (n == 2) return A[0][0]*A[1][1] - A[1][0]*A[0][1];
//altfel, dezvoltare dupa linia 0
d = 0;
for (p = 0 ; p < n ; p++)
{ float **m=minor(A,n,0,p);
d += pow(-1.0, p) * A[0][p] * det(m, n-1);
dezalocare(m,n-1);
}
return d;
}
float ** adjuncta(float **A,int n)
{ float **B=alocare(n);
float **m;
int i,j,l,k;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{ m=minor(A,n,i,j);
B[j][i]=pow(-1,i+j)*det(m,n-1);
}
return B;
}
void afisare(float **A,int n)
// afisarea matricei patratice de ordin n
{ int i,j;
for(i=0;i<n;i++)
{for(j=0;j<n;j++)
cout<<setw(8)<<A[i][j]<<" ";
cout<<endl;
}
}
void main()
{ float A[4][4]={{2,1,-1,3},
{1,-1,2,2},
{4,-2,3,1},
{-2,2,1,-1}};

94

float **m=alocare(4);
clrscr();
//copierea matricei A in zona alocata dinamic
for(int i=0;i<4;i++)
{ for(int j=0;j<4;j++) m[i][j]=A[i][j];}
cout<< "d="<<det(m,4)<<endl;
float **b=adjuncta(m,4);
cout<<"Adjuncta lu A:"<<endl;
afisare(b,4);
}

6) Se consider fotografia alb-negru a unor obiecte, reprezentat sub forma


unui tablou bidimensional cu n linii i n coloane, cu elementele n mulimea {0,1}.
Elementele egale cu 1 corespund poziiilor ce aparin obiectelor. S se scrie un
program pentru a determina cte obiecte sunt fotografiate i din cte elemente de
"1" este compus fiecare obiect.
Rezolvare.
Ct timp sunt elemente egale cu 1, alegem un astfel de element.
Funcia recursiv int fig(int i, int j), nlocuie cu 1
elementul 1 ales i toate elementele 1 "legate" de elementul ales (pentru a nu mai fi
contorizate ulterior), i returneaz numrul poziiilor ce aparin obiectului curent.
Pentru simplificarea testelor matricea a[][] este bordat cu elemente nule.
Funcia void generare(), genereaz o configuraie de obiecte.
Funcia int figNR(int i, int j) reprezint varianta nerecursiv
a funciei int fig(int i, int j). Eliminarea recursivitii s-a fcut prin utilizarea unei
stive format cu ajutorul vectorilor x[] i y[]. Vrful stivei este indicat de
indicele k; (x[k],y[k]) reprezint poziia unui element 1 ce aparine obiectului
curent.
Iniial n stiv se introduce poziia (i,j) a unui element al obiectului
curent (a[i][j] de valoare 1).
Ct timp stiva nu este vid
{ - extragem un element din stiv pe care l contorizm;
- introducem n stiv poziiile elementelor 1 vecine cu elementul extras
- introducerea n stiv este nsoit de nlocuirea corespunztoare,
n matricea a[][], a lui 1 cu -1.
}
#include <iostream.h>
#include<stdlib.h>
const n=6;
int a[n+2][n+2];
int fig(int i,int j)
{ if(a[i][j]==1)
{ a[i][j]=-1;

95

return 1+fig(i-1,j-1)+fig(i-1,j)+fig(i-1,j+1)+
fig(i,j-1)+fig(i,j+1)+
fig(i+1,j-1)+fig(i+1,j)+fig(i+1,j+1);
}
return 0;
}
int figNR(int i,int j)
{int *x=new int[n], *y=new int[n], k=0, nr=0;
x[k]=i; y[k]=j; a[i][j]=-1;
while(k>=0)
{i=x[k]; j=y[k];
k--; nr++;
if(a[i-1][j-1]==1)
{ k++; x[k]=i-1; y[k]=j-1; a[i-1][j-1]=-1;};
if(a[i-1][j]==1)
{ k++; x[k]=i-1; y[k]=j; a[i-1][j]=-1; };
if(a[i-1][j+1]==1)
{ k++; x[k]=i-1; y[k]=j+1; a[i-1][j+1]=-1;};
if(a[i][j-1]==1)
{ k++; x[k]=i; y[k]=j-1; a[i][j-1]=-1; };
if(a[i][j+1]==1)
{ k++; x[k]=i; y[k]=j+1; a[i][j+1]=-1; };
if(a[i+1][j-1]==1)
{ k++; x[k]=i+1; y[k]=j-1; a[i+1][j-1]=-1;};
if(a[i+1][j]==1)
{ k++; x[k]=i+1; y[k]=j; a[i+1][j]=-1; };
if(a[i+1][j+1]==1)
{ k++; x[k]=i+1; y[k]=j+1; a[i+1][j+1]=-1;};
}
delete x; delete y;
return nr;
}
void generare()
{ int i,j,k,m;
randomize();
m=1+random(n*n);
for(k=1;k<=m;k++)
{ i=1+random(n);
j=1+random(n);
a[i][j]=1;
}
}
void afisare()
{ int i,j;
for(i=1;i<=n;i++)
{ for(j=1;j<=n;j++) cout<<' '<<a[i][j];
cout<<endl;
}
}
void main()
{ int i,j,k=0;

96

generare();
afisare();
cout<<" rezolvare utilizind varianta recursiva"<<endl;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if (a[i][j]==1)
{ k++;
cout<<"fig "<<k<<" = "<<fig(i,j)<<" patrate"<<endl;
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=-a[i][j];
cout<<"rezolvare utilizind varianta nerecursiva"<<endl;
k=0;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if (a[i][j]==1)
{ k++;
cout<<"fig "<<k<<" = "<<figNR(i,j)<<" patrate"
<<endl;
}
}

I.22. Structuri de date de tip list


Prin list nelegem o succesiune finit de elemente (eventual vid)
aparinnd unei mulimi de date, ordinea n care apar aceste elemente fiind
esenial. ntr-o structur de tip list ne intereseaz rspunsurile la urmtoarele
ntrebri:
Care este primul element din list ?
Care este ultimul element din list?
Care element precede i care element urmeaz unui element din list?
Asupra listelor se efectueaz operaii de tipul:
Accesul la un anumit element din list, identificat prin valoarea sa sau
prin numrul su de ordine n list;
tergerea (eliminarea) unui element din lista;
Concatenarea a dou sau mai multe liste;
Descompunerea unei liste n mai multe liste;
Reordonarea elementelor unei liste conform unui anumit criteriu.
Memorarea listelor se face n dou modaliti:
a) Memorarea cu alocare secvenial const n memorarea elementelor listei
n locaii succesive de memorie, conform ordinei acestor elemente n list: X[1],
X[2], ..., X[n], n 0. Accesul la elementele listei se face prin intermediul unei
variabile de indexare k, 1 k n.
b)Memorarea nlnuit presupune c fiecare element al listei este nlocuit
cu o celul (nod) format din dou pri: o parte de informaie corespunztoare

97

elementului i o parte de legtur ce conine adresa corespunztoare urmtorului


element. Ca i la memorarea secvenial mai trebuie memorat adresa de baz; n
plus partea de legtur a ultimei celule primete o valoare ce nu poate desemna o
legatur (de obicei valoarea 0).
Celulele vor fi reprezentate sub forma
informaie
legtur
cu semnificaii evidente.
Legturile sunt precizate, de obicei, cu ajutorul sgeilor:
List

Inserare

tergere

O list poate fi transformat ntr-o list circular, dac n partea de legtur a


ultimului element vom pune adresa primului element. Alocarea nlnuit cere mai
mult memorie dect cea secvenial. Trebuie menionat c n aplicaii partea de
informaie este mult mai mare dect cea de legtur. Pe de alt parte memorarea
nlnuit elimin necesitatea deplasrii de elemente pentru operaiile de
introducere i scoatere din list aa cum rezult din figura de mai sus.
Implementarea listelor n limbajul C este posibil deoarece limbajul C
permite definirea de tipuri de date care se autorefer (definite recursiv).
Exemplu:
struct nod
{ int inf;
nod* leg;
};

Crearea unei liste cu elemente de tipul nod, presupune utilizarea variabilelor


cu alocare dinamic (utiliznd funciile new i delete), care se nasc i dispar n
cursul execuiei programului, la cererea programatorului.
void main()
{ nod *p,*q;
p=new nod;
p->inf=5;
p->leg=0;

// alocare

98

q=p;

// q va indica aceeai celul ca i p

q=new nod;
q->inf=p->inf; /* copiaz informaia din celula indicat de p n celula indicat de
q. */
*q=*p; // copiaz coninutul celulei pointate de p n celula pointat de q.
p->leg=q; /* face ca n partea de legtur a variabilei desemnate de p
s se treac adresa variabilei desemnate de q. */
q->leg=0;

/* face ca partea de legtur a variabilei desemnate de q


s pointeze ctre o zon de memorie nul */

Listele liniare n care inserrile, tergerile i accesul la valori au loc aproape


totdeauna la primul sau la ultimul nod sunt frecvent ntlnite i poart denumiri
speciale.

I.23. Implementarea unor liste particulare n limbajul


C
I.23.1. Stiva
Prin stiv nelegem o list liniar pentru care operaiile de introducere i
extragere a unui element se efectueaz la acelai capt al listei, numit vrful stivei.
Cellalt capt al stivei se numete baza stivei.
n alocarea nlnuit, n cazul stivei, legturile merg de la ultimul element al
stivei ctre primul element, ca n figura urmtoare:

Error! Reference source not found.


Urmtorul program implementeaz funcii de lucru cu stiva:
Structura nod cuprinde cmpurile unei celule: inf partea de informaie i
leg partea de legtur.
Funcia int inserare(nod *&cap, int x); realizeaz inserarea
elementului x n stiv. Dac nu este spaiu suficient funcia va returna 0 desemnnd
eecul operaiei de inserare, altfel va returna 1 - inserare cu succes.
Funcia void extragere(nod *&cap,int &x); extrage n x
elementul din varful stivei. Apelul are sens dac stiva este nevid.
Funcia void listare(nod *cap); afieaz elementele stivei.
Funcia void stergere(nod *&cap); terge stiva.
Funcia int virf(nod *cap); returneaz valoarea elementului din
vrful stivei.

99

#include<iostream.h>
#include<conio.h>
struct nod
{int inf;
nod *leg;
};
int inserare(nod *&cap,int x)
{
nod *p=cap;
cap=new nod; // variabila cap va fi nenul daca alocarea s-a fcut cu succes
if (!cap) return 0;// spatiu insuficient
cap->inf=x;
cap->leg=p;
return 1;
}
void extragere(nod *&cap,int &x)
{
nod *p=cap;
x=cap->inf;
cap=cap->leg;
delete p;
}
void listare(nod *cap)
{ while (cap){ cout<<cap->inf<<" "; cap=cap->leg;} }
int virf(nod *cap){ return cap->inf; }
void stergere(nod *&cap)
{ nod *p;
while(cap)
{ p=cap;
cap=cap->leg;
delete p;
}
}
void main()
{nod *s=0; // Stiva vida
int op,x;
do
{cout<<"1 -Inserare"<<endl;
cout<<"2 -Extragere"<<endl;
cout<<"3 -Listare"<<endl;
cout<<"4 -Virf"<<endl;
cout<<"5 -Stergere"<<endl;
cout<<"9 -Stop"<<endl;
cout<<"Tastati optiunea: ";
cin>>op;

100

switch(op)
{case 1:cout<<"x=";cin>>x;inserare(s,x);
break;
case 2:if (s==0) cout<<"stiva vida"<<endl;
else {extragere(s,x);
cout<<"Am extras elementul "<<x<<endl;
}
break;
case 3:cout<<"Continut stiva: ";
listare(s);
cout<<endl;
break;
case 4:if (s==0) cout<<"Stiva vida"<<endl;
else cout<<"Virf ="<<virf(s)<<endl;
break;
case 5:stergere(s);
}
}
while(op!=9);
}

I.23.2. Coada
Prin coad nelegem o list n care introducerile se fac la un capt al listei,
numit baza cozii, iar extragerile se fac la cellalt capt al listei numit vrful cozii.
Alocarea nlnuit a cozilor presupune cunoaterea adresei primului
element al cozii (vrful cozii) i a adresei ultimului element al cozii (baza cozii).
n alocarea nlnuit, legturile merg ca mai jos:
Error! Reference source not found.
Urmtorul program implementeaz funcii de lucru cu o list de tip coad:
Structura nod cuprinde cmpurile unei celule: inf partea de informaie i
leg partea de legtur.
Funcia int inserare(nod *&prim, nod *&ultim, int x);
realizeaz inserarea elementului x n coad. Dac nu este spaiu suficient funcia va
returna 0 desemnnd eecul operaiei de inserare, altfel va returna 1 - inserare cu
succes.
Funcia void extragere(nod *&prim, int &x); extrage
elementul din vrful cozii.
Funcia void listare(nod *prim); afieaz elementele cozii.
#include<iostream.h>
#include<conio.h>
struct nod
{int inf;
nod *leg;
};
int inserare(nod *&prim,nod *&ultim,int x)

101

{ if (prim==0)prim=ultim=new nod;
else ultim=ultim->leg=new nod;
if(!ultim) return 0; //esec la alocare
ultim->inf=x; ultim->leg=0;
return 1; // inserare cu succes;
}
void extragere(nod *&prim,int &x)
{ nod *p=prim;
x=prim->inf; prim=prim->leg;
delete p;
}
void listare(nod *prim)
{ while(prim)
{cout<<prim->inf<<" "; prim=prim->leg; }
}
int virf(nod *prim){ return prim->inf; }
void stergere(nod *&prim)
{ nod *p;
while(prim)
{ p=prim;
prim=prim->leg;
delete p;
}
}
void main()
{ nod *prim=0,*ultim;// coada vida
int op,x;
do
{ cout<<"1 -Adaugare"<<endl;
cout<<"2 -Extragere"<<endl;
cout<<"3 -Listare"<<endl;
cout<<"4 -Virf"<<endl;
cout<<"5 -Stergere"<<endl;
cout<<"9 -Stop"<<endl;
cout<<"Tastati optiunea: ";
cin>>op;
switch(op)
{ case 1:cout<<"x=";cin>>x;
inserare(prim,ultim,x);
break;
case 2:if (prim==0) cout<<"coada vida"<<endl;
else { extragere(prim,x);
cout<<"Am extras elementul "<<x<<endl;
}
break;
case 3:cout<<" Coada este:";
listare(prim); cout<<endl;
break;
case 4:if (prim==0) cout<<"Coada vida"<<endl;

102

else cout<<"Virf ="<<virf(prim)<<endl;


break;
case 5:stergere(prim);
}
}
while(op!=9);
}

I.24. Arbori
Prin arbore nelegem o mulime finit de elemente, numite noduri
A={A1, A2, ... , An}, n>0 care are urmtoarele proprieti:
exist un nod i numai unul numit rdcina arborelui;
celelalte noduri (dac mai exist) sunt submulimi disjuncte ale lui A, care
formeaz fiecare cte un arbore. Arborii respectivi se numesc subarbori ai
rdcinii. ntr-un arbore exist noduri crora nu le mai corespund arbori. Un astfel
de nod se numete nod terminal sau frunz. Un nod rdcin este numit nod tat,
rdcina unui arbore al su este numit nod fiu iar subarborii sunt descendenii lui.
O alt noiune este aceea de nivel. Rdcina arborelui are nivelul 1.
Dac un nod are nivelul n, atunci fiii lui au nivelul n+1.
Dac subarborii unui nod se consider ntr-o anumit ordine, subarborele se
numete ordonat.

I.24.1. Arbori binari


Un arbore binar este o mulime finit de elemente numite noduri
A={A1,A2,...,An}, n>=0, care este sau vid sau conine un element rdcin,

celelalte elemente mprindu-se n dou submulimi disjuncte (considerate ntr-o


anumit ordine), care fiecare, la rndul ei, este un arbore binar.
Arborele binar este ordonat, una dintre submulimi numindu-se subarbore
stng al rdcinii, iar cealalt subarbore drept.
Asupra arborilor se pot defini operaii de tipul:
construirea unui arbore
parcurgerea nodurilor
cutarea unui nod
inserarea i tergerea unui nod
tergerea unui arbore
Grafic un arbore binar se reprezint ca mai jos:

103

Exist trei modaliti importante de parcurgere a nodurilor unui arbore binar:


n preordine: se viziteaz rdcina, apoi tot n preordine se viziteaz
nodurile subarborelui stng i apoi ale subarborelui drept.
Nodurile arborelui de mai sus, vizitate n preordine, sunt: 1,2,3,4,5,6,7,8,9;
n inordine: se viziteaz n inordine nodurile subarborelui stng apoi se
viziteaz rdcina i apoi se viziteaz tot n inordine nodurile subarborelui drept.
Nodurile arborelui vizitate n inordine, sunt: 3,2,5,4,1,6,8,7,9;
n postordine: se viziteaz n postordine nodurile subarborelui stng apoi
ale subarborelui drept i apoi rdcina.
Nodurile arborelui vizitate n preordine, sunt: 3,5,4,2,8,9,7,6,1.
Un arbore binar se poate implementa uor cu ajutorul pointerilor, fiecare nod
coninnd n afar de informaia propriu-zis asociat nodului, adresa fiului stng i
adresa fiului drept, acestea exprimnd legturile existente ntre noduri.

#include<iostream.h>
struct nodArb
{ int inf;
nodArb *ls,*ld;
};
void creArb(nodArb *& p)
{ int x;
cout<<"inf nod(sau punct ptr. sf. ramura):";
if(cin>>x)
{ p=new nodArb;
p->inf=x;
p->ls=0;
p->ld=0;
cout<<" nod stanga:";
creArb(p->ls);
cout<<" nod dreapta:";
creArb(p->ld);
}
else
{cin.clear();cin.ignore(80,'\n');}
}
void prelNod(int x)
{ cout<<x<<" "; }

104

void Inord(nodArb *p)


{ if(p!=0)
{ Inord(p->ls);
prelNod(p->inf);
Inord(p->ld);
}
}
void Preord(nodArb *p)
{ if(p!=0)
{ prelNod(p->inf);
Preord(p->ls);
Preord(p->ld);
}
}

void Postord(nodArb *p)


{ if(p!=0)
{ Postord(p->ls);
Postord(p->ld);
prelNod(p->inf);
}
}
void ActArbSort(nodArb *&p,int x )
{ if(p)
if (x<p->inf) ActArbSort(p->ls,x);
else
ActArbSort(p->ld,x);
else {p=new nodArb;
p->inf=x;
p->ls=0;
p->ld=0;
}
}
void main()
{ nodArb * varf;
creArb(varf);
cout<<"Parcurgere in inordine:"<<endl;
Inord(varf);
cout<<endl;
cout<<"Parcurgere in preordine:"<<endl;
Preord(varf);
cout<<endl;
cout<<"Parcurgere in postordine:"<<endl;
Postord(varf);

105

cout<<endl;

cout<<"Creare arbore de sortare:"<<endl;


varf=0; // Arbore vid
int x;
cout<<"Tastati un sir de numere terminat cu '.':"<<endl;
for( ; ; )
if( cin>>x)ActArbSort(varf,x);
else break;
cin.clear();cin.ignore(80,'\n');
cout<<"sirul sortat:"<<endl;
Inord(varf);
}

I.24.2. Crearea i traversarea arborilor oarecare


Pentru implementarea unui arbore oarecare putem folosi urmtoarea metod:
fiecare nod al arborelui va conine informaia propriu-zis asociat nodului,
numrul de descendeni ai nodului i adresa fiecrui descendent, acestea exprimnd
legturile dintre noduri ca n figura urmtoare:

Construirea arborelui se face prin citirea n postordine a nodurilor. Pentru


fiecare nod se citete informaia util i numrul de descendeni. Nodurile sunt
"pstrate" ntr-o stiv pn cnd apare nodul ai crui fii sunt. n acest moment fiii
sunt scoi din stiv i se actualizeaz referinele descendente (de la tat la fii), dup
care tatl este pus n stiv. n final singurul nod din stiv va fi rdcina iar arborele
va fi gata construit.
Parcurgerea arborelui se va face pe orizontal (nivel dup nivel) utiliznd o
coad pentru pstrarea nodurilor ce urmeaz s fie prelucrate. Iniial se introduce
rdcina arborelui n coada vid, dup care se scoate pe rnd cte un nod din coad
introducndu-se descendenii si. Se verific uor c acest mecanism asigur ntradevr parcurgerea nivel dup nivel.
#include<iostream.h>
struct nodA
{ int inf;
int nrfii;

106

nodA* *leg;
};
struct nod
{ nodA * inf;
nod *leg;
};
void inS(nod *&cap,nodA *x ) // inserare n stiv
{ nod *p=cap;
cap=new nod;
if (!cap) {cout<<"Spatiu insuficient" ;return;};
cap->inf=x;
cap->leg=p;
}
void outS(nod *&cap,nodA * &x) //extragere din stiv
{ nod *p=cap;
x=cap->inf;
cap=cap->leg;
delete p;
}
void inC(nod *&prim,nod *&ultim,nodA* x) // inserare n coad
{ if (prim==0)prim=ultim=new nod;
else ultim=ultim->leg=new nod;
ultim->inf=x;
ultim->leg=0;
}
void outC(nod *&prim,nodA* &x) //extragere din coad
{ nod *p=prim;
x=prim->inf;
prim=prim->leg;
delete p;
}
void prelNod(int x){cout<<x<<" ";}
void creArb(nodA * &rad)
{ nod *S=0; //pointer la stiv
int n;
int inf,nrfii;
nodA *p;
cout<<"Nr.total de noduri:"; cin>>n;
cout<<"Nodurile se vor introduce in postordine"<<endl;
for(int i=1;i<=n;i++)
{ cout<<"inf. nod "<<i<<":";
cin>>inf;
cout<<"nr.fii"; cin>>nrfii;
p=new nodA;
p->inf=inf;
p->nrfii=nrfii;
if(nrfii>0) p->leg=new nodA*[nrfii];
for(int k=nrfii;k>=1;k--)
if(S) outS(S,p->leg[k-1]);

107

else{cerr<<"Ati declarat gresit nr. de descendenti!"


<<endl;
return;
}
inS(S,p);
}
outS(S,rad);
}
void traversare(nodA * &rad )
{ if(rad==0)return;
nod *primC=0,*ultimC=0; //pointeri la coad
inC(primC,ultimC,rad);
nodA* p;
while(primC)
{ outC(primC,p);
prelNod(p->inf);
for(int i=0;i<p->nrfii;i++)
inC(primC,ultimC,p->leg[i]);
}
}
void Preord(nodA* rad)
{ if(rad)
{ prelNod(rad->inf);
for(int i=0;i<rad->nrfii;i++)
Preord(rad->leg[i]);
}
}
void Postord(nodA* rad)
{ if(rad)
{ for(int i=0;i<rad->nrfii;i++)
Preord(rad->leg[i]);
prelNod(rad->inf);
}
}
void main()
{ nodA * A;
creArb(A);
cout<<"Arborele in preordine:"<<endl;
Preord(A);
cout<<endl;
cout<<"Arborele in postordine:"<<endl;
Postord(A);
cout<<endl<<"Arborele pe nivele:"<<endl;
traversare(A);
cout<<endl;
}

108

I.25. Prelucrarea fiierelor n C++


Pentru a realiza operaii de I/E cu fiiere, trebuie s includem n program
fiierul fstream.h. n acest fiier sunt definite clasele ifstream,
ofstream, i fstream. Aceste clase sunt derivate din clasele istream i
ostream derivate la rndul lor din clasa ios clase definite n fiierul
iostream.h. Deci declaraiile claselor ios, istream i ostream rmn valabile i
pentru lucru cu fiiere.
n C++, un fiier este deschis prin cuplarea lui la un stream.
Exist trei tipuri de streamuri:
de intrare;
de ieire;
de intrare/ieire.
Pentru a crea un stream de intrare, el trebuie declarat de tip ifstream, iar
un stream de ieire trebuie declarat de tip ofstream. Streamurile care realizeaz
ambele tipuri de operaii vor fi declarate de tip fstream.
Constructorii implicii ai claselor ifstream, ofstream i fstream iniializeaz
streamuri fr a deschide fiiere.
Funcia open este folosit pentru a asocia un fiier la un stream (dup
crearea streamului). Aceast funcie este membr a tuturor celor trei clase de tip
stream i are prototipul
void open( char* numeFiier, int modDeschidere,
int modProtectie);

Definiii pentru modDeschidere:


Mod
Valoare
Comentariu
deschidere
Deschidere pentru citire. Fiierul trebuie s existe.
ios::in
0x01
ios::out

0x02

ios::ate
ios::app

0x04
0x08

ios::trunc

0x10

ios::nocreate

0x20

ios::noreplace 0x40
ios::binary

0x80

Valoare implicit pentru ifstream


Deschidere pentru scriere. Dac fiierul nu exist, se
creaz iar dac exist, coninutul su se pierde.
Deschidere i poziionare la sfrit de fiier.
Deschidere pentru scriere la sfrit de fiier. Fiierul
trebuie s existe.
Deschidere i trunchiere fiier (la lungime 0), dac
exist.
Fiierul trebuie s existe la deschidere, altfel se
produce eroare.
Fiierul trebuie s fie nou la deschidere, altfel
deschiderea eueaz.
Opusul lui "text" (implicit): nu se traduc perechile
"cr/lf".

Observaie. Pentru activarea mai multor bii se poate folosi operatorul "sau"
binar (|).
Argumentul modProtectie poate lua urmtoarele valori:
0 fiier normal, fr restricii de acces (valoare implicit);
1 fiier de tip "read-only";

109

2 fiier ascuns;
4 fiier de tip sistem;
8 bit de arhivare activ.
Se pot specifica mai multe dintre atribute folosind operatorul "sau" binar (|).
Exemple:
ifstream f;
f.open("f1.dat");
ofstream g;
g.open("f2.dat");
fstream h;
h.open("f3.dat",ios::in|ios::out);
/* pentru a deschide un fiier fstream", pentru operaii de intrare/ieire
trebuie s specificm att ios::in ct i ios::out. */

Clasele ifstream, ofstream, fstream conin funcii constructor care efectueaz


n mod automat operaia de deschidere a fiierului. Ele au aceiai parametri i
valori implicite ca i funcia open:
Deci putem folosi direct:
ifstream f.open("f1.dat");
ofstream g.open("f2.dat");
fstream h("f3.dat",ios::in|ios::out);

Dac operaia de deschidere eueaz streamul va conine valoarea zero, ceea


ce nseamn c putem testa uor dac operaia de deschidere a reuit. Destructorul
clasei ifstream (respectiv ofstream sau fstream) golete tamponul fiierului i
nchide fiierul (dac nu este deja nchis).
nchiderea unui fiier se face cu ajutorul funciei membre:
void close(void);
Funcia membru int eof() ntoarce o valoare diferit de zero dac s-a
atins sfritul fiierului i 0 n caz contrar.
Scrierea i citirea ntr-un, respectiv dintr-un fiier text deschis se poate face
utiliznd operatorii stream "<<" i ">>" n mod similar cu cei utilizai la operaiile
de I/E utiliznd consola cu excepia faptului c, n loc s utilizm dispozitivele
standard cin, cout etc, folosim streamul cuplat la fiier. Toate informaiile sunt
memorate n fiier n acelai format ca i cel utilizat la afiare.
Cnd efectum operaii de I/E cu fiiere de tip text, caracterele newline se
transform n combinaia de caractere cr/lf.
Funcii de I/E de tip binar
Dei fiierele text sunt utile n foarte multe aplicaii, ele nu au flexibilitatea
fiierelor de tip binar; din acest motiv, limbajul C++ asigur numeroase funcii de
I/E de tip binar: get, put, read, write etc.
Funcia get are mai multe forme i anume:
int get();

Extrage din streamul asociat un caracter i returneaz codul caracterului


extras.
istream& get(char& c);

110

Citete din streamul asociat un caracter i l memoreaz n variabila de ieire


c. Funcia napoiaz o referin la streamul asociat care va avea valoarea zero dac
s-a detectat sfritul de fiier.
istream& get(char *p,int n, char delimitator='\n');

Citete n caractere din stream sau pn la ntlnirea delimitatorului dat ca al


treilea argument i i memoreaz n zona pointat de p. Valoarea implicit a
delimitatorului este '\n', i nu este extras din stream.
istream& getline(char *p,int n, char delimitator='\n');

Este similar cu funcia precedent, dar extrage, eventual, i delimitatorul.


Funcia put are prototipul:
ostream& put (char c);

Scrie n streamul asociat caracterul dat ca argument.


Funcia
int peek();

ne furnizeaz urmtorul caracter din streamul de intrare fr s-l extrag din


stream.
Funcia
istream& putback(char c)

reinsereaz un caracter n stream.


Pentru a citi/scrie blocuri de date binare, se utilizeaz funciile read/write,
care au urmtoarele prototipuri:
istream& read(unsigned char * p, int n);
ostream& write(const unsigned char *p, int n);

Funcia read citete n octei din streamul asociat i i plaseaz n zona de


adres p. Dac se detecteaz sfritul fiierului nainte de citirea tuturor octeilor,
funcia read oprete citirea.
Pentru a afla numrul caracterelor citite utilizm funcia:
int gcount ();

Ea napoiaz numrul de caractere citite la ultima operaie de intrare.

Accesul de tip aleator la fiiere binare


Sistemul de intrare/ieire din C++ utilizeaz doi pointeri pentru accesul la
fiiere. Primul pointer numit "get pointer" indic poziia din fiier de unde se va
efectua citirea, iar al doilea numit "put pointer" indic poziia de la care se va face
urmtoarea scriere. Ori de cte ori se va efectua o operaie de intrare/ieire
pointerul corespunztor va fi avansat (n mod automat) secvenial.
Accesul aleator la fiiere se poate efectua prin utilizarea funciilor seekg()
i seekp().
Funcia
ostream& seekg(long n);

111

poziioneaz "get pointerul" pe octetul n n fiier (numerotarea se face de la


0).
Funcia
ostream& seekg(long n, seek_dir origine);

deplaseaz "get pointerul" asociat fiierului respectiv cu n octei fa de


origine.
seek_dir este un tip enumerare cu valorile ios::beg=0, ios::cur=1,
ios::end=2 semnificnd nceputul, poziia curent, respectiv sfritul streamului.
Funciile
ostream& seekp(long n);
ostream& seekp(long n, seek_dir origine);

sunt similare cu seekg dar se aplic pointerului "put pointer".

I.25.1. Aplicaii
1) Urmtorul program conine funcii pentru crearea i exploatarea unui
fiier text.
#include<fstream.h>
#include<iomanip.h>
struct punct { float x,y;};
void creareFisier()
{ ofstream f("punct.dat");
punct P; int i=1;
cout<<"P"<<i<<"(x y):";
while(cin>>P.x>>P.y) /* citire pn la introducerea unui caracter invalid
pentru tipul numeric */
{ f<<P.x<<" "<<P.y<<endl; // scriere n fiier
i++;
cout<<"P"<<i<<"(x y):";
}
cin.clear(); // Anularea indicatorului de eroare
cin.ignore(80,'\n');
f.close();
}
void citireFisier(punct P[],int &n)
{ ifstream f("punct.dat");
for(n=0; ;n++)
{ f>>P[n].x>>P[n].y;
if(f.eof())break;
}
f.close();
}
void afisareVector(float P[],int n)
{for(int i=0; i<n; i++)
cout<<P<<i<<(<<P[i].x<<","<<P[I].y<<) ;
cout<<endl;

112

}
void main()
{ punct P[100];int n;
creareFisier();
citireFisier(P,n);
afisareVector(P,n);
}

2) Urmtorul program conine funcii pentru crearea i exploatarea unui


fiier binar.
#include<fstream.h>
#include <iomanip.h>
#include<conio.h>
struct inregistrare
{char den[20]; // denumire produs
int zz,ll;
// zi, luna aprovizionare
float cant,pret; // cantitate, pre
};
void cit(inregistrare& Art) // citirea unui articol
{cout<<"denumire:"; cin.get(); //extragerea caracterului<enter>
cin.get(Art.den,20);
cout<<"data(zz ll) :"; cin>>Art.zz>>Art.ll;
cout<<"cantitate
:"; cin>>Art.cant;
cout<<"pret
:"; cin>>Art.pret;
}
void afis(inregistrare Art)
{cout<<setprecision(2)<<setiosflags(ios::left);
cout<<setw(20)<<Art.den
<<setiosflags(ios::right)<<setw(4)<<Art.zz
<<"/"<<setw(2)<<Art.ll
<<setw(10)<<Art.cant
<<setw(10)<<Art.pret;
}
void actFis(char* denFis)
{ char ok;
ofstream f(denFis,ios::app|ios::binary);
inregistrare art;
while(1)
{ cit(art);
f.write( (unsigned char*)&art,sizeof(art));
cout<<"continuati?(R:D/N):"; cin>>ok;
if(ok=='n'||ok=='N') break;
}
f.close();
}
void creFis(char* denFis) // creaz un fiier vid

113

{ofstream f(denFis,ios::out|ios::binary);
f.close();
actFis(denFis);
}
void list(char *denFis) //Listare fiier
{ ifstream f(denFis,ios::in|ios::binary);
inregistrare art;
while (1)
{ f.read( (unsigned char*)&art,sizeof(art));
if(f.eof())break;
afis(art); cout<<endl;
}
f.close();
}
void sit(char *denFis)
{ ifstream f(denFis,ios::in|ios::binary);
inregistrare art;
clrscr();
float v=0,tvl=0,tvg=0;
f.read( (unsigned char*)&art,sizeof(art));
if(f.eof()){cout<<" fisier vid "; return;}
int luna=art.ll;
cout<<" SITUATIA APROVIZIONARII "<<endl;
cout<<setprecision(2)<<setiosflags(ios::fixed);
while (! f.eof())
{ if (luna!=art.ll )
{ cout<<"Total luna "
<<setw(2)<<luna<<setw(44)<<tvl<<endl;
tvg+=tvl;
tvl=0;
luna=art.ll;
}
v=art.cant * art.pret;
afis(art);
cout<<setw(10)<<v<<endl;
tvl+=v;
f.read( (unsigned char*)&art,sizeof(art));
}
cout<<"Total luna "<<setw(2)<<luna
<<setw(44)<<tvl<<endl;
tvg+=tvl;
cout<<"Total general"<<setw(44)<<tvg<<endl;
f.close();
}
void main()
{int op;
do
{ cout<<" 1- creare"<<endl;
cout<<" 2- listare"<<endl;

114

cout<<" 3- sit"<<endl;
cout<<" 4- act"<<endl;
cout<<" 9- stop"<<endl;
cout<<"tastati optiunea:"; cin>>op;
switch (op)
{ case 1: creFis("fisier.dat");
break;
case 2: list("fisier.dat");
break;
case 3: sit("fisier.dat");
break;
case 4: actFis("fisier.dat");
break;
}
}
while (op!=9);
}

115

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