Sunteți pe pagina 1din 29

www.cartiaz.

ro – Carti si articole online gratuite de la A la Z

C++ (Laboratoare)

1. Prezentarea notiunii de limbaj de programare


Am vazut in sectiunea precedenta cum pot fi reprezentati algoritmii prin utilizarea pseudocodului sau a schemelor
logice, insa prelucrarea automata a datelor presupune scrierea algoritmului intr-o forma ce poate fi inteleasa de
calculatorul electronic. Algoritmii vor fi scrisi intr-un “limbaj de programare”, care va contine operatii
asemanatoare celor despre care am amintit, numite acum instructiuni.
Limbajul de programare contine:
• ALFABETUL: o multime de simboluri pentru scrierea cuvintelor din limbaj
• VOCABULARUL (LEXICUL): multime de cuvinte acceptate ca facand parte din limbaj
Se numeste UNITATE LEXICALA cea mai mica "imbinare" de caractere din vacabular, care are un inteles. Exista
un set de reguli privind combinarea unitatilor lexicale in cuvinte si a cuvintelor in "fraze" (reguli de SINTAXA),
respectarea regulilor ducand la obtinerea unor constructii corecte. SEMANTICA unui limbaj se refera la intelesul
structurilor obtinute prin combinarea cuvintelor acceptate de limbaj.
In vocabular avem:
• cuvinte cheie= cuvinte sau prescurtari ale unor cuvinte din limba engleza, ce reprezinta
comenzi (instructiuni)
• identificatori= nume folosite pentru variabile, tipuri de date si functii definite de
utilizator. Un identificator este format dintr-un sir de caractere care incepe cu o litera si poate
contine litere, cifre si caracterul "_" (underscore). Identificatorul nu poate contine spatii sau
apostrof, virgula, ghilimele ... Identificatorii nu pot coincide cu cuvintele cheie.
Prin PROGRAM se intelege o succesiune de comenzi(instructiuni) de prelucrare a datelor, scrise intr-un limbaj de
programare. Programul este memorat intr-o entitate numita fisier sursa (este un fisier text).
Prelucrarile dintr-un program C++ sunt grupate in FUNCTII. Rezolvarea unei probleme se face prin utilizarea unor
functii definite in limbaj si/sau a unor functii scrise de programator, atunci cand functiile deja existente nu sunt
suficiente. Functiile pe care limbajul le pune la dispozitia utilizatorului sunt grupate, dupa tipul de prelucrare oferit,
in mai multe fisiere numite "biblioteci" (fisiere HEADER). Pentru a putea utiliza o functie trebuie sa se specifice la
inceputul programului numele bibliotecii care contine functia respectiva.
Orice program C++ trebuie sa contina o functie numita "main" (un fel de “program principal”), instructiunile
continute de aceasta fiind cele prelucrate atunci cand programul este lansat in executie.
Pentru a se putea obtine rezultatele prelucrarii datelor cu ajutorul programelor, trebuiesc parcurse urmatoarele faze:
• scrierea programului (editarea textului sursa);
• compilarea programului (= verificarea corectitudinii sintactice si semantice a textului
sursa si prelucrarea sa ⇒ fisier obiect)
• editarea legaturilor (fisierul/fisierele obiect obtinute in urma compilarii sunt transformate
intr-un fisier executabil, adica intr-un fisier care poate fi lansat in executie prin simpla scriere a
numelui sau la prompt-ul sistemului de operare;
Numim mediu de programare un program care permite asistarea programatorului in toate fazele de elaborare a unui
program, scris intr-un limbaj de programare (editare, depanare, compilare, executie). Mediul de programare Borland
C++ poate fi lansat in executie prin tastarea comanzii bc la prompt-ul MSDOS.
In paragraful urmator vor fi prezentate elementele de baza ale limbajului C.
2. Prezentarea generala a limbajului C++
2.1 Alfabetul
Alfabetul limbajului este format din acele simboluri utilizate la reprezentarea entitatilor unui program, adica a
unitatilor lexicale. Reamintim ca, prin unitati lexicale intelegem cele mai mici entitati cu valoare semantica (i.e au o
semnificatie), prin combinarea carora rezulta constructiile sintactice ("propozitii si fraze").
Alfabetul limbajului C se compune din urmatoarele categorii de simboluri:
• Literele mari si mici ale alfabetului englez si caracterul de subliniere "_" (underscore)
• Cifrelele arabe: 0-9
• Semne de punctuatie: ; , ‘ "
• Alte caractere:
+, -, *, /
(, ), {, }, [, ], \,
~, ^, <, >, =, ?, !, #, &,
Literele si cifrele, precum si caracterul underscore, de multe ori asimilat in multimea literelor, sunt utilizate pentru
construirea identificatorilor si cuvintelor cheie, dupa reguli ce vor fi descrise in paragrafele corespunzatoare. In
www.cartiaz.ro – Carti si articole online gratuite de la A la Z

limbajul C se face diferenta dintre literele mici si majusculele corespunzatoare, deci identificatorul "a" va fi diferit
de identificatorul "A".
2.2 Identificatori
Identificatorul reprezinta nume pe care le atribuim variabilelor, constantelor, functiilor, tipurilor de date definite de
utilizator. Un identificator este o secventa de litere, cifre si caracterul underscore, primul caracter trebuind sa fie
litera sau
underscore. Folositi cu multa precautie identificatori care incep cu underscore, pentru a nu intra in conflict cu
numele rutinelor sistem, a caror ortografiere nu se cunoaste (numele rutinelor sistem incep intotdeauna cu "_").
Regulile de formare a identificatorilor sunt aceleasi cu regulile din Pascal. Un identificator poate avea, teoretic, o
lungime arbitrara, dar numai primele 31 de caractere sunt luate in considerare de compilator.
Identificatorii urmatori:
nume, Nume, NuME, NUMe
sunt diferiti, deoarece literele mici sunt considerate diferite de literele mari corespunzatoare.
2.3 Cuvinte rezervate (keywords)
Numele rezervate instructiunilor, tipurilor predefinite si sintaxei de definire a functiilor si tipurilor de date se numesc
cuvinte cheie. Lista cuvintelor cheie ale limbajului C este:
auto break case char
const continue default do
double else enum extern
float for goto if
int long register return
short signed sizeof static
struct switch typedef union
unsigned void volatile while
Identificatorii definiti de utilizator nu trebuie sa coincida cu cuvintele rezervate. In limbajul C++ se mai adauga
cateva cuvinte cheie, care vor fi descrise la momentul oportun (in capitolul rezervat programarii orientate obiect).
2.4 Comentarii
Comentariile sunt acele siruri de caractere utilizate la explicarea programelor sursa, delimitate prin caractere
speciale care determina ignorarea lor de catre compilator.
Un comentariu are urmatoarea forma:
/* sir de caractere */
sau
// sir de caractere
unde prin sir de caractere se intelege o secventa de caractere din setul caracterelor reprezentabile, mai putin
combinatia */. Nu se admit comentariile imbricate. Comentariul poate fi scris pe mai multe linii daca este scris in
prima forma. A doua forma este
specifica Borland C si permite scrierea unor comentarii ce nu depasesc o linie.
2.5 Tipuri de date
Definitia notiunii de tip de data cuprinde, pe langa multimea de valori a tipului, si alte aspecte:
• dimensiunea memoriei alocate
• multimea operatiilor ce actioneaza asupra elementelor tipului
• timpul de viata asociat datei, dat de clasa de memorie
Tipurile de date sunt:
• tipuri de baza: tipuri predefinite in limbaj;
• caracter (char)
• intreg (int)
• real (float, double)
• tipuri derivate: tipuri definite de utilizator;
• enumerare
• referinta
• structurate:
• tablou
• structura
• uniune
Spre deosebire de Pascal, in C nu este definit tipul logic, considerandu-se ca o expresie este adevarata daca are o
valoare nenula si falsa altfel. Tipul char difera de tipul caracter din Pascal, in C caracterele fiind de fapt intregi, care
desemneaza codul ASCII corespunzator. Se defineste si tipul void, care desemneaza fie "orice tip", fie indica lipsa
oricarui parametru intr-o functie.
www.cartiaz.ro – Carti si articole online gratuite de la A la Z

3. Citirea si afisarea datelor. Primele programe in C++


Pentru introducerea datelor prin intermediul tastaturii avem nevoie de functia CIN, iar pentru afisarea valorilor sau
mesajelor de functia COUT.
Exemplul 1: Cel mai simplu program este programul care nu realizeaza nici o prelucrare:
void main( )
{
}
Exemplul 2: Sa se afiseze pe ecran un mesaj.
#include <iostream.h>
void main()
{
cout<< "Acesta este primul program in C !";
}
Observatii:
1. Linia #include <iostream.h> declara ca se va utiliza biblioteca de functii cu numele "iostream.h", din care
face parte functia de afisare cout.
2. Functia main() este functia principala a unui program C, prelucrarile continute de aceasta fiind primele
efectuate la executarea unui program.
3. Prelucrarile ce apar intr-o functie trebuiesc scrise intre { si }
4. Dupa scrierea unei comenzi (functie/instructiune) se pune ;
Exemplul 3: Reluam exempul precedent:
#include <iostream.h>
void main()
{
cout<< "Acesta este primul program in C ";
cout<<"\n scris in prima ora de laborator ";
}
Observatii:
• Caracterul "\n" are ca efect afisarea a ceea ce urmeaza pe linia urmatoare a ecranului.
• Mesajul trebuie precedat de <<
Exemplul 4: Sa se scrie un program pentru insumarea a doua numere.
#include <iostream.h>
void main()
{
int a; //variabila care va memora primul numar
int b; //variabila care va memora al doilea numar
int s; //variabila care va memora suma celor doua numere
cout <<"Introduceti primul numar:";
cin >> a;
cout <<"Introduceti al doilea numar:";
cin >>b;
s=a+b;
cout<<"Suma "<<a<<"+"<<b<<"="<<c<<"\n";
}
Observatii:
1. Se folosesc trei variabile pentru a memora numerele si suma acestora. Prin "int a" se declara folosirea unei
variabile de tip intreg, avand numele "a".
2. . "cin >> a" determina citirea unei valori de la tastatura, valoare ce va fi memorata in zona de memorie a
variabilei "a". Cel care introduce date trebuie sa tasteze o valoare intreaga, altfel semnalandu-se eroare.
3. Daca se afiseaza un mesaj, continutul acestuia trebuie pus intre ghilimele. Daca se doreste afisarea valorii
unei variabile atunci se scrie, dupa <<, numele acesteia.
4. Executand programul de mai sus veti observa modul de afisare al rezultatului.
5. In textul programului au fost introduse mici comentarii, precedate de //, pentru a facilita intelegerea textului
sursa.
Exemplul 5: Scrieti un program care sa afiseze urmatorul meniu:
Bauturi
Bere …………..12500
Vin ……………34764
Suc………………5000
www.cartiaz.ro – Carti si articole online gratuite de la A la Z

Cafea
Ness…………….10000
Expresso…………6000
#include <iostream.h>
void main( )
{
cout <<”Bauturi:”;
cout <<”\t Bere………………12500”;
cout <<”\t Vin………………..34764”;
cout <<”\t Suc…………………5000”;
cout <<”Cafea:”;
cout <<”\t Ness……………….10000”;
cout <<”\t Expresso……………6000”;
}
Observatii: S-a folosit caracterul \t pentru a se “incepe” un nou paragraf. Caracterele “\t” si “\n” fac parte dintre
caracterele numite caractere escape, deoarece sunt caractere neafisabile pe ecran decat prin utilizarea unor simboluri
(secvente de evitare).

Functia fscanf
Este utilizata pentru citirea datelor dintr-un fisier sau de la tastatura (dispozitivul standard de intrare) si are
urmatoarea sintaxa:
fscanf(tipul_valorii_citite, variabila);
Modul de functionare este urmatorul: se citeste de la tastatura, in variabila data, o valoare de tipul specificat.
Tipul valorii citite se specifica prin
%caracter,
unde caracter poate fi:
• c - daca se citeste un caracter
• d sau i - int
• x - intreg in baza 16
• o -intreg in baza 8
• u - intreg fara semn
• hd, hi, hx, ho, hu, hx - short int
• ld, li, l0, lu, lx - long int
• s -sir de caractere
• f , e, g, E, G- float
• le, lg, lf- double
• Le, Lg, Lf - long double
Inaintea variabilei care stocheaza valoarea citita se va scrie intotdeauna & (operatorul adresa), ca in exemplul
urmator:
fscanf ("%f", &a);
Se citeste o valoare de tip float, valoarea fiind stocata in variabila a.
Observatie: Nu se va folosi operatorul & pentru citire atunci cand variabila este un pointer (care este el insusi o
adresa, dar asta mai tarziu...)
Daca dorim sa citim mai multe valori cu aceeasi functie fscanf, vom specifica pentru fiecare variabila tipul valorii:

int a;
char ch;
float f;

fscanf("%i%c%f",&a, &ch, &:f);


Observatii:
• Sirul de caractere care defineste tipul valorii citite se numeste descriptor de format.
• Numarul descriptorilor de format trebuie sa fie acelasi cu numarul variabilelor din lista
• Ordinea de scriere a descriptorilor este imprtanta
• Nu introduceti alte caractere intre descriptori decat cele permise
www.cartiaz.ro – Carti si articole online gratuite de la A la Z

Functia fprintf
Functia fprintf este utilizata pentru scrierea datelor la dispozitivul standard de iesire. Sintaxa este:
fprintf ( tipul_valorii_scrise, variabila) ;
Semnificatia parametrilor este aceeasi ca si pentru fscanf. Functia are ca efect scrierea pe ecran a unei valori de tipul
specificat, valoare stocata in variabila. Nu se mai foloseste operatorul &.
Exemplu: Calculati suma a doua numere.

int a, b, suma;

printf("Primul numar =");


scanf("%i",&a);
printf("Al doilea numar = ");
scanf("%i",&b);
suma = a+b;
printf("Suma dintre %i si %i este %i", a, b, suma);

cpp.htmcpp.htmcpp2.htmcpp2.htm
1. Tipuri de date predefinite
Tipurile de baza definite in limbajul C sunt: intreg, real si caracter. Exista insa mai multe tipuri intregi si reale, in
functie de numarul de biti pe care se pot memora valorile si daca valorile sunt cu sau fara semn. In plus, unele dintre
aceste tipuri difera de la o implementare la alta a limbajului (in functie de calculatorul pe care se lucreaza). In tabelul
urmator sunt prezentate tipurile fundamentale, memoria necesara stocarii valorilor de acel tip si limita valorilor ce
pot fi memorate intr-o variabila de acel tip.
Tipul Dimensiune memorie Limita valorilor
char 1 byte -128..127
int depinde de implementare -32768..32767
(uzual 2 bytes)
short int 2 bytes -32768..32767
unsigned char 1 byte 0..255
unsigned int depinde de implementare
long int 4 bytes -2147483648..2147483647
unsigned long int 4 bytes 0..4294967295
float 4 bytes
double 8 bytes
long double 10 bytes
Primul tip este tipul caracter. O variabila de acest tip va avea ca valoare codul ASCII asociat caracterului respectiv.
De exemplu, daca unei variabile i se atribuie caracterul ’a’, variabila va contine valoarea 97 (numarul de ordine al
caracterului ‘a’ incodul ASCII).
Tipul intreg cel mai des utilizat in programe este int, dar numarul de bytes pe care se memoreaza valorile de acest
tip difera de la o implementare la alta a limbajului C (in functie de tipul calculatorului). Astfel, tipul int este
echivalent cu short int sau long int, in functie de implementare.
Celelalte tipuri intregi sunt obtinute prin folosirea prefixului signed sau unsigned, indicand daca valorile respective
sunt cu semn (contin si valori negative), respectiv fara semn ( valori naturale).
Ultimele trei tipuri din tabel sunt tipuri reale, diferenta dintre ele constand in cantitatea de memorie utilizata,
intervalul de valori si precizia memorarii valorilor (numarul de zecimale retinute). Valorile reale se reprezinta
conform notatiei din standardul IEEE (folosind semnul, mantisa si exponentul). De exemplu, pentru tipul float se
utilizeaza reprezentarea in simpla precizie, folosind un bit de semn, 7 biti pentru exponent si 24 de biti pentru
mantisa. Aceasta reprezentare are un exponent in limita a 10-37 si 1038 cu pina la 7 zecimale precizie. Valoarea
maxima a unui float este de 1.701411 E38.
Din tabel se observa ca nu exista un tip logic, asa cum este el definit in alte limbaje de programare. In limbajul
Pascal, tipul logic e definit ca multimea cu valorile {false, true} impreuna cu operatorii logici cunoscuti (si, sau ,
negatia logica). In limbajul C nu s-a definit acest tip dar se foloseste urmatoarea conventie: o expresie este
considerata adevarata daca valoarea obtinuta la evaluarea ei este nenula si falsa in caz contrar. Variabilele care se
vor folosi ca variabile logice vor fi declarate de tip intreg
O alta caracteristica aparte o constituie introducerea tipului void, pentru a desemna “nimic” sau “orice tip”, in
functie de contextul in care este utilizat. In exemplele de pina acum tipul void a fost folosit pentru a indica faptul ca
functia main nu intoarce nici o valoare.
Pentru a putea utiliza o variabila intr-un program C, este obligatorie declararea acesteia, astfel:
[clasa_de_memorie] TIP_DE_DATE lista_variabile;
unde:
• clasa_de_memorie specifica locul unde se va aloca memorie pentru variabila si durata sa de viata,
notiuni la care vom reveni mai tarziu). Specificarea clasei de memorie este optionala;
• TIP_DE_DATE este orice tip predefinit sau derivat;
• lista_variabile contine lista variabilelor de acel tip, despartite prin virgula;
Exemple:
int a,b,c;
char ch;
float x,y;
long int z;
int g=7;
OBS: La declararea variabilei intregi g s-a realizat si initializarea acesteia (=stabilirea unei valori initiale).
Variabilele care sunt declarate in interiorul corpului unei functii se numesc variabile locale, iar cele declarate in
afara oricarei functii din program se numesc variabile globale. Variabilele globale vor putea fi utilizate in toate
functiile ce compun programul, iar variabilele locale doar in cadrul functiei in care au fost definite.
2. Operatori
Operatorii constituie unul din conceptele cele mai importante si mai interesante care stau la baza unui limbaj de
programare. Limbajul C este vestit pentru marea varietate de operatori pe care-I pune la dispozitia programatorului
rezultand si o diversitate de expresii ce se pot forma pe baza acestora. Dupa cum se stie, o expresie este formata din
variabile, constante, functii si operatori. In acest paragraf voi aminti cateva din categoriile de operatori ai limbajului
C:
• Operatorii aritmetici:
+ adunare, - scadere, * produs, / impartire, % - restul impartirii intregi
++, -- incrementare si decrementare
• Operatori relationali:
<,>
= = egal
<= mai mic sau egal
>= mai mare sau egal
!= diferit
• Operatori logici:
&& - si logic
|| -sau logic
! - negatie logica
Operatorii logici si relationali sunt implicati in formarea expresiilor cu valoare logica. Spre exemplu:
a<2, 7/5+2<s-1, (X>-3) &&(x<3), !(a==b)
sunt expresii cu valoare logica.
• Operatori de atribuire.
In sectiunea precedenta am amintit, vorbind despre reprezentarea algoritmilor prin scheme logice, de operatia de
atribuire. In limbajul C se considera ca atribuirea este un operator. Atribuirea are urmatoarea sintaxa:
variabila = expresie;
Modul de functionare este urmatorul:
1. se evalueaza expresia;
2. valoarea obtinuta este stocata in zona de memorie a variabilei, realizindu-se eventuale conversii de
tip.
3. valoarea rezultata in urma atribuirii este valoarea atribuita variabilei.
OBS: Atribuirea fiind un operator, se considera ca operanzii sunt variabila din partea stanga, respectiv expresia din
partea dreapta. Orice expresie trebuie sa aiba, in urma evaluarii sale, o valoare (un rezultat). Valoarea expresiei de
atribuire este valoarea obtinuta prin evaluarea expresiei din partea dreapta a atribuirii.
Daca valoarea obtinuta prin evaluarea expresiei din dreapta atribuirii este de alt tip decat tipul variabilei din stanga
atunci se incearca conversia tipului valorii la tipul variabilei. Nu intotdeauna conversia este posibila, caz in care se
va afisa un mesaj de eroare in urma compilarii.
Exemplul 1 : Fie urmatoarea secventa de program:
void main(void)
{
int a;
float c;
a=3./2.+9./4.;
cout<<”a=”<<a<<”\n”;
c=3./2.+9./4.;
cout<<”c=”<<c<<”\n”
/* aceeasi expresie are valori diferite, in functie de tipul variabilei
din stanga atribuirii */
}
Obs: Executand programul de mai sus se vor obtine valori diferite pentru variabilele a si c, desi expresia care apare
in dreapta ambelor atribuiri este aceeasi. Pentru a se obtine valoarea 3, iar pentru c se obtine 3,75. Explicatia sta in
modul in care se realizeaza conversiile de tip in cadrul atribuirilor. Valoarea expresiei 3./2.+9./4. este 3,75 dar
variabilei a i se va atribui partea intreaga a acestei valori, adica 3. Variabila c este de tip float (numar real), deci nu
va mai fi nevoie de conversia rezultatului evaluarii expresiei la tipul variabilei.
Exemplul 2:
void main(void)
{
float a;
a=5/2;
cout<<a;
}
OBS: Executand acest program se va afisa valoarea 2 si nu valoarea 2,5 asa cum ar fi fost de asteptat. Explicatia
este urmatoarea: operatorul / realizeaza, atunci cand operenzii sunt intregi, impartirea intreaga, deci vom obtine catul
impartirii intregi dintre 5 si 2. Exista doua modalitati de rezolvare a problemei: fie inlocuim expresia cu 5./2.
(5.=5.0) fie utilizam operatorul de conversie explicita ( ). Acest nou operator ( numit cast), se utilizeaza astfel:
( tip_de_date) expresie;
Semnificatia este urmatoarea: Se cere convertirea valorii rezultate din evaluarea expresiei la o valoare de tipul
specificat intre paranteze. In exemplul de mai sus vom inlocui atribuirea cu:
a=(float) 5/2;
(rezultatul expresiei va fi de tip float, deci variabilei a i se va atribui valoarea 2.5).
Exercitiu: Fie urmatorul program, care calculeaza media aritmetica a trei numere a,b,c , primele doua introduse de
la tastatura.:
void main(void)
{
int a,b,c;
float s;
cin>>a;
cin>>b;
c=a/2+b/3;
s=(a+b+c)/3;
cout<<”Media aritmetica este=”<<s;
}
Executati acest program si identificati greselile. Corectati greselile gasite.
• operatori de atribuire compusa: +=, -=, *=, /=, %=
Operatorii de atribuire compusa au fost introdusi pentru a fi utilizati in locul atribuirilor de tipul:
v=v+expresie;
v=v-expresie;
v=v*expresie; e.t.c
unde: v-variabila
expresie-orice expresie corecta in limbajul C
In locul acestor expresii se vor folosi:
v+=expresie;
v-=expresie; e.t.c
Folosirea operatorilor de atribuire compusa sporeste lizibilitatea programului si viteza de executie .
Daca atribuirea este de forma:
v=v+1;
sau
v=v-1;
se pot utiliza operatorii de incrementare si decrementare ++ si --. Expresiile de mai sus se vor putea scrie:
v++;
respectiv
v--;
Exemplul 3: Se da urmatorul program:
void main(void)
{
int a,b,i=3;
a=++i; //preincrementare a lui i
cout<<a;
b=a--; //postdecrementare
cout<<”a=”<<a<<”\n”;
cout<<”b=”<<b<<”\n”;
a+=++b; //atribuire compusa
cout<<”a=”<<a<<”\n”;
cout<<”b=”<<b<<”\n”;
}
Obs: Cand apar expresii de tipul :
++variabila
sau
--variabila;
spunem ca se realizeaza o preincrementare, respectiv predecrementare. In cazul preincrementarii, variabila va primi
ca valoare 1+valoarea initiala. Daca preincrementarea apare intr-o expresie se realizeaza intai aceasta operatie si
abia apoi celelalte operatii care mai apar in expresie (preincrementarea are prioritate mai mare). In atribuirea a=++I
se realizeaza intai preincrementarea, in urma careia i va avea valoarea 4, si abia apoi se realizeaza atribuirea (a va
avea valoarea 4).
In expresia b=a—se realizeaza o postdecrementare, adica se modifica valoarea variabilei a doar dupa ce s-au
efectuat celelalte operatii din expresie. In cazul nostru, b va promi valoarea lui a (4, in momentul acela) si abia apoi
se va micsora valoarea lui a cu o unitate.
Exercitiu: Executati programul de mai sus si urmariti rezultatele care se obtin.
Mai exista operatori de atribuire compusa, folosindu-se operatorii logici ce actioneaza la nivel de bit, dar despre
acestia vom vorbi intr-o sectiune viitoare. Tot atunci vom discuta si despre atribuirea multipla.
3. Instructiunea alternativa (IF)
Pana acum am folosit ca exemple programe simple, care contineau doar functiile de intrare/iesire si operatorul de
atribuire. Atunci cand elaboram programe ceva mai complexe este necesar ca, intr-un anumit punct al programului,
sa decidem continuarea acestuia in functie de o conditie. In primul laborator am dat ca exemplu de algoritm
rezolvarea ecuatiei de gradul 1 (pseudocod si schema logica). Intr-o schema logica ni se permitea utilizarea unui
bloc de decizie de urmatorul tip:

cu semnificatia: daca este adevarata conditia se executa prelucrarea B, altfel se executa prelucrarea A.
In limbajul C este utilizata instructiunea IF, cu urmatoarea sintaxa:
if (expresie) instructiune1;
[else instructiune2;}
unde:
expresie -orice expresie valida in limbajul C
instructiune1, instructiune2 - orice instructiune corecta din limbajul C ;
Mod de functionare:
• se evalueaza expresia
• daca expresia este nenula (conventia pentru adevarat) se executa instructiune1
• daca expresia este nula (falsa) se executa instructiune2
• se trece la urmatoarea instructiune a programului
Alternativa else instructiune2 poate sa lipseasca.
Exemplul 4: Sa se scrie un program pentru calcularea maximului a doua numere.
#include <iostream.h>
void main(void)
{
int a,b;
int max;
cout<<”a=”;
cin>>a;
cout<<”\nb=”;
cin>>b;
if (a<=b) max=b;
else max=a;
cout<<”Maximul celor doua numere este=”<<max<<”\n”;
}
Exemplul 5: Scrieti un program care calculeaza maximul a 3 numere.
#include <iostream.h>
void main (void)
{
int a,b,c;
int max;
cout<<”a=”;
cin>>a;
cout<<”\nb=”;
cin>>b;
cout<<”\nc=”;
cin>>c;
if (a<=b)
if (c<=b) max=b;
else max=c;
else if (c<=a) max=a;
else max=c;
cout<<”\nMaximul este=”<<max;
}
Obs. Dupa cum se vede din exemplu, instructiune1 si instructiune2 pot fi deasemenea instructiuni if. Spunem ca
sunt instructiuni if imbricate.
A se observa si modul cum a fost scris programul, astfel incat sa se vada clar carei instructiuni if ii apartine fiecare
else.
Exemplul 6: Se dau trei numere intregi a,b,c. Sa se testeze daca numerele date pot fi lungimile laturilor unui
triunghi.
#include <iostream.h>
void main (void)
{
int a,b,c;
cout<<”a=”;
cin>>a;
cout<<”\nb=”;
cin>>b;
cout<<”\nc=”;
cin>>c;
if (a<b+c) if (b<a+c) if c<a+b) cout<<”Numerele pot fi lungimile laturilor unui triunghi !”;
else cout<<”Numerele nu pot fi lungimile laturilor unui triunghi !”;
else cout<<”Numerele nu pot fi lungimile laturilor unui triunghi !”;
else cout<<”Numerele nu pot fi lungimile laturilor unui triunghi !”;
}
Obs: Nu am mai verificat daca a, b , c sunt pozitive.
Exemplul 7. Reluam exemplul precedent cu intentia de a folosi mai putine instructiuni if.
#include <iostream.h>
void main (void)
{
int a,b,c;
cout<<”a=”;
cin>>a;
cout<<”\nb=”;
cin>>b;
cout<<”\nc=”;
cin>>c;
if ((a<b+c) && (b<a+c) && (c<a+b)) cout<<”Numerele pot fi lungimile laturilor unui triunghi !”;
else cout<<”Numerele nu pot fi lungimile laturilor unui triunghi !”;
}
Obs: Am folosit o singura instructiune if, cele trei conditii anterioare fiind conectate prin operatorul SI logic. Dupa
cum se stie, daca avem propozitiile p,q,r, atunci propozitia p&&q&&r va fi adevarata daca toate propozitiile
componente sunt adevarate si falsa daca una dintre propozitiile componente este falsa.
Este indicata aceasta scriere pentru ca sporeste lizibilitatea programului.
Exemplul 8: Rezolvarea ecuatiei de gradul I.
#include <iostream.h>
void main(void)
{
int a,b;
float x;
cout<<”\na=”;
cin>>a;
cout<<”\nb=”;
cin>>b;
if (a!=0)
{
x=(float) -b/a;
cout<<”\nx=”<<x;
}
else
if (b==0) cout<<”\n x apartine lui R “;
else cout <<”\n Ecuatia nu are solutii”;
}
Obs: In cazul in care a este nenul avem de realizat doua operatii: atribuirea valorii -b/a variabilei x si afisarea valorii
radacinii. Atunci cand se realizeaza mai multe operatii acestea trebuiesc incluse intre { si }.

cpp1.htmcpp1.htmcpp3.htmcpp3.htm
1. Instructiuni iterative
Toate problemele prezentate pana acum au putut fi rezolvate folosind numai functii de citire/scriere, atribuiri si
instructiunea de decizie (IF). Cele mai multe dintre probleme vor necesita structuri de date mai complexe precum si
folosirea unor noi instructiuni, care sa permita repetarea de un numar oarecare de ori a unor parti din algoritm.
Sa luam ca exemplu algoritmul de calcul al sumei a 2 numere introduse de la tastatura. El consta in citirea valorilor
pentru cele doua numere si afisarea sumei acestora. Nu era nevoie decat de doua variabile, cate una pentru fiecare
numar. Acest exemplu este doar unul didactic, in practica neintalnindu-se prea des cazuri in care sa fie nevoie de a
suma doua numere. Generalizarea problemei pentru n numere va modifica substantial algoritmul nostru. Nu vom
putea folosi cate o variabila pentru fiecare numar introdus deoarece nu cunoastem exact cate numere avem (n este
introdus de utilizatorul programului, altfel algoritmul nu ar mai fi general). Chiar daca s-ar sti ca avem, sa zicem,
2500 de numere ar fi cam dificil sa utilizam 2500 de variabile distincte.
Problema noastra se poate rezolva simplu daca utilizam o instructiune iterativa (ciclica), care sa ne permita
repetarea de n ori a urmatoarei secvente de operatii:
• citim o valoare folosind variabila “a”;
• adunam valoarea citita la rezultatul partial, memorat in variabila “s”;
Instructiunile ce descriu aceste prelucrari ciclice sunt compuse din doua parti:
• corpul ciclului, format din prelucrarile ce se doresc a fi realizate de mai multe ori;
• conditia, pe baza careia se stabileste daca se vor mai executa prelucrarile din ciclu (este obligatorie
executarea prelucrarilor din corpul instructiunii de un numar finit de ori);
Corpul ciclului sau conditia trebuie sa contina acele operatii care, dupa efectuarea de un numar de ori a corpului
instructiunii, sa determine schimbarea valorii de adevar a conditiei, permitand incheierea executarii instructiunii
ciclice si trecerea la urmatoarele instructiuni ale algoritmului. In cazul in care este neglijat acest aspect, programul se
va executa la infinit.
Conditia terbuie sa fie o expresie cu valoare logica. Reamintesc faptul ca in limbajul C++ nu exista un tip de date
logic, dar se utilizeaza conventia ca orice valoare nenula sa fie considerata ca adevar iar valoarea zero ca valoarea
fals. In consecinta, orice expresie cu valoare de tip intreg va putea fi utilizata drept conditie intr-o instructiune
iterativa.
In finalul paragrafului o chestiune de terminologie: o executie a corpului instructiunii poarta numele se iteratie.
Instructiunile iterative pot fi clasificate, in functie de momentul evaluarii conditiei, astfel:
• cicluri cu test initial (While si For)-evaluarea conditiei se face inaintea fiecarei iteratii;
• cicluri cu test final (Do..While)- evaluarea conditiei se face la sfarsitul fiecarei iteratii;
2. Instructiunea While
Instructiunea While (“atat timp cat”) este o instructiune iterativa cu test initial si are urmatoarea sintaxa:
while ( <conditie>) instructiune;
unde:
<conditie> -orice expresie cu valoare intreaga;
instructiune- orice instructiune valida a limbajului;
Mod de functionare:
• daca expresia este adevarata se executa prelucrarile din ciclu;
• altfel, se trece la urmatoarea instructiune de dupa while;
Cu alte cuvinte, prelucrarile din ciclu se executa atat timp cat conditia este adevarata. Daca cexpresia este falsa de la
inceput corpul ciclului nu se va executa deloc.
Problema propusa in paragraful precedent se poate rezolva astfel:
Exemplul 1 Suma a n numere introduse de utilizator
#include <iostream.h>
void main()
{
float a;
int i,n;
float suma=0;
i=1;
cout<<"\nNumarul de elemente=";
cin>>n;
while(i<=n)
{
cout<<"Elementul "<<i<<"este: ";
cin>>a;
suma=suma+a; //se mai poate scrie suma+=a
i++;
}
cout<<"Suma este= "<<suma;
}
Exemplul 2: Suma primelor n numere naturale.
#include <iostream.h>
void main()
{
int n;
int i;
int suma=0;
cout<<"n=";
cin>>n;
i=1;
while(i<=n)
{
suma=suma+i;
i++;
}
cout<<"Suma este: "<<suma;
}
Observatie: Se poate utiliza o scriere mai compacta, care elimina si necesitatea utilizarii variabilei i:
while (n--) suma+=n;
Modul de executie este urmatorul:
• valoarea conditiei este valoarea variabilei n, valoare care scade cu o unitate dupa fiecare iteratie
(postdecrementare)
• conditia devine falsa atunci cand valoarea lui n devine zero;
3. Instructiunea do..while
Instructiunea do..while este o instructiune iterativa cu test final si are urmatoarea sintaxa:
do
instructiune;
while (<conditie>)
Mod de functionare:
• se executa corpul instructiunii;
• se evalueaza conditia: daca aceasta este adevarata se reia executia, altfel se trece la urmatoarea
instructiune din program;
Deosebirea esentiala fata de instructiunea while este aceea ca expresia se evalueaza dupa iteratie.
In cazul in care conditia este falsa de la inceput, corpul instructiunii se executa o singura data. Utilizarea
instructiunii do..while este mai putin frecventa (se foloseste pentru acele prelucrari care trebuiesc executate cel putin
o data).
Daca rescriem exemplul 1 utilizand do..while, obtinem:
………………………….
do
{
cin>>a;
suma+=a;
i++;
} while(i<=n);
4. Instructiunea for
Una dintre cele mai puternice instructiuni iterative ale limbajului C (si nu numai) este instructiunea for, care are
urmatoarea sintaxa:
for (expresie1; expresie2; expresie3) [instructiune];
unde:
expresie1, expresie2, expresie3 -expresii valide in C++;
instructiune - orice instructiune a limbajului C++;
Parantezele patrate semnifica faptul ca instructiunea este optionala;
Mod de executie:
• expresiile au urmatoarea semnificatie generala:
• expresie1 - expresie de initializare;
• expresie2 - conditia de continuare a executiei ciclului;
• expresie3 - expresie de actualizare;
• atat timp cat expresie2 este adevarata se executa corpul ciclului;
• de fiecare data se evalueaza expresia de actualizare, care are rolul esential de a determina ca, dupa
un numar de iteratii, expresie2 sa devina falsa;
• expresie1 se evalueaza o singura data;
Exemplul 3: Reluam exemplul 1 folosind instructiunea for:
#include <iostream.h>
void main()
{
int i,n;
float a, suma=0;
cin>>n;
for(i=1;i<=n;i++)
{
cin>>a;
suma+=a;
}
cout<<”suma =”<<suma;
}
Observatii:
Variabila i este utilizata pe post de “contor” al instructiunii for, numarand la a cata iteratie s-a ajuns.
Executia instructiunii for se incheie atunci cand numarul de iteratii devine egal cu n. Initializarea lui i cu 1 se
realizeaza o singura data, la inceput; i<=n este conditia de continuare a executiei; i++ se efectueaza dupa fiecare
executie a ciclului (postincrementare).
Aceasta forma a instructiunii for este cea mai utilizata. Un alt mod de a descrie executia acesteia este urmatorul:
pentru i de la 1 la n se executa corpul instructiunii.
Nu este obligatoriu ca valoarea lui i sa se mareasca de fiecare data cu o unitate.
Nu este obligatorie utilizarea tuturor celor trei expresii din for, dar este obligatorie scrierea separatorului “;” .
Exemplul de mai sus se poate rescrie astfel:
……………………………
for( ;n--; )
{
cin>>a;
suma+=a;
}
……………………………

cpp2.htmcpp2.htmcpp4.htmcpp4.htm
1. Notiunea de tablou
In laboratorul precedent explicam de ce nu putem sa utilizam 2500 de variabile distincte atunci cand dorim sa
insumam 2500 de numere. Rezolvarea propusa atunci se baza pe citirea repetata a cate unei valori, folosind o
variabila a, urmata de adaugarea acesteia la suma partiala. Dezavantajul metodei este acela ca nu se pot memora
toate valorile citite ci doar ultima (citind o valoare intr-o variabila, vechea valoare a acesteia se pierde). Cele mai
multe programe presupun prelucrari complexe asupra datelor de intrare, deci va fi nevoie sa memoram sirul nostru
de numere astfel incat sa poata fi utilizat si in alte prelucrari, nu numai pentru calcularea sumei.
Pentru a rezolva astfel de situatii s-a introdus in limbajele de programare notiunea de tablou. Tablourile ne permit
memorarea unui numar mare de valori utilizand o singura variabila.
Prin tablou se intelege un numar de elemente de acelasi tip, numit tip de baza, stocate intr-o zona compacta de
memorie.
Un tablou poate fi definit astfel:
tip_de_baza nume[dimensiune1][dimensiune2]…[dimensiune_n];
unde:
tip_de_baza = tipul elementelor tabloului;
n = numarul de dimensiuni al tabloului;
[dimensiune_i] = numarul de elemente pe dimensiunea I
tabloul are dimensiune1*…*dimensiune_n elemente
Notiunea de tablou multidimensional poate fi inteleasa mai bine dupa parcurgerea notiunilor referitoare la vectori si
matrice.
2. Tablouri unidimensionale
Declararea unui tablou unidimensional:
tip_de_baza nume[dimensiune];
unde dimensiune specifica numarul de elemente al vectorului.
De exemplu:
int a[30]; declara un vector ce contine 30 de elemente de tip int,
float b[50]; declara un vector cu 50 elemente reale;
“Numerotarea” elementelor se face de la 0 la dimensiune-1, adica cele 30 de elemente ale primului tablou sunt: a[0],
a[1], a[2], …, a[29].
Spunem ca tabloul este o variabila indexata, deoarece fiecare element al tabloului poate fi “gasit” / “utilizat”
cunoscand numarul sau de ordine. Vectorul este un sir de valori in care se cunoaste precis care este primul, al doilea,
….,ultimul element. “Numarul de ordine” al unui element se numeste indice.
Exemplul 1: Sa se calculeze minimul elementelor unui sir de n numere, utilizand vectori.
#include <iostream.h>
void main()
{
int n; //numarul de elemente
int a[50]; //se defineste o variabila de tip tablou cu maxim 50 de elemente, deci n va trebui
// sa fie mai mic decat 50
int min; //variabila ce va memora minimul
int i; //contor in instructiunea for
cout<<”n=”;
cin>>n;
/* se citesc elementele sirului */
for(i=0;i<n;i++)
{
cout<<”a[“<<i<<”]=”;
cin>>a[i];
}
// se calculeaza minimul
min=a[0]; //initializam minimul cu primul element din sir
for(i=1;i<n;i++)
if (a[i]<min) min=a[i];
//afisare minim
cout<<”Minimul este=”<<min;
}
Dupa cum se poate observa din programul de mai sus, fiecare element al sirului se poate utiliza ca si cum ar fi o
variabila de tip int independenta, deci valoarea unui element al vectorului poate fi modificata independent de
celelelate elemente. Sa presupunem ca utilizatorul introduce pentru n valoarea 4. Initial, elementele vectorului nu au
o valoare bine definita; putem reprezenta grafic vectorul astfel:

Sa presupunem ca utilizatorul introduce valorile 3, 7, 2, 9 pentru cele patru elemente ale vectorului. Reprezentarea
vectorului a va fi urmatoarea:

Valoarea oricarui element al vectorului poate fi modificata fie printr-o atribuire, fie prin introducerea unei valori
(folosind functia cin, de exemplu) de la tastatura. Daca vom introduce atribuirea
a[2]=23;
valoarea elementului al treilea din vectorul a nu va mai fi 2 (vechea valoare) ci 23. De asemenea, daca se scrie:
cin>>a[2];
valoarea elementului va fi cea introdusa de utilizator de la tastatura.
Exemplul 2: Se considera n numere intregi introduse de la tastatura. Sa se afle cate numere sunt pare si cate impare.
#include <iostream.h>
#include <conio.h>
void main()
{
int n; //numarul de elemente
int v[30]; //vector cu maxim 30 elemente intregi
int pare,impare; //variabile ce memoreaza nr. Elementelor pare, respectiv impare
int j; //variabila folosita in instructiunea for
clrscr();
//citim numarul de elemente
cout<<”n=”;
cin>>n;
/* se citesc elementele sirului */
for(i=0;i<n;i++)
{
cout<<”v[“<<i<<”]=”;
cin>>v[i];
}
//initializam variabilele
pare=0;
impare=0;
//luam fiecare element din v si testam daca acesta este sau nu par
for(j=0;j<n;j++)
if (v[j] % 2 = =0) pare++;
else impare++;
//afisam rezultatul
cout<<”Am gasit “<<pare<<” numere pare si “<<impare;
}
In programul de mai sus verificam, pentru fiecare element, daca acesta se imparte exact la doi, caz in care am mai
descoperit un element par. In caz contrar, numarul elementelor impare se mareste cu unu.
Am utilizat operatorul % , numit si modulo aritmetic, care are ca rezultat restul impartirii lui v[j] la 2.
Exemplul 3: Sa se introduca de la tastatura un cuvant si sa se afiseze.
#include <iostream.h>
#include <conio.h>
void main()
{
char cuvant[30];
clrscr();
cout<<”Introduceti cuvantul:”;
cin>>cuvant;
cout<<”Cuvantul introdus este:”<<cuvant;
}
Observati cu atentie cum am declarat variabila ce va memora cuvantul: folosim un vector cu elemente de tip
caracter. Acest mod de declarare ne permite sa lucram cu oricare dintre caracterele ce formeaza cuvantul. De
exemplu, daca utilizatorul introduce cuvantul salariu, vectorul nostru de caractere arata cam asa:

Daca dorim sa modificam putin cuvantul putem scrie:


cuvant[6]=’i’;
si vom obtine cuvantul salarii.
Exemplul 4: Sa se citeasca un cuvant si sa se gaseasca numarul de vocale pe care le contine.
#include <iostream.h>
#include <conio.h>
# include <string.h>
void main()
{
char c[30]; //vector pentru memorarea cuvantului
int vocale; //variabila ce va memora numarul vocalelor
int j;
clrscr();
cout<<”Introduceti cuvantul:”;
cin>>c;
vocale=0;
//cautam vocalele
for(j=0;j<strlen(c);j++)
if ( c[j]==’a’ || c[j]==’e’ || c[j]==’i’ || c[j]==’o’ || c[j]==’u’) vocale++;
cout<<”Am gasit “<<vocale<<” vocale.”;
}
Observatii:
• Am utilizat functia strlen, care are ca rezultat numarul de caractere al sirului dat ca parametru. Functia
poate fi utilizata doar daca a fost inclus fisierul header string.h, fisier ce contine functiile ce actioneaza
asupra sirurilor de caractere.
• “Mecanismul “algoritmului este urmatorul: se ia cate un caracter din sirul introdus si se verifica daca
elementul respectiv contine unul dintre caracterele a, e, i, o, u. De fiecare data cand conditia este adevarata
se incrementeaza numarul de vocale.
• Mai multe despre sirurile de caractere vom spune dupa capitolul dedicat pointerilor.
Exemplul 5 (Cautare secventiala) Se considera un sir de n elemente intregi si un numar intreg x. Sa se verifice daca
numarul x face parte din sirul considerat.
#include <iostream,h>
#include <conio.h>
void main()
{
int v[25];
int n;
int x;
int j;
int gasit; //variabila logica ce indica daca x apartine sau nu lui v
clrscr();
//citim numarul de elemente
cout<<”n=”;
cin>>n;
/* se citesc elementele sirului */
for(j=0;j<n;j++)
{
cout<<”v[“<<j<<”]=”;
cin>>v[j];
}
//se citeste elementul x
cout<<”x=”;
cin>>x;
gasit=0;
j=0;
//cautam x in sirul v
while( (j<n)&&(!gasit))
{
if (v[j]==x) gasit=1;
j++;
}
if(gasit) cout<<”Elementul apartine sirului dat !”;
else cout<<”Elementul nu apartine sirului !”;
}
Am utilizat instructiunea while, conditia de efectuare a ciclului fiind (j<n) && (!gasit). Corpul instructiunii while se
va executa atat timp cat nu s-a ajuns la sfarsitul sirului si elementul x nu a fost gasit in v. Conditia de mai sus devine
falsa in doua cazuri: fie am epuizat elementele sirului (j a ajuns egal cu n), fie am gasit un element egal cu x. Dupa
executarea ciclului while testam daca variabila gasit este nenula (adevar), caz in care x apartine lui v, altfel x nu
apartine sirului.
Exemplul 6. (sortare) Se considera un sir cu n elemente reale. Sa se aranjeze elementele in ordine crescatoare
utilizand acelasi vector.
#include <iostream.h>
#include <conio.h>
void main()
{
double v[40];
int n;
int j, k;
cout<<”n=”;
cin>>n;
for(j=0;j<n;j++)
{
cout<<”v[“<<j<<”]=”;
cin>>v[j];
}
//sortarea crescatoare a sirului v
for(j=0;j<n-1;j++)
for(k=j+1; k<n;k++)
if (v[j]>v[k])
{
//interschimbam valorile v[j] si v[k]
temp=v[j];
v[j]=v[k];
v[k]=temp;
}
//afisarea valorilor sortate crescator
for(k=0;k<n;k++) cout<<v[k]<<”\t”;
}
3. Tablouri bidimensionale (matrice)
Pe langa vectori, cel mai utilizat tip de tablou de numere este tabloul bidimensional, numit de cele mai multe ori
matrice. Declararea unei matrice se face astfel:
tip_de_baza nume[dimensiune_1][dimensiune_2];
Exemplu:
double a[10][5]; //tablou cu 10 linii si 5 coloane de elemente reale
int a[3][2]; //tablou cu 3 linii si 2 coloane de elemente intregi
Reprezentarea grafica a unei matrice este urmatoarea:

Pentru a putea avea acces la valoarea unui element al matricei, trebuie sa precizam linia si coloana pe care se afla
acesta. Un element poate fi specificat prin a[i][j], i - reprezentand linia si j -coloana. In cazul vectorilor citeam o
valoare repezentand numarul de elemente. Pentru matrice vom citi o valoare m- numarul maxim de linii si o valoare
n- numarul maxim de coloane. O matrice cu m linii si n coloane va avea m*n elemente.
Daca m=n atunci matricea se numeste matrice patrata de ordin n.
Exemplul 7. Sa se citeasca elementele unei matrice si sa se afiseze.
#include <iostream.h>
#include <conio.h>
void main()
{
int a[20][20]; //matrice cu elemente intregi
int m,n; //numarul de linii, respectiv coloane
int i, j; //variabile folosite in instr. For
//citim numarul de linii si coloane
cout<<”Numarul de linii:”;
cin>>m;
cout<<”Numarul de coloane:”;
cin>>n;
//se citesc elementele matricei
for(i=0;i<m;i++)
for(j=0;j<n;j++)
{
cout<<”a[“<<i<<”][“<<j<<”]=”;
cin>>a[i][j];
}
//afisarea elementelor matricei
for(i=0;i<m;i++)
{
for(j=0;j<n;j++) cout<<a[i]][j]<<”\t”;
cout<<”\n”;
}
}
Exemplul 8. Se dau doua matrice cu m linii si n coloane. Sa se calculeze matricea suma.
……………………………………………….
int a[20][20], b[20][20], c[20][20];
int m,n;
int i, j;
………………………………………………..
//se citesc dimensiunile m, n si cele doua matrice a si b
……………………………………………….
//calculam matricea suma
for(i=0;i<m;i++)
for(j=0;j<n;j++) c[i][j]=a[i][j]+b[i][j];
//se afiseaza matricea c
………………………………………………..
Atunci cand lucram cu matrice avem nevoie de doi indici: i pentru a parcurge liniile matricei si j pentru a parcurge
coloanele acesteia. Pentru fiecare valoare a lui i, j ia toate valorile intre 0 si n-1, deci se parcurge linia i.
In ultimul exemplu am utilizat trei matrice. Pentru mai multa claritate, putem declara un tip ale carui elemente sa fie
matrice:
typedef int matrice[20][20];
matrice a, b, c;
Am definit un tip de date (tip de date definit de utilizator) ale carui elemente sunt matrice cu maxim 20 de linii si
coloane cu elemente intregi. Numele noului tip este matrice. Declararea variabilelor de acest tip se poate face
oriunde in programul in care apare definitia. Definirea unui tip de date se poate face numai prin utilizarea cuvantului
cheie typedef inaintea declaratiei. Daca definim mai multe tipuri se va folosi typedef pentru fiecare definitie.

cpp3.htmcpp3.htmcpp5.htmcpp5.htm
1. Notiunea de pointer
Pointerii au fost introdusi in limbajele de programare pentru a putea rezolva mai eficient anumite probleme sau
pentru a da mai multa claritate anumitor programe.
O prima definitie poate fi urmatoarea:
Pointerul este o variabila ce contine adresa unui obiect.
Obiectul a carei adresa este retinuta de pointer poate fi:
• variabila
• functie
Fie urmatorul exemplu:
int x;
int *px;
Am definit o variabila de tip intreg x si o variabila pointer, care poate contine adresa unei variabile de tip intreg.
Simbolul * ce apare in stanga variabilei px arata ca px este o variabila pointer.
Prin atribuirea
px=&x;
pointerul va avea ca valoare adresa de memorie alocata variabilei x (vezi laboratorul nr.1, definitia variabilei).
Operatorul unar & este utilizat pentru a se obtine adresa variabilei x (operator unar=are un singur operand)
Acum putem sa lucram cu continutul variabilei x (i.e cu valoarea acesteia) prin intermediul pointerului px, deci
indirect, fara sa mai folosim variabila x. La prima vedere, aceasta modalitate de lucru poate parea dificila si nu
tocmai utila. Necesitatea utilizarii pointerilor va apare cu mai multa claritate in sectiunea dedicata sirurilor de
caractere si functiilor.
Exemplul 1. Fie programul urmator:
#include <iostream.h>
void main()
{
int x,y;
int *px;
cout<<"x=";
cin>>x;
cout<<"y=";
cin>>y;
px=&x;
cout<<"x are valoarea "<<*px;
*px=y;
cout<<"\nx a devenit "<<x;
}
In programul de mai sus am introdus valorile variabilelor intregi x si y, am definit un pointer la variabila x si am
atribuit acestuia adresa de memorie alocat variabilei x. Sa analizam atent linia:
cout<<"x are valoarea "<<*px;
Prin *px se intelege valoarea aflata in zona de memorie a carei adresa este memorata in pointerul px. Valoarea
afisata va fi chiar valoarea introdusa pentru x deoarece, inainte de afisare, pointerul px a primit ca valoare adresa
variabilei x, adresa la care se afla valoarea acesteia (valoare dobandita prin utilizarea functiei cin).
Atribuirea *px=y; va modifica valolarea care se afla la adresa memorata de px, valoare care va fi valoarea introdusa
de utilizator pentru variabila y. Astfel va fi modificata chiar valoarea pe care o are variabila x.
Fireste ca era mai simplu sa folosim atribuirea x=y; care are acelasi efect si ne scuteste de de-a mai folosi pointeri,
insa exemplul este pur didactic.
Operatorul unar * este folosit sub forma *variabila_pointer, valoarea acestei expresii fiind valoarea care se gaseste
in memorie la adresa memorata de pointerul ce apare ca operand. In concluzie, prin px avem acces la adresa
variabilei x, iar prin *px la valoarea variabilei x.
Vom spune ca un pointer “refera” indirect un obiect sau ca “pointeaza”(arata) la obiectul respectiv. Variabilele
pointer pot fi incadrate ca fiind de tip referinta.
Exemplul 2. Sa se calculeze suma a doua numere reale folosind pointeri.
#include <iostream.h>
void main()
{
double x,y,z;
double *px, *py, *pz;
cin>>x;
cin>>y;
px=&x;
py=&y;
pz=&z;
*pz=*px+*py;
cout<<"Suma este: "<<*pz;
}
2. Pointeri si tablouri
In limbajul C, exista o foarte stransa legatura intre pointeri si tablouri, astfel ca pointerii si tablourile sunt tratate la
fel. Orice program in care apar tablouri poate fi modificat astfel incat sa foloseasca poiteri in locul tablourilor. In
aceasta sectiune vom discuta despre legatura dintre pointeri si vectori (tablouri unidimensionale).
Fie urmatoarele declaratii:
int a[20];
int *pa;
Am declarat o variabila a , care este un vector cu maxim 20 elemente intregi si un pointer la o variabila de tip intreg.
Dupa cum se stie, o valoare int are nevoie de 16 biti pentru a fi memorata, adica 2 bytes ( o variabila int poate retine
numere intregi intre -32768 si 32767, vezi curs Bazele Informaticii). Pentru tabloul a vor fi alocati 2• 20=40 bytes
consecutivi in memorie adica, pentru primul element a[0] sunt alocati primii 2 bytes, pentru a[1] urmatorii 2 bytes,
…, pentru a[19] ultimii 2 bytes din cei 40 alocati.
Fie atribuirea:
pa=&a[0];
Dupa aceasta atribuire, pointerul pa contine adresa primului element al vectorului, adica pa pointeaza la inceputul
vectorului a.
Daca scriem pa=&a[3]; atunci pa va referi elementul al 4-lea din vectorul a, iar *pa va contine valoarea sa.
Operatiile care se pot realiza cu pointeri sunt:
• comparatia
• adunarea unui pointer cu un intreg
• scaderea unui intreg dintr-un pointer
Doi pointeri pot fi comparati folosind operatori relationali. In comparatia:
if(p1==p2) cout<<”Adrese identice”;
else cout<<”Adrese diferite”;
se verifica daca adresa memorata de p1 este aceeasi cu adresa retinuta de p2, unde p1 si p2 sunt pointeri de acelasi
tip.
Se poate compara un pointer cu valoarea NULL (sau 0). Un pointer are valoarea NULL (valoare nedefinita) daca nu
refera nici un obiect.
Adunarea unui pointer cu un intreg este definita numai atunci cand pointerul refera un tablou (un element al
tabloului). Scaderea este definita in acelasi caz.
Exemplul 3. Sa se citeasca elementele unui vector si sa se afiseze acestea utilizand pointeri.
#include <iostream.h>
void main()
{
int a[20];
int *pa;
int i,n;
cout<<"Numarul de elemente= ";
cin>>n;
for(i=0;i<n;i++)
{
cout<<"Elementul"<<i<<"=";
cin>>a[i];
}
//afisarea vectorului folosind pointeri
pa=&a[0];
for(i=0;i<n;i++)
{
cout<<*pa<<"\n";
pa++;
}
}
Prima pate a programului nu contine elemente noi, doar a doua parte meritand atentie. Mai intai initializam pointerul
pa cu valoarea primului element al vectorului a. Ciclul for contine urmatoarele prelucrari:
• afiseaza valoarea aflata la adresa indicata de pointer;
• aduna pointerul pa cu 1
Incrementarea pointerului pa are ca efect modificarea adresei memorate in pa. Noua adresa este adresa zonei de
memorie corespunzatoare elementului urmator, o adresa cu 2 bytes mai mare decat precedenta. Observam ca marirea
pointerului cu o unitate inseamna de fapt trecerea la urmatorul element din vector.
Daca vom introduce pentru n o valoare mai mare decat 20 (numarul maxim de elemente ale vectorului, asa cum
reiese din declaratie) atunci pointerul pa va depasi zona de memorie alocata vectorului si va referi o adresa la care se
pot afla date importante pentru program. Urmarile pot fi imprevizibile, de la blocarea programului pana la blocarea
sau inchiderea calculatorului !!!

cpp4.htmcpp4.htmcpp6.htmcpp6.htm
1. Notiunea de functie. Structura si definirea functiilor
Notiunea de functie este o notiune de mare importanta in informatica, orice limbaj de programare furnizand facilitati
de lucru cu functii.
In matematica, functia era definita ca fiind tripletul (A, B, f), unde:
• A - domeniul de definitie;
• B - codomeniul sau domeniul de valori;
• f - lege, conventie, prin care fiecarui element din domeniul de definitie i se asociaza un unic
element din codomeniu;
In informatica, notiunea de functie difera putin de modul matematic de abordare. In limbajul C, orice program
trebuie sa contina obligatoriu o functie numita main. Daca prelucrarile ce compun programul sunt foarte complexe,
utilizarea unei singure functii duce la un program greu de inteles si depanat. In acest caz este bine ca problema de
rezolvat sa fie impartita in subprobleme prin a caror combinare sa se obtina rezolvarea problemei initiale. Pentru
rezolvarea fiecarei subprobleme se poate utiliza cate o functie separata. Functia main (“programul principal”) nu va
mai fi de mare intindere, ea continand doar apeluri catre functiile deja definite.
Decizia de a folosi o functie poate fi luata si in cazul in care anumite prelucrari trebuiesc realizate de mai multe ori,
cum se va vedea si in exemplul de mai jos.
Exemplul 1. Sa se calculeze aria a n triunghiuri, daca se cunosc lungimile laturilor acestora.
#include <iostream.h>
#include <conio.h>
#include <math.h>
float aria(int a, int b, int c)
{
float p,s;
p=(float)(a+b+c)/2;
s=sqrt(p*(p-a)*(p-b)*(p-c));
return s;
}
void main()
{
int a,b,c;
float S;
int i,n;
cout<<"Numarul de triunghiuri= ";
cin>>n;
i=1;
for(i=1;i<=n;i++)
{
cout<<"a=";
cin>>a;
cout<<"b=";
cin>>b;
cout<<"c=";
cin>>c;
S=aria(a,b,c);
cout<<"Aria triunghiului "<<i<<" este "<<S<<"\n";
}
}
Programul trebuie sa calculeze aria a n triunghiuri, deci calculul ariei trebuie realizat de n ori. Am definit functia
aria, care calculeaza aria triunghiului cu lungimile laturilor a, b, c prin formula lui Heron. Structura functiei este
urmatoarea:
• antet:
float aria(int a, int b, int c)
care contine urmatoarele elemente:
• tipul rezultatului functiei (codomeniul)-rezultatul functiei va fi o valoare de tipul declarat;
• numele functiei:- numele nu poate fi identic cu un cuvant cheie
• lista parametrilor formali - variabilele de care depinde calcularea rezultatului (“argumentele
functiei”); pentru fiecare parametru formal se specifica tipul.
• corpul functiei:
{
float p,s;
p=(float)(a+b+c)/2;
s=sqrt(p*(p-a)*(p-b)*(p-c));
return s;
}
Corpul functiei contine declaratiile variabilelor utilizate in functie si prelucrarile realizate de functie.Variabilele
utilizate in functia aria, numite si variabile locale, sunt semiperimetrul p si aria s. Nu declaram variabilele a, b, c
(parametrii formali nu se declara in corpul functiei) si nici nu citim valori pentru ele in cadrul functiei.
Orice functie care are drept codomeniu un tip diferit de tipul void trebuie sa contina in corpul functiei o instructiune
return expresie;
unde expresie este orice expresie corecta in C cu valoare de tipul declarat pentru codomeniu.
Instructiunea return este utilizata pentru a semnala faptul ca valoarea functiei este valoarea expresiei.
In programul principal (functia main) se citeste numarul de triunghiuri n. Instructiunea for va repeta de n ori (pentru
fiecare triunghi) urmatoarele prelucrari:
• se citesc valori pentru variabilele a, b, c care reprezinta lungimile laturilor triunghiului curent;
• se calculeaza aria triunghiului pentru valorile date;
• se afiseaza valoarea ariei triunghiului curent;
Modul de utilizare al functiei aria este interesant. Atribuirea:
S=aria(a,b,c);
are urmatorul efect;
• se evalueaza expresia din dreapta atribuirii, expresie ce consta din apelul functiei aria pentru
valorile a, ,b, c
• evaluarea functiei inseamna executarea prelucrarilor din functie pentru valorile parametrilor
formali a, b, c
• valoarea intoarsa de functie este valoarea variabilei s, care apare in return;
• valoarea este memorata in zona de memorie a variabilei S.
Functiile pot fi clasificate astfel:
• functii predefinite= functii deja definite de autorii mediului de programare C si grupate, in functie
de utilitatea lor, in biblioteci numite fisiere header. De exemplu, in biblioteca math.h sunt grupate
functiile matematice, in string.h avem functiile de lucru cu siruri de caractere, in iostream.h
functii pentru introducerea si afisarea datelor, in malloc.h si alloc.h functii pentru alocarea
memoriei…
• functii definite de utilizator= functii scrise de creatorul unui program pentru acele prelucrari pentru
care nu exista functii predefinite (caz destul de frecvent);
O functie poate sa aiba drept codomeniu orice tip predefinit scalar (intreg, caracter sau real), tip compus (uniune sau
structura), precum si pointeri la orice tip. Tipul void inseamna ca functia nu returneaza nici o valoare.
Programatorul poate sa stranga functiile definite de el intr-un fisier header propriu, care se poate include in program
prin #include “nume_fisier.h”.
2. Apelul functiilor si transferul parametrilor
Orice aparitie a numelul functiei insotit de un numar de valori egal cu numarul parametrilor formali se numeste apel
al functiei.
Puteam apela functia si in modul urmator:
cout<<aria(3,4,5);
Aceasta instructiune are ca efect afisarea ariei triunghiului cu laturile de lungimi 3, 4, 5. Observati ca nu este
obligatoriu ca parametrii din apel sa fie variabile, ci pot fi expresii.
Daca functia noastra ar aparea intr-o expresie ca 23*aria(3,4,5)-2*aria(2,6,6), evaluarea expresiei ar incepe cu
executarea functiei aria pentru valorile 3, 4, 5 si apoi pentru 2, 6, 6; dupa ce se obtin rezultatele celor doua apeluri
ale functiei se realizeaza evaluarea celorlaltor operatori (inmultirile si apoi scaderea).
Functia in care apare un apel al altei functii se numeste functie apelanta.
Parametrii sunt de doua tipuri:
• parametri formali:
• valoare
• referinta (pointer)
• parametri efectivi (actuali)
Parametrii sunt utilizati pentru a putea transmite din functia apelanta valorile necesare prelucrarilor efectuate de
functia apelata. Atunci cand parametrii formali sunt utilizati doar pentru a transmite valori in functia apelata, acesti
parametrii se numesc parametri valoare. Daca se doreste transmiterea ca parametru a unei variabile, in scopul
modificarii valorii acesteia astfel incat modificarea sa fie disponibila in functia apelanta, avem de-a face cu un
parametru formal referinta (se realizeaza printr-o variabila de tip pointer).
Pentru a putea apela o functie, trebuie sa precizam, pe langa numele acesteia, valorile parametrilor pentru care se
realizeaza apelul (parametri actuali). Numarul parametrilor actuali dintr-un apel de functie trebuie sa fie acelasi cu
numarul parametrilor formali din definitia functiei apelate si sa corespunda ca tip.
De exemplu, in programul de mai sus, nu puteam apela functia aria ca
s=aria(4.56, 5, 5);
deoarece primul parametru formal din definitia functiei este definit ca de tip int, iar parametrul actual (4.56) este de
tip real (incompatibilitate de tip).
Nu este obligatoriu sa existe parametrii formali intr-o functie daca nu este nevoie. De asemenea, nu toate functiile
intorc o valoare. Aceste aspecte sunt tratate in urmatoarele exemple.
Exemplul 2. Sa se scrie o functie care afiseaza pe ecran un numar dat de asteriscuri.
void asterisc(int nr)
{
int j;
for(j=1;j<=nr;j++) cout<<”* ”;
}
Functia are un singur parametru formal, un intreg nr reprezentand numarul de asteriscuri ce trebuie afisate. Functia
poate fi apelata prin
asterisc(10);
care are ca efect afisarea a 10 asteriscuri.
Functia nu intoarce nici o valoare, deoarece nu este necesar (n-are sens sa intoarcem vreo valoare), deci codomeniul
va fi tipul void. Din moment ce functia nu intoarce vreo valoare, nu se va mai utiliza return.
Exemplul 3. Scrieti o functie care sa afiseze un mesaj.
void mesaj( )
{
cout<<”Traiasca Reforma !!!”;
}
Functia mesaj nu intoarce nici o valoare si nici nu contine parametrii formali (nu exista valori care sa fie necesare
executiei functiei). Apelul functiei se va face prin: mesaj(), exact ca si pentru functia predefinita clrscr( ).
Daca am dori ca functia sa afiseze un mesaj dat, obtinem:
void mesaj(char s[80])
{
cout<<s;
}
Apelul functiei poate fi: mesaj(“Traiasca pacea si bunastarea poporului chinez !!!”);
Exemplul 4. Scrieti o functie care stabileste daca un numar este prim.
#include <iostream.h>
int este_prim(int n)
{
int j;
int este;
este=1; //presupunem ca numarul este prim
for(j=1;j<=n-1;j++)
if(n%j==0) este=0;
return este;
}
void main()
{
int numar;
cout<<”Introduceti numarul=”;
cin>>numar;
if(este_prim(numar)!=0) cout<<”Numarul este prim !”;
else cout<<”Numarul nu este prim !”;
}
Exercitiul 1: Folositi functia este_prim pentru a afisa toate numerele prime mai mici decat un numar intreg dat.
Exemplul 5. Scrieti o functie care sa citeasca un vector de numere intregi.
void citeste(int a[30], int n)
{
int k;
for(k=0;k<n; k++)
cin>>a[k];
}
Functia are doi parametri: variabila de tip vector care va retine numerele citite si variabila n, care ne spune cate
elemente trebuiesc citite. Functia main poate sa arate astfel:
void main ()
{
int b[30];
int n;
cout<<”n=”;
cin>>n;
citeste(a,n);
}
Exercitiul 2: Scrieti o functie pentru afisarea elementelor unui vector si adaugati-o exemplului precedent.
Exemplul 6. Scrieti o functie care calculeaza suma elementelor dintr-un vector.
int suma(int a[40], int n)
{
int k;
int s;
s=0;
for(k=0;k<n;k++) s=s+a[k];
return s;
}
Este necesar sa introducem ca parametru si numarul de elemente din vector n.
Exercitiul 3: Folositi functia de mai sus in programul de la exercitiul precedent.
Exemplul 7. Scrieti o functie care calculeaza ax, unde a real si x iintreg pozitiv.
float putere(float a, int x)
{
int k;
int p; //retine puterea
p=1;
for(k=1;k<=x;k++) p=p*a;
return p;
}
Exercitiul 4. Modificati functia din exemplul 7 astfel incat sa poata ridica pe a si la puteri negative.
Exemplul 8. Scrieti o functie pentru a calcula cel mai mare divizor comun a 2 numere intregi folosind algoritmul lui
Euclid.
#include <iostream.h>
int cmmdc(int m, int n)
{
int r;
int temp;
if(n>m)
{
temp=m;
m=n;
n=temp;
}
do
{
r=m%n;
m=n;
n=r;
}while(r!=0);
return m;
}
void main()
{
int a,b;
cout<<"Primul numar=";
cin>>a;
cout<<"Al doilea numar=";
cin>>b;
cout<<cmmdc(a,b);
}
Exemplul 9 Sa se scrie o functie care verifica daca un intreg x apartine unui vector v.
int cauta(int v[50], int n)
{
int k;
int apartine;
apartine=0; //se presupune ca x nu este element in v
for(k=0;k<n;k++)
if(v[k]==x) apartine=1;
return apartine;
}
Exemplul 10. Sa se scrie o functie care realizeaza suma a doua matrice cu m linii si n coloane.
void suma_mat(int a[20][20], int b[20][20], int c[20][20], int m, int n)
{
int j, k; //variabile contor in for
for(j=0;j<m;j++)
for(k=0;k<n;k++) c[j][k]=a[j][k]+b[j][k];
}
Parametrii de care depinde rezolvarea sarcinii sunt:
• a - prima matrice
• b - a doua matrice
• c - matricea suma (rezultatul sumei)
• m - numarul de linii
• n - numarul de coloane
Exercitiul 5. Sa se scrie functia main corespunzatoare functiei de mai sus, precum si functii pentru citirea si afisarea
unei matrice.
O situatie interesanta apare atunci cand vrem ca variabilele ce apar ca parametri formali sa poata fi modificate in
cadrul functiei, modificarile fiind disponibile in functia apelanta.
Sa luam urmatorul exemplu:
Exemplul 11. Sa se scrie o functie care interschimba valorile a doua variabile intregi.
Varianta urmatoare este gresita:
void schimba(int x, int y)
{
int temp;
temp=x;
x=y;
y=temp;
}
void main()
{
int a, b;
cin>>a;
cin>>b;
schimba(a,b);
cout<<a;
cout<<b;
}
La prima vedere functia pare corecta, insa lucrurile stau tocmai pe dos. Daca introducem valorile 5 pentru a si 7
pentru b, programul ar trebui sa schimbe intre ele valorile celor doua variabile (a trebuie sa devina 7, iar b sa devina
5). Programul de mai sus nu va realiza acest lucru. Explicatia este ca, atunci cand parametri formali sunt parametri
valoare, chiar daca se modifica valoarea lor in cadrul functiei aceste modificari nu vor avea efect in functia apelanta
(in cazul nostru, in functia main nu va fi sesizabila schimbarea realizata in functia schimba).
Problema se poate rezolva daca parametrii din functia schimba vor fi parametri referinta (pointeri).
Varianta corecta este urmatoarea:
void schimba(int *x, int *y)
{
int temp;
temp=*x;
*x=*y;
*y=temp;
}
Singura schimbare din functia main este apelul functiei, care devine
schimba(&a, &b);
Explicatia corectitudinii acestei variante este aceea ca se lucreaza cu adresele variabilelor, deci orice modificare a
continutului zonelor de memorie alocate variabilelor x si y va fi resimtita si in functia main.
Parcurgeti din nou exemplul 10 si priviti cu atentie antetul functiei suma_mat. Parametrul formal c este o matrice
calculata ca suma matricelor a si b, deci valoarea elementelor lui c este modificata in cadrul functiei, dar parametrul
formal este corect ? Raspunsul este afirmativ deoarece, dupa cum stiti, tablourile sunt tratate exact ca si pointerii,
deci tablourile care apar ca parametrii formali se considera parametri referinta.
3. Variabile locale si variabile globale
Un program C este compus din una sau mai multe functii (cel putin functia main) repartizate in unul sau mai multe
fisiere. Structura de principiu a unui program C este urmatoarea:
• directive de preprocesare (de exemplu #include)
• declaratii de tipuri si variabile globale (imdeiat dupa directivele de preprocesare, in afara
oricaror functii)
• definitii de functii
• functia main()
Toate variabilele declarate in afara oricarei functii se numesc variabile globale, acestea putand fi utilizate in orice
functie din program. Variabilele definite in interiorul unei functii se numesc variabile locale si pot fi utilizate doar
in functia unde au fost declarate. Putem declara o variabila k in mai multe functii, fara sa fie influentata
corectitudinea programului. Este de preferat ca variabilele globale sa fie in numar limitat, doar atunci cand este
nevoie neaparata. Folosirea neatenta a variabilelor globale poate duce la erori greu depistabile.

cpp5.htmcpp5.htm

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