Explorați Cărți electronice
Categorii
Explorați Cărți audio
Categorii
Explorați Reviste
Categorii
Explorați Documente
Categorii
INTRODUCERE
Limbajele C i C++ sunt limbaje de programare de nivel nalt.
Limbajul C a aprut n anii 1970 i a fost creat de Dennis Ritchie n laboratoarele AT&T Bell. Limbajul C
face parte din familia de limbaje concepute pe principiile programrii structurate, la care ideea central este
structureaz pentru a stpni o aplicaie. Popularitatea limbajului a crescut rapid datorit eleganei i a
multiplelor posibiliti oferite programatorului.
Limbajul C++ apare la nceputul anilor 80 i l are ca autor pe Bjarne Stroustrup. El este o variant de
limbaj C mbuntit, mai riguroas i mai puternic, completat cu construciile necesare aplicrii
principiilor programrii orientate pe obiecte (POO). Limbajul C++ pstreaz toate elementele limbajului C,
beneficiind de eficiena i flexibilitatea acestuia. Limbajul C++ este un superset al limbajului C.
Incompatibilitile sunt minore, de aceea, modulele C pot fi ncorporate n proiecte C++ cu un efort minim.
Lucrarea cuprinde dou pri.
Prima parte se adreseaz programatorilor nceptori. Ea prezint elementele de baz i construciile
limbajului C, completate cu extensiile limbajului C++. Acestea permit rezolvarea problemelor prin metoda
programrii structurate.
Partea a doua se adreseaz cunosctorilor limbajului C dornici s-i modernizeze stilul i concepia abordrii
proiectelor informatice. Elementele prezentate sunt specifice limbajului C++ i permit stiluri de programare
impracticabile n C: programarea prin abstractizarea datelor i programarea orientat obiect. Citndu-l chiar
pe Bjarne Stroustrup, C++ este un limbaj de programare general, conceput astfel nct s-i fac pe
programatorii serioi s programeze ntr-o manier ct mai plcut.
i cum cea mai bun metod de nvare este practica, prezentarea aspectelor teoretice este nsoit de multe
exemple i probleme rezolvate. Deasemenea, ntrebrile teoretice i problemele propuse spre rezolvare, de la
sfritul fiecrui capitol, permit cititorului s-i verifice cunotinele dobndite. Un aspect foarte important l
constituie implementarea i testarea pe calculator a exemplelor i a problemelor rezolvate sau propuse,
gsirea unor soluii proprii.
Sperm ca acest material s constituie un sprijin real pentru cei care doresc s ptrund n tainele limbajelor
C/C++, ct i un punct de plecare n activitatea de programare.
Dorim s mulumim i pe acest cale domnului prof. Severin BUMBARU i colegilor pentru observaiile i
sfaturile care au condus la forma actual a crii.
Sugestiile cititorilor sunt ateptate la adresele: Diana.Stefanescu@ugal.ro, Cristina.Segal@ugal.ro.
AUTORII
Page 10 of 238
NOIUNI INTRODUCTIVE
1.1. Structura general a unui sistem de calcul 1.2.2. Definiii i caracteristici
1.2. Algoritmi 1.2.3. Reprezentarea algorimilor
1.2.1. Noiuni generale 1.3. Teoria rezolvrii problemelor
1.1. STRUCTURA GENERAL A UNUI SISTEM DE CALCUL
Calculatorul reprezint un sistem electronic (ansamblu de dispozitive i circuite diverse) complex care
prelucreaz datele introduse ntr-o form prestabilit, efectueaz diverse operaii asupra acestora i
furnizeaz rezultatele obinute (figura 1.1.).
Principalele avantaje ale folosirii calculatorului constau n:
viteza mare de efectuare a operaiilor;
capacitatea extins de prelucrare i memorare a informaiei.
Dei construcia unui calculator - determinat de tehnologia existent la un moment dat, de domeniul de
aplicaie, de costul echipamentului i de performanele cerute - a evoluat rapid n ultimii ani, sistemele de
calcul, indiferent de model, serie sau generaie, au o serie de caracteristici comune. Cunoaterea acestor
caracteristici uureaz procesul de nelegere i nvare a modului de funcionare i de utilizare a
calculatorului.
n orice sistem de calcul vom gsi dou pri distincte i la fel de importante: hardware-ul i software-ul.
Hardware-ul este reprezentat de totalitatea echipamentelor i dispozitivelor fizice;
Software-ul este reprezentat prin totalitatea programelor care ajut utilizatorul n rezolvarea problemelor
sale (figura 1.2.).
Software-ul are dou componente principale:
Sistemul de operare (de exploatare) care coordoneaz ntreaga activitate a echipamentului de calcul.
Sistemul de operare intr n funciune la pornirea calculatorului i asigur, n principal, trei funcii:
Gestiunea echitabil i eficient a resurselor din cadrul sistemului de calcul;
Realizarea interfeei cu utilizatorul;
Furnizarea suportului pentru dezvoltarea i execuia aplicaiilor.
Exemple de sisteme de operare: RSX11, CP/M, MS-DOS, LINUX, WINDOWS NT, UNIX.
Sistemul de aplicaii (de programare): medii de programare, editoare de texte, compilatoare,
programe aplicative din diverse domenii (economic, tiinific, financiar, divertisment).
Componentele unui sistem de calcul pot fi grupate n uniti cu funcii complexe, dar bine precizate, numite
uniti funcionale. Modelul din figura 1.3. face o prezentare simplificat a structurii unui calculator,
facilitnd nelegerea unor noiuni i concepte de baz privind funcionarea i utilizarea acestuia. Denumirea
fiecrei uniti indic funcia ei, iar sgeile - modul de transfer al informaiei.
Date de intrare
(datele iniiale ale
problemei)
Date de ieire (rezultatele
obinute)
PROGRAM (ir de aciuni ,
prelucrri, algoritm)
Figura 1.1. Calculatorul - sistem automat de prelucrare a datelor
1
HARDWA
RE
SISTEM
OPERARE
UTILIZATO
R
Page 11 of 238
Vom utiliza n continuare termenii de citire pentru operaia de introducere (de intrare) de la tastatur a
datelor iniiale ale unei probleme, i scriere pentru operaia de afiare (de ieire) a rezultatelor obinute. n
cazul n care utilizatorul dorete s rezolve o problem cu ajutorul calculatorului, informaia de intrare
(furnizat calculatorului de ctre utilizator) va consta din datele iniiale ale problemei de rezolvat i dintr-un
program (numit program surs). n programul surs utilizatorul implementeaz (traduce) ntr-un limbaj de
programare un algoritm (aciunile executate asupra datelor de intrare pentru a obine rezultatele). Aceast
informaie de intrare este prezentat ntr-o forma extern, accesibil omului (numere, text, grafic) i va fi
transformat de ctre calculator ntr-o forma intern, binar.
Unitatea de intrare (cu funcia de citire) realizeaz aceast conversie a informaiei din format extern n cel
intern. Din punct de vedere logic, fluxul (informaia) de intrare este un ir de caractere, din exterior ctre
memoria calculatorului. Din punct de vedere fizic, unitatea de intrare standard este tastatura calculatorului.
Tot ca uniti de intrare, pot fi enumerate: mouse-ul, joystick-ul, scanner-ul (pentru introducerea
informaiilor grafice).
Unitatea de ieire (cu funcia de scriere, afiare) realizeaz conversia invers, din formatul intern n cel
extern, accesibil omului. Din punct de vedere fizic, unitatea de ieire standard este monitorul calculatorului.
Ca uniti de ieire ntr-un sistem de calcul, mai putem enumera: imprimanta, plotter-ul, etc.
Informaia este nregistrat n memorie.
Memoria intern (memoria RAM - Random Acces Memory) se prezint ca o succesiune de octei (octet
sau byte sau locaie de memorie). Un octet are 8 bii. Bit-ul reprezint unitatea elementar de informaie i
poate avea una din valorile: 0 sau 1.
Capacitatea unei memorii este dat de numrul de locaii pe care aceasta le conine i se msoar n
multiplii de 1024 (2
10
). De exemplu, 1 Mbyte=1024Kbytes; 1Kbyte=1024bytes.
Numrul de ordine al unui octet n memorie se poate specifica printr-un cod, numit adres. Ordinea
n care sunt adresate locaiile de memorie nu este impus, memoria fiind un dispozitiv cu acces
aleator la informaie.
n memorie se nregistreaz dou categorii de informaii:
Date - informaii de prelucrat;
Programe - conin descrierea (implementarea ntr-un limbaj de programare) a aciunilor care vor
fi executate asupra datelor, n vederea prelucrrii acestora.
n memoria intern este pstrat doar informaia prelucrat la un moment dat. Memoria intern are capacitate
redus; accesul la informaia pastrat n aceasta este extrem de rapid, iar datele nu sunt pstrate dup
terminarea prelucrrii (au un caracter temporar).
Unitatea central prelucreaz datele din memoria intern i coordoneaz activitatea tuturor componentelor
fizice ale unui sistem de calcul. Ea nglobeaz:
Microprocesorul- circuit integrat complex cu urmtoarele componente de baz:
Unitatea de execuie (realizeaz operaii logice i matematice);
Unitatea de interfa a magistralei (transfer datele la/de la microprocesor).
Page 12 of 238
Coprocesorul matematic circuit integrat destinat realizrii cu vitez sporit a operaiilor cu
numere reale.
n funcie de numrul de bii transferai simultan pe magistrala de date, microprocesoarele pot fi clasificate
astfel: microprocesoare pe 8 bii (Z80, 8080); microprocesoare pe 16 bii (8086, 8088, 80286) cu
coprocesoarele corespunztoare (8087, 80287); familii de procesoare pe 32 bii (80386DX, 80486,
PENTIUM) cu coprocesoarele corespunztoare (ncepnd de la 486, coprocesoare sunt ncorporate
microprocesoarelor).
Memoria extern este reprezentat, fizic, prin unitile de discuri (discuri dure-hard disk, discuri flexibile-
floppy disk, discuri de pe care informaia poate fi doar citit-CDROM, DVDROM, etc). Spre deosebire de
memoria intern, memoria extern are capacitate mult mai mare, datele nregistrate au caracter permanent, n
dezavantajul timpului de acces la informaie.
1.2. ALGORITMI
1.2.1. NOIUNI GENERALE
Algoritmul este conceptul fundamental al informaticii. Orice echipament de calcul poate fi considerat o
main algoritmic. ntr-o definiie aproximativ algoritmul este un set de pai care definete modul n care
poate fi dus la ndeplinire o anumit sarcin. Exemplu de algoritm: algoritmul de interpretare a unei buci
muzicale (descris n partitur). Pentru ca o main de calcul s poat rezolva o anumit problem,
programatorul trebuie mai nti s stabileasc un algoritm care s conduc la efectuarea la sarcinii respective.
Exemplu:
Algoritmul lui Euclid pentru determinarea celui mai mare divizor comun (cmmdc) a 2 numere
ntregi pozitive.
Date de intrare: cele 2 numere ntregi
Date de iesire: cmmdc
1. Se noteaz cu A i B- cea mai mare, respectiv cea mai mic, dintre datele de intrare
2. Se mparte A la B i se noteaz cu R restul mpririi
3. a. Dac R diferit de 0, se atribuie lui A valoarea lui B i lui B valoarea lui R. Se revine la
pasul 2.
b. Dac R este 0, atunci cmmdc este B.
Probleme legate de algoritmi
Descoperirea unui algoritm care s rezolve o problem echivaleaz n esen cu descoperirea unei soluii a
problemei. Dup descoperirea algoritmului, pasul urmtor este ca algoritmul respectiv s fie reprezentat ntr-
o form n care s poat fi comunicat unei maini de calcul. Algoritmul trebuie transcris din forma
conceptual ntr-un set clar de instruciuni. Aceste instruciuni trebuie reprezentate ntr-un mod lipsit de
ambiguitate. n acest domeniu, studiile se bazeaz pe cunotinele privitoare la gramatic i limbaj i au dus
Unitate de intrare (flux de
intrare - istream n C++)
Memorie intern
Unitate de ieire (flux de
ieire - ostream n C++)
Unitate central
Memorie extern
Figura 1.3. Unitile funcionale ale unui sistem de calcul
Page 13 of 238
la o mare varietate de scheme de reprezentare a algoritmilor (numite limbaje de programare), bazate pe
diverse abordri ale procesului de programare (numite paradigme de programare).
Cutarea unor algoritmi pentru rezolvarea unor probleme din ce n ce mai complexe a avut ca urmare apariia
unor ntrebri legate de limitele proceselor algoritmice, cum ar fi:
Ce probleme pot fi rezolvate prin intermediul proceselor algoritmice?
Cum trebuie procedat pentru descoperirea algoritmilor?
Cum pot fi mbuntite tehnicile de reprezentare i comunicare a algoritmilor?
Cum pot fi aplicate cunotinele dobndite n vederea obinerii unor maini algoritmice mai performante?
Cum pot fi analizate i comparate caracteristicile diverilor algoritmi?
1.2.2. DEFINIII I CARACTERISTICI
Definiii:
Algoritmul unei prelucrri const ntr-o secven de primitive care descrie prelucrarea.
Algoritmul este un set ordonat de pai executabili, descrii fr echivoc, care definesc un proces
finit.
Proprietile fundamentale ale algoritmilor:
Caracterul finit: orice algoritm bine proiectat se termin ntr-un numr finit de pai;
Caracterul unic i universal: orice algoritm trebuie s rezolve toate problemele dintr-o clas de
probleme;
Realizabilitatea: orice algoritm trebuie s poat fi codificat ntr-un limbaj de programare;
Caracterul discret: fiecare aciune se execut la un moment dat de timp;
Caracterul determinist: ordinea aciunilor n execuie este determinat n mod unic de rezultatele
obinute la fiecare moment de timp.
Nerespectarea acestor caracteristici generale conduce la obinerea de algoritmi neperformani, posibil infinii
sau nerealizabili.
1.2.3. REPREZENTAREA ALGORITMILOR
Reprezentarea (descrierea) unui algoritm nu se poate face n absena unui limbaj comun celor care vor s l
neleag. De aceea s-a stabilit o mulime bine definit de primitive (blocuri elementare care stau la baza
reprezentrii algoritmilor). Fiecare primitiv se caracterizeaz prin sintax i semantic. Sintaxa se refer la
reprezentarea simbolic a primitivei; semantica se refer la semnificaia primitivei. Exemplu de primitiv:
aer-din punct de vedere sintactic este un cuvnt format din trei simboluri (litere); din punct de vedere
semantic este o substan gazoas care nconjoar globul pmntesc.
Algoritmii se reprezint prin:
scheme logice;
pseudocod.
1.2.3.1. Reprezentarea algoritmilor prin scheme logice
Primitivele utilizate n schemele logice sunt simboluri grafice, cu funciuni (reprezentnd procese de calcul)
bine precizate. Aceste simboluri sunt unite prin arce orientate care indic ordinea de execuie a proceselor de
calcul.
Categorii de simboluri:
Simboluri de nceput i sfrit
Simbolul START desemneaz nceputul unui
program sau al unui subprogram.
Simbolul STOP desemneaz sfritul unui
program sau al unui subprogram. Prezena lor
este obligatorie.
Page 14 of 238
Simbolul paralelogram
Simbolul dreptunghi
Simbolul romb
Cu ajutorul acestor simboluri grafice se poate reprezenta orice algoritm.
Repetarea unei secvene se realizeaz prin combinarea simbolurilor de decizie i de atribuire.
Structurile repetitive obinute pot fi: cu test iniial sau cu test final.
Structuri repetitive cu test initial
Exis i situaii n care se tie de la nceput de cte ori se va repeta o anumit aciune. n aceste cazuri se
folosete tot o structur de control repetitiv cu test iniial. Se utilizeaz un contor (numeric) pentru a ine o
eviden a numrului de execuii ale aciunii. De cte ori se execut aciunea, contorul este incrementat.
Semnific procese (operaii) de
intrare/ieire (citirea sau scrierea)
CITETE a,
b
AFIEAZ a,
b
a 34
START STOP
Semnific o atribuire (modificarea
valorii unei date).
Figura 1.4. Structura de decizie
D
A
NU
ACIUNE2 ACIUNE1
Simbolul romb este utilizat pentru decizii
(figura 1.4.). Se testeaz ndeplinirea
condiiei din blocul de decizie. Dac
aceast condiie este ndeplinit, se
execut ACIUNE1. Dac nu, se
execut ACIUNE2. La un moment dat,
se execut sau ACIUNE1, sau
ACIUNE2.
Condiie
ndeplini
t?
Se evalueaz condiia de test (figura 1.5.).
Dac aceasta este ndeplinit, se execut
ACIUNE1. Se revine apoi i se testeaz iar
condiia. Dac este ndeplinit, se execut (se
repet) ACIUNE1, .a.m.d. Abia n
momentul n care condiia nu mai este
ndeplinit, se trece la execuia ACIUNE2.
Astfel, ct timp condiia este ndeplinit, se
repet ACIUNE1. n cazul n care, la prima
testare a condiiei, aceasta nu este ndeplinit,
se execut ACIUNE2. Astfel, este posibil
ca ACIUNE1 s nu fie executat niciodat.
DA N
U
ACIUNE2 ACIUNE
1
Condiie
ndeplin
it?
Figura 1.5. Structur repetitiv cu test iniial
Figura 1.6. Structur repetitiv cu test iniial, cu
Se atribuie contorului valoarea iniial
(figura 1.6.). Ct timp condiia (valoarea
contorului este mai mic sau egal cu
valoarea final) este ndeplinit, se repet:
ACIUNE
incrementare contor (se adun 1 la
valoarea anterioar a contorului).
contor valoare_iniial
valoare_contor<=
valoare_final
ACIUNE
valoare_contor valoare_contor +
1
DA
NU
Page 15 of 238
Structur repetitiv cu test final:
1.2.3.2. Reprezentarea algoritmilor prin pseudocod
Pseudocodul este inspirat din limbajele de programare, nefiind ns att de formalizat ca acestea.
Pseudocodul reprezint o punte de legtur ntre limbajul natural i limbajele de programare. Nu exist un
standard pentru regulile lexicale. Limbajul pseudocod permite comunicarea ntre oameni, i nu comunicarea
om-maina (precum limbajele de programare). Pseudocodul utilizeaz cuvinte cheie (scrise cu majuscule
subliniate) cu urmtoarele semnificaii:
Sfrit algoritm: SFRIT
nceput algoritm: NCEPUT
Citire (introducere) date: CITETE lista
Scriere (afiare) date: SCRIE lista
Atribuire: <-
Structura de decizie (alternativ): DAC condiie
ATUNCI aciune1
ALTFEL aciune2
Structuri repetitive cu test iniial: CT TIMP condiie
REPET aciune
PENTRU contor=val_ini LA val_fin [PAS]
REPET aciune;
Structuri repetitive cu test final:
REPET aciune CT TIMP condiie
sau:
REPET aciune PN CND condiie
Pe lng cuvintele cheie, n reprezentarea algoritmilor n pseudocod pot apare i propoziii nestandard a caror
detaliere va fi realizat ulterior.
n cazul n care se realizeaz un algoritm modularizat, pot apare cuvintele cheie:
SUBALGORITM nume (lista_intrri)
CHEAM nume (lista_valori_efective_de_intrare)
Se execut mai nti ACIUNE1. Se
testeaz apoi condiia (figura 1.7.). Se
repet ACIUNE1 ct timp condiia
este ndeplinit.
n acest caz, corpul ciclului (ACIUNE1)
este executat cel puin o dat.
NU
DA
ACIUNE 1
ACIUNE
2
Condiie
ndeplini
t?
Figura 1.7. Structur repetitiv cu test final
Page 16 of 238
Exemple:
Se vor reprezinta n continuare algoritmii de rezolvare pentru cteva probleme simple (pentru primele 2
probleme se va exemplifica i modul de implementare a acestor algoritmi n limbajul C++).
1. Se citesc 2 valori numerice reale, care reprezint dimensiunile (lungimea i limea unui dreptunghi). S
se calculeze i s se afieze aria dreptunghiului.
2. Se citesc 2 valori reale. S se afiseze valoarea maximului dintre cele 2 numere.
Implementare n limbajul C++:
3. S se citeasc cte 2 numere ntregi, pn la ntlnirea perechii de numere 0, 0. Pentru fiecare pereche de
numere citite, s se afieze maximul.
Algoritm care utilizeaz structur repetitiv cu test iniial:
START
CITETE L, l
aria <- L * l
AFIEAZ
aria
STOP
#include <iostream.h>
void main( )
{ double L, l;
cout<<"Lungime=";
cin>>L;
cout<<"Laime=";
cin>>l;
double aria = L * l;
cout << "Aria="<< aria;
}
ALGORITM
aflare_arie_drept
INCEPUT
CITETE L,l
aria <- L*l
AFIEAZA aria
SFARIT
Implementare:
ALGORITM max_2_nr
INCEPUT
CITESTE a, b
DACA a >= b
ATUNCI max<-a
ALTFEL max<-b
AFISEAZA max
SFARIT
ALGORITM max_2_nr
NCEPUT
CITETE a, b
DACA a >= b
ATUNCI
AFISEAZA a
ALTFEL
AFISEAZA b
SFARIT
#include <iostream.h>
void main( )
{ float a, b;
cout<<"a=";cin>>a;
cout<<"b="; cin>>b;
if (a >= b)
cout<<"Maximul
este:"<<a;
else
cout<<"Maximul este:"<<b; }
#include <iostream.h>
void main( )
{ float a, b, max;
cout<<"a="; cin>>a;
cout<<"b="; cin>>b;
if (a >= b)
max = a;
else max = b;
cout<<"Maximul
este:"<<max;}
Sau:
ALGORITM max_perechi1
INCEPUT
CITESTE a,b
CAT TIMP(a#0sau
b#0)REPETA
INCEPUT
DACA (a>=b)
ATUNCI AFISEAZA
a
ALTFEL AFISEAZA
b
CITESTE a,b
SFARSIT
SFARSIT
ALGORITM max_perechi2
INCEPUT
a 3
CAT TIMP (a#0 sau b#0)
REPETA
INCEPUT
CITESTE a, b
DACA (a>=b)
ATUNCI AFISEAZA
a
ALTFEL AFISEAZA
b
SFARSIT
SFARSIT
Page 17 of 238
Algoritm care utilizeaz structur repetitiv cu test final:
1.3. TEORIA REZOLVRII PROBLEMELOR
Creterea complexitii problemelor supuse rezolvrii automate (cu ajutorul calculatorului) a determinat ca
activitatea de programare s devin, de fapt, un complex de activiti.
Pentru rezolvarea unei probleme trebuie parcurse urmtoarele etape:
Analiza problemei (nelegerea problemei i specificarea cerinelor acesteia). Se stabileste ce trebuie s
fac aplicaia, i nu cum. Se stabilesc datele de intrare (identificarea mediului iniial) i se stabilesc
obiectivele (identificarea mediului final, a rezultatelor);
Proiectarea (conceperea unei metode de rezolvare a problemei printr-o metod algoritmic);
Implementarea (codificarea algoritmului ales ntr-un limbaj de programare);
Testarea aplicaiei obinute (verificarea corectitudinii programului);
Exploatarea i ntreinerea (mentenana, activitatea de modificare a aplicaiei la cererea beneficiarului sau
n urma unor deficiene constatate pe parcursul utilizrii aplicaiei).
n acest context, activitatea de programare a devenit o activitate organizat, definindu-se metode formale de
dezvoltare a fiecrei etape. Etapele descrise anterior alctuiesc ciclul de via al unui produs software i
constituie obiectul de studiu al disciplinei numite ingineria sistemulor de programe (software engineering).
Teoreticienii ingineriei programrii consider c rezolvarea unei probleme se poate face pe 3 direcii:
Rezolvarea orientat pe algoritm (pe aciune), n care organizarea datelor este neesenial;
Rezolvarea orientat pe date, aciunile fiind determinate doar de organizarea datelor;
Rezolvarea orientat obiect, care combin tendinele primelor dou abordri.
Abordarea aleas determin modelarea problemei de rezolvat.
Dintre metodele de proiectare orientate pe algoritm amintim: metoda programrii structurate i metoda
rafinrii succesive. Ambele au ca punct de plecare metoda de proiectare top-down, considerat ca fiind o
metod clasic de formalizare a procesului de dezvoltare a unui produs software.
La baza metodei top-down st descompunerea funcional a problemei P, adica gsirea unui numr de
subprobleme P
1
, P
2
, ... P
n
, cu urmtoarele proprieti:
Fiecare subproblem P
i
(1<=i<=n) poate fi rezolvat independent. Dac nu constituie o problem
elementar, poate fi, la randul ei, descompus;
Fiecare subproblem P
i
este mai simpl dect problema P;
Soluia problemei P se obine prin reuniunea soluiilor subproblemelor P
i
;
Procesul de descompunere se oprete n momentul n care toate subproblemele P
i
obinute sunt
elementare, deci pot fi implementate;
Comunicarea ntre aceste subprobleme se realizeaz prin intermediul parametrilor. Implementarea metodei
top-down ntr-un limbaj de programare se face cu ajutorul modulelor de program (funcii sau proceduri n
limbajul Pascal, funcii n limbajul C).
ALGORITM max_perechi3
INCEPUT
REPETA
INCEPUT
CITETE a,b
DACA (a>=b)
ATUNCI AFIEAZA a
ALTFEL AFIEAZA b
SFARIT
CAT TIMP (a#0 sau b#0)
SFARIT
Descompunerea funcional a unui
program P const n identificarea
funciilor (task-urilor, sarcinilor)
principale ale programului (P
1
, P
2
, P
3
), fiecare dintre aceste funcii
reprezentnd un subprogram (figura
1.8.). Problemele de pe acelai nivel i
sunt independente unele fa de altele.
P
P3
P
2
P
P
1
Page 18 of 238
1.3.1. Etapele rezolvrii unei probleme cu ajutorul calculatorului
S detaliem n continuare etapa de implementare. Dup analiza problemei i stabilirea algoritmului, acesta
trebuie tradus (implementat) ntr-un limbaj de programare.
Srierea (editarea) programului surs.
Programele surs sunt fiiere text care conin instruciuni (cu sintactica i semantica proprii limbajului
utilizat). Programul (fiierul) surs este creat cu ajutorul unui editor de texte i va fi salvat pe disc
(programele surs C primesc, de obicei, extensia .c, iar cele C++, extensia .cpp).
Pentru a putea fi executat, programul surs trebuie compilat i linkeditat.
Compilarea
Procesul de compilare este realizat cu ajutorul compilatorului, care translateaz codul surs n cod obiect
(cod main), pentru ca programul s poat fi neles de calculator. n cazul limbajului C, n prima faz a
compilrii este invocat preprocesorul. Acesta recunoate i analizeaz mai nti o serie de instruciuni
speciale, numite directive procesor. Verific apoi codul surs pentru a constata dac acesta respect
sintaxa i semantica limbajului. Dac exist erori, acestea sunt semnalate utilizatorului. Utilizatorul
trebuie s corecteze erorile (modificnd programul surs). Abia apoi codul surs este translatat n cod de
asamblare, iar n final, n cod main, binar, propriu calculatorului. Acest cod binar este numit cod obiect
i de obicei este memorat ntr-un alt fiier, numit fiier obiect. Fiierul obiect va avea, de obicei, acelai
nume cu fiierul surs i extensia .obj.
Linkeditarea
Dupa ce programul surs a fost translatat n program obiect, el este va fi supus operaiei de linkeditare.
Scopul fazei de linkeditare este acela de a obine o form final a programului, n vederea execuiei
acestuia. Linkeditorul leag modulele obiect, rezolv referinele ctre funciile externe i rutinele din
biblioteci i produce cod executabil, memorat ntr-un alt fisier, numit fiier executabil (acelai nume,
extensia .exe)
Execuia
Lansarea n execuie const n ncrcarea programului executabil n memorie i startarea execuiei sale.
Observaii:
Cod surs
(Preprocesor)
Compilator
Linkeditor
Cod obiect
Cod
executabil
Figura 1.9. Etapele necesare obinerii fiierului executabil
Page 19 of 238
1. Mediile de programare integrate (BORLANDC, TURBOC) nglobeaz editorul, compilatorul,
linkeditorul i depanatorul (utilizat n situaiile n care apar erori la execuie);
2. Dac nu se utilizeaz un mediu integrat, programatorul va apela n mod explicit (n linie de comand) un
editor de texte, compilatorul, linkeditorul. Lansarea n execuie se va face tot din linie de comand.
3. Extensiile specificate pentru fiierele surs, obiect i executabile sunt
NTREBRI I EXERCIII
Chestiuni teoretice
1. Enumerai unitile funcionale componente
ale unui sistem de calcul.
2. Care sunt diferenele ntre soft-ul de aplicaie
i sistemul de operare?
3. Care este deosebirea ntre algoritm i
program?
4. Care sunt proprietile fundamentale ale
algoritmilor?
5. Care sunt modalitile de reprezentare a
algoritmilor?
19
Chestiuni practice
1. Reprezentai algoritmul lui Euclid (pentru calculul celui mai mare divizor comun a 2 numere ntregi)
prin schema logic.
2. Proiectai un algoritm care s rezolve o ecuaie de gradul I (de forma ax + b = 0), unde a,b sunt numere
reale. Discuie dup coeficieni.
3. Proiectai un algoritm care s rezolve o ecuaie de gradul II (de forma ax
2
+ bx + c = 0), unde a,b,c sunt
numere reale. Discuie dup coeficieni.
4. Proiectai un algoritm care s testeze dac un numr ntreg dat este numr prim.
5. Proiectai un algoritm care s afieze toi divizorii unui numr ntreg introdus de la tastatur.
6. Proiectai un algoritm care s afieze toi divizorii primi ai unui numr ntreg introdus de la tastatur.
7. Proiectai un algoritm care calculeaz factorialul unui numr natural dat. (Prin definiie 0!=1)
20
DATE, OPERATORI I EXPRESII
2.1. Limbajele C i C++ 2.5.1. Tipuri de date
2.2. Programe n limbajul C/C++ 2.5.2. Constante
2.3. Preprocesorul 2.5.3. Variabile
2.4. Elemente de baz ale limbajului 2.6. Operatori i expresii
2.4.1. Vocabularul 2.6.1. Operatori
2.4.2. Unitile lexicale 2.6.2. Expresii
2.5. Date n limbajul C/C++ 2.7. Conversii de tip
2.1. LIMBAJELE C I C++
Aa cum comunicarea dintre dou persoane se realizeaz prin intermediul limbajului natural, comunicarea
dintre om i calculator este mijlocit de un limbaj de programare. Limbajele C i C++ sunt limbaje de
programare de nivel nalt.
Limbajul C a aprut n anii 1970 i a fost creat de Dennis Ritchie n laboratoarele AT&T Bell. Limbajul C
face parte din familia de limbaje concepute pe principiile programrii structurate, la care ideea central este
structureaz pentru a stpni o aplicaie. Popularitatea limbajului a crescut rapid datorit eleganei i a
multiplelor posibiliti oferite programatorului (puterea i flexibilitatea unui limbaj de asamblare); ca urmare,
au aprut numeroase alte implementri. De aceea, n anii 80 se impune necesitatea standardizrii acestui
limbaj. n perioada 1983-1990, un comitet desemnat de ANSI (American National Standards Institute) a
elaborat un compilator ANSI C, care permite scrierea unor programe care pot fi portate fr modificri, pe
orice sistem.
Limbajul C++ apare la nceputul anilor 80 i l are ca autor pe Bjarne Stroustrup. El este o variant de
limbaj C mbuntit, mai riguroas i mai puternic, completat cu construciile necesare aplicrii
principiilor programrii orientate pe obiecte (POO). Limbajul C++ pstreaz toate elementele limbajului C,
beneficiind de eficiena i flexibilitatea acestuia. Limbajul C++ este un superset al limbajului C.
Incompatibilitile sunt minore, de aceea, modulele C pot fi ncorporate n proiecte C++ cu un efort minim.
2.2. PROGRAME N LIMBAJUL C/C++
Un program scris n limbajul C (sau C++) este compus din unul sau mai multe fiiere surs. Un fiier surs
este un fiier text care conine codul surs (n limbajul C) al unui program. Fiecare fiier surs conine una
sau mai multe funcii i eventual, referine ctre unul sau mai multe fiiere header (figura 2.1.).
Funcia principal a unui program este numit main. Execuia programului ncepe cu execuia acestei funcii,
care poate apela, la rndul ei, alte funcii. Toate funciile folosite n program trebuie descrise n fiierele
surs (cele scrise de ctre programator), n fiiere header (funciile predefinite, existente n limbaj), sau n
biblioteci de funcii.
Un fiier header este un fiier aflat n sistem sau creat de ctre programator, care conine declaraii i definiii
de funcii i variabile.
Aciunile din fiecare funcie sunt codificate prin instruciuni (figura 2.2.a.). Exist mai multe tipuri de
instruciuni, care vor fi discutate n capitolul urmtor. O instruciune este orice expresie valid (de obicei, o
asignare sau un apel de funcie), urmat de simbolul ;. n figura 2.2.b. este dat un exemplu de instruciune
simpl. Uneori, ca instruciune poate apare instruciunea nul (doar ;), sau instruciunea compus (privit ca
o succesiune de instruciuni simple, ncadrate ntre acoladele delimitatoare {}.
2
Fiiere header
Fiier surs
Program
21
O expresie este o structur corect sintactic, format din operanzi i operatori (figura 2.2.c.).
Pentru a nelege mai bine noiunile prezentate, s considerm un exemplu foarte simplu. Programul urmtor
afieaz pe ecran un mesaj (mesajul Primul meu program). Informaia de prelucrat (de intrare) este nsui
mesajul (o constant ir), iar prelucrarea ei const n afiarea pe ecran.
Exemplu:
#include <iostream.h> // linia 1
void main() // linia 2 - antetul funciei main
{ /* linia 3 - nceputul corpului funciei, a unei intruciuni
compuse */
cout<<Primul meu program in limbajul C++\n; // linia 5
} // linia6-sfritul corpului funciei
Prima linie este o directiv preprocesor (indicat de simbolul #) care determin includerea n fiierul surs a
fiierului header cu numele iostream.h. Acest header permite realizarea afirii pe monitor.
Programul conine o singur funcie, funcia principal, numit main, al crui antet (linia 2) indic:
- tipul valorii returnate de funcie (void, ceea ce nseamn c funcia nu returneaz nici o valoare)
- numele funciei (main)
- lista argumentelor primite de funcie, ncadrat de cele 2 paranteze rotunde.
Funciile comunic ntre ele prin argumente. Aceste argumente reprezint datele de intrare ale funciei. n
cazul nostru, nu avem nici un argument n acea list, deci puteam s scriem antetul funciei i astfel:
Instruciunea1
Instruciunea2
Instruciunea3
.
.
.
.
FUNCII
Expresie;
INSTRUCIUNI
Operatori
Operanzi
EXPRESII
Figura 2.2. Funcie, instruciune, expresie
2.2.a. 2.2.b.
2.2.c.
22
void main(void)
Ceea ce urmeaz dup simbolul //, pn la sfritul liniei, este un comentariu, care va fi ignorat de ctre
compilator. Comentariul poate conine un text explicativ; informaii lmuritoare la anumite aspecte ale
problemei sau observaii. Dac vrem s folosim un comentariu care cuprinde mai multe linii, vom delimita
nceputul acestuia indicat prin simbolulurile /*, iar sfritul - prin */ (vezi liniile 3, 4). Introducerea
comentariilor n programele surs uureaz nelegerea acestora. n general, se recomand introducerea unor
comentarii dup antetul unei funciei, pentru a preciza prelucrrile efectuate n funcie, anumite limite
impuse datelor de intrare, etc.
nceputul i sfritul corpului funciei main sunt indicate de cele dou acoalade { (linia3) i }(linia 6).
Corpul funciei (linia 5) este format dintr-o singur instruciune, care implementeaz o operaie de scriere.
Cuvantul cout este un cuvnt predefinit al limbajului C++ - console output - care desemneaz dispozitivul
logic de iesire; simbolul << este operatorul de transfer a informaiei. Folosite astfel, se deschide un canal de
comunicaie a datelor ctre dispozitivul de ieire, n cazul acesta, monitorul. Dup operator se specific
informaiile care vor fi afiate (n acest exemplu, un ir de caractere constant). Faptul c este un ir constant
de caractere este indicat de ghilimelele care l ncadreaz. Pe ecran va fi afiat fiecare caracter din acest ir,
cu excepia grupului \n. Dei grupul este format din dou caractere, acesta va fi interpretat ca un singur
caracter - numit caracter escape - care determin poziionarea cursorului la nceputul urmtoarei linii. O
secven escape (cum este \n) furnizeaz un mecanism general i extensibil pentru reprezentarea
caracterelor invizibile sau greu de obinut. La sfritul instruciunii care implementeaz operaia de scriere,
apare ; .
2.3. PREPROCESORUL
Aa cum am menionat n capitolul 1.3., n faza de compilare a fiierului surs este invocat nti
preprocesorul. Acesta trateaz directivele speciale - numite directive preprocesor - pe care le gsete n
fiierul surs. Directivele preprocesor sunt identificate prin simbolul #, care trebuie s fie primul caracter,
diferit de spaiu, dintr-o linie. Directivele preprocesor sunt utilizate la includerea fiierelor header, la
definirea numelor constantelor simbolice, la definirea macro-urilor, sau la realizarea altor funcii (de
exemplu, compilarea condiionat), aa cum ilustreaz exemplele urmtoare:
Includerea fiierelor header n codul surs:
Exemplul1:
#include <stdio.h>
Cnd procesorul ntlnete aceast linie, datorit simbolului #, o recunoate ca fiind o directiv
preprocesor, localizeaz fiierul header indicat (parantezele unghiulare < > indic faptul c este
vorba de un fiier header sistem).
Exemplul 2:
#include "headerul_meu.h"
Numele fiierului header inclus ntre ghilimele, indic faptul c headerul_meu.h este un fiier
header creat de utilizator. Preprocesorul va cuta s localizeze acest fiier n directorul curent de
lucru al utilizatorului. n cazul n care fiierul header nu se afl n directorul curent, se va indica i
calea ctre acesta.
Exemplul 3:
#include "c:\\bc\\head\\headerul_meu.h"
n acest exemplu, pentru interpretarea corect a caracterului backslash \, a fost necesar "dublarea"
acestuia, din motive pe care le vom prezenta n paragraful 2.5.2.4.
Asignarea de nume simbolice constantelor:
23
Exemplu:
#define TRUE 1
#define FALSE 0
Tratarea acestor directive preprocesor are ca efect asignarea (atribuirea) valorii ntregi 1 numelui
(constantei simbolice) TRUE, i a valorii 0 numelui simbolic FALSE. Ca urmare, naintea compilrii
propriu-zise, n programul surs, apariiile numelor TRUE i FALSE vor fi nlocuite cu valorile 1,
respectiv 0.
Macrodefiniii:
Directiva #define este folosit i n macrodefiniii. Macrodefiniiile permit folosirea unor nume
simbolice pentru expresiile indicate n directiv.
Exemplu:
#define NEGATIV(x) -(x)
ntre numele macrodefiniiei i paranteza stng ( NEGATIV() ) nu sunt permise spaii albe. La
ntalnirea n programul surs a macrodefiniiei NEGATIV, preprocesorul subtituie argumentul
acesteia cu expresia (negativarea argumentului). Macrodefiniia din exemplu poate fi folosit n
programul surs astfel: NEGATIV(a+b). Cnd preprocesorul ntlnete numele expresiei,
subtituie literalii din parantez, a+b, cu argumentul din macrodefiniie, x, obinndu-se -(a+b).
Dac macrodefiniia ar fi fost de forma:
#define NEGATIV(x) -x
NEGATIV(a+b) ar fi fost tratat ca -a+b.
2.4. ELEMENTE DE BAZ ALE LIMBAJULUI
2.4.1. VOCABULARUL
n scrierea programelor n limbajul C/C++ pot fi folosite doar anumite simboluri care alctuiesc alfabetul
limbajului. Acesta cuprinde:
Literele mari sau mici de la A la Z (a-z);
Caracterul subliniere ( _ underscore), folosit, de obicei, ca element de legtura ntre cuvintele compuse;
Cifrele zecimale (0-9);
Simboluri speciale:
Caractere:
operatori (Exemple: +, *, !=);
delimitatori (Exemple: blank (spaiu), tab \t, newline \n, cu rolul de a separa cuvintele);
Grupuri (perechi de caractere).
Grupurile de caractere, numire adesea separatori, pot fi:
( ) - ncadreaz lista de argumente ale unei funcii sau sunt folosite n expresii pentru
schimbarea ordinii de efectuare a operaiilor (n ultimul caz, fiind operator);
{ } - ncadreaz instruciunile compuse;
// - Indic nceputul unui comentariu care se poate ntinde pn la sfritul liniei;
/* */ - Indic nceputul i sfritul unui comentariu care poate cuprinde mai multe linii;
" " - ncadreaz o constant ir (un ir de caractere);
' ' - ncadreaz o constant caracter (un caracter imprimabil sau o secven escape).
2.4.2. UNITILE LEXICALE
Unitile lexicale (cuvintele) limbajului C/C++ reprezint grupuri de caractere cu o semnificaie de sine
stttoare. Acestea sunt:
Identificatori;
Cuvinte cheie ale limbajului;
24
Identificatorii reprezint numele unor date (constante sau variabile), sau ale unor funcii. Identificatorul este
format dintr-un ir de litere, cifre sau caracterul de subliniere (underscore), trebuie s nceap cu o liter sau
cu caracterul de subliniere i s fie sugestivi.
Exemple: vitez, greutate_net, Viteza, Viteza1, GreutateNet
Identificatorii pot conine litere mici sau mari, dar limbajul C++ este senzitiv la majuscule i minuscule
(case-sensitive). Astfel, identificatorii viteza i Viteza sunt diferii.
Nu pot fi folosii ca identificatori cuvintele cheie. Identificatorii pot fi standard (ca de exemplu numele unor
funcii predefinite: scanf, clear, etc.) sau alei de utilizator.
Cuvintele cheie sunt cuvinte ale limbajului, mprumutate din limba englez, crora programatorul nu le
poate da o alt utilizare. Cuvintele cheie se scriu cu litere mici i pot reprezenta:
Tipuri de date (Exemple: int, char, double);
Clase de memorare (Exemple: extern, static, register);
Instruciuni (Exemple: if, for, while);
Operatori (Exemplu: sizeof).
Sensul cuvintelor cheie va fi explicat pe masur ce vor fi prezentate construciile n care acestea apar.
2.5. DATE N LIMBAJUL C/C++
Aa cum s-a vzut n capitolul 1, un program realizeaz o prelucrare de informaie. Termenul de prelucrare
trebuie s fie considerat ntr-un sens foarte general (de exemplu, n programul prezentat n paragraful 2.2.,
prelucrarea se referea la un text i consta n afiarea lui). n program datele apar fie sub forma unor constante
(valori cunoscute anticipat, care nu se modific), fie sub forma de variabile. Constantele i variabilele sunt
obiectele informaionale de baz manipulate ntr-un program.
Fiecare categorie de date este caracterizat de atributele:
Nume;
Valoare;
Tip;
Clasa de memorare.
De primele trei tipuri de atribute ne vom ocupa n continuare, urmnd ca de atributul clas de memorare s
ne ocupm n paragraful 6.8.
Numele unei date
Numele unei date este un identificator i, ca urmare, trebuie s respecte regulile specifice identificatorilor.
Deasemenea, numrul de caractere care intr n compunerea unui identificator este nelimitat, ns, implicit,
numai primele 32 de caractere sunt luate n considerare. Aceasta nseamn c doi identificatori care au
primele 32 de caractere identice, difereniindu-se prin caracterul 33, vor fi considerai identici.
2.5.1. TIPURI DE DATE
Tipul unei date const ntr-o mulime de valori pentru care s-a adoptat un anumit mod de reprezentare n
memoria calculatorului i o mulime de operatori care pot fi aplicai acestor valori. Tipul unei date determin
lungimea zonei de memorie ocupat de acea dat. n general, lungimea zonei de memorare este dependent
de calculatorul pe care s-a implementat compilatorul. Tabelul 2.1. prezint lungimea zonei de memorie
ocupat de fiecare tip de dat pentru compilatoarele sub MS-DOS i UNIX/LINUX.
Tipurile de baz sunt:
char un singur octet (1 byte=8 bii), capabil s conin codul unui caracter din setul
local de caractere;
int numr ntreg, reflect n mod tipic mrimea natural din calculatorul utilizat;
float numr real, n virgul mobil, simpl precizie;
double numr real, n virgul mobil, dubl precizie.
25
n completare exist un numr de calificatori, care se pot aplica tipurilor de baz char, int, float sau
double: short, long, signed i unsigned. Astfel, se obin tipurile derivate de date. Short i
long se refer la mrimea diferit a ntregilor, iar datele de tip unsigned int sunt ntotdeauna
pozitive. S-a intenionat ca short i long s furnizeze diferite lungimi de ntregi, int reflectnd
mrimea cea mai "natural" pentru un anumit calculator. Fiecare compilator este liber s interpreteze
short i long n mod adecvat propriului hardware; n nici un caz, ns, short nu este mai lung dect
long. Toi aceti calificatori pot aplicai tipului int. Calificatorii signed (cel implicit) i unsigned
se aplic tipului char. Calificatorul long se aplic tipului double. Dac ntr-o declaraie se omite tipul
de baz, implicit, acesta va fi int.
Tabelul 2.1.
Tip Lungimea zonei
de memorie
ocupate (n bii)
Descriere
MS-
DOS
UNIX
LINUX
char 8 8 Valoarea unui singur caracter; poate fi ntlnit n expresii cu
extensie de semn
unsigned char 8 8 Aceeai ca la char, far extensie de semn
signed char 8 8 Aceeai ca la char, cu extensie de semn obligatorie
int 16 32 Valoare ntreag
long 32 64 Valoare ntreag cu precizie mare
(long int)
long long int 32 64 Valoare ntreag cu precizie mare
short int 16 32 Valoare ntreag cu precizie mic
unsigned int 16 32 Valoare ntreag, fr semn
unsigned long
int
32 64 Valoare ntreag, fr semn
float 32 32 Valoare numeric cu zecimale, simpl precizie (6 )
double 64 64 Valoare numeric cu zecimale, dubl precizie (10 )
long double 80 128 Valoare numeric cu zecimale, dubl precizie
S considerm, de exmplu, tipul int, folosit pentru date ntregi (pozitive sau negative). Evident c mulimea
valorilor pentru acest tip va fi, de fapt, o submulime finit de numere ntregi. Dac pentru memorarea unei
date de tip int se folosesc 2 octei de memorie, atunci valoarea maxim pentru aceasta va fi
2
1
2
16
- 1, deci
2
15
- 1 (32767), iar valoarea minim va fi -
2
1
2
16
, deci -2
15
(-32768). ncercarea de a calcula o expresie
de tip int a crei valoare se situeaz n afara acestui domeniu va conduce la o eroare de execuie.
Mulimea valorilor pentru o dat de tip unsigned int (ntreg fr semn) va fi format din numerele
ntregi situate n intervalul [0, 2
16
- 1].
n header-ul <values.h> sunt definite constantele simbolice (cum ar fi: MAXINT, MAXSHORT, MAXLONG,
MINDOUBLE, MINFLOAT, etc.) care au ca valoare limitele inferioar i superioar ale intervalului de valori
pentru tipurile de date enumerate. (de exemplu MAXINT reprezint valoarea ntregului maxim care se poate
memora, etc. )
Fr a detalia foarte mult modul de reprezentare a datelor reale (de tip float sau double), vom sublinia
faptul c, pentru acestea, este important i precizia de reprezentare. Deoarece calculatorul poate reprezenta
doar o submulime finit de valori reale, n anumite cazuri, pot apare erori importante.
Numerele reale pot fi scrise sub forma: N = mantisa baza
exponent
26
unde:baza reprezint baza sistemului de numeraie; mantisa (coeficientul) este un numr fracionar
normalizat ( n faa virgulei se afl 0, iar prima cifr de dup virgul este diferit de zero); exponentul
este un numr ntreg. Deoarece forma intern de reprezentare este binar, baza=2. n memorie vor fi
reprezentate doar mantisa i exponentul. Numrul de cifre de dup virgul determin precizia de exprimare a
numrului. Ce alte cuvinte, pe un calculator cu o precizie de 6 cifre semnificative, dou valori reale care
difer la a 7-a cifr zecimal, vor avea aceeai reprezentare. Pentru datele de tip float, precizia de
reprezentare este 6; pentru cele de tip double, precizia este 14, iar pentru cele de tip long double, precizia este
20.
Lungimea zonei de memorie ocupate de o dat de un anumit tip (pe ci octei este memorat data) poate fi
aflat cu ajutorul operatorului sizeof.
Exemplu:
cout<<"Un int este memorat pe "<<sizeof(int)<<"octeti.\n";
Instruciunea are ca efect afiarea pe monitor a mesajului: Un int este memorat pe 2 octei.
2.5.2. CONSTANTE
O constant este un literal (o form extern de reprezentare) numeric, caracter sau ir de caractere. Numele
i valoarea unei constante sunt identice. Valoarea unei constante nu poate fi schimbat n timpul execuiei
programului n care a fost utilizat. Tipul i valoarea ei sunt determinate n mod automat, de ctre
compilator, pe baza caracterelor care compun literalul.
2.5.2.1. Constante ntregi
Constantele ntregi sunt literali numerici (compui din cifre), fr punct zecimal.
Constante ntregi n baza 10, 8 sau 16
Constante ntregi n baza 10
Exemple:
45
-78 // constante ntregi decimale (n baza 10), tip int
Constante ntregi octale
Dac n faa numrului apare cifra zero (0), acest lucru indic faptul c acea constant este de tipul
int, in baza opt (constant octal).
Exemple:
056
077 // constante ntregi octale, tip int
Constante ntregi hexagesimale
Dac n faa numrului apar caracterele zero (0) i x (sau X), acest lucru indic faptul c acea
constant este de tipul int, n baza 16 (constant hexagesimal). Amintim c n baza 16 cifrele sunt:
0-9, A (sau a) cu valoare 10, B (sau b) cu valoare 11, C (sau c) cu valoare 12, D (sau d) cu valoare
13, E (sau e) cu valoare 14, F (sau f) cu valoare 15.
Exemple:
0x45
0x3A
0Xbc // constante ntregi hexagesimale, tip int
Constante ntregi, de tipuri derivate
Dac secvena de cifre este urmat de L sau l, tipul constantei este long int.
Exemple:
145677L
897655l // tip decimal long int
Dac secvena de cifre este urmat de U sau u, tipul constantei este unsigned int.
Exemple:
65555u
Dac secvena de cifre este urmat de U (u) i L (l), tipul constantei este unsigned long int.
27
Exemple: 7899UL //tip decimal unsigned long int
2.5.2.2. Constante numerice, reale
Dac o constant numeric conine punctul zecimal, ea este de tipul double.
Exemplu:
3.1459 //tip double
Dac numrul este urmat de F sau f, constante este de tip float.
Dac numrul este urmat de L sau l, este de tip long double.
Exemplu:
0.45f //tip float
9.788L //tip long double
Constante reale n format tiinific
Numrul poate fi urmat de caracterul e sau E i de un numr ntreg, cu sau fr semn. n acest caz,
constanta este n notaie tiinific. n aceast form extern de reprezentare, numrul din faa literei E
reprezint mantisa, iar numrul ntreg care urmeaz caracterului E reprezint exponentul. In forma
extern de reprezentare, baza de numeraie este 10, deci valoarea constantei va fi dat de mantisa10
onent exp
.
Exemplu:
1.5e-2 //tip double, n notaie tiinific, valoare 1.510
2
Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
#include <values.h>
#define PI 3.14359
int main()
{
cout<<"Tipul int memorat pe: "<<sizeof(int)<<" octeti\n";
cout<<"Tipul int memorat pe: "<<sizeof(23)<<" octeti\n"; //23-
const. zecimala int
cout<<"Int maxim="<<MAXINT<<\n;
//const. simbolice MAXINT, MAXLONG, etc. - definite in <values.h>
cout<<"Const. octala 077 are val decimala:"<<077<<\n;
cout<<"Const. hexagesimala d3 are val decimala:"<<0xd3<<\n;
cout<<"Tipul unsigned int memorat pe:"<<sizeof(unsigned
int)<<" octeti\n";
cout<<"Tipul unsigned int memorat pe: "<<sizeof(23U)<<"
octeti\n";
cout<<"Tipul unsigned int memorat pe: "<<sizeof(23u)<<"
octeti\n";
cout<<"Tipul long int memorat pe: "<<sizeof(long int)<<"
octeti\n";
cout<<"Tipul long int memorat pe: "<<sizeof(23L)<<"
octeti\n";
cout<<"Tipul long int memorat pe: "<<sizeof(23l)<<"
octeti\n";
//23L sau 23l-const. decimala long int
cout<<"Long int maxim="<<MAXLONG<<\n;
cout<<"Tipul unsigned long memorat pe:";
cout<<sizeof(unsigned long int)<<" octeti\n";
28
cout<<"Tipul unsigned long memorat pe: "<<sizeof(23UL)<<"
octeti\n";
cout<<"Tipul unsigned long memorat pe: "<<sizeof(23ul)<<"
octeti\n";
//23UL sau 23ul-const. decimala unsigned long int
cout<<"Tipul long long int memorat pe: ";
cout<<sizeof(long long int)<<" octeti\n";
cout<<"Tipul long long int memorat pe: "<<sizeof(d)<<"
octeti\n";
cout<<"Tipul short int memorat pe: "<<sizeof(short int)<<"
octeti\n";
cout<<"Short int maxim="<<MAXSHORT<<\n;
cout<<"Tipul float memorat pe: "<<sizeof(float)<<" octeti\n";
cout<<"Tipul float memorat pe: "<<sizeof(23.7f)<<" octeti\n";
//23.7f-const. decimala float
cout<<"Float maxim="<<MAXFLOAT<<\n;
cout<<"Float minim="<<MINFLOAT<<\n;
cout<<"Tipul double memorat pe: "<<sizeof(double)<<"
octeti\n";
cout<<"Tipul double memorat pe: "<<sizeof(23.7)<<" octeti\n";
//23.7-const. decimala double
cout<<"Const. decim. doubla in notatie stiintifica:"<<23.7e-
5<<\n;
cout<<Const. PI este:<<PI<<\n;
cout<<Constanta PI este memorata
pe:<<sizeof(PI)<<octeti\n:
cout<<"Double maxim="<<MAXDOUBLE<<\n<<"Double
minim="<<MINDOUBLE<<\n;
cout<<"Tipul long double memorat pe: "<<sizeof(long
double)<<" octeti\n";
cout<<"Tipul long double memorat pe: "<<sizeof(23.7L)<<"
octeti\n";
//23.7L-const. decimala long double
cout<<"Cifra A din HEXA are val.:"<<0xA<<"\n";
cout<<"Cifra B din HEXA are val.:"<<0XB<<"\n";
cout<<"Cifra C din HEXA are val.:"<<0xc<<"\n";
cout<<" Cifra D din HEXA are val.:"<<0xD<<"\n";
cout<<" Cifra E din HEXA are val.:"<<0XE<<"\n";
cout<<" Cifra F din HEXA are val.:"<<0xf<<"\n";
cout<<"Val. const. hexa 0x7ac1e este: "<<0x7ac1e<<'\n';
cout<<"Val. const. octale 171 este: "<<0171<<'\n';
cout<<"O const. octala se memoreaza pe "<<sizeof(011)<<"
octeti\n";
cout<<"O const.oct.long se mem pe ";cout<<sizeof(011L)<<"
octeti\n";}
2.5.2.3. Constante caracter
Constantele caracter sunt ncadrate ntre apostroafe.
Exemplu:
'a' //tip char
O constant caracter are ca valoare codul ASCII al caracterului pe care l reprezint.
29
Acest set de caractere are urmtoarele proprieti:
Fiecrui caracter i corespunde o valoare ntreag distinct (ordinal);
Valorile ordinale ale literelor mari sunt ordonate i consecutive ('A' are codul ASCII 65, 'B' - codul 66,
'C' - codul 67, etc.);
Valorile ordinale ale literelor mici sunt ordonate i consecutive ('a' are codul ASCII 97, 'b' - codul 98, 'c'
- codul 99, etc.);
Valorile ordinale ale cifrelor sunt ordonate i consecutive ('0' are codul ASCII 48, '1' - codul 49, '2' -
codul 50, etc.).
Constante caracter corespunztoare caracterelor imprimabile
O constant caracter corespunztoare unui caracter imprimabil se reprezint prin caracterul respectiv
inclus ntre apostroafe.
Exemplu:
Constant caracter Valoare
A 65
a 97
0 48
* 42
Excepii de la regula de mai sus le constituie caracterele imprimabile apostrof (') i backslash (\).
Caracterul backslash se reprezint: '\\'. Caracterul apostrof se reprezint: '\''.
Constante caracter corespunztoare caracterelor neimprimabile
Pentru caracterele neimprimabile, se folosesc secvene escape. O secven escape furnizeaz un
mecanism general i extensibil pentru reprezentarea caracterelor invizibile sau greu de obinut. n
tabelul 2.2. sunt prezentate cteva caractere escape utilizate frecvent.
Tabelul 2.2.
Constant
caracter
Valoare
(Cod ASCII)
Denumirea
caracterului
Utilizare
\n 10 LF rnd nou (Line Feed)
\t 9 HT tabulator orizontal
\r 13 CR poziioneaz cursorul n coloana 1 din rndul curent
\f 12 FF salt de pagin la imprimant (Form Feed)
\a 7 BEL activare sunet
O constant caracter pentru o secven escape poate apare ns, i sub o form n care se indic codul ASCII,
n octal, al caracterului dorit:
\ddd unde d este o cifr octal.
Exemple:
\11 (pentru \t)
reprezint constanta caracter backspace, cu codul 9 n baza 10, deci codul 11 n baza 8.
\15 (pentru \r)
reprezint constanta caracter CR, cu codul 13 n baza 10, deci codul 11 n baza 8.
Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void main(void)
{
cout<<"Un caracter este memorat pe "<<sizeof(char)<<"
octet\n";
cout<<"Caracterul escape \\n este memorat pe ";
cout<<sizeof('\n')<<" octet\n";
cout<<"Caracterul escape '\\n\' este memorat pe
"<<sizeof('\n');
cout<<" octet\n";
30
cout<<"Caracterul '9' este memorat pe "<<sizeof('9')<<"
octet\n";
cout<<'B';cout<<' ';cout<<'c';cout<<'\t';
cout<<'\t';cout<<'9';cout<<'\b';cout<<'\a';
cout<<'L';cout<<'\v';cout<<'L';
cout<<'\'';cout<<'\t';cout<<'\"';cout<<'\\';cout<<'\n';
cout<<'\a';cout<<'\7';
}
2.5.2.4. Constante ir de caractere
Constanta ir este o succesiune de zero sau mai multe caractere, ncadrate de ghilimele. n componena unui
ir de caractere, poate intra orice caracter, deci i caracterele escape. Lungimea unui ir este practic
nelimitat. Dac se dorete continuarea unui ir pe rndul urmtor, se folosete caracterul backslash.
Caracterele componente ale unui ir sunt memorate ntr-o zon continu de memorie (la adrese succesive).
Pentru fiecare caracter se memoreaz codul ASCII al acestuia. Dup ultimul caracter al irului, compilatorul
plaseaz automat caracterul NULL (\0), caracter care reprezint marcatorul sfritului de ir. Numrul de
octei pe care este memorat un ir va fi, deci, mai mare cu 1 dect numrul de caractere din ir.
Exemple:
Acesta este un ir de caractere //constant ir memorat pe 32 octei
ir de caractere continuat\
pe rndul urmtor! //constant ir memorat pe 45 octei
ir \t cu secvene escape\n //constant ir memorat pe 26 octei
\n //constant caracter memorat pe un octet
\n //constanta ir memorat pe 2 octei (codul caracterului escape i terminatorul de ir)
a\a4 /*ir memorat pe 4 octei:
Pe primul octet: codul ASCII al caracterului a
Pe al doilea octet: codul ASCII al caracterului escape \a
Pe al treilea octet: codul ASCII al caracterului 4
Pe al patrulea octet: terminatorul de ir NULL, cod ASCII 0 */
\\ASCII\\ /*ir memorat pe 8 octei:
Pe primul octet: codul ASCII al caracterului backslah
Pe al doilea octet: codul ASCII al caracterului A
Pe al treilea octet: codul ASCII al caracterului S
Pe al patrulea octet: codul ASCII al caracterului S
Pe al 6-lea octet: codul ASCII al caracterului I
Pe al 7-lea octet: codul ASCII al caracterului I
Pe al 8-lea octet: codul ASCII al caracterului backslah
Pe al 9-ea octet: terminatorul de ir NULL, de cod ASCII 0 */
1\175a /*ir memorat pe 4 octei:
Primul octet: Codul ASCII al caracterul 1
Al 2-lea octet: codul ASCII 125 (175 in octal) al caracterului }
Al 3-lea octet: codul ASCII al caracterului a
Al 4-lea octet: codul ASCII 0 pentru terminatorul irului */
Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void main()
{ cout<<"irul \"Ab9d\" este memorat pe:"<<sizeof("Ab9d")<<"
octei\n";
cout<<"irul \"Abcd\\t\" este memorat
pe:"<<sizeof("Abcd\t")<<" octei\n";
31
cout<<"irul \"\n\" este memorat pe "<<sizeof("\n")<<"
octei\n";
cout<<"irul \"\\n\" este memorat pe "<<sizeof("\n")<<"
octei\n";
cout<<"irul \"ABCDE\" se memoreaz pe "<<sizeof("ABCDE")<<"
octei\n";}
2.5.3. VARIABILE
Spre deosebire de constante, variabilele sunt date (obiecte informaionale) ale cror valori se pot modifica n
timpul execuiei programului. i variabilele sunt caracterizate de atributele nume, tip, valoare i clas de
memorare. Variabilele sunt nume simbolice utilizate pentru memorarea valorilor introduse pentru datele de
intrare sau a rezultatelor. Dac la o constant ne puteam referi folosind caracterele componente, la o variabil
ne vom referi prin numele ei. Numele unei variabile ne permite accesul la valoarea ei, sau schimbarea valorii
sale, dac este necesar acest lucru. Numele unei variabile este un identificator ales de programator. Ca
urmare, trebuie respectate regulile enumerate n seciunea identificatori.
Dac o dat nu are legturi cu alte date (de exemplu, relaia de ordine), vom spune c este o dat izolat. O
dat izolat este o variabil simpl. Dac datele se grupeaz ntr-un anumit mod (n tablouri - vectori,
matrici - sau structuri), variabilele sunt compuse (structurate).
n cazul constantelor, n funcie de componena literalului, compilatorul stabilea, automat, tipul constantei. n
cazul variabilelor este necesar specificarea tipului fiecreia, la declararea acesteia. Toate variabilele care vor
fi folosite n program, trebuie declarate nainte de utilizare.
2.5.3.1. Declararea variabilelor
Modul general de declarare a variabilelor este:
tip_variabile list_nume_variabile;
Se specific tipul variabilei(lor) i o list format din unul sau mai muli identificatori ai variabilelor de tipul
respectiv. ntr-un program n limbajul C++, declaraiile de variabile pot apare n orice loc n programul
surs. La declararea variabilelor, se rezerv n memorie un numr de octei corespunztor tipului variabilei,
urmnd ca ulterior, n acea zon de memorie, s fie depus (memorat, nregistrat) o anumit valoare.
Exemple:
int i, j;/*declararea var. simple i, j, de tip int. Se rezerv pentru i i j cte 16 bii (2octei)*/
char c; /* declararea variabilei simple c, de tip char. Se rezerv un octet. */
float lungime; /* declararea variabilei simple lungime; se rezerv 4 octei */
2.5.3.2. Iniializarea variabilelor n declaraii
n momentul declarrii unei variabile, acesteia i se poate da (asigna, atribui) o anumit valoare. n acest caz,
n memorie se rezerv numrul de locaii corespunztor tipului variabilei respective, iar valoarea va fi depus
(memorat) n acele locaii.
Forma unei declaraii de variabile cu atribuire este:
tip_variabil nume_variabil=expresie;
Se evalueaz expresia, iar rezultatul acesteia este asignat variabilei specificate.
Exemple:
char backslash=\\; //declararea i iniializarea variabilei simple backslash
int a=7*9+2; /* declararea variabilei simple a, de tip int i iniializarea ei cu valoarea 65*/
float radiani, pi=3.14;/*declararea variabilei radiani;declararea i iniializarea var.
pi*/
short int z=3; //declararea i iniializarea variabilei simple z
32
char d=\011;
char LinieNoua=\n;
double x=9.8, y=0;
Compilatorul C++ furnizeaz mecanisme care permit programatorului s influeneze codul generat la
compilare, prin aa-numiii calificatori.
Acetia sunt:
const;
volatile.
Calificatorul const asociat unei variabile, nu va permite modificarea ulterioar a valorii acesteia, prin
program (printr-o atribuire). Calificatorul volatile (cel implicit) are efect invers calificatorului const. Dac
dup calificator nu este specificat tipul datei, acesta este considerat tipul implicit, adic int.
Exemple:
const float b=8.8;
volatile char terminator;terminator=@;terminator=*;
//permis
b=4/5; //nepermisa modificarea valorii variabilei b
const w; volatile g; //w, g de tip int, implicit
2.5.3.3. Operaii de intrare/ieire
Limbajele C/C++ nu posed instruciuni de intrare/ieire, deci de citire/scriere (ca limbajul PASCAL, de
exemplu). n limbajul C aceste operaii se realizeaz cu ajutorul unor funcii (de exemplu, printf i scanf), iar
n limbajul C++ prin suprancrcarea operatorilor (definirea unor noi proprieti ale unor operatori existeni,
fr ca proprietile anterioare s dispar), mai precis a operatorilor >> i << . Vom folosi n continuare
abordarea limbajului C++, fiind, n momentul de fa, mai simpl. n limbajul C++ sunt predefinite
urmtoarele dispozitive logice de intrare/ieire:
cin - console input - dispozitivul de intrare (tastatura);
cout - console output - dispozitivul de ieire (monitorul).
Aa cum se va vedea n capitolul 9, cin i cout sunt, de fapt, obiecte (predefinite). Transferul informaiei
se realizeaz cu operatorul >> pentru intrare i operatorul << pentru ieire. Utilizarea dispozitivelor de
intrare/ieire cu operatorii corespunztori determin deschiderea unui canal de comunicaie a datelor ctre
dispozitivul respectiv. Dup operator se specific informaiile care vor fi citite sau afiate.
Exemple:
cout << var; /* afieaz valoarea variabilei var pe monitor*/
cin >> var; /* citete valoarea variabilei var de la tasatatur */
Sunt posibile operarii multiple, de tipul:
Exemple:
cout << var1 << var2 << var3;
cin >> var1 >> var2 >> var3;
n acest caz, se efectueaz succesiv, de la stnga la dreapta, scrierea, respectiv citirea valorilor variabilelor
var1, var2 i var3.
Operatorul >> se numete operator extractor (extrage valori din fluxul datelor de intrare, conform tipului
acestora), iar operatorul << se numete operator insertor (insereaz valori n fluxul datelor de ieire,
conform tipului acestora). Tipurile de date citite de la tastatur pot fi toate tipurile numerice, caracter sau ir
de caractere. Tipurile de date transferate ctre ieire pot fi: toate tipurile numerice, caracter sau ir de
caractere. Operanzii operatorului extractor (>>) pot fi doar nume de variabile. Operanzii operatorului
insertor (<<) pot fi nume de variabile (caz n care se afieaz valoarea variabilei), constante sau expresii.
Utilizarea dispozitivelor i operatorilor de intrare/ieire n C++ impune includerea fiierului
iostream.h.
33
Exemple:
char c;
cout<<"Astept un caracter:"; //afiarea constantei ir de caractere, deci a
mesajului
cin>>c; //citirea valorii variabilei c, de tip caracter
int a, b, e; double d;
cin>>a>>b>>e>>d; //citirea valorilor variabilelor a, b, e, d de tip int, int, int,
double
cout<<"a="<<a<<"Valoarea expresiei a+b este:"<<a+b<<'\n';
2.6. OPERATORI I EXPRESII
Datele (constante sau variabile) legate prin operatori, formeaz expresii (figura 2.4). Operatorii care pot fi
aplicai datelor (operanzilor) depind de tipul operanzilor, datorit faptului c tipul unei date const ntr-o
mulime de valori pentru care s-a adoptat un anumit mod de reprezentare n memoria calculatorului i o
mulime de operatori care pot fi aplicai acestor valori.
Operatorii pot fi:
unari (necesit un singur operand);
binari (necesit doi operanzi);
ternari (trei operanzi).
O expresie este o combinaie corect din punct de vedere sintactic, format din operanzi i operatori.
Expresiile, ca i operanzii, au tip i valoare.
2.6.1. OPERATORI
Operatorul unar adres &, aplicat identificatorului unei variabile, furnizeaz adresa la care este memorat
aceasta. Poate fi aplicat oricrui tip de date i se mai numete operator de refereniere.
Exemplu:
int a;
cout<<"Adresa la care este memorata variabila a este:"<<&a;
Operatorul de atribuire (de asignare) este un operator binar care se aplic tuturor tipurilor de variabile.
Este folosit sub formele urmtoare:
nume_variabil=expresie;
sau: expresie1=expresie2;
Se evalueaz expresia din membrul drept, iar valoarea acesteia este atribuit variabilei din membrul stng.
Dac tipurile membrilor stng i drept difer, se pot realiza anumite conversii, prezentate n paragraful 2.7.
Exemplu:
float x; int a,b; x=9.18;
a=b=10;
int s; s=a+20*5; //rezultat: s=110
s=x+2; //rezultat s=11, deoarece s este int.
Aa cum se observ n linia a 2-a din exemplul precedent, operatorul de atribuire poate fi utilizat de mai
multe ori n aceeai expresie. Asociativitatea operatorului are loc de la dreapta la stnga. Astfel, mai nti
b=10, apoi a=b.
Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void main()
{
34
float x,y=4.25; char car=A; int a,b,c;
cout<<Val. lui y este:<<y<<\n; //Afiare: Val. lui y
este:4.25
x=y; cout<<Val. lui x este:<<x<<\n; //Afiare: Val. lui x este:4.25
a=x;cout<<Val.lui a este:<<a<<\n; //Afiare:Val. lui a este:4, deoarece a
de tip int!!!
c=b=a; cout<<b=<<b<<\tc=<<c<<\n; //Afiare: b=4 c=4
cout<<Introducei val. lui c:; cin>>c; // citire val. pentru
c
cout<<Val. lui c este:<<c<<\n; //Afiare: Val. lui c este:4
}
Operatorul poate fi aplicat tipurilor de date ntregi, reale, caracter, i chiar iruri de caractere, aa cum vom
vedea n capitolele urmtoare (exemplu: char ir [10]=a5dfgthklj).
Operatori aritmetici unari:
Operator Semnificaie Exemple
- Minus unar -a
++ Operator de incrementare a++ sau
(adun 1 la valoarea operandului) ++a
-- Operator de decrementare a-- sau
(scade 1 din valoarea operandului) --a
Operatorul - unar schimb semnul operandului.
Exemplu:
int a,b; cout<<a=<<-a<<\n; b=-a;
cout<<b=<<b<<\n;
Operatorul - unar poate fi aplicat datelor ntregi, reale, caracter.
Operatorii de incrementare i decrementare pot fi aplicai datelor numerice sau caracter.
Ambii operatori pot fi folosii n form prefixat, naintea operandului, (++a, respectiv --a) sau
postfixat, dup operand (a++, respectiv a--).
Operatorul de decrementare -- care poate fi folosit n form prefixat (--a) sau postfixat (a--).
Utilizarea acestor operatori n expresii, n form prefixat sau postfixat, determin evaluarea
acestora n moduri diferite, astfel:
y=++x este echivalent cu: x=x+1;
y=x;
y=x++ este echivalent cu: y=x;
x=x+1;
y=--x este echivalent cu: x=x-1;
y=x;
y=x-- este echivalent cu: y=x;
x=x-1;
Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void main()
{ int a=9; cout<<a++=<<a++<<\n; //Afiare: a++=9
cout<<a=<<a<<\n; //Afiare: a=10
a=9; //Revenire in situatia anterioara
cout<<++a=<<++a<<\n; //Afiare: ++a=10
cout<<a=<<a<<\n; //Afiare: a=10
35
a=9; cout<<a--=<<a--<<\n; //Afiare: a--=9
cout<<a=<<a<<\n; //Afiare: a=8
a=9; //Revenire in situaia anterioara
cout<<--a=<<--a<<\n; //Afiare: --a=8
cout<<a=<<a<<\n; //Afiare: a=8
int z,x=3; z=x++-2;
cout<<z=<<z<<\n; //Afiare: z=1
cout<<"x=<<x<<\n; //Afiare: x=4
x=3; z=++x-2; cout<<z=<<z<<\n; //Afiare: z=2
cout<<"x=<<x<<\n; //Afiare: x=4
}
Operatori aritmetici binari:
Operator Semnificaie Exemple
+ Adunarea celor doi operanzi a+b
- Scderea celor doi operanzi a-b
* nmulirea celor doi operanzi a*b
/ mprirea celor doi operanzi a/b
% Operatorul modulo (operatorul rest) a%b
(furnizeaz restul mpririi operatorului stng la operatorul drept).
Operatorul modulo se aplic numai operanzilor ntregi (de tip int sau char). Ceilali operatori aritmetici binari
pot fi aplicai datelor ntregi sau reale.
Dac ntr-o expresie cu 2 operanzi i un operator binar aritmetic, ambii operanzi sunt ntregi, rezultatul
expresiei va fi tot un numr ntreg. De exemplu, la evaluarea expresiei 9/2, ambii operanzi fiind ntregi,
rezultatul furnizat este numrul ntreg 4.
Operatorii prezentai respect o serie de reguli de preceden (prioritate) i asociativitate, care determin
precis modul n care va fi evaluat expresia n care acetia apar. n tabelul 2.3 sunt prezentai operatorii
anteriori, n ordinea descresctoare a prioritii. Precedena operatorilor poate fi schimbat cu ajutorul
parantezelor.
Tabelul 2.3.
Clas de operatori Operatori Asociativitate
Unari - (unar) ++ -- de la dreapta la stnga
Multiplicativi * / % de la stnga la dreapta
Aditivi + - de la stnga la dreapta
Atribuire = de la dreapta la stnga
Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void main()
{
int rezult, a=20,b=2,c=25,d=4; rezult=a-b;
cout<<a-b=<<rezult<<\n; // Afiare: a-b=18
rezult=a+b; cout<<a+b=<<rezult<<\n; // Afiare: a+b=22
rezult=a*b;cout<<c*b=<<rezult<<\n; // Afiare: c*b=50
rezult=a/d; cout<<a/d=<<rezult<<\n; // Afiare: a/d=5
rezult=c%b; cout<<c%b=<<rezult<<\n; // Afiare: c%b=1
rezult=c/b*d; cout<<c/b*d=<<rezult<<\n; // Afiare: c/b*d=48
rezult= -b+a; cout<<-b+a=<<rezult<<\n; // Afiare: -b+a=18
rezult= -(b+a); cout<<-(b+a)=<<rezult<<\n; // Afiare: -(b+a)=-
22
rezult=b+c*d;cout<<b+c*d=<<rezult<<\n; // Afiare: b+c*d=102
36
rezult=(b+c)*d;cout<<(b+c)*d=<<rezult<<\n; // Afiare:
(b+c)*d=108
}
Operatori aritmetici binari compui
Operator Semnificaie Exemple
+= a=a+b a+=b
-= a=a+b a-=b
*= a=a*b a*=b
/= a=a/b a/=b
%= a=a%b a%=b
Aceti operatori se obin prin combinarea operatorilor aritmetici binari cu operatorul de atribuire i sunt
folosii sub forma urmtoare:
expresie1 operator= expresie2;
Rezultatul obinut este acelai cu rezultatul obinut prin:
expresie1 = expresie1 operator expresie2;
Toi aceti operatorii modific valoarea operandului stng prin adunarea, scderea, nmulirea sau mprirea
acestuia prin valoarea operandului drept.
Construcia x+=1 genereaz acelai rezultat ca expresia x=x+1.
Observaiile referitoare la operatorii aritmetici binari sunt valabile i pentru operatorii aritmetici binari
compui. Operatorii aritmetici binari compui au aceeai prioritate i asociativitate ca i operatorul de
atribuire.
Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void main()
{
int a,b; float c=9.3; a=3; b=8;
cout<<a=<<a<<\n; //Afiare a=3
a+=b; cout<<a=<<a<<\n; //Afiare a=11
a-=b; cout<<a=<<a<<\n; //Afiare a=-5
a*=b; cout<<a=<<a<<\n; //Afiare a=24
a/=b; cout<<a=<<a<<\n; //Afiare a=0
a%=b; cout<<a=<<a<<\n; //Afisare a=3
}
Operatori relaionali binari
Operator Semnificaie Exemple
== Egal cu a==b
!= Diferit de a!=b
< Mai mic dect a<b
<= Mai mic sau egal a<=b
> Mai mare dect a>b
>= Mai mare sau egal a>=b
Primii doi operatori mai sunt numii operatori de egalitate. Operatorii relaionali servesc la compararea
valorilor celor doi operanzi i nu modific valorile operanzilor. Rezultatul unei expresii n care apare unul
din operatorii relaionali binari este ntreg i are valoarea zero (0) dac relaia este fals, sau valoarea unu (1)
(sau diferit de 0 n cazul compilatoarelor sub UNIX), dac relaia este adevrat. Aceti operatorii pot fi
aplicai datelor de tip ntreg, real sau char.
Regulile de preceden i asociativitate ale acestor operatori sunt prezentate n tabelul 2.4.
Tabelul 2.4.
Clas de operatori Operatori Asociativitate
Unari - (unar) ++ -- de la dreapta la stnga
37
Multiplicativi * / % de la stnga la dreapta
Aditivi + - de la stnga la dreapta
Atribuire = de la dreapta la stnga
Relaionali < <= > >= de la stnga la dreapta
De egalitate == != de la stnga la dreapta
Atribuire i aritmetici binari = *= /= %= += -= de la dreapta la stnga
Observaie: Deosebirea dintre operatorii == (relaional, de egalitate) i = (de atribuire) const n faptul c
primul nu modific valoarea nici unuia dintre operanzii si, pe cnd cel de-al doilea modific valoarea
operandului stng (vezi exemplul urmtor)
Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void main()
{
int a=1, b=20, lim=100; int rezult; rezult=a<b;
cout<<a<b=<<rezult<<\n;
// Afiare: a<b=1 (sau o alt valoare diferit de zero pentru alte compilatoare)
rezult=a<=b;
//operatorul realional <= are prioritate mai mare dect cel de atribuire
cout<<a<=b=<<rezult<<\n;
// Afisare: a<b=1 (sau o alta valoare diferit de zero pentru alte compilatoare)
rezult=a>b; cout<<a>b=<<rezult<<\n; // Afiare: a<b=0
rezult=a+10>=lim; cout<<a+10>=lim=<<rezult<<\n;
/* Operatorul + are prioritate mai mare dect operatorul >= . Afiare: a+10>=lim=0 */
rezult=a+(10>=lim); cout<<a+(10>=lim)=<<rezult<<\n;
/* Schimbarea prioritatii operatorilor prin folosirea parantezelor; Afiare: a+(10>=lim)=1 */
rezult=a==b;
cout<<a==b=<<rezult<<\n; // Afiare: a==b=0
cout<<a=<<a<<\n; // Afiare: a=1
cout<<b=<<b<<\n; // Afiare: b=20
rezult=a=b; cout<<a=b=<<rezult<<\n; // Afiare: a=b=20
cout<<a=<<a<<\n; // Afiare: a=20
cout<<b=<<b<<\n; // Afiare: b=20
rezult=5>b>10;cout<<b=<<b<<\n; // Afiare: b=20
cout<<5>b>10=<<rezult<<\n; //Echivalent cu (5>b)>10 Afiare:
5>b>10=0
}
Operatori logici pe cuvnt
Operator Semnificaie Exemple
! Not (negaie logic) !(a==b)
&& And (conjuncie, i logic) (a>b) && (b>c)
|| Or (disjuncie, sau logic) (a>b) || (b>c)
Aceti operatori pot fi aplicai datelor de tip ntreg, real sau caracter. Evaluarea unei expresii n care intervin
operatorii logici se face conform tabelului 2.5.
Tabelul 2.5.
x y !x x&&y x||y
adevrat (1) adevrat (1) fals (0) adevrat (1) adevrat (1)
adevrat (1) fals (0) fals (0) fals (0) adevrat (1)
fals (0) adevrat (1) adevrat (1) fals (0) adevrat (1)
fals (0) fals (0) adevrat (1) fals (0) fals (0)
38
Expresia !expresie are valoarea 0 (fals) dac expresia-operand are o valoare diferit de zero i valoarea
unu (adevrat) dac expresia-operand are valoarea zero.
Expresia expresie1||expresie2 are valoarea diferit de 0 (true) dac FIE expresie1, FIE expresie2
au valori diferite de zero.
Expresia expresie1 && expresie2 are valoarea diferit de 0 (true) dac AMBELE expresii-
operand ( expresie1 i expresie2) au valori diferite de zero.
Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void main()
{ int a=0, b=10, c=100, d=200; int rezult; rezult=a&&b;
cout<<a&&b=<<rezult<<\n; //Afiare a&&b=0
rezult=a||b; cout<<a||b=<<rezult<<\n;//Afiare a||b=1 (sau valoare
nenula)
rezult=!a;cout<<!a=<<rezult<<\n; //Afiare !a=1 (sau valoare nenula)
rezult=!b; cout<<!b=<<rezult<<\n; //Afiare !b=0
rezult=(a>b) || (b>c);cout<<(a>b) || (b>c)=<<rezult<<\n;
//Afiare (a>b) || (b>c) =1(sau valoare nenula)
rezult=!(c<d);cout<<!(c<d)=<<rezult<<\n;//Afiare !(c>d)=0
rezult=(a-b)&&1;cout<<(a-b)&&1=<<rezult<<\n;
//Afiare (a-b)&&1 =1(sau valoare nenula)
rezult=d||b&&a;cout<<d||b&&a=<<rezult<<\n;//Afiare d||b&&a =1
}// n evaluarea expresiilor din exemplu, s-au aplicat prioritile operatorilor, indicate n tabelul. 2.6.
Tabelul 2.6.
Clas de operatori Operatori Asociativitate
Unari ! - (unar) ++ -- de la dreapta la stnga
Multiplicativi * / % de la stnga la dreapta
Aditivi + - de la stnga la dreapta
Atribuire = de la dreapta la stnga
relaionali < <= > >= de la stnga la dreapta
de egalitate == != de la stnga la dreapta
logici && de la stnga la dreapta
logici || de la stnga la dreapta
atribuire i aritmetici binari = *= /= %= += -= de la dreapta la stnga
Exerciiu: S se scrie un program care citete un numr real i afieaz 1 dac numrul citit aparine unui
interval ale crui limite sunt introduse tot de la tastatur, sau 0 n caz contrar.
#include <iostream.h>
void main()
{
double lmin, lmax, nr;cout<<"Numar=";cin>>nr;
cout<<Limita inferioar a intervalului:; cin>>lmin;
cout<<Limita superioar a intervalului:; cin>>lmax;
cout<<(nr>=lmin && nr<=lmax); }
Operatori logici pe bit
Operator Semnificaie Exemple
~ Negaie (cod complementar fa de unu) ~a
& AND (Conjuncie, i logic pe bit a & 0377
| OR (Disjuncie, sau logic pe bit) a | 0377
^ XOR (Sau exclusiv logic pe bit) a^b
<< Deplasare stnga 0377 << 2
>> Deplasare dreapta 0377 >> 2
39
Aceti operatori nu se aplic numerelor reale, ci numai datelor de tip ntreg sau caracter. Primul operator este
unar, ceilali binari. Operatorii acioneaz la nivel de bit, la nivelul reprezentrii interne (n binar), conform
tabelelului 2.7.
Tabelul 2.7.
x y x&y x | y x^y ~x
1 1 1 1 0 0
1 0 0 1 1 0
0 1 0 1 1 1
0 0 0 0 0 1
Operatorul ~ are aceeai prioritate ca i ceilali operatori unari. El furnizeaz complementul fa de unu al
unui ntreg, adic va schimba fiecare bit de pe 1 n zero i invers. Operatorii de deplasare pe bit (<< i >>)
efectueaz deplasarea la stnga sau la dreapta a operandului stng, cu numrul de bii indicai de operandul
drept. Astfel, x<<2 deplaseaz biii din x la stnga, cu dou poziii, introducnd zero pe poziiile rmase
vacante.
Exemple:
int a=3; //Reprezentare intern a lui a (pe 2 octei): 0000000000000011
int b=5; //Reprezentare intern a lui b (pe 2 octei): 0000000000000101
int rez=~a;
cout<<"~"<<a<<'='<<rez<<'\n'; //~3= -4
//Complementul fa de unu este: 1111111111111100 (n octal: 0177777774 (!a= - 4)
rez=a & b; cout<<a<<'&'<<b<<'='<<rez<<'\n'; //3&5=1
//a&b=0000000000000001 =1
rez=a^b; cout<<a<<'^'<<b<<'='<<rez; // 3^5= 6
//a ^b = 0000000000000110
rez=a|b; cout<<a<<'|'<<b<<'='<<rez; //3|5= 7
//a | b = 0000000000000111
rez=a<<2; cout<<a<<"<<"<<3<<'='<<rez; //3<<2=16=2*2
3
//a<<2= 0000000001100000
rez=5>>2; cout<<b<<">>"<<2<<'='<<rez; //5>>2=1=5/2
2
//b>>2= 0000000000000001
Operatorul binar ^ i gsete o utilizare tipic n expresii ca: x&^077, care mascheaz ultimii 6 bii ai lui x
pe zero.
Operatorul & este adesea utilizat n expresii ca x&0177, unde seteaz toi biii pe zero, cu excepia celor de
ordin inferior din x.
Operatorul | este utilizat n expresii ca: x&MASK , unde seteaz pe unu biii care n x i masca MASK sunt
setai pe unu.
Operatorii logici pe bit & i | sunt diferii de operatorii logici && i || (pe cuvnt).
Deplasarea la stnga a unei date cu n poziii este echivalent cu nmulirea valorii acesteia cu 2
n
. Deplasarea
la dreapta a unei date fr semn cu n poziii este echivalent cu mprirea valorii acesteia cu 2
n
.
Combinnd operatorii logici pe bit cu operatorul de atribuire, se obin operatorii:
&=, ^=, |=, <<=, >>=.
Operatorul condiional
Este un operator ternar (necesit 3 operanzi), utilizat n construcii de forma:
expresie1?expresie2:expresie3
Se evalueaz expresia1. Dac aceasta are o valoare diferit de zero, atunci tipul i valoarea ntregii expresii
vor fi aceleai cu tipul i valoarea expresiei2. Altfel (dac expresie1 are valoarea zero), tipul i valoarea
ntregii expresii vor fi aceleai cu tipul i valoarea expresiei3. Deci operatorul condiional este folosit pentru
40
a atribui ntregii expresii tipul i valoarea expresiei2 sau a expresiei3, n funcie de o anumit condiie. Acest
lucru este echivalent cu:
Dac expresie1 diferit de zero
Atunci evalueaz expresie2
Altfel evalueaz expresie3
Exemplu:
int semn=(x<0)?-1:1
Dac x<0, atunci semn=-1, altfel semn=1.
Operatorul virgul
Este utilizat n construcii de forma:
expresie1 , expresie2
Operatorul virgul foreaz evaluarea unei expresii de la stnga la dreapta. Tipul i valoarea ntregii expresii
este dat de tipul i valoarea expresiei2. Operatorul virgul este folosit n instruciunea for. Operatorul
virgul are cea mai mic prioritate.
Exemplu:
int x, c, y;
cout<<Astept val. ptr. y:; cin>>y;
x=(c=y, c<=5); /* c va primi valoarea lui y (citit); se verific dac c este mai mic sau
egal cu 5. Daca nu, x=0; daca da, x=1 sau x=valoare diferit de zero)*/
x++, y--; //nti este incrementat x, apoi este decrementat y
Operatorul sizeof()
Este un operator unar, care are ca rezultat numrul de octei pe care este memorat o dat de un
anumit tip. Operandul este un tip sau o dat (constant sau variabil) de un anumit tip.
Exemple:
cout<<sizeof(int); // afieaz numrul de octei pe care este memorat un ntreg (2)
cout<<sizeof(ab6*);// afieaz 5, nr. de octei pe care este memorat constanta ir
ab6*
Operatorul (tip)
Este un operator unar care apare n construcii numite cast i convertete tipul operandului su la
tipul specificat ntre paranteze.
Exemple:
int a; (float) a; // convertete operandul a (care era de tip ntreg) n float
n afara operatorilor prezentai, exist i alii, pe care i vom enumera n continuare. Despre aceti operatori
vom discuta n capitolele viitoare, cnd cunotinele acumulate vor permite acest lucru.
Operatorul unar *
Este operator unar, numit i operator de defereniere. Se aplic unei expresii de tip pointer i este
folosit pentru a accesa coninutul unei zone de memorie spre care pointeaz operatorul. Operatorii &
(adres) i * sunt complementari.
Exemplu: Expresia *a este nlocuit cu valoarea de la adresa coninut n variabila pointer a.
Operatorii parantez
Parantezele rotunde ( ) se utilizeaz n expresii, pentru schimbarea ordinii de efectuare a
operaiilor, sau la apelul funciilor. La apelul funciilor, parantezele rotunde ncadreaz lista
parametrilor efectivi. Din acest motiv, parantezele rotunde sunt numite i operatori de apel de
funcie.
Exemplu:
double sum(double a, double b);
/*declar. funciei sum, care primete 2 argumente reale(double) i returneaz o valoare tip double */
void main()
{
. . .
41
double a=sum(89.9, 56.6); //apelul funciei sum, cu parametri efectivi 89.9 i 56.6
int s0=6; double s1=(s0+9)/a; //folosirea parantezelor n expresii
. . .
}
Operatorii de indexare
Operatorii de indexare sunt parantezele ptrate []. Acestea includ expresii ntregi care reprezint
indici ai unui tablou.
Operatori de acces la membri structurilor
Operatorii ::, ., ->, .* i ->* permit accesul la componentele unei structuri. Ei vor fi studiai n
capitolul 7.
n tabelul 2.8. sunt prezentai toi operatorii, grupai pe categorii, cu prioritile lor i regulile de
asociativitate. Operatorii dintr-o categorie au aceeai prioritate.
Tabelul 2.8.
Nr. Clas de operatori Operatori Asociativitate
1. Primari () [] . -> :: de la stnga la dreapta
2. Unari ! ~ ++ -- sizeof (tip)
-(unar) *(defereniere) &(refereniere)
de la stnga la dreapta
3. Multiplicativi * / % de la stnga la dreapta
4. Aditivi + - de la stnga la dreapta
5. Deplasare pe bit << >> de la stnga la dreapta
6. Relaionali < <= > >= de la stnga la dreapta
7. De egalitate == != de la stnga la dreapta
8. & (I logic pe bit) de la stnga la dreapta
9. ^ (XOR pe bit) de la stnga la dreapta
10. | (SAU logic pe bit) de la stnga la dreapta
11. && de la stnga la dreapta
12. || de la stnga la dreapta
13. Condiional ?: de la dreapta la stnga
14. De atribuire = += -= *= %=
&= ^= |= <<= >>=
de la dreapta la stnga
15. Virgul , de la stnga la dreapta
2.6.2. EXPRESII
Prin combinarea operanzilor i a operatorilor se obin expresii. Tipul unei expresii este dat de tipul
rezultatului obinut n urma evalurii acesteia. La evaluarea unei expresii se aplic regulile de prioritate i
asociativitate a operatorilor din expresie. Ordinea de aplicare a operatorilor poate fi schimbat prin folosirea
parantezelor. La alctuirea expresiilor, este indicat evitarea expresiilor n care un operand apare de mai
multe ori.
2.6.3. CONVERSII DE TIP
La evaluarea expresiilor, se realizeaz conversii ale tipului operanzilor. Conversiile sunt:
Automate;
Cerute de evaluarea expresiilor;
Cerute de programator (prin construciile cast), explicite.
Conversiile automate sunt realizate de ctre compilator:
char, short int -> int
Ele sunt realizate de fiecare dat cnd ntr-o expresie apar operanzi de tipul char sau short int.
Conversiile cerute de evaluarea expresiilor sunt efectuate n cazurile n care n expresii apar operanzi de
tipuri diferite. naintea aplicrii operatorilor, se realizeaz conversia unuia sau a ambilor operanzi:
42
Dac un operand este de tip long int, cellalt este convertit la acelai tip; tipul expresiei este long int.
Dac un operand este de tipul double, cellalt este convertit la acelai tip; tipul expresiei este double.
Dac un operand este de tipul float, cellalt este convertit la acelai tip; tipul expresiei este float.
Conversiile explicite (cerute de programator) se realizeaz cu ajutorul construciilor cast.
Exemplu:
int x=3; float y; y=(float)x/2;
nainte de a se efectua mprirea celor 2 operanzi, operandul x (ntreg) este convertit n numr real
simpl precizie. Dup atribuire, valoarea lui y va fi 1.5. Dac nu ar fi fost folosit operatorul de conversie n
expresia y=x / 2, operanzii x i 2 fiind ntregi, rezultatul mpririi este ntreg, deci y ar fi avut valoarea 1.
NTREBRI I EXERCIII
Chestiuni teoretice
1. Ce reprezint datele i care sunt atributele lor?
2. Care sunt diferenele ntre constante i
variabile?
3. Cine determin tipul unei constante?
4. Ce sunt identificatorii?
5. Ce sunt directivele preprocesor?
6. Ce reprezinta variabilele?
7. Ce sunt constantele?
8. Enumerai tipurile simple de variabile.
9. Cte tipuri de directive preprocesor
cunoastei? Exemple.
10. Care este modalitatea de a interzice
modificarea valorii unei variabile?
11. Ce loc ocup declararea varibilelor n cadrul
unui program surs scris n limbajul C++?
12. Ce conin fiierele header?
13. Ce tipuri de variabile se utilizeaz pentru
datele numerice?
14. Care sunt calificatorii folosii alturi de
tipurile de baz pentru obinerea tipurilor
derivate de date?
15. Ce semnific parantezele unghiulare < > care
ncadreaz numele unui fiier header?
16. Care este diferena ntre constantele 35.2e-1 i
3.52 ? Dar ntre "\t" i '\t'?
17. Ce tip are constanta 6.44 ?
18. Care este diferena ntre operatorii = i = = ?
19. Ce reprezint caracterele "escape"?
20. Constante ntregi.
21. Constante caracter.
22. Ce tipuri de conversii cunoatei?
23. Care sunt conversiile realizate n mod
automat, de ctre compilator?
24. Constante ir de caractere.
25. Constante reale.
26. Ce operatori ternari cunoastei?
27. Operatorul virgul.
28. Operatorul sizeof.
29. Operatori aritmetici binari compui.
30. Operatorul de refereniere.
31. Operatori relaionali binari.
41
Chestiuni aplicative
1. S se scrie declaraiile pentru definirea constantelor simbolice: pi, g (acceleraia gravitaional),
unghi_drept, dimensiune_MAX.
2. Care va fi rezultatul afiat pe ecran n urma execuiei urmtoarelor secvene de instruciuni:
double a=9/2; cout<<a*5<<\n;
double a=9.7, b=5.6; cout<<(a+6<b)<<\n;
double a=9/4; cout<<a*6<<\n;
double x=3;int y=++x+5;cout<<y<<\n;
int a=7; cout<<(!a)<<\n;
int a=10.5; cout<<a++<<\n; cout<<a<<\n;
int a=7; cout<<++a<<\n; cout<<a<<\n;
int a=10; cout<<a++<<\n; cout<<a<<\n;
double a=7/2; cout<<a<<\n;
int x=3; int y=x++-2; cout<<y<<\n;
int x=3; int y=++x+5; cout<<y<<\n;
double a=5.6, b=7.45; cout<<(a>b)<<\n;
3. S se verifice corectitudinea urmtoarelor secvene. Pentru cele incorecte, explicai sursa erorilor.
double a=9.7, b=5.2; int c=(a+6<b)++; cout<<c<<\n;
double a=7/5; double c=a*5++; cout<<c<<\n;
double a=9.7, b=5.6; int c=(a%6<b)++; cout<<c<<\n;
double a=5.6, b=7.45; cout<<++(a+5>b)<<\n;
double a=9.8; double b=9.7; cout<<a%b<<\n;
cout<<&(a+8)<<'\n';
int I=8; cout<<(I+10)++<<'\n';
double a=8.7; A=(a+8)/56; cout<<A<<'\n';
int x=3/5; int y=x++; char x='J'; cout<<"y="<<y<<'\n';
char a='X'; const int b=89; b+=8; cout<<"b="<<b<<"
a="<<a<<'\n';
4. S se scrie un program care afieaz urmtoarele mesaje:
Sirul "este dupa-amiaza" este memorat pe .... octeti.
O marime intreaga este memorata pe ... octeti.
O marime reala, in simpla precizie este memorata pe ... octeti!
O marime reala, in dubla precizie este memorata pe ... byti!
Constanta caracter 'Q' memorata pe ... octeti!
Sirul "a\n\n" este memorat pe ... octei!
Sirul "\n" este memorat pe ... biti!
Caracterul '\' este memorat pe .... biti.
5. S se evalueze expresiile, tiind c: int i=1;int j=2;int k=-7;double x=0;double
y=2.3;
-i - 5 * j >= k + 1
3 < j < 5
i + j + k == -2 * j
x && i || j - 3
6. Ce operaie logic i ce masc trebuie s folosii pentru a converti codurile ASCII ale literelor mici n
litere mari? Dar pentru conversia invers?
7. O deplasare la dreapta cu 3 bii este echivalent cu o rotaie la stnga cu ci bii?
8. S se seteze pe 1 toi biii dintr-un octet, cu excepia bitului cel mai semnificativ.
9. S se scrie un program care citete o valoare ntreag. S se afieze un mesaj care s indice dac numrul
citit este par sau impar.
10. S se citeasca dou valori ntregi. S se calculeze i s se afieze restul mpririi celor dou numere.
42
IMPLEMENTAREA STRUCTURILOR
DE CONTROL
3.1. Implementarea structurii secveniale 3.3. Implementarea structurilor repetitive
3.2. Implementarea structurii de decizie 3.4. Faciliti de ntrerupere a unei secvene
Algoritmul proiectat pentru rezolvarea unei anumite probleme trebuie implementat ntr-un limbaj de
programare; prelucrarea datelor se realizeaz cu ajutorul instruciunilor. Instruciunea descrie un proces de
prelucrare pe care un calculator l poate executa. O instruciune este o construcie valid (care respect
sintaxa limbajului) urmat de ; . Ordinea n care se execut instruciunile unui program definete aa-numita
structur de control a programului.
Limbajele moderne sunt alctuite pe principiile programrii structurate. Conform lui C. Bohm i G.
Jacobini, orice algoritm poate fi realizat prin combinarea a trei structuri fundamentale:
structura secvenial;
structura alternativ (de decizie, de selecie);
structura repetitiv (ciclic).
3.1. IMPLEMENTAREA STRUCTURII SECVENIALE
Structura secvenial este o niruire de secvene de prelucrare (instruciuni), plasate una dup alta, n ordinea
n care se dorete execuia acestora.
Implementarea structurii secveniale se realizeaz cu ajutorul instruciunilor:
Instruciunea vid
Sintaxa: ;
Instruciunea vid nu are nici un efect. Se utilizeaz n construcii n care se cere prezena unei instruciuni,
dar nu se execut nimic (de obicei, n instruciunile repetitive).
Exemple:
int a;
. . . . . .
int j;
;
for (;;)
3
Reprezentarea structurii secveniale cu
ajutorul schemei logice ( figura 3.1.):
Reprezentarea structurii secveniale cu
ajutorul pseudocodului:
instr1;
instr2;
. . . . .
S1
S2
Sn
Figura 3.1. Schema logic pentru structura
secvenial
43
{
. . . .
}
Instruciunea expresie
Sintaxa: expresie;
sau: apel_funcie;
Exemple:
int b, a=9;
double c;
b=a+9;
cout<<a;
c=sqrt(a);
clrcsr();//apelul funciei predefinite care terge ecranul; prototipul n headerul conio.h
Instruciunea compus (instruciunea bloc)
Sintaxa: {
declaratii;
instr1;
instr2;
. . . .
}
ntr-un bloc se pot declara i variabile care pot fi accesate doar n corpul blocului. Instruciunea bloc este
utilizat n locurile n care este necesar prezena unei singure instruciuni, ns procesul de calcul este mai
complex, deci trebuie descris n mai multe secvene.
3.2. IMPLEMENTAREA STRUCTURII DE DECIZIE (ALTERNATIVE, DE SELECIE)
Reprezentarea prin schem logic i prin pseudocod a structurilor de decizie i repetitive sunt descrise n
capitolul 1. Se vor prezenta n continure doar instruciunile care le implementeaz.
Instruciunea if:
Sintaxa:
if (expresie)
instruciune1;
[ else
instruciune2; ]
Ramura else este opional.
La ntlnirea instruciunii if, se evalueaz expresie (care reprezint o condiie) din paranteze. Dac
valoarea expresiei este 1 (condiia este ndeplinit) se execut instruciune1; dac valoarea expresiei
este 0 (condiia nu este ndeplinit), se execut instruciune2. Deci, la un moment dat, se execut
doar una dintre cele dou instruciuni: fie instruciune1, fie instruciune2. Dup execuia instruciunii if se
trece la execuia instruciunii care urmeaz acesteia.
Observaii:
1. Instruciune1 i instruciune2 pot fi instruciuni compuse (blocuri), sau chiar alte
instruciuni if (if-uri imbricate).
2. Deoarece instruciunea if testeaz valoarea numeric a expresiei (condiiei), este posibil prescurtarea:
if (expresie), n loc de if (expresie != 0).
3. Deoarece ramura else a instruciunii if este opional, n cazul n care aceasta este omis din
secvenele if-else imbricate, se produce o ambiguitate. De obicei, ramura else se asociaz ultimei
instruciuni if.
44
Exemplu:
if (n>0)
if (a>b)
z=a;
else z=b;
4. Pentru claritatea programelor surs se recomand alinierea instruciunilor prin utilizarea tabulatorului
orizontal.
5. Deseori, apare construcia:
if (expresie1)
instruciune1;
else
if (expresie2)
instruciune2;
else
if (expresie3)
instruciune3;
. . . . . . . . .
else
instruciune_n;
Expresiile sunt evaluate n ordine; dac una dintre expresii are valoarea 1, se execut instruciunea
corespunztoare i se termin ntreaga nlnuire. Ultima parte a lui else furnizeaz cazul cnd nici una
dintre expresiile 1,2,. . ., n-1 nu are valoarea 1.
6. n cazul n care instruciunile din cadrul if-else sunt simple, se poate folosi operatorul condiional.
Exerciii:
1. S se citeasc de la tastatur un numr real. Daca acesta se afl n intervalul [-1000, 1000], s se afiseze
1, dac nu, s se afiseze -1.
#include <iostream.h>
void main()
{
double nr; cout<<Astept numar:; cin>>nr;
int afis = (nr>= -1000 && nr <= 1000 ? 1 : -1); cout<<afis;
/* int afis;
if (nr >= -1000 && nr <= 10000)
afis = 1;
else afis= -1;
cout<<afis; */
}
2. S se calculeze valoarea funciei f(x), tiind c x este un numr real introdus de la tastatur:
- 6x + 20 , dac x e [- , -7 ]
f(x) = x + 30 , dac x e (-7, 0]
x , dac x>0
#include <iostream.h>
#include <math.h>
void main()
{
double x,f;cout<<x=;cin>>x;
if (x <= -7)
f= -x* 6 +20;
Aceeai construcie poate fi scris i
astfel:
if (expresie1)
instruciune1;
else if (expresie2)
instruciune2;
else if (expresie3)
instruciune3;
. . . . .. . . . . .
else
instruciune_n;
#include <iostream.h>
#include <math.h>
void main()
{
double
x,f;cout<<x=;cin>>x;
if (x <= 7)
f= -x* 6 +20;
if (x>=-7 && x<=0 )
f= x+30;
if (x>0) f=sqrt(x);
cout<<f=<<f<<\n;
}
Sau:
45
else
if ( x<=0 )
f= x+30;
else f=sqrt(x);
cout<<f=<<f<<\n;
}
Uneori, construcia if-else este utilizat pentru a compara valoarea unei variabile cu diferite valori constante,
ca n programul urmtor:
3. Se citete un caracter reprezentnd un operator aritmetic binar simplu. n funcie de caracterul citit, se
afieaz numele operaiei pe care acesta o poate realiza.
#include <iostream.h>
void main()
{
char oper;
cout<<Introdu operator aritmetic, simplu, binar:;
cin>>oper;
if (oper == +)
cout<<Operatorul de adunare!\n;
else if (oper==- )
cout<<Operatorul de scadere!\n;
else if (oper==* )
cout<<Operatorul de inmultire!\n;
else if (oper==/ )
cout<<Operatorul de impartire!\n;
else if (oper==% )
cout<<Operatorul rest!\n;
else cout<<Operator ilegal!!!\n;
}
Instruciunea switch
n unele cazuri este necesar o decizie multipl special. Instruciunea switch permite acest lucru.
Reprezentare prin schema logic (figura 3.2):
break
break
instruciune1
instruciune2
instruciune_n
Reprezentare prin pseudocod:
Dac expresie=expr_const_1
instruciune1;
[ieire;]
Altfel dac
expresie=expr_const_2
instruciune2;
[ieire;]
Altfel dac
expresie=expr_const_n-1
instruciune_n-1;
[ieire;]
Altfel instruciune_n;
Figura 3.2. Decizia multipl
test_expresie
46
Se testeaz dac valoarea pentru expresie este una dintre constantele specificate (expr_const_1,
expr_const_2, etc.) i se execut instruciunea de pe ramura corespunztoare. n schema logic
test_expresie este una din condiiile: expresie=expr_const_1,
expresie=expr_const_2, etc.
Sintaxa:
switch (expresie)
{
case expresie_const_1: instructiune_1;
[break;]
case expresie_const_2: instructiune_2;
[break;]
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
case expresie_const_n-1: instructiune_n-1;
[break;]
[ default: instructiune_n; ]
}
Este evaluat expresie (expresie aritmetic), iar valoarea ei este comparat cu valoarea expresiilor
constante 1, 2, etc. (expresii constante=expresii care nu conin variabile). n situaia n care valoarea
expresie este egal cu valoarea expr_const_k, se execut instruciunea corespunztoare acelei ramuri
(instruciune_k). Dac se ntlnete instruciunea break, parcurgerea este ntrerupt, deci se va trece
la execuia primei instruciuni de dup switch. Dac nu este ntlnit instruciunea break, parcurgerea
continu. Break-ul cauzeaz deci, ieirea imediat din switch.
n cazul n care valoarea expresiei nu este gsit printre valorile expresiilor constante, se execut cazul
marcat cu eticheta default (cnd acesta exist). Expresiile expresie, expresie_const_1,
expresie_const_2,etc., trebuie s fie ntregi. n exemplul urmtor, ele sunt de tip char, dar o dat de
tip char este convertit automat n tipul int.
Exerciiu: S rescriem programul pentru problema 3, utiliznd instruciunea switch.
#include <iostream.h>
void main()
{
char oper;
cout<<Introdu operator aritmetic, simplu, binar:;
cin>>oper;
switch (oper)
{
case (+):
cout<<Operatorul de adunare!\n;
break;
case (-):
cout<<Operatorul de scadere!\n;
break;
case (*):
cout<< Operatorul de inmultire!\n;
break;
case (/):
cout<<Operatorul de impartire!\n;
break;
case (%):
cout<<Operatorul rest!\n;
break;
default:
cout<<Operator ilegal!\n;
47
}
}
3.3. IMPLEMENTAREA STRUCTURILOR REPETITIVE (CICLICE)
Exist dou categorii de instruciuni ciclice: cu test iniial i cu test final.
3.3.1. Implementarea structurilor ciclice cu test iniial
Structura ciclic cu test iniial este implementat prin instruciunile while i for.
Instruciunea while
Sintaxa:
while (expresie)
instructiune;
La ntlnirea acestei instruciuni, se evalueaz expresie. Dac aceasta are valoarea 1 - sau diferit de 0 -
(condiie ndeplinit), se execut instruciune. Se revine apoi n punctul n care se evalueaz din nou
valoarea expresiei. Dac ea este tot 1, se repet instruciune, .a.m.d. Astfel, instruciunea (corpul
ciclului) se repet att timp ct expresie are valoarea 1. n momentul n care expresie ia valoarea 0
(condiie nendeplinit), se iese din ciclu i se trece la urmtoarea instruciune de dup while.
Observaii:
1. n cazul n care la prima evaluare a expresiei, aceasta are valoarea zero, corpul instruciunii while nu va
fi executat niciodat.
2. Instruciune din corpul ciclului while poate fi compus (un bloc), sau o alt instruciune ciclic.
3. Este de dorit ca instruciunea din corpul ciclului while s modifice valoarea expresiei. Dac nu se
realizeaz acest lucru, corpul instruciunii while se repet de un numr infinit de ori.
Exemplu:
int a=7;
while (a==7)
cout<<Buna ziua!\n; // ciclu infinit; se repet la infinit afiarea
mesajului
Instruciunea for
n majoritatea limbajelor de programare de nivel nalt, instruciunea for implementeaz structura ciclic cu
numr cunoscut de pai (vezi reprezentarea prin schema logic i pseudocod din capitolul 1). n limbajul C
instruciunea for poate fi utilizat ntr-un mod mult mai flexibil.
Reprezentare n pseudocod:
evaluare expresie1
CT TIMP expresie2
REPET
NCEPUT
instruciune
evaluare
expresie3
SFRIT
0
evaluare expresie1 (particular iniializare contor)
instruciune
expresie2
evaluare expresie3 (particular
incrementare contor)
1
Reprezentare prin schema logic (figura 3.3.):
Figura 3.3. Structura ciclic cu test iniial
48
Sintaxa:
for (expresie1; expresie2; expresie3)
instructiune;
Nu este obligatorie prezena expresiilor, ci doar a instruciunilor vide.
Exemplu:
3.3.2. Implementarea structurilor ciclice cu test final
Instruciunea do-while
Sintaxa:
do instructiune;
while(expresie);
Se execut instruciune. Se evalueaz apoi expresie. Dac aceasta are valoarea 1, se execut
instruciune. Se testeaz din nou valoarea expresiei. Se repet instruciune ct timp valoarea
expresiei este 1 (condiia este ndeplinit). n cazul instruciunii do-while, corpul ciclului se execut cel puin
o dat.
Exerciii:
1. Se citete cte un caracter, pn la ntlnirea caracterului @. Pentru fiecare caracter citit, s se afieze un
mesaj care s indice dac s-a citit o liter mare, o liter mic, o cifr sau un alt caracter. S se afieze cte
litere mari au fost introduse, cte litere mici, cte cifre i cte alte caractere. Se prezint trei modaliti de
implementare (cu instruciunea while, cu instruciunea for i cu instruciunea do-while).
for ( ; expresie2; ) sau: for ( ; ; )
instructiune; instructiune;
instructiune;
#include <iostream.h>
#include <conio.h>
void main()
{ char c;clrscr();
intlmic=0,lmare=0,lcif=0;int
altcar=0;
cout<<"Atept caract.:";
Pentru implementarea aceluiai algoritm
se poate utiliza instruciunea for. n
cadrul acesteia, expresie1 i expresie3
lipsesc, ns prezena instruciunilor
vide este obligatorie.
#include <iostream.h>
#include <conio.h>
void main()
{ char c; clrscr();
int lmic=0, lmare=0, lcif=0;
int altcar=0;
cout<<"Atept car.:"; cin>>c;
while (c!='@'){
if (c>='A' && c<='Z') {
cout<<"Lit.
mare!\n";
lmare++; }
else if (c>='a' &&
c<='z') {
cout<<"Lit.
mic!\n";
lmica++; }
else if (c>='0' &&
c<='9') {
cout<<"Cifr!\n";
lcif++; }
else {
cout<<"Alt car.!\n";
altcar++; }
cout<<"Atept
car.:";cin>>c;
}
cout<<"Ai introdus \n";
cout<<lmare<<" litere mari, ";
cout<<lmic<<" litere mici\n";
Observaii legate de implementare
Variabila c (tip char) memoreaz caracterul
introdus la un moment dat, de la tastatur.
Variabilele ntregi lmic, lmare, lcif i altcar
sunt utilizate pe post de contor pentru litere
mari, mici, cifre, respectiv alte caractere.
Aciunea care se repet ct timp caracterul
citit este diferit de constanta caracter '@'
const din mai multe aciuni simple: citirea
unui caracter (cu afiarea n prealabil a
mesajului "Atept car.:"; testarea
caracterului citit (operatorii relaionali pot fi
aplicai datelor de tip char).
Ca urmare, aciunea din corpul instructiunii
while a fost implementat printr-o
instruciune bloc.
Tot instruciuni bloc au fost utilizate pe
fiecare ramur a instruciunii if (afiare
mesaj referitor la caracter i incrementare
contor).
49
O alt variant de implementare poate fi urmtoarea, n care i iniializarea variabilelor contor se realizeaz
n cadrul expresiei expresie1.
int lmic, lmare, lcif, altcar;
for(lmare=0, lmic=0, lcif=0, altcar=0; c!='@'; ){
// corp identic
}
Variant de implementare care utilizeaz instruciunea do-while:
2. S se calculeze suma i produsul primelor n numere naturale, n fiind introdus de la tastatur. Se vor
exemplifica modalitile de implementare cu ajutorul instruciunilor do-while, while, i for. (Se
observ c: S =
=
n
k
k
1
, P =
[
=
n
k
k
1
).
Pentru a ilustra multiplele posibiliti oferite de instruciunea for, prezentm variantele
int lmic=0, lmare=0, lcif=0;
int altcar=0;
cout<<"Atept
caract.:";cin>>c;
do {
//corp do-while
} while (c!='@');
cout<<"Ai introdus \n";
//. . .
cout<<"n="; int n; cin>>n;
int S=0, P=1, k=1;
while (k <= n){
S+=k; P*=k;
k++;
}
cout<<"P="<<P<<"\tS="<<S<<'\
n';
cout<<"n="; int n; cin>>n;
int S=0, P=1, k=1;
do{
S+=k; P*=k;
k++;
} while (k <= n);
cout<<"P="<<P<<"\tS="<<S<<
'\n';
// varianta1
int S=0, P=1, k;
for (k=1; k<=n;
k++){
S+=k; P*=k;
}
cout<<"P="<<P<<"\tS=
";
cout<<S<<'\n';
// varianta2
int S=0, P=1;
for (int k=1; k<=n; k++){
S+=k; P*=k;
}
cout<<"P="<<P<<"\tS=";
cout<<S<<'\n';
// varianta3
for (int S=0, P=1, k=1; k<=n; k++){
S+=k; P*=k;
}
cout<<"P="<<P<<"\tS="<<cout<<S<<'\n';
// varianta4
for (int S=0, P=1, k=1; k<=n; S+=k,
50
3. S se citeasc un ir de numere reale, pn la ntlnirea numrului 900. S se afieze maximul numerelor
citite.
4. S se afieze literele mari ale alfabetului i codurile aferente acestora n ordine cresctoare, iar literele
mici i codurile aferente n ordine descresctoare. Afiarea se va face cu pauz dup fiecare ecran.
#include <iostream.h>
#include <conio.h>
#define DIM_PAG 22 //dimensiunea paginii (numarul de randuri de pe o pagina)
void main()
{clrscr();
cout<<"LITERELE MARI:\n";int nr_lin=0; // nr_lin este contorul de linii de
pe un ecran
for (char LitMare='A'; LitMare<='Z'; LitMare++){
if (nr_lin==DIM_PAG){
cout<<"Apasa o tasta...."; getch(); clrscr(); nr_lin=0;}
cout<<"Litera "<<LitMare<<" cu codul ASCII
"<<(int)LitMare<<'\n';
// conversia explicita (int)LitMare permite afisarea codului ASCII al caracterului
nr_lin++;
}
cout<<"LITERELE MICI:\n";
for (char LitMica='z'; LitMica>='a'; LitMica--){
if (nr_lin==DIM_PAG){
cout<<"Apasa o tasta...."; getch(); clrscr(); nr_lin=0;}
cout<<"Litera "<<LitMica<<" cu codul ASCII
"<<(int)LitMica<<'\n';
nr_lin++;
}
}
5. S se scrie un program care realizeaz conversia numrului N ntreg, din baza 10 ntr-o alt baz de
numeraie, b<10 (N i b citite de la tastatur). Conversia unui numr ntreg din baza 10 n baza b se
realizeaz prin mpriri succesive la b i memorarea resturilor, n ordine invers. De exemplu:
547:8=68 rest 3; 68:8=8 rest 4; 8:8=1 rest 0; 1:8=0 rest 1 547
10
= 1043
8
#include <iostream.h>
void main()
{double n;
cout<<"Introdu nr:"; cin>>n;
double max=n;
while (n!=900)
{ if (n>=max)
max=n;
cout<<"Introdu nr:";
cin>>n;
}
cout<<"Max ir
este:"<<max<<'\n';
}
Se presupune c primul element din irul de
numere are valoarea maxim. Se memoreaz
valoarea sa n variabila max. Se parcurge apoi
irul, comparndu-se valoarea fiecrui element
cu valoarea variabilei max. n cazul n care se
gsete un element cu o valoare mai mare dect
a variabilei max, se reine noua valoare
(max=n).
51
#include <iostream.h>
void main()
{ int nrcif=0,N,b,rest,Nv,p=1;
long Nnou=0;
cout<<"\nIntroduceti baza<10, b=";cin>>b;
cout<<"Introduceti numarul in baza 10, nr=";cin>>N;
Nv=N;
while(N!=0)
{
rest=N%b; N/=b; cout<<"nr="<<N<<'\n';
cout<<"rest="<<rest<<'\n';
nrcif++; Nnou+=rest*p; p*=10; cout<<"Nr.
nou="<<Nnou<<'\n';
}
cout<<"Numarul de cifre este "<<nrcif<<'\n'; cout<<"Nr. in
baza 10 "<<Nv;
cout<<" convertit in baza "<<b<<" este "<<Nnou<<'\n'; }
6. S se calculeze seria urmtoare cu o eroare mai mic dect EPS (EPS introdus de la tastatur): 1+
=1 k
k
k
x
, xe[0,1], x citit de la tastatur. Vom aduna la sum nc un termen ct timp diferena dintre suma
calculat la pasul curent i cea calculat la pasul anterior este mai mare sau egal cu EPS.
#include <iostream.h>
#include <conio.h>
#include <math.h>
void main()
{ double T,S,S1;long k;k=1;T=1;S=T;double x; cout<<"x=";
cin>>x;
// T= termenul general de la pasul curent; S=suma la pasul curent; S1=suma la pasul anterior
do {
S1=S;k=k+1;T=pow(x,k)/k; //funcia pow(x, k), aflat n <math.h> calculeaz x
k
S=S+T; // cout<<k<<" "<<T<<" "<<S<<'\n';getch();
} while ((S-S1)>=EPS);
cout<<"Nr termeni="<<k<<" T="<<T<<" S="<<S<<'\n'; }
3.4. FACILITI DE NTRERUPERE A UNEI SECVENE
Pentru o mai mare flexibilitate (tratarea excepiilor care pot apare n procesul de prelucrare), n limbajul C se
utilizeaz instruciunile break i continue. Ambele instruciuni sunt utilizate n instruciunile ciclice. n
plus, instruciunea break poate fi folosit n instruciunea switch.
Instruciunea break
Aa cum se observ din figura 3.4., utilizat n cadrul instruciunilor ciclice, instruciunea break "foreaz"
ieirea din acestea. Fr a se mai testa valoarea expresiei (condiia) care determin repetarea corpului
instruciunii ciclice, se continu execuia cu instructiunea care urmeaz instructiunii ciclice. Astfel, se
ntrerupe repetarea corpului instruciunii ciclice, indiferent de valoarea condiiei de test.
Utilizarea n cadrul instruciunii switch: n situaia n care s-a ajuns la o valoare a unei expresiei constante
egal cu cea a expresiei aritmetice, se execut instruciunea corespunztoare acelei ramuri. Dac se ntlnete
instruciunea break, parcurgerea este ntrerupt (nu se mai compar valoarea expresiei aritmetice cu
urmtoarele constante), deci se va trece la execuia primei instruciuni de dup switch. Dac nu este ntlnit
break, parcurgerea continu. Instruciunea breakl cauzeaz deci, ieirea imediat din switch.
52
Instruciunea continue
ntlnirea instruciunii continue (figura 3.4.) determin ignorarea instruciunilor care o urmeaz n corpul
instruciunii ciclice i reluarea execuiei cu testarea valorii expresiei care determin repetarea sau nu a
corpului ciclului.
Exemplu: S revenim la programul realizat pentru problema 1, care folosete instruciunea dowhile. Dac
primul caracter citit este chiar caracterul @, se realizeaz testarea acestuia; ca urmare, se afieaz mesajul
"Alt car.!" i se incrementeaz valoarea contorului altcar. Dac nu se dorete ca acest caracter s fie
testat i numrat, n corpul instruciunii do while putem face un test suplimentar.
NTREBRI I EXERCIII
Chestiuni teoretice
1. Care sunt instruciunile care implementeaz n
limbajul C structura condiional?
2. Care sunt instruciunile care implementeaz n
limbajul C structura secvenial?
3. Care sunt instruciunile care implementeaz n
limbajul C structura repetitiv cu test iniial?
4. Care sunt instruciunile care implementeaz n
limbajul C structura repetitiv cu test final?
5. Ce deosebiri sunt ntre instruciunea while i
instruciunea do-while?
6. Pornind de la sintaxa instruciunii for, stabilii
echivalena ntre aceasta i instruciunile
while i do-while.
int lmic=0,lmare=0,lcif=0,altcar=0;cout<<"Atept
caract.:";cin>>c;
do {
if (c == '@') break; //ieire din do while
//corp do-while
} while (c!='@');
cout<<"Ai introdus \n";
//. . .
do{
instructiune1;
instructiune2;
if (expresie2)
break;
else
continue;
instructiune3;
} while (expresie1);
for (expr1; expr2;
expr3)){
instructiune1;
instructiune2;
if (expresie2)
break;
else
continue;
instructiune3;
}
Figura 3.4. Modul de utilizare a instruciunilor break i
continue
while (expresie1){
instructiune1;
instructiune2;
if (expresie2)
break;
else
continue;
instructiune3;
}
53
Chestiuni practice
1. S se implementeze programele cu exemplele prezentate.
2. S se scrie programele pentru exerciiile rezolvate care au fost prezentate.
3. S se implementeze algoritmii proiectai pentru problemele 1-7 din capitolul 1.
4. S se calculeze aria unui triunghi, cunoscndu-se mrimea laturilor sale. Numerele care reprezint
mrimile laturilor vor fi introduse de utilizator. Se va testa mai nti dac cele 3 numere reprezentnd
mrimea laturilor pot forma un triunghi ( a <= b+c, b <= c+d, c <= a+b).
5. S se rescrie urmtoarea secven, folosind o singur instruciune if.
if (n<0)
if (n>=90)
if (x!=0)
int b= n/x;
6. S se citeasc un numar natural n. S se scrie un program care afieaz dac numrul n citit reprezint
sau nu, un an bisect (anii biseci sunt multipli de 4, exceptnd multiplii de 100, dar incluznd multiplii de
400).
7. S se gseasc toate numerele de dou cifre care satisfac relaia:
8. S se citeasc un ir de numere reale, pn la ntlnirea numarului 800 i s se afieze valoarea minim
introdus, suma i produsul elementelor irului.
9. Scriei un program care s verifice inegalitatea 1/(n+1) < ln[(n+1)/n] < 1/n, unde n este un numr natural
pozitiv, introdus de la tastatur.
10. Fie funcia
e
3 x
, xe[0, 1)
f(x)= sinx+cosx , xe[1, 2)
0,9ln(x+3) , xe[2, 100]
11. S se scrie un program care calculeaz i afieaz maximul a 3 numere reale (a, b i c) citite de la
tastatur.
12. S se scrie un program care calculeaz i afieaz minimul a 3 numere reale (a, b i c) citite de la
tastatur.
13. S se citeasc 2 caractere care reprezint 2 litere mari. S se afieze caracterele citite n ordine alfabetic.
14. S se citeasc 3 caractere care reprezint 3 litere mici. S se afieze caracterele citite n ordine alfabetic.
15. S se scrie un program care citete o cifr. n funcie de valoarea ei, s se fac urmtorul calcul: dac
cifra este 3, 5 sau 7 s se afieze ptratul valorii numerice a cifrei; dac cifra este 2, 4 sau 6 s se afieze
cubul valorii numerice a cifrei; dac cifra este 0 sau 1 s se afieze mesajul "Valori mici"; altfel., s se
afieze mesajul "Caz ignorat!".
16. Fie irul lui Fibonacci, definit astfel:
f(0)=0, f(1)=1, f(n)=f(n-1)+f(n-2) n cazul n care n>1.
S se scrie un program care implementeaz algoritmul de calcul al irului Fibonacci.
17. S se calculeze valoarea polinomului Cebev de ordin n ntr-un punct x dat, cunoscnd relaia:
T
0
(x)=1, T
1
(x)=x i T
1 + k
(x) - 2xT
k
(x) + T
1 k
(x) = 0
18. S se citeasc cte 2 numere ntregi, pn la ntlnirea perechii (0, 0). Pentru fiecare pereche de numere,
s se calculeze i s se afieze cel mai mare divizor comun.
19. Se citesc cte 3 numere reale, pn la ntlnirea numerelor 9, 9, 9. Pentru fiecare triplet de numere citit,
s se afieze maximul.
20. Se citete cte un caracter pn la ntlnirea caracterului @. S se afieze numrul literelor mari, numarul
literelor mici i numrul cifrelor citite; care este cea mai mare (lexicografic) liter mare, liter mic i
cifr introdus.
21. Se citesc cte 2 numere ntregi, pn la ntlnirea perechii de numere 9, 9. Pentru fiecare pereche de
numere citite, s se afieze cel mai mare divizor comun al acestora.
22. S se calculeze suma seriei
1 + x
3
/3 - x
5
/5 + x
7
/7 -
2
) ( y x xy + =
S se calculeze f(x), x citit de la tastatur.
54
cu o eroare mai mic dect epsilon (epsilon citit de la tastatur). S se afieze i numrul de termeni ai
sumei.
23. S se citeasc un numr ntreg format din 4 cifre (abcd). S se calculeze i s se afieze valoarea
expresiei reale: 4*a + b/20 -c + 1/d.
24. S se scrie un program care afieaz literele mari ale alfabetului n ordine cresctoare, iar literele mici -
n ordine descresctoare.
25. S se scrie un program care genereaz toate numerele perfecte pn la o limit dat, LIM. Un numr
perfect este egal cu suma divizorilor lui, inclusiv 1 (exemplu: 6=1+2+3).
26. S se calculeze valoarea sumei urmatoare, cu o eroare EPS mai mic de 0.0001:
S=1+(x+1)/ 2! + (x+2)/ 3! + (x+3)/ 3! + ... , unde 0<=x<=1, x citit de la tastatur.
27. S se genereze toate numerele naturale de 3 cifre pentru care cifra sutelor este egal cu suma cifrelor
zecilor i unitilor.
28. S se citeasc cte un numr ntreg, pn la ntlnirea numrului 90. Pentru fiecare numar s se afieze
un mesaj care indic dac numrul este pozitiv sau negativ. S se afieze cel mai mic numr din ir.
29. S se genereze toate numerele naturale de 3 cifre pentru care cifra zecilor este egal cu diferena cifrelor
sutelor i unitilor.
30. S se calculeze suma:
(1 + 2!) / (2 + 3!) - (2+3!) / (3+4!) + (3+4!) / (4+5!) - .....
55
TABLOURI
4.1. Declararea tablourilor 4.3. Tablouri bidimensionale
4.2. Tablouri unidimensionale 4.4. iruri de caractere
4.1. DECLARAREA TABOURILOR
Numim tablou o colecie (grup, mulime ordonat) de date, de acelai tip, situate ntr-o zon de memorie
continu (elementele tabloului se afl la adrese succesive). Tablourile sunt variabile compuse (structurate),
deoarece grupeaz mai multe elemente. Variabilele tablou au nume, iar tipul tabloului este dat de tipul
elementelor sale. Elementele tabloului pot fi referite prin numele tabloului i indicii (numere ntregi) care
reprezint poziia elementului n cadrul tabloului.
n funcie de numrul indicilor utilizai pentru a referi elementele tabloului, putem ntlni tablouri
unidimensionale (vectorii) sau multidimensionale (matricile sunt tablouri bidimensionale).
Ca i variabilele simple, variabilele tablou trebuie declarate nainte de utilizare.
Modul de declarare:
tip nume_tablou[dim_1][dim_2][dim_n];
unde:tip reprezint tipul elementelor tabloului; dim_1,dim_2,...,dim_n sunt numere ntregi sau
expresii constante ntregi (a cror valoare este evaluat la compilare) care reprezint limitele superioare ale
indicilor tabloului.
Exemple:
//1
int vect[20]; // declararea tabloului vect, de maximum 20 de elemente, de tipul int.
// Se rezerv 20*sizeof(int)=20 * 2 = 40 octei
//2
double p,q,tab[10];
// declararea variabilelor simple p, q i a vectorului tab, de maximum 10 elemente, tip
double
//3
#define MAX 10
char tabc[MAX]; /*declararea tabloului tabc, de maximum MAX (10) elemente de
tip char*/
//4
double matrice[2][3]; // declararea tabloului matrice (bidimensional),
// maximum 2 linii i maximum 3 coloane, tip double
4.2. TABLOURI UNIDIMENSIONALE
Tablourile unidimensionale sunt tablouri cu un singur indice (vectori). Dac tabloul conine dim_1
elemente, indicii elementelor au valori ntregi din intervalul [0, dim_1-1].
La ntlnirea declaraiei unei variabile tablou, compilatorul aloc o zon de memorie continu (dat de
produsul dintre dimensiunea maxim i numrul de octei corespunztor tipului tabloului) pentru pstrarea
valorilor elementelor sale. Numele tabloului poate fi utilizat n diferite expresii i valoarea lui este chiar
adresa de nceput a zonei de memorie care i-a fost alocat. Un element al unui tablou poate fi utilizat ca orice
alt variabil (n exemplul urmtor, atribuirea de valori elementelor tabloului vector). Se pot efectua
operaii asupra fiecrui element al tabloului, nu asupra ntregului tablou.
4
56
Exemplu:
// Declararea tabloului vector
int vector[6];
// Iniializarea elementelor tabloului
vector[0]=100;
vector[1]=101;
vector[2]=102;
vector[3]=103;
vector[4]=104;
vector[5]=105;
Exemplu:
double alpha[5], beta[5], gama[5];
int i=2;
alpha[2*i-1] = 5.78;
alpha[0]=2*beta[i]+3.5;
gama[i]=aplha[i]+beta[i]; //permis
gama=alpha+beta; //nepermis
Variabilele tablou pot fi iniializate n momentul declarrii:
declaraie_tablou=list_valori;
Valorile din lista de valori sunt separate prin virgul, iar ntreaga list este inclus ntre acolade:
Exemple:
//1
int vector[6]={100,101,102,103,104,105};
[0] [5]
//2
double x=9.8;
double a[5]={1.2, 3.5, x, x-1, 7.5};
La declararea unui vector cu iniializarea elementelor sale, numrul maxim de elemente ale tabloului poate fi
omis, caz n care compilatorul determin automat mrimea tabloului, n funcie de numrul elementelor
iniializate.
Exemplu:
char tab[]={ A, C, D, C};
[0] [3]
float data[5]={ 1.2, 2.3, 3.4 };
[0] [4]
Adresa elementului de indice i dintr-un tablou unidimensional poate fi calculat astfel:
adresa_elementului_i = adresa_de_baz + i- lungime_element
Exerciii:
//1 Citirea elementelor unui vector:
double a[5];
vector
vector
100 101 102 103 104 105
tab
A B
1
C
D
data 1.2 2.3 3.4 ? ?
100
101
102
103
104
105
vector[0]
vector[1]
vector[2]
vector[3]
vector[4]
vector[5]
Figura 4.1.
57
int i;
for (i=0; i<5; i++)
{ cout<<a["<<i<<]=; //afiarea unui mesaj prealabil citirii fiecrui
element
cin>>a[i]; //citirea valorii elementului de indice i
}
//Sau:
double a[20]; int i, n;
cout<<Dim. Max. =; cin>>n;
for (i=0; i<n; i++)
{ cout<<a[<<i<<]=;
cin>>a[i];
}
//2 Afiarea elementelor unui vector:
cout<<Vectorul introdus este:\n;
for (i=0; i<n i++)
cout<<a[i]<< ;
//3 Afiarea elementelor unui vector n ordine invers:
cout<<Elementele vectorului n ordine invers:\n;
for (i=n-1; i>=0 i++)
cout<<a[i]<< ;
//3 Vectorul sum (c) a vectorilor a i b, cu acelai numr de elemente:
for (i=0; i<n i++)
c[i]=a[i]+b[i];
//4 Vectorul diferen (c) a vectorilor a i b, cu acelai numr de elemente:
for (i=0; i<n i++)
c[i]=a[i] - b[i];
//5 Produsul scalar (p) a vectorilor a i b, cu acelai numr de elemente:
p= a b
i i
i
n
-
=
0
1
double p=0;
for (i=0; i<n i++)
p += a[i] - b[i];
4.2. TABLOURI BIDIMENSIONALE
Din punct de vedere conceptual, elementele unui tablou bidimensional sunt plasate n spaiu pe dou direcii.
Matricea reprezint o aplicaie natural a tablourilor bidimensionale.
n matematic:
q
11
q
12
q
13
. . . q
1n
q
21
q
22
q
23
. . . q
2n
Q= . . . . . . . . . . . . . . . . . . . . . . . . . . Q
m n
q
m1
q
m2
q
m3
. . . q
mn
n limbajele C/C++ (indicii de linie i de coloan pornesc de la 0):
q
00
q
01
q
02
. . . q
0 1 ,n
q
10
q
11
q
12
. . . q
1 1 ,n
Q
m n
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
q
m1 0 ,
q
m1 1 ,
q
m1 2 ,
. . . q
m n 1 1 ,
Exemplu:
Q=
58
double q[3][2]; // declararea matricii q, cu maxim3 linii i 2 coloane, tip double
n memorie, elementele unei matrici sunt memorate pe linii:
q
00
q
01
q
10
q
11
q
20
q
21
. . .
Dac notm cu k poziia n memorie a unui element, valoarea lui k = i - m + j (unde m este numrul maxim
de linii, i este indicele de linie, j este indicele de coloan).
Dac se dorete iniializarea elementelor unei matrici n momentul declarrii acesteia, se poate proceda
astfel:
int mat[4][3] = {
{10, -50, 3},
{32, 20, 1},
{-1, 1, -2},
{7, -8, 19} };
Prin aceast construcie, elementele matricii mat se iniializeaz n modul urmtor:
mat[0][0]=10, mat[0][1]=-50, mat[0][2]=3
mat[1][0]=32, mat[1][1]=20, mat[1][2]=1
mat[2][0]=-1, mat[2][1]=1, mat[2][2]=-2
mat[3][0]=7, mat[3][1]=-8, mat[3][2]=19
La declararea unei matrici i iniializarea elementelor sale, se poate omite numrul maxim de linii, n schimb,
datorit modului de memorare, trebuie specificat numrul maxim de coloane:
int mat[][3] = {
{10, -5, 3},
{32, 20, 1},
{-1, 1, -2},
{7, -8, 9} };
Construcia are acelai efect ca precedenta.
int mat[][3] = {
{1, 1},
{ -1},
{3, 2, 1}};
mat reprezint o matrice 3 - 3, ale crei elemente se iniializeaz astfel:
mat[0][0]=1, mat[0][1]=1, mat[1][0]=-1, mat[2][0]=3, mat[2][1]=2, mat[2][2]=1
Elementele mat[0][2], mat[1][1], mat[1][2] nu sunt initalizate. Ele au valoarea zero dac tabloul este global
i valori iniiale nedefinite dac tabloul este automatic.
Construciile utilizate la iniializarea tablourilor bidimensionale se extind pentru tablouri multidimensionale,
cu mai mult de doi indici.
Exemplu:
int a[2][2][3]={
{ {10, 20}, {1, -1}, {3, 4}},
{ {20, 30}, {50, -40}, {11, 12}}
};
Exerciiu: S se citeasc de la tastatur elementele unei matrici de maxim 10 linii i 10 coloane. S se
afieze matricea citit.
#include <iostream.h>
void main(void)
{int A[10][10]; int nr_lin, nr_col; cout<<"Nr. linii:";
cin>>nr_lin;
cout<<"Nr. coloane:"; cin>>nr_col;int i, j;
//citirea elementelor unei matrici
for (i=0; i<nr_lin; i++)
q[0][0] q[0][1] q[0][2] . . . . . .
.
q[0][n-1] q[1][0] . . . . . .
q[m-1][0] . . . q[m-1][n-1]
59
for (j=0; j<nr_col; j++) {
cout<<"A["<<i<<","<<j<<"]="; //afiarea unui mesaj prealabil
citirii
cin>>A[i][j];
}
//afiarea elementelor matricii
for (i=0; i<nr_lin; i++) {
for (j=0; j<nr_col; j++)
cout<<A[i][j]<<'\t';
cout<<'\n'; // dup afiarea elementelor unei linii, se trece pe linia urmtoare
}
}
4.3. IRURI DE CARACTERE
irurile de caractere sunt tablouri de caractere, care au ca ultim element un terminator de ir, caracterul null
(zero ASCII), \0.
Exemplu:
char tc[5] = {a, b, c, d, e}; // tablou de caractere
char sc[5] = {a, b, c, d, \0}; // irul de caractere cu
elementele abcd
Limbajul C/C++ permite iniializarea unui tablou de caractere printr-o constant ir (ir ntre ghilimele), care
include automat caracterul null. Deci ultima iniializare este echivalent cu:
char sc[5] = abcd; //sau cu
char sc[] = abcd;
Exemplu:
char tc[5] = {a, b, c, d, e};
char sc[5] = {a, b, c, d, \0};
char sc1[5] = abcd;
char s[10];
cout<<sc<<\n; //afieaz abcd
cout<<tc<<\n;
//eroare: tabloul de caractere nu conine terminatorul de ir, deci nu poate fi afiat ca ir
cout<<s<<\n; // eroare: tablou neiniializat
cout<<sc1[2]; // afieaz al treilea element din irul sc1
sc1[1]=K; // elementului din ir de indice 1 i se atribuie valoarea K;
4.3.1. FUNCII PENTRU OPERAII CU IRURI DE CARACTERE
Funciile pentru operaii cu iruri se gsesc n header-ul <string.h>.
strlen (nume_ir)
Returneaz un numr ntreg ce reprezint lungimea unui ir de caractere, fr a numra terminatorul de ir.
strcmp (ir_1, ir_2)
Funcia compar cele dou iruri date ca argument i returneaz o valoare ntreag egal diferena dintre
codurile ASCII ale primelor caractere care nu coincid.
strcpy (ir_destinaie, ir_surs)
60
Funcia copie irul surs n irul destinaie. Pentru a fi posibil copierea, lungimea irului destinaie trebuie
s fie mai mare sau egal cu cea a irului surs, altfel pot apare erori grave.
strcat (ir_destinaie, ir_surs)
Funcia concateneaz cele dou iruri: irul surs este adugat la sfritul irului destinaie. Tabloul care
conine irul destinaie trebuie s aib suficiente elemente.
Exemplu:
#include <iostream.h>
#include <string.h>
void main()
{
char sir1[] = abcd, sir2[] = abcde, sir3 = "abcdef, sir4
= "de;
cout<<strcmp(sir1, sir2)<<\n; // afiare: -101
// e = 101, a = 97, d = 100
//0 - e = -101
cout<<strcmp(sir2, sir1)<<\n; //afiare: 101
cout<<strcmp(sir1, "")<< '; //compararea variabilei sir1 cu constanta ir
vid
char str1[20]=hello;
char str2[20]=goodbye;
char str3[20];
int difer, lungime;
cout<<str1=<<str1<< str2=<<str2<<\n;
difer=strcmp(str1, str2);
if (difer == 0)
cout<<Siruri echivalente!\n;
else if (difer>0)
cout<<str1<< mai mare (lexicografic) dect
<<str2<<\n;
else
cout<<str1<< mai mic (lexicografic) dect
<<str2<<\n;
cout<<str1=<<str1<<\n; cout<<str3=<<str3<<\n;
strcpy (str3, str1); cout<<str1=<<str1<<\n;
cout<<str3=<<str3<<\n;
strcat (str3, str1);
cout<<str1=<<str1<<\n;
cout<<str3=<<str3<<\n;
}
Exemplu: S se citeasc elementele unui vector cu maxim 100 de elemente reale.
a) S se interschimbe elementele vectorului n modul urmtor: primul cu ultimul, al doilea cu penultimul, etc.
b) S se ordoneze cresctor elementele vectorului.
// a)
#define FALSE 0
#define TRUE 1
#include <iostream.h>
void main()
{ double vect[100];int n;//n-numarul de elemente ale vectorului
cout<<"Nr. elemente"; cin>>n; double aux;
// de completat exemplul cu secventa de citire a elementelor vectorului
3
2
1
vect[i]
vect[n-i-1]
aux
Figura 4.2. Interschimbarea
a dou variabile
61
for (int i=0; i<n/2; i++){
aux=vect[i];
vect[i]=vect[n-1-i];
vect[n-1-i]=aux;
}
// de completat exemplul cu secventa de afisare a vectorului
}
Pentru schimbarea elementelor vectorului s-a folosit variabila auxiliar aux (figura 4.2.). Fr aceast
variabil, la atribuirea vect[i]=vect[n-1-i], valoarea elementului vect[i] s-ar fi pierdut.
Trebuie observat, deasemenea, c variabila contor i ia valori ntre 0 i n/2 (de exemplu, dac vectorul are 4
sau 5 elemente sunt necesare 2 interschimbri).
b) Pentru ordonarea elementelor vectorului, este prezentat un algoritmi de sortare. Metoda Bubble Sort
compar fiecare element al vectorului cu cel vecin, iar dac este cazul, le schimb ntre ele.
ALGORITM Bubble_Sort
INCEPUT
gata false
CIT TIMP not gata REPETA
INCEPUT
gata = true
PENTRU i=0 LA n-2 REPETA
INCEPUT
DACA vect[i] > vect[i+1] ATUNCI
` INCEPUT
aux=vect[i]
vect[i]=vect[i+1]
vect[i+1]=aux
gata=fals
SFARSIT
SFARSIT
SFARSIT
SFARSIT
// implementarea metodei BubbleSort
int gata =FALSE;int i;
while (!gata){
gata=TRUE;
for (i=0; i<=n-2; i++)
if (vect[i]>vect[i+1]){
aux=vect[i];
vect[i]=vect[i+1];
vect[i+1]=aux;
gata=FALSE;}
}
Exemplu: S se citeasc elementele matricilor A(MXN), B(NXP) i C(MXN), unde M<=10, N<=10 i P<=10.
S se interschimbe liniile matricii A n modul urmtor: prima cu ultima, a doua cu penultima, etc. S se
calculeze i s se afieze matricile: AT=A
T
, SUM=A+C, PROD=AXB. Implementarea citirilor i afirilor
se va completa conform exemplului dat n capitolul 4.2.
#include <iostream.h>
void main()
{
double a[10][10], b[10][10], c[10][10];
62
int m,n,p,j;
cout<<"m="; cin>>m; cout<<"n="; cin>>n; cout<<"p="; cin>>p;
// de completat secvena de citire a elementelor matricii a, cu m linii i n coloane
// de completat secvena de citire a elementelor matricii b, cu n linii i p coloane
// de completat secvena de afiare a matricii a
//interschimbarea liniilor matricii A:
for (i=0; i<m/2; i++)
for (j=0; j<n; j++){
double aux=a[i][j];a[i][j]=a[m-1-i][j];a[m-1-
i][j]=aux;
}
cout<<"Matricea A cu liniile interschimbate:\n";
// de completat secvena de afiare a matricii a
// calculul matricii AT =A
T
double at[10][10]; // at este matricea transpusa
for (i=0; i<n; i++)
for (j=0; j<m; j++)
at[i][j]=a[j][i];
cout<<"A transpus=\n";
// de completat secvena de afiare a matricii at, cu n linii si m coloane
// de completat secvena de citire a elementelor matricii c, cu m linii i n coloane
// calculul matricii SUM=A+C, SUM(MxN):
double sum[10][10]; // sum este matricea suma dintre a si c
for (i=0; i<m; i++)
for (j=0; j<n; j++)
sum[i][j]=a[i][j]+ c[i][j];
cout<<"Matricea SUM=A+C este:\n";
// de completat secvena de afiare a matricii sum
double prod[10][10]; // prod este matricea produs dintre a si b
for (i=0; i<m; i++)
for (j=0; j<p; j++){
prod[i][j]=0;
for (k=0; k<n; k++)
prod[i][j]+=a[i][k]*b[k][j];
}
cout<<"Matricea produs dintre A si B este:\n";
// de completat secvena de afiare a matricii prod, cu m linii si p coloane
}
Se observ c fiecare element din matricea produs PROD=AXB ( A(MXN), B(NXP) ), PROD(MXP) este de
forma: prod
j i ,
=
j k
n
k
k i
b a
,
1
0
,
*
=
, unde i= 1 , 0 m i j= 1 , 0 n .
NTREBRI I EXERCIII
Chestiuni teoretice
1. Care este diferena dintre irurile de caractere
i vectorii de caractere?
2. Ce sunt tablourile?
3. De ce tablourile reprezint date structurate?
4. Prin ce se refer elementele unui tablou?
5. Cine impune tipul unui tablou?
61
Chestiuni aplicative
31. S se implementeze programele cu exemplele prezentate.
32. S se scrie programele pentru exerciiile rezolvate care au fost prezentate.
3. Se citesc de la tastatura elementele unei matrici de caractere (nr. linii=nr. coloane), A(NXN), N<=10.
a) S se afieze matricea A;
b) S se formeze i s se afieze cuvntul format din caracterele pe pe diagonala principal a matricii A;
c) S se calculeze i s se afieze numrul de litere mari, litere mici i cifre din matrice;
d) S se afieze cuvntul format din caracterele de pe diagonala secundar;
e) S se afieze procentul literelor mari, al literelor mici i al cifrelor de pe cele 2 diagonale;
f) S se afieze caracterele comune aflate pe liniile p i q (p, q < N, p i q citite de la tastatur);
g) S se afieze n ordine alfabetic, cresctoare, literele mari aflate pe coloanele impare.
4. Se citesc de la tastatur elementele unei matrici cu elemente reale, B (N X N), N<=8.
a) S se afieze matricea B;
b) S se calculeze i s se afieze produsul elementelor de pe coloanele impare;
c) S se calculeze i s se afieze matricea A, unde: A = ( B +
T
B )
2
;
d) S se formeze i s se afieze vectorul V, ale crui elemente sunt elementele pozitive din matricea A;
e) S se calculeze i s se afieze sumele i produsele elementelor matricii A, aflate n triunghiurile
haurate:
f) S se calculeze procentul elementelor pozitive aflate pe diagonala secundar;
g) S se calculeze i s se afieze matricea C, unde: C = 3 * B
T
+ B
2
;
h) S se calculeze i s se afieze matricea D, unde: D = B + B
2
+ B
3
+ B
4
;
i) S se interschimbe coloanele matricii A astfel: prima cu ultima, a doua cu antipenultima, etc.
5. Se citesc de la tastatur elementele unei matrici de numere ntregi C (N X N), N<=10.
a) S se afieze matricea C;
b) S se calculeze i s se afieze procentul elementelor impare de pe liniile pare;
c) S se calculeze i s se afieze matricea B, unde: B=C
2
;
d) S se calculeze i s se afieze matricea E, unde: E = (C + C
T
)
2
+ I, unde I este matricea unitate;
e) S se afle elementul minim din matricea C;
f) S se nlocuiasc elementul maxim din matricea C cu valoarea val, introdus de la tastatur;
g) S se afieze elementele matricii C care sunt numere prime;
h) S se calculeze i s se afieze sumele i produsele elementelor matricii A, aflate n triunghiurile
haurate:
62
POINTERI
5.1.Variabile pointer 5.3.1. Pointeri i iruri de caractere
5.1.1. Declararea variabilelor pointer 5.3.2. Pointeri i tablouri bidimensionale
5.1.2. Iniializarea variabilelor pointer 5.4. Tablouri de pointeri
5.1.3. Pointeri generici 5.5. Pointeri la pointeri
5.2. Operaii cu pointeri 5.6. Modificatorul const n declararea
5.3. Pointeri i tablouri pointerilor
5.1. VARIABILE POINTER
Pointerii sunt variabile care au ca valori sunt adresele altor variabile (obiecte). Variabila este un nume
simbolic utilizat pentru un grup de locaii de memorie. Valoarea memorat ntr-o variabil pointer este o
adres.
Din punctul de vedere al coninutului zonei de memorie adresate, se disting urmtoarele categorii de pointeri:
pointeri de date (obiecte) - conin adresa unei variabile din memorie;
pointeri generici (numii i pointeri void) - conin adresa unui obiect oarecare, de tip neprecizat;
pointeri de funcii (prezentai n capitolul 6.11.)- conin adresa codului executabil al unei funcii.
n figura 5.1, variabila x este memorat la adresa 1024 i are valoarea 5. Variabila ptrx este memorat la
adresa de memorie 1028 i are valoarea 1024 (adresa variabilei x). Vom spune c ptrx pointeaz ctre x,
deoarece valoarea variabilei ptrx este chiar adresa de memorie a variabilei x.
5.1.1. DECLARAREA VARIABILELOR POINTER
Sintaxa declaraiei unui pointer de date este:
tip - identificator_pointer;
Simbolul - precizeaz c identificator_pointer este numele unei variabile pointer de date, iar tip
este tipul obiectelor a cror adres o va conine.
Exemplu:
int u, v, - p, - q; // - p, - q sunt pointeri de date (ctre int)
double a, b, - p1, - q1; // - p1, - q1 sunt pointeri ctre date de tip double
Pentru pointerii generici, se folosete declaraia:
void - identificator_pointer;
Exemplu:
void - m;
Aceasta permite declararea unui pointer generic, care nu are asociat un tip de date precis. Din acest motiv, n
cazul unui pointer vid, dimensiunea zonei de memorie adresate i interpretarea informaiei nu sunt definite,
iar proprietile difer de ale pointerilor de date.
5.1.2. INIIALIZAEA VARIABILELOR POINTER
5
Variabil pointer
ptrx
Variabil
x
5
Nume variabil
Valoare
1024
1024 adres 1028
Figura 5.1. Variabile pointer
63
Exist doi operatori unari care permit utilizarea variabilelor pointer:
& - operatorul adres (de refereniere) - pentru aflarea adresei din memorie a unei variabile;
- - operatorul de indirectare (de defereniere) - care furnizeaz valoarea din zona de memorie spre care
pointeaz pointerul operand.
n exemplul prezentat n figura 5.1, pentru variabila ntreag x, expresia &x furnizeaz adresa
variabilei x. Pentru variabila pointer de obiecte int, numit ptr, expresia - ptr nseamn coninutul locaiei
de memorie a crei adres este memorat n variabila ptr. Expresia - ptr poate fi folosit att pentru aflarea
valorii obiectului spre care pointeaz ptr, ct i pentru modificarea acesteia (printr-o operaie de atribuire).
Exemplu:
int x, y, - ptr;
// ptr- variabil pointer ctre un int; x,y-variabile predefinite, simple, de tip int
x=5; cout<<Adresa variabilei x este:<<&x<<\n;
cout<<Valoarea lui x:<<x<<\n;
ptr=&x; // atribuire: variabila ptr conine adresa variabilei x
cout<<Variabila pointer ptr are valoarea:<<ptr;
cout<< si adreseaza obiectul:<< - ptr<<\n;
y=- ptr; cout<<y=<<y<<\n; // y=5
x=4; cout<<x=<<x<<\n; cout<<- ptr=<<- ptr<<\n;
// x si - ptr reprezinta acelasi obiect, un intreg cu valoarea 4
x=70; // echivalenta cu - ptr=70;
y=x+10; // echivalenta cu y=- ptr+10
n exemplul anterior, atribuirea ptr=&x se execut astfel: operatorul & furnizeaz adresa lui x;
operatorul = atribuie valoarea (care este o adres) variabilei pointer ptr.
Atribuirea y=- ptr se realizeaz astfel: operatorul - acceseaz coninutul locaiei a crei adres este
coninut n variabila ptr; operatorul = atribuie valoarea variabilei y.
Declaraia int - ptr; poate fi, deci, interpretat n dou moduri, ambele corecte:
ptr este de tipul int - ( ptr este de tip pointer spre int)
- ptr este de tipul int (coninutul locaiei spre care pointeaz variabila ptr este de tipul int)
Construcia tip - este de tipul pointer ctre int.
Atribuirea x=8;este echivalent cu ptr=&x; - p=x;
Variabilele pointer, alturi de operatorii de refereniere i de defereniere, pot apare n expresii.
Exemple:
int x, y, - q; q=&x;
- q=8; // echivalent cu x=8;
q=&5; // invalid - constantele nu au adres
- x=9; // invalid - x nu este variabil pointer
x=&y; //invalid: x nu este variabil pointer, deci nu poate fi folosit cu operatorul de indirectare
y=- q + 3; // echivalent cu y=x+3;
- q = 0; // seteaz x pe 0
- q += 1; // echivalent cu ( - q)++ sau cu x++
int - r; r = q;
/* copiaz coninutul lui q (adresa lui x) n r, deci r va pointa tot ctre x (va conine tot adresa lui x)*/
double w, - r = &w, - r1, - r2; r1= &w; r2=r1;
cout<<r1=<<r1<<\n; //afieaz valoarea pointerului r1 (adresa lui w)
cout<<&r1=<<&r1<<\n; // afieaz adresa variabilei r1
cout<<- r1= <<- r1<<\n;
double z=- r1; // echivalent cu z=w
cout<<z=<<z<<\n;
5.1.3. POINTERI GENERICI
64
La declararea pointerilor generici ( void - nume; ) nu se specific un tip, deci unui pointer void i se pot
atribui adrese de memorie care pot conine date de diferite tipuri: int, float, char, etc. Aceti pointeri pot fi
folosii cu mai multe tipuri de date, de aceea este necesar folosirea conversiilor explicite prin expresii de tip
cast, pentru a preciza tipul datei spre care pointeaz la un moment dat pointerul generic.
Exemplu:
void - v1, - v2; int a, b, - q1, - q2;
q1 = &a; q2 = q1; v1 = q1;
q2 = v1; // eroare: unui pointer cu tip nu i se poate atribui un pointer generic
q2 = (int - ) v1; double s, - ps = &s;
int c, - l; void - sv;
l = (int - ) sv; ps = (double - ) sv;
- (char - ) sv = 'a'; /*Interpretare: adresa la care se gsete valoarea lui sv este
interpretat ca fiind adresa zonei de memorie care conine o data de tip char. */
Pe baza exemplului anterior, se pot face observaiile:
1. Conversia tipului pointer generic spre un tip concret nseamn, de fapt, precizarea tipului de pointer pe
care l are valoarea pointerului la care se aplic conversia respectiv.
2. Conversia tipului pointer generic asigur o flexibilitate mai mare n utilizarea pointerilor.
3. Utilizarea n mod abuziv a pointerilor generici poate constitui o surs de erori.
5.2. OPERAII CU POINTERI
n afara operaiei de atribuire (prezentat n paragraful 5.1.2.), asupra variabilelor pointer se pot realiza
operaii de comparare, adunare i scdere (inclusiv incrementare i decrementare).
Compararea valorilor variabilelor pointer
Valorile a doi pointeri pot fi comparate, folosind operatorii relaionali, ca n exemplul:
Exemplu:
int - p1, - p2;
if (p1<p2)
cout<<p1=<<p1<<<<<p2=<<p2<<\n;
else cout<<p1=<<p1<<>=<<p2=<<p2<<\n;
O operaie uzual este compararea unui pointer cu valoarea nul, pentru a verifica dac acesta
adreseaz un obiect. Compararea se face cu constanta simbolic NULL (definit n header-ul stdio.h)
sau cu valoarea 0.
Exemplu:
if (!p1) // sau if (p1 != NULL)
. . . . . ; // pointer nul
else . . . . ; // pointer nenul
Adunarea sau scderea
Sunt permise operaii de adunare sau scdere ntre un pointer de obiecte i un ntreg:
Astfel, dac ptr este un pointer ctre tipul tip (tip - ptr;), iar n este un ntreg, expresiile
ptr + n i ptr - n
au ca valoare, valoarea lui ptr la care se adaug, respectiv, se scade n - sizeof(tip).
Un caz particular al adunrii sau scderii dintre un pointer de date i un ntreg (n=1) l reprezint
incrementarea i decrementarea unui pointer de date. n expresiile ptr++, respectiv ptr--, valoarea
variabilei ptr devine ptr+sizeof(tip), respectiv, ptr-sizeof(tip).
Este permis scderea a doi pointeri de obiecte de acelai tip, rezultatul fiind o valoare ntreag care
reprezint diferena de adrese divizat prin dimensiunea tipului de baz.
65
Exemplu:
int a, - pa, - pb;
cout<<&a=<<&a<<\n; pa=&a; cout<<pa=<<pa<<\n;
cout<<pa+2<<pa+2<<\n; pb=pa++; cout<<pb=<<pb<<\n;
int i=pa-pb; cout<<i=<<i<<\n;
5.3. POINTERI I TABLOURI
n limbajele C/C++ exist o strns legtur ntre pointeri i tablouri, deoarece numele unui tablou este un
pointer (constant!) care are ca valoare adresa primului element din tablou. Diferena dintre numele unui
tablou i o variabil pointer este aceea c unei variabile de tip pointer i se pot atribui valori la execuie, lucru
imposibil pentru numele unui tablou. Acesta are tot timpul, ca valoare, adresa primului su element. De
aceea, se spune c numele unui tablou este un pointer constant (valoarea lui nu poate fi schimbat). Numele
unui tablou este considerat ca fiind un rvalue (right value-valoare dreapta), deci nu poate apare dect n
partea dreapt a unei expresii de atribuire. Numele unui pointer (n exemplul urmtor, - ptr) este considerat
ca fiind un lvalue (left value-valoare stnga), deci poate fi folosit att pentru a obine valoarea obiectului, ct
i pentru a o modifica printr-o operaie de atribuire.
Exemplu:
int a[10], - ptr; // a este definit ca &a[0]; a este pointer constant
a = a + 1; // ilegal
ptr = a ; // legal: ptr are aceeai valoare ca i a, respectiv adresa elementului a[0]
// ptr este variabil pointer, a este constant pointer.
int x = a[0]; // echivalent cu x = - ptr; se atribuie lui x valoarea lui a[0]
Deoarece numele tabloului a este sinonim pentru adresa elementului de indice zero din tablou, asignarea
ptr=&a[0] poate fi nlocuit, ca n exemplul anterior, cu ptr=a.
5.3.1. POINTERI I IRURI DE CARACTERE
Aa cum s-a artat n capitolul 4, un ir de caractere poate fi memorat ntr-un vector de caractere. Spre
deosebire de celelalte constante, constantele ir de caractere nu au o lungime fix, deci numrul de octei
alocai la compilare pentru memorarea irului, variaz. Deoarece valoarea variabilelor pointer poate fi
schimbat n orice moment, cu mult uurin, este preferabil utilizarea acestora, n locul tablourilor de
caractere (vezi exemplul urmtor).
Exemplu:
char sir[10]; char - psir;
sir = hello; // ilegal
psir = hello; // legal
Operaia de indexare a elementelor unui tablou poate fi realizat cu ajutorul variabilelor pointer.
Exemplu:
int a[10], - ptr; // a este pointer constant; ptr este variabil pointer
ptr = a; // ptr este adresa lui a[0]
ptr+i nseamn ptr+(i- sizeof(int)), deci: ptr + i & a[i]
Deoarece numele unui tablou este un pointer (constant), putem concluziona (figura 5.2):
a+i & a[i]
a[i] - (a+i)
a=&a[0] a+1=&a[1] . . . a+9=&a[9]
- a=a[0] - (a+1)=a[1] . . . - (a+9)=a[9]
a
a[0] a[1] . . . . a[9]
66
Exerciiu: S se scrie urmtorul program (care ilustreaz legtura dintre pointeri i vectori) i s se
urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void main(void)
{int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int - pi1 = a ;
int - pi2 = &a[0]; int - pi3;
cout<<a=<<a<<&a=<<&a<<- a=<<- a<<\n;
cout<<a+1=<<(a+1)<< &a[1]=<< &a[1]<<\n;
cout<<a[1]=<<a[1]<< - (a+1)=<< - (a+1)<<\n;
cout<<pi1=<<pi1<<pi2=<<pi2<<\n; int x=- pi1;
/* x primete valoarea locaiei a carei adres se afl n variabila pointer pi1, deci valoarea lui a[0] */
cout<<x=<<x<<\n; x=- pi1++; // echivalent cu - (pi1++) x=1
cout<<x=<<x<<\n; x=(- pi1)++;
/* x=0: nti atribuirea, apoi incrementarea valorii spre care pointeaz pi1. n urma incrementrii,
valoarea lui a[0] devine 1 */
cout<<x=<<x<<\n; cout<<- pi1<<\n;x=- ++pi1; //echivalent cu - (++pi1)
cout<<x=<<x<<\n; x=++(- pi1); cout<<x=<<x<<\n; pi1=a;
pi3=pi1+3;
cout<<pi1=<<pi1<<- pi1=<<- pi1<<&pi1=<<&pi1<<\n;
cout<<pi3=<<pi3<<- pi3=<<- pi3<<&pi3=<<&pi3<<\n;
cout<<pi3-pi1=<<(pi3-pi1)<<\n; //pi3-pi1=3
}
Exerciiu: S se scrie urmtorul program (legtura pointeri-iruri de caractere) i s se urmreasc
rezultatele execuiei acestuia.
#include <iostream.h>
void main(void)
{int a=-5, b=12, - pi=&a; double u=7.13, v=-2.24, - pd=&v;
char sir1[]=sirul 1, sir2[]=sirul 2, - psir=sir1;
cout<<a=<<a<< &a=<<&a<< b=<<b<< &b=<<&b<<\n;
cout<<- pi=<<- pi<<pi=<<pi<< &pi=<<&pi<<\n;
cout<<- pd=<<- pd<<pd=<<pd<< &pd=<<&pd<<\n;
cout<<- sir1=<<- sir1<< sir1=<<sir1<< &sir1=<<&sir1<<\n;
// *sir1=s sir1=sirul 1 &sir1=0xffd6
cout<<- sir2=<<- sir2<< sir2=<<sir2<< &sir2=<<&sir2<<\n;
// *sir2=s sir2=sirul 2 &sir1=0xffce
cout<<- psir=<<- psir<< psir=<<psir<< &psir=<<&psir<<\n;
// *psir=s psir=sirul 1 &sir1=0xffcc
cout<<sir1+2=<<(sir1+2)<< psir+2=<<(psir+2)<<\n;
// sir1+2=rul 1 psir+2=rul 1
cout<<- (sir1+2)=<< - (sir1+2)<<\n;
// *(sir1+2)=r valoarea elementului de indice 2
void - pv1, - pv2;
pv1=psir; pv2=sir1;
cout<<pv1=<<pv1<<&pv1=<<&pv1<<\n;
cout<<pv2=<<pv2<<&pv2=<<&pv2<<\n;
pi=&b; pd=&v; psir=sir2;
cout<<- pi=<<- pi<<pi=<<pi<< &pi=<<&pi<<\n;
cout<<- pd=<<- pd<<pd=<<pd<< &pd=<<&pd<<\n;
cout<<- psir=<<- psir<<psir=<<psir<< &psir=<<&psir<<\n;
67
}
Exerciiu: S se scrie un program care citete elementele unui vector de ntregi, cu maxim 20
elemente i nlocuiete elementul maxim din vector cu o valoare introdus de la tastatur. Se va folosi
aritmetica pointerilor.
#include <iostream.h>
void main()
{ int a[20];
int n, max, indice; cout<<Nr. elemente:; cin>>n;
for (i=0; i<n; i++)
{ cout<<a[<<i<<]=; cin>>- (a+i);}
// citirea elementelor vectorului
max=- a; indice=0;
for (i=0; i<n; i++)
if (max<=- (a+i))
{ max=- (a+i); indice=i;}
// aflarea valorii elementului maxim din vector i a poziiei acestuia
int val;
cout<<Valoare de inlocuire:; cin >> val;
- (a+indice)=val;
// citirea valorii cu care se va nlocui elementul maxim
for (i=0; i<n; i++)
cout<<- (a+i);<<'\t';
cout<<'\n';
// afiarea noului vector
/* n acest mod de implementare, n situaia n care n vector exist mai multe elemente a cror
valoare este egal cu valoarea elementului maxim, va fi nlocuit doar ultimul dintre acestea (cel de
indice maxim).*/
}
5.3.2. POINTERI I TABLOURI MULTIDIMENSIONALE
Elementele unui tablou bidimensional sunt pstrate tot ntr-o zon continu de memorie, dar inconvenientul
const n faptul c ne gndim la aceste elemente n termeni de rnduri (linii) i coloane (figura 5.3). Un
tablou bidimensional este tratat ca un tablou unidimensional ale crui elemente sunt tablouri
unidimensionale.
int M[4][3]={ {10, 5, -3}, {9, 18, 0}, {32, 20, 1}, {-1, 0, 8} };
Compilatorul trateaz att M, ct i M[0], ca tablouri de mrimi diferite. Astfel:
cout<<Marime M:<<sizeof(M)<<\n; // 24 = 2octei - 12elemente
cout<<Marime M[0]<<sizeof(M[0])<<\n; // 6 = 2octei - 3elemente
cout<<Marime M[0][0]<<sizeof(M[0][0])<<\n; // 4 octei (sizeof(int))
Aa cum compilatorul evalueaz referina ctre un tablou unidimensional ca un pointer, un tablou
bidimensional este referit ntr-o manier similar. Numele tabloului bidimensional, M, reprezint adresa
(pointer) ctre primul element din tabloul bidimensional, acesta fiind prima linie, M[0] (tablou
10 5 -3
9 18 0
32 20 1
-1 0 8
M[0]
M[1]
M[2]
M[3]
Matricea M
Matricea M are 4 linii i 3 coloane.
Numele tabloului bidimensional, M, refer ntregul tablou;
M[0] refer prima linie din tablou;
M[0][0] refer primul element al tabloului.
Figura 5.3. Matricea M
68
unidimensional). M[0] este adresa primului element (M[0][0]) din linie (tablou unidimensional), deci M[0]
este un pointer ctre int: M = M[0] = &M[0][0]. Astfel, M i M[linie] sunt pointeri constani.
Putem concluziona:
M este un pointer ctre un tablou unidimensional (de ntregi, n exemplul anterior).
- M este pointer ctre int (pentru c M[0] este pointer ctre int), i - M = - (M + 0) M[0].
- - M este ntreg; deoarece M[0][0] este int, - - M=- (- M)- (M[0])=- (M[0]+0) M[0][0].
Exerciiu: S se testeze programul urmtor, urmrind cu atenie rezultatele obinute.
#include <iostream.h>
#include <conio.h>
void main()
{int a[3][3]={{5,6,7}, {55,66,77}, {555,666,777}};
clrscr();
cout<<"a="<<a<<" &a="<<&a<<" &a[0]="<<&a[0]<<'\n';
cout<<"Pointeri catre vectorii linii\n";
for (int i=0; i<3; i++){
cout<<" *(a+"<<i<<")="<<*(a+i);
cout<<" a["<<i<<"]="<<a[i]<<'\n';
}
// afiarea matricii
for (i=0; i<3; i++){
for (int j=0; j<3; j++)
cout<<*(*(a+i)+j)<<'\t'; //sau:
cout<<*(a[i]+j)<<'\t';
cout<<'\n';
}
}
5.4. TABLOURI DE POINTERI
Un tablou de pointeri este un tablou ale crui elemente sunt pointeri. Modul general de declarare a unui
tablou de pointeri:
tip - nume_tablou[dim];
S considerm exemplul n care se declar i se iniializeaz tabloul de pointeri str_ptr (figura 5.4.):
char - str_ptr[3] = { Programarea, este, frumoas! };
n ceea ce privete declaraia: char- (str_ptr[3]), se poate observa:
1. str_ptr[3] este de tipul char - (fiecare dintre cele trei elemente ale vectorului str_ptr[3] este de
tipul pointer ctre char);
2. - (str_ptr[3]) este de tip char (coninutul locaiei adresate de un element din str_ptr[3] este de
tip char).
Fiecare element (pointer) din str_ptr este iniializat s pointeze ctre un ir de caractere constant. Fiecare
dintre aceste iruri de caractere se gsesc n memorie la adresele memorate n elementele vectorului
str_ptr: str_ptr[0], str_ptr[1], etc.
Figura 5.4. Tabloul de pointeri str_ptr
str_ptr
Programarea
este
frumoas!
str_ptr[0]
str_ptr[1]
str_ptr[2]
Deoarece operatorul de indexare [ ] are
prioritate mai mare dect operatorul de
defereniere - , declaraia char- str_ptr[3]
este echivalent cu char- (str_ptr[3]), care
precizeaz c str_ptr este un vector de trei
elemente, fiecare element este pointer ctre
caracter.
69
S ne amintim de la pointeri ctre iruri de caractere:
char - p=heLLO;
- ( p+1) = e p[1] = e;
n mod analog:
str_ptr[1] = este;
- ( str_ptr[1] + 1) = s; str_ptr[1][1]=s;
Putem conculziona:
str_ptr este un pointer ctre un pointer de caractere.
- str_ptr este pointer ctre char. Este evident, deoarece str_ptr[0] este pointer ctre char, iar
- str_ptr = - (str_ptr [0] + 0 ) str_ptr[0].
- - str_ptr este un de tip char. Este evident, deoarece str_ptr[0][0] este de tip char, iar
- - str_ptr=- (- str_ptr)- (str_ptr[0])=- (str_ptr[0]+0)
str_ptr[0][0].
5.5. POINTERI LA POINTERI
S revedem exemplul cu tabloul de pointeri str_ptr. irurile spre care pointeaz elementele tabloului pot
fi accesate prin str_ptr[index], ns deoarece str_ptr este un pointer constant, acestuia nu i se pot
aplica operatorii de incrementare i decrementare. Este ilegal :
for (i=0;i<3;i++)
cout<<str_ptr++ ;
De aceea, putem declara o variabil pointer ptr_ptr, care s pointeze ctre primul element din str_ptr.
Variabila ptr_ptr este pointer ctre pointer i se declar astfel:
char - - ptr_ptr;
n exemplul urmtor este prezentat modul de utilizare a pointerului la pointer ptr_ptr (figura 5.5).
Exemplu:
char - - ptr_ptr;
char - str_ptr[3] = { Programarea, este, frumoas! };
char - - ptr_ptr;
ptr_ptr = str_ptr;
Referitor la declaraia char - - ptr_ptr, putem concluziona:
ptr_ptr este de tipul char- - (ptr_ptr este pointer la pointer ctre char);
- ptr_ptr este de tipul char- (coninutul locaiei ptr_ptr este de tipul pointer ctre char);
- - ptr_ptr este de tipul char (- - ptr_ptr - (- ptr_ptr); coninutul locaiei - ptr_ptr
este de tipul char).
Figura 5.5. Pointerul la pointer ptr_ptr
str_ptr
Programarea
este
frumoas!
ptr_ptr
Dup atribuire, i str_ptr i ptr_ptr
pointeaz ctre aceeai locaie de memorie
(primul element al tabloului str_str). n
timp ce fiecare element al lui str_str este un
pointer, ptr_ptr este un pointer ctre pointer.
Deoarece ptr_ptr este un pointer variabil,
valoarea lui poate fi schimbat:
for (i=0;i<3;i++)
cout<<ptr_ptr++ ;
70
5.6. MODIFICATORUL const N DECLARAREA POINTERILOR
Modificatorul const se utilizeaz frecvent n declararea pointerilor, avnd urmtoarele roluri:
Declararea unui pointer spre o dat constant
const *tip nume_pointer=dat_constant;
Exemplu:
const char *sirul=azi;
//variabila sirul este pointer spre un ir constant de caractere
Atribuirile de forma:
*sirul=coco;
*(sirul+2)=A;
nu sunt acceptate, deoarece pointerul sirul pointeaz ctre o dat constant (ir constant).
Declararea unui pointer constant ctre o dat care nu este constant
tip * const nume_pointer=dat_neconst;
Exemplu:
char * const psir=abcd; const char *sir=un text;
sir=alt sir; //incorect, sir pointeaz ctre dat constant
psir=sir; //incorect, deoarece psir este pointer constant
Declararea unui pointer constant ctre o dat constant
const tip * const nume_pointer=dat_constant;
Exemplu:
const char * const psir1="mnP";
*(psir1+2)='Z'; // incorect, data spre care pointez psir1 este constant
psir1++; // incorect, psir1 este pointer constant
NTREBRI I EXERCIII
Chestiuni teoretice
1. n ce const operaia de incrementare a
pointerilor?
2. Tablouri de pointeri.
3. Ce sunt pointerii generici?
4. Ce operaii se pot realiza asupra variabilelor
pointer?
5. De ce numele unui pointer este lvalue?
6. Ce fel de variabile pot constitui operandul
operatorului de defereniere?
7. Operatorul de refereniere.
8. Unui pointer generic i se poate atribui
valoarea unui pointer cu tip?
9. Care este legtura ntre tablouri i pointeri?
10. De ce numele unui tablou este rvalue?
71
Chestiuni practice
33. S se implementeze programele cu exemplele prezentate.
34. S se scrie programele pentru exerciiile rezolvate care au fost prezentate.
3. Analizai urmtoarele secvene de instruciuni. Identificai secvenele incorecte (acolo unde este cazul) i
sursele erorilor:
int a,b,*c; a=7; b=90; c=a;
double y, z, *x=&z; z=&y;
char x, **p, *q; x = 'A'; q = &x; p = &q; cout<<x=<<x<<\n;
cout<<**p=<<**p<<\n; cout<<*q=<<*q<<\n;
cout<<p=<<p<< q=<<q<<*p=<<*p<<\n;
char *p, x[3] = {'a', 'b', 'c'}; int i, *q, y[3] = {10, 20, 30};
p = &x[0];
for (i = 0; i < 3; i++)
{
cout<<*p=<<*p<< p=<<p<<\n;
p++;
}
q = &y[0];
for (i = 0; i < 3; i++)
{
cout<<*q=<<*q<<q=<<q<<\n;
q++;
}
const char *sirul=s programm; *(sirul)++;
double a, *s; s=&(a+89); cout<<s=s<<\n;
double a1, *a2, *a3; a2=&a1; a2+=7.8; a3=a2; a3++;
int m[10], *p;p=m;
for (int i=0; i<10; i++)
cout<<*m++;
void *p1; int *p2; int x; p2=&x; p2=p1;
char c=A; char *cc=&c; cout<<(*cc)++<<\n;
4. Rescriei programele pentru problemele din capitolul 4 (3.a.-3.g., 4.a.-4.i., 5.a.-5.h.), utiliznd aritmetica
pointerilor.
72
FUNCII
6.1. Structura unei funcii 6.4. Tablouri ca parametri
6.2. Apelul i prototipul unei funcii 6.5. Funcii cu parametri implicii
6.3. Transferul parametrilor unei funcii 6.6. Funcii cu numr variabil de parametri
6.3.1.Transferul parametrilor prin valoare 6.7. Funcii predefinite
6.3.2.Transferul prin pointeri 6.8. Clase de memorare
6.3.3.Transferul prin referin 6.9. Moduri de alocare a memoriei
6.3.4.Transferul parametrilor ctre funcia
main
6.10.Funcii recursive
6.11.Pointeri ctre funcii
6.1. STRUCTURA UNEI FUNCII
Un program scris n limbajul C/C++ este un ansamblu de funcii, fiecare dintre acestea efectund o activitate
bine definit. Din punct de vedere conceptual, funcia reprezint o aplicaie definit pe o mulime D
(D=mulimea, domeniul de definiie), cu valori n mulimea C (C=mulimea de valori, codomeniul), care
ndeplinete condiia c oricrui element din D i corespunde un unic element din C.
Funciile comunic prin argumennte: ele primesc ca parametri (argumente) datele de intrare, efectueaz
prelucrrile descrise n corpul funciei asupra acestora i pot returna o valoare (rezultatul, datele de ieire).
Execuia programului ncepe cu funcia principal, numit main. Funciile pot fi descrise n cadrul aceluiai
fiier, sau n fiiere diferite, care sunt testate i compilate separat, asamblarea lor realizndu-se cu ajutorul
linkeditorului de legturi.
O funcie este formata din antet si corp:
antet_funcie
{
corpul_funciei
}
Sau:
tip_val_return nume_func (lista_declaraiilor_param_ formali)
{
declaraii_variabile_locale
instruciuni
return valoare
}
Prima linie reprezint antetul funciei, n care se indic: tipul funciei, numele acesteia i lista declaraiilor
parametrilor formali. La fel ca un operand sau o expresie, o funcie are un tip, care este dat de tipul valorii
returnate de funcie n funcia apelant. Dac funcia nu ntoarce nici o valoare, n locul tip_vali_return se
specific void. Dac tip_val_return lipsete, se consider, implicit, c acesta este int. Nume_funcie este
un identificator.
Lista_declaraiilor_param_formali (ncadrat ntre paranteze rotunde) const ntr-o list (enumerare) care
conine tipul i identificatorul fiecrui parametru de intrare, desprite prin virgul. Tipul unui parametru
poate fi oricare, chiar i tipul pointer. Dac lista parametrilor formali este vid, n antet, dup numele
funciei, apar doar parantezele ( ), sau (void).
Corpul funciei este un bloc, care implementeaz algoritmul de calcul folosit de ctre funcie. n corpul
funciei apar (n orice ordine) declaraii pentru variabilele locale i instruciuni. Dac funcia ntoarce o
valoare, se folosete instruciunea return valoare. La execuie, la ntlnirea acestei instruciuni, se
revine n funcia apelant.
n limbajul C/C++ se utilizeaz declaraii i definiii de funcii.
6
73
Declaraia conine antetul funciei i informeaz compilatorul asupra tipului, numelui funciei i a listei
parametrilor formali (n care se poate indica doar tipul parametrilor formali, nu i numele acestora).
Declaraiile de funcii se numesc prototipuri, i sunt constituite din antetul funciei, din care pot lipsi numele
parametrilor formali.
Definiia conine antetul funciei i corpul acesteia. Nu este admis definirea unei funcii n corpul altei
funcii.
O form nvechit a antetului unei funcii este aceea de a specifica n lista parametrilor formali doar numele
acestora, nu i tipul. Aceast libertate n omiterea tipului parametrilor constituie o surs de erori.
tipul_valorii_returnate nume_funcie (lista_parametrilor_ formali)
declararea_parametrilor_formali
{
declaraii_variabile_locale
instruciuni
return valoare
}
6.2. APELUL I PROTOTIPUL FUNCIILOR
O funcie poate fi apelat printr-o construcie urmat de punct i virgul, numit instruciune de apel, de
forma:
nume_funcie (lista_parametrilor_efectivi);
Parametrii efectivi trebuie s corespund cu cei formali ca ordine i tip. La apel, se atribuie parametrilor
formali valorile parametrilor efectivi, dup care se execut instruciunile din corpul funciei. La revenirea din
funcie, controlul este redat funciei apelante, i execuia continu cu instruciunea urmtoare instruciunii de
apel, din funcia apelant. O alt posibilitate de a apela o funcie este aceea n care apelul funciei constituie
operandul unei expresii. Acest lucru este posibil doar n cazul n care funcia returneaz o valoare, folosit n
calculul expresiei.
Parametrii declarai n antetul unei funcii sunt numii formali, pentru a sublinia faptul c ei nu reprezint
valori concrete, ci numai in locul acestora pentru a putea exprima procesul de calcul realizat prin funcie. Ei
se concretizeaz la execuie prin apelurile funciei.
Parametrii folosii la apelul unei funcii sunt parametri reali, efectivi, concrei, iar valorile lor vor fi atribuite
parametrilor formali, la execuie. Utilizarea parametrilor formali la implementarea funciilor i atribuirea de
valori concrete pentru ei, la execuie, reprezint un prim nivel de abstractizare n programare. Acest mod de
programare se numete programare procedural i realizeaz un proces de abstractizare prin parametri.
Variabilele declarate n interiorul unei funcii, ct i parametrii formali ai acesteia nu pot fi accesai dect n
interiorul acesteia. Aceste variabile sunt numite variabile locale i nu pot fi accesate din alte funcii.
Domeniul de vizibilitate a unei variabile este poriunea de cod la a crei execuie variabila respectiv este
accesibil. Deci, domeniul de vizibilitate a unei variabile locale este funcia n care ea a fost definit (vezi i
paragraful 6.8.).
Exemplu:
int f1(void)
{ double a,b; int c;
. . .
return c; // a, b, c - variabile locale, vizibile doar n corpul funciei
}
void main()
{ . . . . . . // variabile a i b nu sunt accesibile n main()
}
Dac n interiorul unei funcii exist instruciuni compuse (blocuri) care conin declaraii de variabile, aceste
variabile nu sunt vizibile n afara blocului.
Exemplu:
74
void main()
{ int a=1, b=2;
cout << "a=<<a<< b=<<b<< c=<<c\n; // a=1 b=2, c
nedeclarat
. . . . . . . .
{ int a=5; b=6; int c=9;
cout << "a=<<a<< b=<<b<<\n; // a=5 b=6 c=9
. . . . . . . .
}
cout << "a=<<a<< b=<<b<< c=<<c\n; // a=1 b=6, c
nedeclarat
. . . . . . . . . . . .
}
Exerciiu: S se scrie urmtorul program (pentru nelegerea modului de apel al unei funcii) i s se
urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
void f_afis(void)
{
cout<<Se execut instruciunile din corpul funciei\n;
double a=3, b=9.4; cout<<a<<*<<b<<=<<a*b<<\n;
cout<<Ieire din funcie!\n; }
void main()
{
cout<<Intrare n funcia principal\n;
f_afis( ); //apelul funciei f_afis, printr-o instruciune de apel
cout<<Terminat MAIN!\n; }
Exerciiu: S se scrie un program care citete dou numere i afieaz cele mai mare divizor comun al
acestora, folosind o funcie care l calculeaz.
#include <iostream.h>
int cmmdc(int x, int y)
{
if (x==0 || y==1 || x==1 || y==0) return 1;
if (x<0) x=-x;
if (y<0) y=-y;
while (x != 0){
if ( y > x )
{int z=x; x=y; y=z; }
x-=y; // sau: x%=y;
}
return y;}
void main()
{
int n1,n2; cout<<n1=;cin>>n1; cout<<n2=;cin>>n2;
int diviz=cmmdc(n1,n2);
cout<<Cel mai mare divizor comun al nr-lor:<<n1<< i ;
cout<<n2<< este:<<diviz<<\n;
/* sau:
cout<<Cel mai mare divizor comun al nr-lor:<<n1<< i ;
cout<<n2<< este:<<cmmdc(n1,n2)<<\n;*/ }
75
Exerciiu: S se calculeze valoarea lui y, u i m fiind citite de la tastatur:
z=2e ( 2 (u) + 1, m) + e (2 u
2
- 3, m + 1), unde:
e (x,n) = sin( ) cos( ) ix ix
i
n
2
1 =
, (x) =
2
1
x
e
+ , e : R x N R, : R
R
#include <iostream.h>
#include <math.h>
double omega(double x, int n)
{ double s=0; int i;
for (i=1; i<=n; i++) s+=sin(i*x)*cos(i*x);
return s;
}
double psi( double x)
{ return sqrt( 1 + exp (- pow (x, 2)));}
void main()
{double u, z; int m; cout<<u=; cin>>u; cout<<m=; cin>>m;
z=2*omega(2* psi(u) + 1, m) + omega(2*pow(u,2) - 3, m+1);
cout<<z=<<z<<\n; }
n exemplele anterioare, nainte de apelul funciilor folosite, acestea au fost definite (antet+corp). Exist
cazuri n care definirea unei funcii nu poate fi fcut naintea apelului acesteia (cazul funciilor care se
apeleaz unele pe altele). S rezolvm ultimul exerciiu, folosind declaraiile funciilor omega i psi, i nu
definiiile lor.
Exerciiu:
#include <iostream.h>
#include <math.h>
double omega(double, int);
// prototipul funciei omega - antet din care lipsesc numele parametrilor formali
double psi(double); // prototipul funciei psi
void main()
{double u, z; int m; cout<<u=; cin>>u; cout<<m=; cin>>m;
z=2*omega(2* psi(u) + 1, m) + omega(2*pow(u,2) - 3, m+1);
cout<<z=<<z<<\n; }
double omega(double x, int i); // definiia funciei omega
{ double s=0; int i;
for (i=1; i<=n; i++) s += sin (i*x) * cos (i*x);
return s; }
double psi( double x) // definiia funciei psi
{ return sqrt( 1 + exp (- pow (x, 2))); }
Prototipurile funciilor din biblioteci (predefinite) se gsesc n headere. Utilizarea unei astfel de funcii
impune doar includerea n program a headerului asociat, cu ajutorul directivei preprocesor #include.
Programatorul i poate crea propriile headere, care s conin declaraii de funcii, tipuri globale,
macrodefiniii, etc.
76
Similar cu declaraia de variabil, domeniul de valabilitate (vizibilitate) a unei funcii este:
fiierul surs, dac declaraia funciei apare n afara oricrei funcii (la nivel global);
funcia sau blocul n care apare declaraia.
6.3. TRANSFERUL PARAMETRILOR UNEI FUNCII
Funciile comunic ntre ele prin argumente (parametrii).
Exist urmtoarele moduri de transfer (transmitere) a parametrilor ctre funciile apelate:
Transfer prin valoare;
Transfer prin pointeri;
Transfer prin referin.
6.3.1. TRANFERUL PARAMETRILOR PRIN VALOARE
n exemplele anterioare, parametrii de la funcia apelant la funcia apelat au fost transmii prin valoare. De
la programul apelant ctre funcia apelat, prin apel, se transmit valorile partametrilor efectivi, reali. Aceste
valori vor fi atribuite, la apel, parametrilor formali. Deci procedeul de transmitere a parametrilor prin valoare
const n ncrcarea valorii parametrilor efectivi n zona de memorie a parametrilor formali (n stiv). La
apelul unei funcii, parametrii reali trebuie s corespund - ca ordine i tip - cu cei formali.
Exerciiu: S se scrie urmtorul program (care ilustreaz legtura dintre pointeri i vectori) i s se
urmreasc rezultatele execuiei acestuia.
void f1(float intr,int nr)// intr, nr - parametri formali
{
for (int i=0; i<nr;i++) intr *= 2.0;
cout<<Val. Param. intr=<<intr<<\n;// intr=12
}
void main()
{
float data=1.5; f1(data,3);
// apelul funciei f1; data, 3 sunt parametri efectivi
cout<<data=<<data<<\n;
// data=1.5 (nemodificat)
}
Fiecare argument efectiv utilizat la apelul funciei este evaluat, iar valoarea este atribuit parametrului formal
corespunztor. n interiorul funciei, o copie local a acestei valori va fi memorat n parametrul formal. O
modificare a valorii parametrului formal n interiorul funciei (printr-o operaie din corpul funciei), nu va
modifica valoarea parametrului efectiv, ci doar valoarea parametrului formal, deci a copiei locale a
parametrului efectiv (figura 6.1.). Faptul c variabila din programul apelant (parametrul efectiv) i
parametrul formal sunt obiecte distincte, poate constitui un mijloc util de protecie. Astfel, n funcia f1,
valoarea parametrului formal intr este modificat (alterat) prin instruciunea ciclic for. n schimb, valoarea
parametrului efectiv (data) din funcia apelant, rmne nemodificat.
n cazul transmiterii parametrilor prin valoare, parametrii efectivi pot fi chiar expresii. Acestea sunt evaluate,
iar valoarea lor va iniializa, la apel, parametrii formali.
Exemplu:
double psi(int a, double b)
{
if (a > 0) return a*b*2;
else return -a+3*b; }
Copiere valoare
intr
data
1.5
1.5
Figura 6.1. Transmiterea prin
valoare
77
void main()
{ int x=4; double y=12.6, z; z=psi ( 3*x+9, y-5) + 28;
cout<<z=<<z<<\n; }
Transferul valorii este nsoit de eventuale conversii de tip. Aceste conversii sunt realizate automat de
compilator, n urma verificrii apelului de funcie, pe baza informaiilor despre funcie, sau sunt conversii
explicite, specificate de programator, prin operatorul cast.
Exemplu:
float f1(double, int);
void main()
{
int a, b; float g=f1(a, b); // conversie automat: int a -> double a
float h=f1( (double) a, b); // conversie explicit
}
Limbajul C este numit limbajul apelului prin valoare, deoarece, de fiecare dat cnd o funcie transmite
argumente unei funcii apelate, este transmis, de fapt, o copie a parametrilor efectivi. n acest mod, dac
valoarea parametrilor formali (iniializai cu valorile parametrilor efectivi) se modific n interiorul funciei
apelate, valorile parametrilor efectivi din funcia apelant nu vor fi afectate.
6.3.2. TRANSFERUL PARAMETRILOR PRIN POINTERI
n unele cazuri, parametrii transmii unei funcii pot fi pointeri (variabile care conin adrese). n aceste
cazuri, parametrii formali ai funciei apelate vor fi iniializai cu valorile parametrilor efectivi, deci cu
valorile unor adrese. Astfel, funcia apelat poate modifica coninutul locaiilor spre care pointeaz
argumentele (pointerii).
Exerciiu: S se citeasc 2 valori ntregi i s se interschimbe cele dou valori. Se va folosi o funcie de
interschimbare.
#include <iostream.h>
void schimb(int *, int *); //prototipul functiei schimba
void main()
{
int x, y, *ptx, *pty; ptx=&x; pty=&y;
cout<<x=;cin>>x;cout<<y=;cin>>y;cout<<x=<<x;cout<<y=<
<y<<\n;
cout<<"Adr. lui x:"<<&x<<" Val lui x:"<<x<<'\n';
cout<<"Adr.lui y:"<<&y<<" Val y:"<<y<<'\n'; cout<<"Val. lui
ptx:"<<ptx;
cout<<" Cont. locaiei spre care pointeaz ptx:<<*ptx<<'\n';
cout<<"Val. lui pty:"<<pty;
cout<<"Cont. locaiei spre care pointeaz pty:"<<*pty;
schimba(ptx, pty);
// SAU: schimba(&x, &y);
cout<<"Adr. lui x:"<<&x<<" %x Val lui x: %d\n, &x, x);
cout<<"Adr. y:"<<&y<<" Val lui y:"<<y<<'\n';cout<<"Val. lui
ptx:"<<ptx;
cout<<" Cont. locaiei spre care pointeaz ptx:<<*ptx<<'\n';
cout<<"Val. lui pty:"<<pty;
cout<<" Cont. locaiei spre care pointeaz pty:"<<*pty<<'\n';
}
void schimb( int *p1, int *p2)
{
78
cout<<"Val. lui p1:"<<p1;
cout<<" Cont. locaiei spre care pointeaz p1:"<<*p1<<'\n';
cout<<"Val. lui p2:"<<p2;
cout<<" Cont. locaiei spre care pointeaz p2:"<<*p2<<'\n';
int t = *p1; // int *t ; t=p1;
*p2=*p1; *p1=t;
cout<<"Val. lui p1:"<<p1;
cout<<" Cont. locaiei spre care pointeaz p1:<<*p1<<'\n';
cout<<"Val. lui p2:"<<p2;
cout<<" Cont. locaiei spre care pointeaz p2:"<<*p2<<'\n';
}
Dac parametrii funciei schimb ar fi fost transmii prin valoare, aceast funcie ar fi interschimbat copiile
parametrilor formali, iar n funcia main modificrile asupra parametrilor transmii nu s-ar fi pstrat. n
figura 6.2. sunt prezentate mecanismul de transmitere a parametrilor (prin pointeri) i modificrile efectuate
asupra lor de ctre funcia schimb.
Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
double omega (long *k)
{
cout<<"k=", k);
// k conine adr. lui i
cout<<*k=;
cout<<k<<\n;
// *k = 35001
double s=2+(*k)-3;
// s = 35000
cout<<s=<<s<<\n;
*k+=17; // *k = 35017
cout<<*k=<<*k;
cout<<\n;
return s; }
void main()
{
long i = 35001; double w;
cout<<"i="<<i;cout<<"Adr.lui i:"<<&i<<'\n';
w=omega(&i); cout<<i=<<i<< w=<<w<<\n; // i = 350017 w = 35000
}
y x
Parametrii formali p1 i p2, la apelul
funciei schimb, primesc valorile
parametrilor efectivi ptx i pty, care
reprezint adresele variabilelor x i y.
Astfel, variabilele pointer p1 i ptx,
respectiv p2 i pty pointeaz ctre x i
y. Modificrile asupra valorilor
variabilelor x i y realizate n corpul
funciei schimb, se pstreaz i n
funcia main.
0x34
0x5A
pty
10 30 30 10
0x34 0x5A
ptx
0x34
p1
0x5A
p2
Figura 6.2. Transmiterea parametrilor unei funcii prin pointeri
0x451
n funcia main
n funcia omega
35001 (apoi 35017)
i
0x451 (adr.lui i)
k
35000
s
35000
w
Figura 6.3. Transferul parametrilor prin pointeri
79
6.3.2.1. Funcii care returneaz pointeri
Valoarea returnat de o funcie poate fi pointer, aa cum se observ n exemplul urmtor:
Exemplu:
#include <iostream.h>
double *f (double *w, int k)
{ // w conine adr. de nceput a vectorului a
cout<<"w="<<w<<" *w="<<*w<<'\n'; // w= adr. lui a ;*w = a[0]=10
return w+=k;
/*incrementeaza pointerului w cu 2(val. lui k); deci w pointeaz ctre elementul de indice 2 din
vectorul a*/
}
void main()
{double a[10]={10,1,2,3,4,5,6,7,8,9}; int i=2;
cout<<"Adr. lui a este:"<<a;
double *pa=a; // double *pa; pa=a;
cout<<"pa="<<pa<<'\n' // pointerul pa conine adresa de nceput a tabloului a
// a[i] = * (a + i)
// &a[i] = a + i
pa=f(a,i); cout<<"pa="<<pa<<" *pa="<<*pa<<'\n';
// pa conine adr. lui a[2], adica adr. a + 2 * sizeof(double);
*pa=2;
}
6.3.3. TRANSFERUL PARAMETRILOR PRIN REFERIN
n acest mod de transmitere a parametrilor, unui parametru formal i se poate asocia (atribui) chiar obiectul
parametrului efectiv. Astfel, parametrul efectiv poate fi modificat direct prin operaiile din corpul funciei
apelate.
n exemplul urmtor definim variabila br, variabil referin ctre variabila b. Variabilele b i br se gsesc,
n memorie, la aceeai adres i sunt variabile sinonime.
Exemplu:
#include <stdio.h>
#include <iostream.h>
void main()
{
int b,c;
int &br=b; //br referin la alt variabil (b)
br=7;
cout<<"b="<<b<<'\n'; //b=7
cout<<"br="<<br<<'\n'; //br=7
cout<<"Adr. br este:"<<&br; //Adr. br este:0xfff4
printf("Adr. b este:"<<&b<<'\n'; //Adr. b este:0xfff4
b=12; cout<<"br="<<br<<'\n'; //br=12
cout<<"b="<<b<<'\n'; //b=12
c=br; cout<<"c="<<c<<'\n'; //c=12
}
c
b, br 7 12
12
Figura 6.4. Variabilele referin b, br
80
Exemplul devenit clasic pentru explicarea apelului prin referin este cel al funciei de permutare
(interschimbare) a dou variabile.
Fie funcia schimb definit astfel:
void schimb (double x, double y)
{ double t=x; x=y; y=t; }
void main()
{ double a=4.7, b=9.7;
. . . . . . . . . . .
schimb(a, b); // apel funcie
. . . . . . . . . . . }
Pentru ca funcia de interschimbare s poat permuta valorile parametrilor efectivi, n limbajul C/C++
parametrii formali trebuie s fie pointeri ctre valorile care trebuie interschimbate:
void pschimb(double *x, double *y)
{ int t=*x; *x=*y; *y=t; }
void main()
{ double a=4.7, b=9.7;
. . . . . . . . . . .
pschimb(&a, &b); // apel funcie
/* SAU:
double *pa, *pb;
pa=&a; pb=&b;
pschimb(pa, pb);*/
. . . . . . . . . . . }
n limbajul C++ acceai funcie de permutare se poate defini cu parametri formali de tip referin.
void rschimb(double &x, double &y)
{ int t=x; x=y; y=t; }
void main()
{ double a=4.7, b=9.7;
. . . . . . . . . . . . . . .
rschimb(a, b); // apel funcie
. . . . . . . . . . . . . . . }
n acest caz, x i y sunt sinonime cu a i b (nume diferite pentru aceleai grupuri de locaii de memorie).
Interschimbarea valorilor variabilelor de x i y nseamn interschimbarea valorilor variabilelor a i b (fig.
6.6.).
Se atribuie pointerilor x i y valorile
pointerilor pa, pb, deci adresele
variabilelor a i b. Funcia pschimb
permut valorile spre care pointeaz
pointerii x i y, deci valorile lui a i b
(figura 6.5).
Parametri funciei schimb sunt transmii
prin valoare: parametrilor formali x, y li se
atribuie (la apel) valorile parametrilor
efectivi a, b. Funcia schimb permut
valorile parametrilor formali x i y, dar
permutarea nu are efect asupra parametrilor
efectivi a i b.
pschimb
&a
&b
4.7
*x
*y
aux
main
a
b
4.7 9.7
9.7 4.7
Figura 6.5. Transferul parametrilor
prin pointeri
rschimb
4.7
aux
main
x;
a
y;b
4.7 9.7
9.7 4.7
Figura 6.6. Transferul parametrilor prin
referin
81
Comparnd funciile pschimb i rschimb, se observ c diferena dintre ele const n modul de
declarare a parametrilor formali. n cazul funciei pschimb parametrii formali sunt pointeri (de tip
*double), n cazul funciei rschimb, parametrii formali sunt referine ctre date de tip double. n cazul
transferului parametrilor prin referin, parametrii formali ai funciei refer aceleai locaii de memorie (sunt
sinonime pentru) parametrii efectivi.
Comparnd cele trei moduri de transmitere a parametrilor ctre o funcie, se poate observa:
1. La apelul prin valoare transferul datelor este unidirecional, adic valorile se transfer numai de la funcia
apelant ctre cea apelat. La apelul prin referin transferul datelor este bidirecional, deoarece o
modificare a parametrilor formali determin modificarea parametrilor efectivi, care sunt sinonime (au
nume diferite, dar refer aceleai locaii de memorie).
2. La transmiterea parametrilor prin valoare, ca parametrii efectivi pot apare expresii sau nume de variabile.
La transmiterea parametrilor prin referin, ca parametri efectivi nu pot apare expresii, ci doar nume de
variabile. La transmiterea parametrilor prin pointeri, ca parametri efectivi pot apare expresii de pointeri.
3. Transmiterea parametrilor unei funcii prin referin este specific limbajului C++.
4. Limbajul C este numit limbajul apelului prin valoare. Apelul poate deveni, ns, apel prin referin n
cazul variabilelor simple, folosind pointeri, sau aa cum vom vedea n paragraful 6.4., n cazul n care
parametru efectiv este un tablou.
5. n limbajul C++ se poate alege, pentru fiecare parametru, tipul de apel: prin valoare sau prin referin, aa
cum ilustreaz exemplele urmtoare:
Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
#include <stdio.h>
double func(int a, double b, double *c, double &d)
{cout<<"*********************** func *****************\n";
cout<<"a="<<a<<" b="<<b; //a=7 (a=t prin val); b=21 (b=u prin val)
cout<<" c="<<c<<" *c="<<*c<<'\n'; // c=ffe(c=w=&u) *c=21
cout<<" d="<<d; //d=17
cout<<"Adr d="<<&d<<'\n'; //Adr d=ffe6 (adr d=adr v)
a+=2; cout<<"a="<<a<<'\n'; //a=9
d=2*a+b; cout<<"d="<<d<<'\n'; //d=39
/*c=500;
cout<<" c="<<c<<" *c="<<*c<<'\n'; // c=ffe(c=w=&u) *c=21*/
cout<<"*********************** func *****************\n";
return b+(*c);
}
void main()
{cout<<"\n\n \n MAIN MAIN";
int t=7; double u=12, v=17, *w, z; cout<<"u="<<u<<'\n';
//u=12
w=&u; *w=21;
cout<<"t="<<t<<" u="<<u<<" v="<<v; //t=7 u=12 v=17 *w=21
cout<<" *w="<<*w<<" u="<<u<<'\n'; //*w=21 u=21
printf("w=%x Adr. u=%x\n",w,&u); //w=ffee Adr. u=ffee
printf("v=%f Adr v=%x\n",v,&v); //v=17.000 Adr v=ffe6
z=func(t,u,w, v);
cout<<"t="<<t<<"u="<<u<<"v="<<v; //t=7 u=21 (NESCHIMBATI) v=39
(v=d)
cout<<" *w="<<*w<<" z="<<z<<'\n'; //*w=21 w=ffee z=42
printf(" w=%x\n",w);
82
}
Exemplul ilustreaz urmtoarele probleme:
La apelul funciei func, parametrii t i u sunt transmii prin valoare, deci valorile lor vor fi atribuite
parametrilor formali a i b. Orice modificare a parametrilor formali a i b, n funcia func, nu va avea
efect asupra parametrilor efectivi t i u. Al treilea parametru formal al funciei func este transmis prin
pointeri, deci c este de tip double * (pointer ctre un real), sau *c este de tip double.
La apelul funciei, valoarea pointerului w (adresa lui u : w=&u) este atribuit pointerului c. Deci pointerii w
i c conin aceeai adres, pointnd ctre un real. Dac s-ar modifica valoarea spre care pointeaz c n
func (vezi instruciunile din comentariu *c=500), aceast modificare ar fi reflectat i n funcia apelant,
deoarece pointerul w are acelai coninut ca i pointerul c, deci pointeaz ctre aceeai locaie de memorie.
Parametrul formal d se transmite prin referin, deci, n momentul apelului, d i v devin similare (d i v
sunt memorate la aceeai adres). Modificarea valorii variabilei d n func se reflect, deci, i asupra
parametrului efectiv din funcia main.
Exerciiu: S se scrie urmtorul program (care ilustreaz legtura dintre pointeri i vectori) i s se
urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
#include <stdio.h>
double omega(long &k)
{printf("Adr k=%x Val k=%ld\n",&k,k); //Adr k=fff2 Val k=200001
double s=2+k-3;cout<<"s="<<s<<'\n'; //s=200000
k+=17;printf("Adr k=%x Val k=%ld\n",&k,k); //Adr k=fff2 Val k=200018
return s;
}
void main()
{long a=200001;
printf("Adr a=%x Val a=%ld\n",&a,a); //Adr a=fff2 Val a=200001
double w=omega(a); cout<<"w="<<w<<'\n'; //s=200000
}
Aa cum s-a prezentat n paragrafele 2.5.3.2. i 5.6., modificatorii sunt cuvinte cheie utilizai n declaraii sau
definiii de variabile sau funcii. Modificatorul de acces const poate apare n:
Declaraia unei variabile (precede tipul variabilei) restricionnd modificarea valorii datei;
La declararea variabilelor pointeri definind pointeri constani ctre date neconstante, pointeri neconstani
ctre date constante i pointeri constani ctre date constante.
n lista declaraiilor parametrilor formali ai unei funcii, conducnd la imposibilitatea de a modifica
valoarea parametrului respectiv n corpul funciei, ca n exemplul urmtor:
Exemplu:
#include <iostream.h>
#include <stdio.h>
int func(const int &a)
{printf("Adr a=%x Val a=%d\n",&a,a);int b=2*a+1;
//modificarea valorii parametrului a nu este permis
cout<<"b="<<b<<'\n';return b;}
void main()
{const int c=33;int u;printf("Adr c=%x Val c=%d\n",&c,c);
u=func(c);cout<<"u="<<u<<'\n'; }
83
6.3.4. TRANSFERUL PARAMETRILOR CTRE FUNCIA main
n situaiile n care se dorete transmiterea a unor informaii (opiuni, date iniiale, etc) ctre un program, la
lansarea n execuie a acestuia, este necesar definirea unor parametri ctre funcia main. Se utilizeaz trei
parametrii speciali: argc, argv i env. Trebuie inclus headerul stdarg.h.
Prototipul funciei main cu parametri n linia de comand este:
main (int argc, char *argv[ ], char *env[ ])
Dac nu se lucreaz cu un mediu de programare integrat, argumentele transmise ctre funcia main trebuie
editate (specificate) n linia de comand prin care se lanseaz n execuie programul respectiv. Linia de
comand tastat la lansarea n execuie a programului este format din grupuri de caractere delimitate de
spaiu sau tab. Fiecare grup este memorat ntr-un ir de caractere. Dac se lucreaz cu un mediu integrat (de
exemplu, BorlandC), selecia comanzii Arguments din meniul Run determin afiarea unei casete de
dialog n care utilizatorul poate introduce argumentele funciei main.
Adresele de nceput ale acestor iruri sunt memorate n tabloul de pointeri argv[], n ordinea n care
apar n linia de comand (argv[0] memoreaz adresa irului care constituie numele programului,
argv[1] - adresa primului argument, etc.).
Parametrul ntreg argc memoreaz numrul de elemente din tabloul argv (argc>=1).
Parametrul env[] este un tablou de pointeri ctre iruri de caractere care pot specifica parametri ai
sistemului de operare.
Funcia main poate returna o valoare ntreag. n acest caz n antetul funciei se specific la tipul valorii
returnate int, sau nu se specific nimic (implicit, tipul este int), iar n corpul funciei apare instruciunea
return valoare_intreag;. Numrul returnat este transferat sistemului de operare (programul apelant) i poate
fi tratat ca un cod de eroare sau de succes al ncheierii execuiei programului.
Exerciiu: S se implementeze un program care afieaz argumentele transmise ctre funcia main.
#include <iostream.h>
#include <stdarg.h>
void main(int argc, char *argv[], char *env[])
{cout<<"Nume program:"<<argv[0]<<'\n';//argv[0] contine numele programului
if(argc==1)
cout<<"Lipsa argumente!\n";
else
for (int i=1; i<argc; i++){
cout<<"Argumentul "<<i<<":"<<argv[i]<<'\n';
}
6.4. TABLOURI CA PARAMETRI
n limbajul C, cazul parametrilor tablou constituie o excepie de la regula transferului parametrilor prin
valoare. Numele unui tablou reprezint, de fapt, adresa tabloului, deci a primului element din tablou.
Exerciiu: S se afle elementul minim dintr-un vector de maxim 10 elemente. Se vor scrie dou funcii: de
citire a elementelor vectorului i de aflare a elementului minim:
#include <iostream.h>
int min_tab(int a[], int nr_elem)
{int elm=a[0];
for (int ind=0; ind<nr_elem; ind++)
if (elm>=a[ind]) elm=a[ind];
return elm;
}
84
void citireVector(int b[], int nr_el)
{ for (int ind=0; ind<nr_el; ind++){
cout<<"Elem "<<ind+1<<"="; cin>>b[ind];}
}
void main()
{
int a[10]; int i,j,n; cout<<"n="; cin>>n;
citireVector(a,n);
int min=min_tab(a,n); cout<<"Elem. min:"<<min<<'\n'; }
Aceleeai problem poate fi implementat folosind aritmetica pointerilor:
#include <iostream.h>
void citireVector(int *b, int nr_el)
{ for (int ind=0; ind<nr_el; ind++){
cout<<"Elem "<<ind+1<<"="; cin>>*b(ind+ind);}
}
int min_tab(int *a, int nr_elem)
{int elm=*a;
for (int ind=0; ind<nr_elem; ind++)
if ( elm>=*(a+ind) ) elm=*(a+ind);
return elm;
}
void main()
{
int a[10]; int i,j,n; cout<<"n="; cin>>n;
citireVector(a, n);
int min=min_tab(a,n);
cout<<"Elem. min:"<<min<<'\n';
}
Din exemplele anterioare se poate observa:
1. Prototipul funciei min_tab poate fi unul dintre:
int min_tab(int a[], int nr_elem);
int min_tab(int *a, int nr_elem);
2. Echivalene:
int *a int a[]
a[i] *(a+i)
3. Apelul funciilor:
citireVector(a,n);
int min=min_tab(a,n);
4. Pentru tablourile unidimensionale, la apel, nu trebuie specificat numrul de elemente. Dimensiunea
tabloului trebuie s fie cunoscut n funcia care l primete ca parametru. De obicei, dimensiunea tabloului
se transfer ca parametru separat (nr_elem).
Exerciiu: S se scrie urmtorul program i s se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
#include <stdio.h>
double omega(int j, double x, double t[], double *w)
{double s; cout<<"n funcia omega:";
cout<<"j="<<j<<" t[j]="<<t[j]<<" t[j+1]="<<t[j+1]<<'\n';
//j=2 (=i din main)
//t[j]=-3.21 t[j+1]=7.44
85
cout<<"j="<<j<<" w[j]="<<w[j]<<" w[j+1]="<<w[j+1]<<'\n';
//j=2 (=i din main)
//w[j]=-21.16 w[j+1]=92.2
t[j]=100; *(t+j+1)=200; w[j]=300; *(w+j+1)=400;
cout<<"Dup atribuiri:\n";
cout<<"j="<<j<<" t[j]="<< t[j]<<" t[j+1]="<<t[j+1]<<'\n';
//Dup atribuiri:
//j=2
//t[j]=100 t[j+1]=200
//w[j]=300 w[j+1]=400
cout<<"j="<<j<<" w[j]="<<w[j]<<" w[j+1]="<<w[j+1]<<'\n';
int i=2*j+1; x=x+2.29*i; s=x+2*t[0]-w[1];
cout<<"i="<<i<<" x="<<x<<" s="<<s<<'\n';
//i=5 x=1.123+2.29+5 s=x+2*1.32-(-15.34)
return s;
}
void switch1(double *x, double *y)
{double t=*x; *x=*y; *y=t;}
void switch2(double &x, double &y)
{double t; t=x;x=y;y=t;}
void main()
{double a=123, b=456, u=1.123;
int i=2;
double r[]={1.32, 2.15, -3.21, 7.44, -15.8};
double q[]={12.26, -15.34, -21.16, 92.2, 71.6};
cout<<"i="<<i<<" u="<<u<<'\n';
double y=omega(i,u,r,q);
cout<<"i="<<i<<" u="<<u<<'\n';
//i=2 u=....
cout<<"omega(i,u,r,q)=y="<<y<<'\n';
cout<<"r[i]="<<r[i]<<" r[i+1]="<<r[i+1]<<;
cout<<" q[i]="<<q[i]<<" q[i+1]="<<q[i]<<'\n';
//r[i]=100 r[i+1]=200 q[i]=300 q[i+1]=400
cout<<"a="<<a<<" b="<<b<<'\n'; //a=123 b=456
switch1(&a,&b);
cout<<"Rez. intersch. a="<<a<<" b="<<b<<'\n'; //a=456 b=123
switch2(a,b);
cout<<"Rez. intersch. a="<<a<<" b="<<b<<'\n'; //a=123 b=456
cout<<"r[i]="<<r[i]<<" r[i+1]="<<r[i+1]<<'\n';
switch1(r+i,r+i+1);
cout<<"Rez. intersch. r[i]="<<r[i]<<" r[i+1]="<<r[i+1]<<'\n';
switch2(r[i],r[i+1]);
//switch2(*(r+i),*(r+i+1));
cout<<"Rez. intersch. r[i]="<<r[i]<<" r[i+1]="<<r[i+1]<<'\n';
}
n exemplul anterior, parametrii formali i i x din funcia omega sunt transmii prin valoare; parametrii t
i w sunt parametri tablou, transmii prin referin (referin i pointeri). n funcia switch1 parametrii
sunt transmii prin pointeri. n funcia switch2 parametrii sunt transmii prin referin.
Pentru tablourile multidimensionale, pentru ca elementele tabloului s poat fi referite n funcie,
compilatorul trebuie informat asupra modului de organizare a tabloului.
86
Pentru tablourile bidimensionale (vectori de vectori), poate fi omis doar precizarea numrului de linii,
deoarece pentru a adresa elementul a[i][j], compilatorul utilizeaz relaia: &mat[i][j]=&mat+(i*
N+j)*sizeof(tip), n care N reprezint numrul de coloane, iar tip reprezint tipul tabloului.
Exerciiu: Fie o matrice de maxim 10 linii i 10 coloane, ale crei elemente se introduc de la tastatur. S se
implementeze dou funcii care afieaz matricea i calculeaz elementul minim din matrice.
#include <iostream.h>
int min_tab(int a[][10], int nr_lin, int nr_col)
{int elm=a[0][0];
for (int il=0; il<nr_lin; il++)
for (int ic=0; ic<nr_col; ic++)
if (elm>=a[il][ic]) elm=a[il][ic];
return elm;
}
void afisare(int a[][10], int nr_lin, int nr_col)
{
for (int i=0; i<nr_lin; i++)
{for (int j=0; j<nr_col; j++) cout<<a[i][j]<<'\t';
cout<<'\n';
}
}
void main()
{
int mat[10][10];int i, j, M, N;cout<<"Nr. linii:"; cin>>M;
cout<<"Nr. coloane:"; cin>>N;
for (i=0; i<M; i++)
for (j=0; j<N; j++)
{ cout<<"mat["<<i<<","<<j<<"]="; cin>>mat[i][j];}
afisare(mat, M, N);
int min=min_tab(mat, M, N);
cout<<"Elem. min:"<<min<<'\n';
}
Valoarea returnat de o funcie poate s fie transmis i prin referin, cum ilustreaz exemplul
urmtor:
Exemplu:
#include <iostream.h>
#include <stdio.h>
double &func(double &a, double b)
{ printf("n funcie:\n");
printf("Val a=%f Adr a=%x\n", a, &a); //Val a=1.20 Adr a=fffe
cout<<"b="<<b<<'\n'; //b=2.2
a=2*b+1; printf(" Dup atrib: val a=%f Adr a=%x\n", a, &a);
//Val a=5.40 Adr a=fffe
return a;
}
void main()
{double c=1.2;cout<<"***************MAIN****************\n";
printf("Val c=%f Adr c=%x\n",c, &c); //Val c=1.20 Adr c=fffe
double d; printf("Adr. d=%x\n", &d); //Adr. d=ffe6
d=func(c,2.2);
87
printf("Val d=%f Adr d=%x\n", d, &d); //Val d=5.40 Adr d=ffe6
}
6.5. FUNCII CU PARAMETRI IMPLICII
Spre deosebire de limbajul C, n limbajul C++ se pot face iniializri ale parametrilor formali. Parametrii
formali iniializai se numesc parametri implicii. De exemplu, antetul funciei cmmdc (care calculeaz i
returneaz cel mai mare divizor comun al numerelor ntregi primite ca argumente) poate avea aceasta form:
int cmmdc(int x, int y=1);
Parametrul formal y este iniializat cu valoarea 1 i este parametru implicit. La apelul funciilor cu parametri
implicii, unui parametru implicit, poate s-i corespund sau nu, un parametru efectiv. Dac la apel nu i
corespunde un parametru efectiv, atunci parametrul formal va primi valoarea prin care a fost iniializat
(valoarea implicit). Dac la apel i corespunde un parametru efectiv, parametrul formal va fi iniializat cu
valoarea acestuia, negijndu-se astfel valoarea implicit a parametrului formal. n exemplul anterior, la
apelul: int div=cmmdc(9);
x va lua valoarea 9, iar y va lua valoarea 1 (implicit).
Dac n lista de parametri formali ai unei funcii exist i parametri implicii i parametri neiniializai,
parametrii implicii trebuie s ocupe ultimele poziii n list, nefiind permis intercalarea acestora printre
parametrii neiniializai.
6.6. FUNCII CU NUMR VARIABIL DE PARAMETRI
n limbajele C i C++ se pot defini funcii cu un numr variabil de parametri. Parametrii care trebuie s fie
prezeni la orice apel al funciei se numesc parametri fici, ceilali se numesc parametri variabili. Parametrii
fici preced parametrii variabili. Prezena parametrilor variabili se indic n antetul funciei prin trei puncte
care se scriu dup ultimul parametru fix al funciei.
De exemplu, fie antetul funciei numite vrf:
void vrf (int n, double a, . . . )
Funcia vrf are doi parametri fici (n i a ) i parametri variabili, pentru care nu se precizeaz n
prealabil numrul i tipul; numrul i tipul parametrilor variabili difer de la un apel la altul.
Funciile cu un numr variabil de parametri sunt, de obicei, funcii de bibliotec (ex: printf, scanf) i se
definesc folosind nite macrouri speciale care permit accesul la parametrii variabili i se gsesc n headerul
stdarg.h.
6.7. FUNCII PREDEFINITE
Orice mediu de programare este prevzut cu una sau mai multe biblioteci de funcii predefinite. Orice
bibliotec este format din:
fiierele header (conine prototipurile funciilor, declaraiile de variabile);
biblioteca (arhiva) propriu-zis (conine definiii de funcii).
Pentru ca funciile predefinite s poat fi utilizate, fiierele header n care se gsesc prototipurile acestora
trebuie inclus n funcia (programul) apelant printr-o directiv preprocesor (exemplu #include
<stdio.h>). Deasemenea, utilizatorul i poate crea propriile headere proprii. Pentru a putea utiliza
funciile proprii, el trebuie s includ aceste headere n programul apelant (exemplu #include
"my_header.h").
88
Pentru funciile predefinite, au fost create fiiere header orientate pe anumite numite tipuri de aplicaii. De
exemplu, funciile matematice se gsesc n headerul <math.h>. Headerul <stdlib.h> care conine
funcii standard. Headerul <values.h> definete o serie de constante simbolice (exemplu MAXINT,
MAXLONG) care reprezint, n principal, valorile maxime i minime ale diferitelor tipuri de date.
6.7.1. Funcii matematice (headerul <math.h>)
Funcii aritmetice
Valori absolute
int abs(int x);
Returneaz un ntreg care reprezint valoarea absolut a argumentului.
long int labs(long int x);
Analog cu funcia abs, cu deosebirea c argumentul i valoarea returnat sunt de tip long int.
double fabs(double x);
Returneaz un real care reprezint valoarea absolut a argumentului real.
Funcii de rotunjire
double floor(double x);
Returneaz un real care reprezint cel mai apropiat numr, fr zecimale, mai mic sau egal
cu x (rotunjire prin lips).
double ceil(double x);
Returneaz un real care reprezint cel mai apropiat numr, fr zecimale, mai mare sau egal
cu x (rotunjire prin adaos).
Funcii trigonometrice
double sin(double x);
Returneaz valoarea lui sin(x), unde x este dat n radiani. Numrul real returnat se afl n
intervalul [-1, 1].
double cos(double x);
Returneaz valoarea lui cos(x), unde x este dat n radiani. Numrul real returnat se afl n
intervalul [-1, 1].
double tan(double x);
Returneaz valoarea lui tg(x), unde x este dat n radiani.
Funcii trigonometrice inverse
double asin(double x);
Returneaz valoarea lui arcsin(x), unde x se afl n intervalul [-1, 1]. Numrul real returnat
(n radiani) se afl n intervalul [-pi/2, pi/2].
double acos(double x);
Returneaz valoarea lui arccos(x), unde x se afl n intervalul [-1, 1]. Numrul real returnat
se afl n intervalul [0, pi].
double atan(double x);
Returneaz valoarea lui arctg(x), unde x este dat n radiani. Numrul real returnat se afl n
intervalul [0, pi].
double atan2(double y, double x);
Returneaz valoarea lui tg(y/x), cu excepia faptului ca semnele argumentelor x i y permit
stabilirea cadranului i x poate fi zero. Valoarea returnat se afl n intervalul [-pi,pi]. Dac x
i y sunt coordonatele unui punct n plan, funcia returneaz valoarea unghiului format de
dreapta care unete originea axelor carteziene cu punctul, fa de axa absciselor. Funcia
folosete, deasemenea, la transformarea coordonatelor cartezine n coordonate polare.
Funcii exponeniale i logaritmice
double exp(double x);
long double exp(long double x);
Returneaz valoarea e .
x
89
double log(double x);
Returneaz logaritmul natural al argumentului ( ln(x) ).
double log10(double x);
Returneaz logaritmul zecimal al argumentului (lg (x) ).
double pow(double baza, double exponent);
Returneaz un real care reprezint rezultatul ridicrii bazei la exponent ( ).
double sqrt(double x);
Returneaz rdcina ptrat a argumentului
x .
double hypot(double x, double y);
Funcia distanei euclidiene - returneaz
2 2
y x + , deci lungimea ipotenuzei unui triunghi
dreptunghic, sau distana punctului P(x, y) fa de origine.
Funcii de generare a numerelor aleatoare
int rand(void) <stdlib.h>
Genereaz un numr aleator n intervalul [0, RAND_MAX].
6.7.2. Funcii de clasificare (testare) a caracterelor
Au prototipul n headerul <ctype.h>. Toate aceste funcii primesc ca argument un caracter i
returneaz un numr ntreg care este pozitiv dac argumentul ndeplinete o anumit condiie, sau
valoarea zero dac argumentul nu ndeplinete condiia.
int isalnum(int c);
Returneaz valoare ntreag pozitiv daca argumentul este liter sau cifr. Echivalent cu:
isalpha(c)||isdigit(c)
int isalpha(int c);
Testeaz dac argumentul este liter mare sau mic. Echivalent cu isupper(c)||
islower(c).
int iscntrl(int c);
Testeaz dac argumentul este caracter de control (neimprimabil).
int isdigit(int c);
Testeaz dac argumentul este cifr.
int isxdigit(int c);
Testeaz dac argumentul este cifr hexagesimal (0-9, a-f, A-F).
int islower(int c);
Testeaz dac argumentul este liter mic.
int isupper(int c);
Testeaz dac argumentul este liter mare.
int ispunct(int c);
Testeaz dac argumentul este caracter de punctuaie (caracter imprimabil, dar nu
liter sau spaiu).
int isspace(int c);
Testeaz dac argumentul este spaiu alb (' ', '\n', '\t', '\v', '\r')
int isprint(int c);
Testeaz dac argumentul este caracter imprimabil, inclusiv blancul.
6.7.3. Funcii de conversie a caracterelor (prototip n <ctype.h>)
int tolower(int c);
Funcia schimb caracterul primit ca argument din liter mare, n liter mic i
returneaz codul ASCII al literei mici. Dac argumentul nu este liter mare, codul returnat
este chiar codul argumentului.
int toupper(int c);
Funcia schimb caracterul primit ca argument din liter mic, n liter mare i
returneaz codul acesteia. Dac argumentul nu este liter mic, codul returnat este chiar
codul argumentului.
baza
onent exp
90
6.7.4. Funcii de conversie din ir n numr (de citire a unui numr dintr-un ir)
(prototip n <stdlib.h>)
long int atol(const char *npr);
Funcia convertete irul transmis ca argument (spre care pointeaz npr) ntr-un
numr cu semn, care este returnat ca o valoare de tipul long int. irul poate conine
caracterele '+' sau '-'. Se consider c numrul este n baza 10 i funcia nu semnalizeaz
eventualele erori de depire care pot apare la conversia din ir n numr.
int atoi(const char *sir);
Converteste irul spre care pointeaza sir ntr-un numr ntreg.
double atof(const char *sir);
Funcia converteste irul transmis ca argument ntr-un numr real cu semn
(returneaz valoare de tipul double). n secvena de cifre din ir poate apare litera 'e' sau
'E' (exponentul), urmat de caracterul '+' sau '-' i o alt secven de cifre. Funcia nu
semnaleaz eventualele erori de depire care pot apare.
6.7.5. Funcii de terminare a unui proces (program)
(prototip n <process.h>)
void exit(int status);
Termin execuia unui program. Codul returnat de terminarea corect este memorat
n constanta simbolic EXIT_SUCCES, iar codul de eroare - n EXIT_FAILURE.
void abort();
Termin forat execuia unui program.
int system(const char *comanda); prototip n <system.h>
Permite execuia unei comenzi DOS, specificate prin irul de caractere transmis ca
parametru.
6.7.6. Funcii de intrare/ieire (prototip n <stdio.h>)
Streamurile (fluxurile de date) implicite sunt: stdin (fiierul, dispozitivul standard de intrare), stdout
(fiierul, dispozitivul standard de ieire), stderr (fiier standard pentru erori), stdprn (fiier standard
pentru imprimant) i stdaux (dispozitivul auxiliar standard). De cte ori este executat un program,
streamurile implicite sunt deschise automat de ctre sistem. n headerul <stdio.h> sunt definite i
constantele NULL (definit ca 0) i EOF (sfrit de fiier, definit ca -1, CTRL/Z).
int getchar(void);
Citete un caracter (cu ecou) din fiierul standard de intrare (tastatur).
int putchar(int c);
Afieaz caracterul primit ca argument n fiierul standard de ieire (monitor).
char *gets(char *sir);
Citete un ir de caractere din fiierul standard de intrare (pn la primul blank
ntlnit sau linie nou). Returneaz pointerul ctre irul citit.
int puts(const char *sir);
Afieaz irul argument n fiierul standard de ieire i adaug terminatorul de ir.
Returneaz codul ultimului caracter al irului (caracterul care precede NULL) sau -1 n caz
de eroare.
int printf(const char *format, ... );
Funcia permite scrierea n fiierul standard de ieire (pe monitor) a datelor, ntr-un anumit format.
Funcia returneaz numrul de octei (caractere) afiai, sau 1 n cazul unei erori.
1. Parametrul fix al funciei conine:
Succesiuni de caractere afiate ca atare
Exemplu:
printf("\n Buna ziua!\n\n); // afiare: Buna ziua!
Specificatori de format care definesc conversiile care vor fi realizate asupra datelor de ieire,
din formatul intern, n cel extren (de afiare).
2. Parametrii variabili ai funciei sunt expresii. Valorile obinute n urma evalurii acestora sunt
afiate corespunztor specificatorilor de format care apar n parametrul fix. De obicei,
91
parametrul fix conine att specificatori de format, ct i alte caractere. Numrul i tipul
parametrilor variabili trebuie s corespund specificatorului de format.
Un specificator de format care apare n parametrul fix poate avea urmtoarea form:
% [-|c|][sir_cifre_eventual_punct_zecimal] una_sau_doua_litere
- Implicit, datele se cadreaz (aliniaz) la dreapta cmpului n care se scriu. Prezena caracterului
determin cadrarea la stnga.
irul de cifre definete dimensiunea cmpului n care se scrie data. Dac scrierea datei necesit un
cmp de lungime mai mare, lungimea indicat n specificator este ignorat. Dac scrierea datei
necesit un cmp de lungime mai mic, data se va scrie n cmp, cadrat la dreapta sau la stnga
(dac apare semnul - ), completndu-se restul cmpului cu caracterele nesemnificative implicite,
adica spaii. irul de cifre aflate dupa punct definesc precizia (numarul de zecimale cu care este
afiat un numar real - implicit sunt afiate 6 zecimale).
Literele definesc tipul conversiei aplicat datei afiate:
c Afieaz un caracter
s Afieaz un ir de caractere
d Afieaz date ntregi; cele negative sunt precedate de semnul -.
o Afieaz date de tip int sau unsigned int n octal.
x sau X - Afieaz date de tip int sau unsigned int n hexagesimal.
fAfieaz date de tip float sau double n forma: parte_ntreag.parte_fract
e sau E-Afieaz date de tip float sau double n forma:
parte_ntreag.parte_fractionar exponent
Exponentul ncepe cu e sau E i definete o putere a lui zece care nmulit cu restul numrului d
valoarea real a acestuia.
g sau GAfieaz o dat real fie ca n cazul specificatorului terminat cu f, fie ca n cazul
specificatorului terminat cu e. Criteriul de afisare se alege automat, astfel nct afiarea s ocupe un
numr minim de poziii n cmpul de afiare.
l Precede una din literele d, o, x, X, u. La afiare se fac conversii din tipul long sau unsigned long.
L Precede una din literele f, e, E, g, G. La afiare se fac conversii din tipul long double.
int scanf(const char *format, ... );
Funcia citete din fiierul standard de intrare valorile unor variabile i le depune n memorie, la
adresele specificate. Funcia returneaz numrul cmpurilor citite corect.
1. Parametrul fix al funciei conine:
Specificatorii de format care definesc conversiile aplicate datelor de intrare, din formatul extern,
n cel intren (n care sunt memorate). Specificatorii de format sunt asemantori celor folosii de
funcia printf: c, s, d, o, x sau X, u, f, l, L.
2. Parametrii varaibili reprezint o list de adrese ale variabilelor care vor fi citite, deci n aceast
list, numele unei varaibile simple va fi precedat de operatorul adres &.
int sprintf(char *sir_cu_format, const char *format, ... );
Funcia permite scrierea unor date n irul transmis ca prim argument, ntr-un anumit format.
Valoarea returnat reprezint numrul de octei (caractere) scrise n ir, sau 1 n cazul unei erori.
int sscanf(char *sir_cu_format, const char *format, ... );
Funcia citete valorile unor variabile din irul transmis ca prim argument i le depune n memorie, la
adresele specificate. Returneaz numrul cmpurilor citite corect.
Exemplu: S se scrie urmtorul program (care ilustreaz modalitile de folosire a funciilor predefinite) i s
se urmreasc rezultatele execuiei acestuia.
#include <iostream.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <stdio.h>
void main()
92
{ int x=-34; int a=abs(x); cout<<"a="<<a<<'\n';
long int y=-566666;
cout<<"labs(y)="<<labs(y)<<"fabs(-45.67)="<<fabs(-45.67)<<'\n';
cout<<"fabs(45.67)="<<fabs(45.67)<<'\n';
cout<<floor(78.99)<<'\n'; //78
cout<<floor(78.45)<<'\n'; //78
cout<<floor(-78.45)<<'\n'; //-79
cout<<ceil(78.99)<<'\n'; //79
cout<<ceil(78.45)<<'\n'; //79
cout<<ceil(-78.45)<<'\n'; //-78
cout<<isalpha('8')<<'\n'; //0
cout<<isalpha('f')<<'\n'; //val diferita de zero
cout<<isalpha('%')<<'\n'; //0
cout<<tolower('D')<<'\n'; //100 (codul caracterului 'd')
cout<<toupper('a')<<'\n'; //65 (codul caracterului 'A')
char s1[]="-56.234 h mk"; cout<<atol(s1)<<'\n'; //-56
cout<<atoi(s1)<<'\n'; //-56
cout<<atof(s1)<<'\n'; //-56.234
cout<<atof("45E+3 n")<<'\n'; //45000
cout<<"EXECUTIA COMENZII DOS DIR\n"; int cod_ret=system("dir");
cout<<"Val. cod retur="<<cod_ret<<'\n';
int c;cout<<"Astept car:"; c=getchar(); //Presupunem caracter introdus: e
cout<<"Caracterul citit este:"<<putchar(c);//Caracterul citit este: 101
// 101=codul carcterului e
cout<<'\n';puts(s1);cout<<'\n'; printf("Afisarea unui mesaj\n");
int intreg=-45;
printf("VALOAREA VARIABILEI INTREG ESTE:%d\n", intreg);
printf("VALOAREA VARIABILEI INTREG ESTE:%10d\n", intreg);
printf("VALOAREA VARIABILEI INTREG ESTE:%-10d\n", intreg);
double real=2.45;
printf("VALOAREA VARIABILEI real ESTE:%f\n", real);
printf("VALOAREA VARIABILEI real ESTE:%10.3f\n", real);
printf("VALOAREA VARIABILEI real ESTE:%10.5f\n", real);
printf("VALOAREA VARIABILEI real ESTE:%e\n", real);
printf("VAL VAR real:%f si\neste mem. la adr.%x\n",real,&real );
printf("astept sir:");scanf("%s",s1);
printf("Sirul citit este: %s \n", s1);
char sir_f[100];
sprintf(sir_f,"Codul caracterului %c este:%d",c, (int)c);
puts(sir_f);
}
6.8. CLASE DE MEMORARE
Definiii:
Variabilele declarate n afara oricrei funcii sunt variabilele globale.
Variabilele declarate n interiorul unui bloc sunt variabilele locale.
Poriunea de cod n care o variabil este accesibil reprezint scopul (domeniul de vizibilitate) al
variabilei respective.
Parametrii formali ai unei funcii sunt variabile locale ale funciei respective.
Domeniul de vizibilitate al unei variabile locale este blocul n care variabila respectiv este definit.
n situaia n care numele unei variabile globale coincide cu numele unei variabile locale, variabila local o
"mascheaz" pe cea global, ca n exemplul urmtor: n interiorul blocului din funcia main s-a redefinit
variabila a, care este variabil local n interiorul blocului. Variabila local a mascheaz variablila global
numit tot a.
93
Exemplu:
#include <stdio.h>
void main()
{ int a,b; a=1; b=2;
printf("n afara blocului a=%d b=%d\n", a, b);
{int a=5; b=6;
printf("n interiorul blocului a=%d b=%d\n",a,b);
}
printf("n afara blocului a=%d b=%d\n", a, b);
}
n cazul variabilelor locale, compilatorul aloc memorie n momentul execuiei blocului sau funciei n care
acestea sunt definite. Cnd execuia funciei sau blocului se termin, se elibereaz memoria pentru acestea i
valorile pentru variabilele locale se pierd.
Definiii:
Timpul de via a unei variabile locale este durata de execuie a blocului (sau a funciei) n care
aceasta este definit.
Timpul de via a unei variabile globale este durata de execuie a programului.
n exemplul urmtor, variabila ntreag x este vizibil att n funcia main, ct i n funcia func1 (x este
variabila global, fiind definit n exteriorul oricrei funcii). Variabilele a i b sunt variabile locale n
funcia main (vizibile doar n main). Variabilele c i d sunt variabile locale n funcia func1 (vizibile
doar n func1). Varabila y este variabil extern i este vizibil din punctul n care a fost definit, pn la
sfritul fiierului surs (n acest caz, n funcia func1).
Exemplu:
int x;
void main()
{int a,b;
//- - - - - - - - -
}
int y;
void func1(void)
{int c,d;
//- - - - - - - -
}
Clase de memorare
O variabil se caracterizeaz prin: nume, tip, valoare i clas de memorare.
Clasa de memorare se specific la declararea variabilei, prin unul din urmtoarele cuvinte cheie:
auto;
register;
extern;
static.
Clasa de memorare determin timpul de via i domeniul de vizibilitate (scopul) unei variabile (tabelul 6.1).
Exemplu:
auto int a;
static int x;
extern double y;
94
register char c;
Clasa de memorare auto
Dac o variabil local este declarat fr a se indica n mod explicit o clas de memorare, clasa de
memorare considerat implicit este auto. Pentru acea variabil se aloc memorie automat, la intrarea n
blocul sau n funcia n care ea este declarat. Deci domeniul de vizibilitate al variabilei este blocul sau
funcia n care aceasta a fost definit. Timpul de via este durata de execuie a blocului sau a funciei.
Clasa de memorare register
Variabilele din clasa register au acelai domeniu de vizibilitate i timp de via ca i cele din clasa auto.
Deosebirea fa de variabilele din clasa auto const n faptul c pentru memorarea variabilelor register,
compilatorul utilizeaz regitrii interni (ceea ce conduce la creterea eficienei). Unei variabile pentru
care se specific drept clas de memorare register, nu i se poate aplica operatorul de refereniere.
Clasa de memorare extern
O variabil global declarat fr specificarea unei clase de memorare, este considerat ca avnd clasa
de memorare extern. Domeniul de vizibilitate este din momentul declarrii pn la sfritul fiierului
surs. Timpul de via este durata execuiei fiierului. O variabil din clasa extern este iniializat
automat cu valoarea 0.
Clasa de memorare static
Clasa de memorare static are dou utilizri distincte:
Variabilele locale statice au ca domeniu de vizibilitate blocul sau funcia n care sunt definite, iar ca
timp de via - durata de execuie a programului. Se iniializeaz automat cu 0.
Variabilele globale statice au ca domeniu de vizibilitate punctul n care au fost definite pn la
sfritul fiierului surs, iar ca timp de via - durata execuiei programului.
Tabelul 6.1.
Clasa de
memorare
Variabila Domeniu vizibilitate Timp de via
auto
(registe
r)
local (intern) Blocul sau funcia Durara de execuie a blocului
sau a funciei
extern global Din punctul definirii, pn la
sfritul fiierului (ROF)
Alte fiiere
Durara de execuie a blocului
sau a programului
static global ROF -"-
local Bloc sau funcie -"-
nespecificat global Vezi extern Vezi extern
local Vezi auto Vezi auto
6.9. MODURI DE ALOCARE A MEMORIEI
Alocarea memoriei se poate realiza n urmtoarele moduri:
alocare static;
alocare dinamic;
alocare pe stiv.
Se aloc static memorie n urmtoarele cazuri:
pentru instruciunile de control propriu-zise;
pentru variabilele globale i variabilele locale declarate n mod explicit static.
Se aloc memorie pe stiv pentru variabilele locale.
Se aloca dinamic memorie n mod explicit, cu ajutorul funciilor de alocare dinamica, aflate n
headerul <alloc.h>.
95
Exemplu:
int a,b; double x;
double f1(int c, double v)
{int b;
static double z;
}
double w;
int f1(int w)
{double a;
}
void main()
{double b, c; int k;
b=f1(k,c);
}
6.9.1. Alocarea memoriei n mod dinamic
Pentru toate tipurile de date (simple sau structurate), la declararea acestora, compilatorul aloc automat un
numr de locaii de memorie (corespunztor tipului datei). Dimensiunea zonei de memorie necesar pentru
pstrarea valorilor datelor este fixat naintea lansrii n execuie a programului. n cazul declarrii unui
tablou de ntregi cu maximum 100 de elemente vor fi alocai 100*sizeof(int) locaii de memorie
succesive. n situaia n care la un moment dat tabloul are doar 20 de elemente, pentru a aloca doar atta
memorie ct este necesar n momentul respectiv, se va aloca memorie n mod dinamic.
Este de dorit ca n cazul datelor a cror dimensiune nu este cunoscut a priori sau variaz n limite largi, s se
utilizeze o alt abordare: alocarea memoriei n mod dinamic. n mod dinamic, memoria nu mai este alocat
n momentul compilrii, ci n momentul execuiei. Alocarea dinamic elimin necesitatea definirii complete
a tuturor cerinelor de memorie n momentul compilrii. n limbajul C, alocarea memoriei n mod dinamic se
face cu ajutorul funciilor malloc, calloc, realloc; eliberarea zonei de memorie se face cu ajutorul
funciei free. Funciile de alocare/dezalocare a memoriei au prototipurile n header-ele <stdlib.h> i
<alloc.h>:
void *malloc(size_t nr_octei_de_alocat);
Funcia malloc necesit un singur argument (numrul de octei care vor fi alocai) i returneaz un pointer
generic ctre zona de memorie alocat (pointerul conine adresa primului octet al zonei de memorie
rezervate).
void *calloc(size_t nr_elemente, size_t mrimea_n_octei_ a_unui_elem);
Funcia calloc lucreaz n mod similar cu malloc; aloc memorie pentru un tablou de nr_elemente,
numrul de octei pe care este memorat un element este mrimea_n_octei_a_unui_elem i returneaz un
pointer ctre zona de memorie alocat.
void *realloc(void *ptr, size_t mrime);
Funcia realloc permite modificarea zonei de memorie alocat dinamic cu ajutorul funciilor malloc sau
calloc.
Observaie:
n cazul n care nu se reuete alocarea dinamic a memoriei (memorie insuficient), funciile malloc, calloc
i realloc returneaz un pointer null. Deoarece funciile malloc, calloc, realloc returneaz un pointer generic,
rezultatul poate fi atribuit oricrui tip de pointer. La atribuire, este indicat s se utilizeze operatorul de
conversie explicit (vezi exemplu).
Eliberarea memoriei (alocate dinamic cu una dintre funciile malloc, calloc sau realloc) se realizeaz cu
ajutorul funciei free.
void free(void *ptr);
96
Exemplu: S se aloce dinamic memorie pentru 20 de valori ntregi.
int *p;
p=(int*)malloc(20*sizeof(int));
//p=(int*)calloc(20, sizeof(int));
Exerciiu: S se scrie un program care implementeaz funcia numit introd_val. Funcia trebuie s
permit introducerea unui numr de valori reale, pentru care se aloc memorie dinamic. Valorile citite cu
ajutorul funciei introd_val sunt prelucrate n funcia main, apoi memoria este eliberat.
#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
float *introd_val()
/* pentru a putea realiza eliberarea memoriei n funcia main, funcia introd_val trebuie s returneze
adresa de nceput a zonei de memorie alocate dinamic */
{double *p; int nr;printf("Numr valori:"); scanf("%d", nr);
if (!(p=(float*)malloc(nr*sizeof(float))) ){
printf("Memorie insuficient!\n");return NULL;
}
for (int i=0; i<nr; i++){
printf("Val %d=", i+1); scanf("%lf", p+i); return p;}
}
void main()
{float *pt; pt=introd_val();
// prelucrare tablou
free(pt);
}
Exerciiu: S se scrie un program care citete numele angajailor unei ntreprinderi. Numrul angajailor este
transmis ca argument ctre funcia main. Alocarea memoriei pentru cei nr_ang angajai, ct i pentru numele
fiecruia dintre acetia se va face n mod dinamic.
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
void main(int argc, char *argv[])
{char **ang_ptr;
char *nume;
int nr_ang, i;
if (argc==2){
nr_ang=atoi(argv[1]);/* numrul angajailor este transmis ca argument ctre funcia
main. El este convertit din ir de caractere n numr */
ang_ptr=(char**)calloc(nr_ang, sizeof(char*));
if ((ang_ptr==0){
printf("Memorie insuficient!\n");exit(1);}
nume=(char*)calloc(30, sizeof(char));
for (i=0; i<nr_ang; ++i){
printf("Nume angajat:");
scanf("%s",nume);
ang_ptr[i]=(char*)calloc(strlen(nume)+1, sizeof(char));
strcpy(ang_ptr[i], nume);
}
free(nume);
printf("\n");
for (i=0; i<nr_ang; i++)
printf("Angajat nr %d: %s\n", i+1, ang_ptr[i]);
}
else
printf("Lansare n execuie: %s numr_de_angajai\n", argv[0]);
97
}
n limbajul C++ alocarea dinamic a memoriei i eliberarea ei se pot realiza cu operatorii new i delete.
Folosirea acestor operatori reprezint o metod superioar, adaptat programrii orientate obiect.
Operatorul new este un operator unar care returneaz un pointer la zona de memorie alocat dinamic. n
situaia n care nu exist suficient memorie i alocarea nu reuete, operatorul new returneaz pointerul
NULL. Operatorul delete elibereaz zona de memorie spre care pointeaz argumentul su.
Sintaxa:
tipdata_pointer = new tipdata;
tipdata_pointer = new tipdata(val_iniializare);
//pentru iniializarea datei pentru care se aloc memorie dinamic
tipdata_pointer = new tipdata[nr_elem]; //alocarea memoriei pentru un tablou
delete tipdata_pointer;
delete [nr_elem] tipdata_pointer; //eliberarea memoriei pentru tablouri
Tipdata reprezint tipul datei (predefinit sau obiect) pentru care se aloc dinamic memorie, iar
tipdata_pointer este o variabil pointer ctre tipul tipdata.
Pentru a putea afla memoria RAM disponibil la un moment dat, se poate utiliza funcia coreleft:
unsigned coreleft(void);
Exerciiu: S se aloce dinamic memorie pentru o dat de tip ntreg:
int *pint;
pint=new int;
//Sau:
int &i=*new int;
i=100; //i permite referirea la ntregul pstrat n zona de memorie alocat dinamic
Exerciiu: S se aloce dinamic memorie pentru o dat real, dubl precizie, iniializnd-o cu valoarea -7.2.
double *p;
p=new double(-7.2);
//Sau:
double &p=* new double(-7.2);
Exerciiu: S se aloce dinamic memorie pentru un vector de m elemente reale.
double *vector; vector=new double[m];
Exemplu: S se urmreasc rezultatele execuiei urmtorului program, care utilizeaz funcia coreleft.
#include <iostream.h>
#include <alloc.h>
#include <conio.h>
void main()
{ int *a,*b; clrscr();
cout<<"Mem. libera inainte de alocare:"<<coreleft()<<'\n';
cout<<"Adr. pointerilor a si b:"<<&a<<" "<<&b<<'\n';
cout<<"Valorile pointeri a si b inainte de alocare:"<<a<<"
"<<b<<'\n';
a=new int; b=new int[10];
cout<<"Mem. libera dupa alocare:"<<coreleft()<<'\n';
cout<<"Valorile pointerilor a si b dupa alocare:"<<a<<"
"<<b<<'\n';
cout<<"Continutul memoriei
alocate:\n"<<"*a="<<*a<<"\n*b="<<*b<<'\n';
98
for (int k=0;k<10;k++) cout<<"\nb["<<k<<"]="<<b[k];
cout<<'\n';
getch();
*a=1732;
for (int u=0;u<10;u++) b[u]=2*u+1;
cout<<"Cont. zonelor alocate dupa
atribuire:"<<"\n*a="<<*a<<"\nb=";
for (u=0;u<10;u++) cout<<"\nb["<<u<<"]="<<b[u];
delete a; delete b;
cout<<"Mem. libera dupa eliberare:"<<coreleft()<<'\n';
cout<<"Valorile pointerilor a si b dupa eliberare:"<<a<<"
"<<b<<'\n';
cout<<"Continutul memoriei
eliberate:\n"<<"*a="<<*a<<"\n*b="<<*b<<'\n';
for (k=0;k<10;k++) cout<<"\nb["<<k<<"]="<<b[k]; cout<<'\n';
cout<<b[3];
getch();
}
6.10. FUNCII RECURSIVE
O funcie este numit funcie recursiv dac ea se autoapeleaz, fie direct (n definiia ei se face apel la ea
nsi), fie indirect (prin apelul altor funcii). Limbajele C/C++ dispun de mecanisme speciale care permit
suspendarea execuiei unei funcii, salvarea datelor i reactivarea execuiei la momentul potrivit. Pentru
fiecare apel al funciei, parametrii i variabilele automatice se memoreaz pe stiv, avnd valori distincte.
Variabilele statice ocup tot timpul aceeai zon de memorie (figureaz ntr-un singur exemplar) i i
pstreaz valoarea de la un apel la altul. Orice apel al unei funcii conduce la o revenire n funcia respectiv,
n punctul urmtor instruciunii de apel. La revenirea dintr-o funcie, stiva este curat (stiva revine la starea
dinaintea apelului).
Un exemplu de funcie recursiv este funcia de calcul a factorialului, definit astfel:
fact(n)=1, dac n=0;
fact(n)=n*fact(n-1), dac n>0;
Exemplu: S se implementeze recursiv funcia care calculeaz n!, unde n este introdus de la tastatur:
#include <iostream.h>
int fact(int n)
{if (n<0){
cout<<"Argument negativ!\n";
exit(2);
}
else if (n==0) return 1;
else return n*fact(n-1);
}
void main()
{int nr, f; cout<<"nr="; cin>>nr;
f=fact(nr); cout<<nr<<"!="<<f<<'\n';
}
Se observ c n corpul funciei fact se apeleaz nsi funcia fact. Presupunem c nr=4 (iniial,
funcia fact este apelat pentru a calcula 4!). S urmrim diagramele din figurile 6.7. i 6.8. La apelul funciei
fact, valoarea parametrului de apel nr (nr=4) iniializeaz parametrul formal n. Pe stiv se memoreaz
99
adresa de revenire n funcia apelant (adr1) i valoarea lui n (n=4) (figura 6.7.a.). Deoarece n>0, se execut
intruciunea de pe ramura else (return n*fact(n-1)). Funcia fact se autoapeleaz direct. Se memoreaz pe
stiv noua adres de revenire i noua valoare a parametrului n (n=3) (figura 6.7.b.).
La noul reapel al funciei fact, se execut din nou intruciunea de pe ramura else (return n*fact(n-1)). Se
memoreaz pe stiv adresa de revenire i noua valoare a parametrului n (n=2) (figura 6.7.c.). La noul reapel
al funciei fact, se execut din nou intruciunea de pe ramura else (return n*fact(n-1)). Se memoreaz pe stiv
adresa de revenire i noua valoare a parametrului n (n=1) (figura 6.7.d.). La noul reapel al funciei fact, se
execut din nou intruciunea de pe ramura else (return n*fact(n-1)). Se memoreaz pe stiv adresa de
revenire i noua valoare a parametrului n (n=0) (figura 6.7.e.).
n acest moment n=0 i se revine din funcie cu valoarea 1 (1*fact(0)=1*1), la configuraia stivei din figura
6.7.d.) (se cur stiva i se ajunge la configuraia din figura 6.7.d.). n acest moment n=1 i se revine cu
valoarea 2*fact(1)=2*1=2, se cura stiva i se ajunge la configuraia stivei din figura 6.7.c. n acest moment
n=2 i se revine cu valoarea 3*fact(2)=3*2=6, se cura stiva i se ajunge la configuraia stivei din figura
6.7.b. Se cur stiva i se ajunge la configuraia stivei din figura 6.7.a.. n acest moment n=3 i se revine cu
valoarea 4*fact(3)=4*6=24.
O funcie recursiv poate fi realizat i iterativ. Modul de implementare trebuie ales n funcie de problem.
Dei implementarea recursiv a unui algoritm permite o descriere clar i compact, recursivitatea nu
conduce la economie de memorie i nici la execuia mai rapid a programelor. n general, se recomand
utilizarea funciilor recursive n anumite tehnici de programare, cum ar fi unele metode de cutare
(backtracking).
Exerciiu: Fie irul lui Fibonacci, definit astfel: f(0)=0, f(1)=1, f(n)=f(n-1)+f(n-2), dac
n>1. S se scrie un program care implementeaz algoritmul de calcul al irului Fibonacci att recursiv, ct i
iterativ. S se compare timpul de execuie n cele dou situaii.
#include <iostream.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#include <stdio.h>
long int iterativ_fib(long int n) //varianta de implementare iterativ
{if (n==0) return 0;
if (n==1) return 1;
int i; long int a, b, c; a=0; b=1;
for (i=2; i<=n; i++){
c=b; b+=a; a=c;}
return b;
}
long int recursiv_fib(long int n) //varianta de implementare recursiv
Figura 6.7. Configuraia stivei
adr1
n=4
(a)
adr2
n=3
adr1
n=4
(b)
adr2
n=2
adr2
n=3
adr1
n=4
(c)
adr2
n=1
adr2
n=2
adr2
n=3
adr1
n=4
(d)
0!=1
adr2
n=0
adr2
n=1
adr2
n=2
adr2
n=3
adr1
n=4
(e)
6
2
1
1 0
1
2
3
2
4
4
fact
fact
fact
fact
fact
Figura 6.8. Parametri funciei
fact
100
{if (n==0) return 0;
if (n==1) return 1;
long int i1=recursiv_fib(n-1);
long int i2=recursiv_fib(n-2);
return i1+i2;
}
void main()
{int n; clrscr();
cout<<MAXLONG<<'\n';
for (n=10; n<=40; n++) {
clock_t t1, t2, t3;
cout<<CLK_TCK<<'\n';
t1=clock(); long int f1=iterativ_fib(n);
t2=clock(); long f2=recursiv_fib(n); t3=clock();
double timp1=(double)(t2-t1)/CLK_TCK;
double timp2=(double)(t3-t2)/CLK_TCK;
printf("ITERATIV: %10ld t=%20.10lf\n",f1,timp1);
printf("RECURSIV: %10ld t=%20.10lf\n",f2,timp2);
cout<<"Apasa o tasta....\n"; getch();
} }
n exemplul anterior, pentru msurarea timpului de execuie s-a utilizat funcia clock, al crei prototip se
afl n header-ul time.h. Variabilele t1, t2 i t3 sunt de tipul clock_t, tip definit n acelai header.
Constanta simbolic CLK_TCK definete numrul de bti ale ceasului, pe secund.
n general, orice algoritm care poate fi implementat iterativ, poate fi implementat i recursiv. Timpul de
execuie a unei recursii este semnificativ mai mare dect cel necesar execuiei iteraiei echivalente.
Exerciiu: S se implementeze i s se testeze un program care:
a) Genereaz aleator i afieaz elementele unui vector ;
b) Sorteaz aceste elemente, cresctor, aplicnd metodele de sortare BubbleSort, InsertSort, i
QuickSort;
c) S se compare viteza de sortare pentru vectori de diverse dimensiuni (10,30,50,100 elemete).
Metoda BubbleSort a fost prezentat n capitolul 4.
Metoda QuickSort reprezint o alt metod de sortare a elementelor unui vector. Algoritmul este
recursiv: se mparte vectorul n dou partiii, fa de un element pivot (de obicei, elementul din "mijlocul
vectorului"). Partiia stng ncepe de la indexul i (la primul apel i=0), iar partiia dreapt se termin cu
indexul j (la primul apel j=n -1) (figura 6.9.).
Partiia stng este extins la dreapta (i incrementat) pn cnd se gsete un element mai mare dect pivotul;
partiia dreapt este extins la stnga (j decrementat) pn cnd se gsete un element mai mic dect pivotul.
Cele dou elemente gsite, vect[i] i vect[j], sunt interschimbate.
Se reia ciclic extinderea partiiilor pn cnd i i j se "ncrucieaz" (i devine mai mare ca j). n final,
partiia stng va conine elementele mai mici dect pivotul, iar partiia dreapt - elementele mai mari dect
pivotul, dar nesortate.
j i
. . . . . . .
0 n - 1
0
pivot i
j
n - 1
Figura 6.9. Sortare prin metoda QuickSort
101
Algoritmul este reluat prin recursie pentru partiia stng (cu limitele ntre 0 i j ), apoi pentru partiia dreapt
(cu limitele ntre i i n-1 ). Recursia pentru partea stng se oprete atunci cnd j atinge limita stng (devine
0), iar recursia pentru partiia dreapt se oprete cnd i atinge limita dreapt (devine n-1).
SUBALGORITM QuickSort (vect[ ], stg, drt) //la primul apel stg = 0 si drt = n - 1
NCEPUT SUBALGORITM
istg
jdrt
DAC i < j ATUNCI
NCEPUT
pivot=vect[(stg+drt)/2]
CT TIMP i <= j REPET
//extinderea partiiilor stnga i dreapta pn cnd i se ncrucieaz cu j
NCEPUT
CT TIMP i<drt si vect[i]<pivot REPET
i = i + 1
CT TIMP j<stg si vect[j] >pivot REPET
j = j - 1
DAC i<=j ATUNCI
NCEPUT //interschimb elementele vect[i] i vect[j]
auxvect[i]
vect[i]vect[j]
vect[j]aux
ii+1
jj-1
SFRIT
SFRIT
DAC j > stg ATUNCI // partiia stng s-a extins la maxim, apel qiuckSort
pentru ea
CHEAM QuickSort(vect, stg, j)
DAC i < drt ATUNCI // partiia dreapt s-a extins la maxim, apel qiuckSort
pentru ea
CHEAM QuickSort(vect, i, drt)
SFRIT
SFRIT SUBALGORITM
Metoda InsertSort (metoda inseriei)
Metoda identific cel mai mic element al vectorului i l schimb cu primul element. Se reia procedura
pentru vectorul iniial, fr primul element i se caut minimul n acest nou vector, etc.
SUBALGORITM InsertSort (vect[ ], nr_elem)
NCEPUT SUBALGORITM
CT TIMP i< nr_elem REPET
NCEPUT
pozMincautMinim(vect, i) // se apeleaz algoritmul cautMinim
auxvect[i]
vect[i]vect[pozMin]
vect[pozMin]aux
ii+1
SFRIT
102
SFRIT SUBALGORITM
Funcia cautMin(vect[ ], indexIni, nr_elem) caut elementul minim al unui vector,
ncepnd de la poziia indexIni i returneaz poziia minimului gsit.
Mod de implementare (Se va completa programul cu instruciunile care obin i afieaz timpului necesar
ordonrii prin fiecare metod. Se vor compara rezultatele pentru un vector de 10, 30, 50, 100 elemente):
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#define TRUE 1
#define FALSE 0
void gener(double v[], int n)
//functia de generare aleatoare a elementelor vectorului v, cu n elemente
{for (int i=0; i<n; i++)
v[i]=1.0*rand()/100000;
}
void afis(double v[], int n)
//functia de afisare a vectorului
{for (int i=0; i<n; i++)
printf("%10.2f",v[i]);
printf("\n");
}
void copie_vect(double v1[], double v[], int n)
//functie de "duplicare "a unui vector; copie vectorul v in vectorul v1
{for (int i=0; i<n; i++)
v1[i]=v[i];
}
void bubbleSort(double v[], int n)
{int gata; gata=FALSE;
while (!gata){
gata=TRUE;
for (int i=0; i<n-1; i++)
if (v[i]>=v[i+1]){
double aux=v[i];
v[i]=v[i+1];
v[i+1]=aux;
// printf("Interschimbare element %d cu %d",i,i+1);
// afis(v,n);
gata=FALSE;}
}
}
int cautMin(double v[], int indexIni, int n)
// cauta elementul minim, incepnd de la pozitia indexIni, inclusiv
{ double min=v[indexIni];
int pozMin=indexIni;
for (int i=indexIni; i<n; i++)
if (v[i]<=min){
min=v[i]; pozMin=i;
}
return pozMin;
}
103
void insertSort(double v[], int n)
{ int i;
for (i=0; i<n; i++){
int poz=cautMin(v, i, n);
double aux=v[i];
v[i]=v[poz];
v[poz]=aux;
}
}
void quickSort(double v[], int stg, int drt)
{int i,j; i=stg; j=drt; double pivot, aux;
if (i<j){
pivot=v[(stg+drt)/2];
while (i<=j){ //extindere partitie st si dr pana i se incrucis cu j
while (i<drt && v[i]<pivot) i++;
while (j>stg && v[j]>pivot) j--;
if (i<=j){
aux=v[i];v[i]=v[j];v[j]=aux; //interschimbare elemente
i++; j--;
}
}
if (j>stg) quickSort(v, stg, j);
if (i<drt) quickSort(v, i, drt);
}
}
void main()
{
clock_t ti,tf; int n; //n = nr elemente vector
printf("Nr componente vector:"); scanf("%d", &n);
double v[200], v1[200], v2[200], v3[200];
gener(v, n);
copie_vect(v1,v,n);
printf("\nInainte de ordonare: v1="); afis(v1, n); ti=clock();
bubbleSort(v1,n); tf=clock(); printf("\nDupa ordonare :
v1=");afis(v1, n);
printf("%10.7f", dif_b);
printf("\n\n****** INSERT SORT ******\n");
copie_vect(v2,v,n);
printf("\nInainte de ordonare INSERT: v2="); afis(v2, n);
insertSort(v2,n); printf("\nDupa ordonare INSERT:
v2=");afis(v2, n);
int st=0; int dr=n-1; copie_vect(v3, v, n);
printf("\n\n****** QUICK SORT ******\n");
printf("\nInainte ordonare QUICK: v3="); afis(v3, n);
quickSort(v3, st, dr); printf("\nDupa ordonare QUICK: v3=");
afis(v3, n);
}
6.11. POINTERI CTRE FUNCII
Aa cum s-a evideniat n capitolul 5, exista trei categorii de variabilele pointer:
104
Pointeri cu tip;
Pointeri generici (void);
Pointeri ctre funcii.
Pointerii ctre funcii sunt variabile pointer care conin adresa de nceput a codului executabil al unei
funcii. Pointerii ctre funcii permit:
Transferul ca parametru al adresei unei funcii;
Apelul funciei cu ajutorul pointerului.
Declaraia unui pointer ctre funcie are urmtoarea form:
tip_val_intoarse (*nume_point)(lista_declar_param_formali); , unde:
nume_point este un pointer de tipul funcie cu rezultatul tipul_valorii_ntoarse. n declaraia anterioar
trebuie remarcat rolul parantezelor, pentru a putea face distincie ntre declaraia unei funcii care ntoarce un
pointer i declaraia unui pointer de funcie:
tip_val_intoarse * nume_point (lista_declar_param_formali);
tip_val_intoarse (* nume_point)(lista_declar_param_formali);
Exemplu:
int f(double u, int v); //prototipul funciei f
int (*pf)(double, int); //pointer ctre funcia f
int i, j; double d;
pf=f; //atribuie adresa codului executabil al funciei f pointerului
pf
j=*pf(d, i); //apelul funciei f, folosind pf
Exerciiu: S se implementeze un program care calculeaz o funcie a crei valoare este integrala altei
funcii. Pentru calculul integralei se va folosi metoda trapezelor.
Relaia pentru calculul integralei prin metoda
trapezelor pentru
}
b
a
dx x f ) ( este:
I = (f(a)+f(b))/2 +
=
+
1
1
) * (
n
k
h k a f
S se calculeze
}
+ + +
+
b
a
x
x
e
) 1 ln( 3 . 0 1
2 . 0
4
2
| |
dx,
cu o eroare mai mic dect eps (valoarea erorii introdus de la tastatur).
#include <conio.h>
#include <math.h>
#include <iostream.h>
double functie(double x)
{return sqrt(0.1+exp(0.5*fabs(x)))/(1+sqrt(0.3+log(1+pow(x,4))));}
double intrap(double a, double b, long int n, double
(*f)(double))
{double h,s=0; long k;
if (a>=b) return 0;
if (n<=0) n=1;
h=(b-a)/n;
for (k=1; k<n; k++) s+=f(a+k*h);
return ((f(a)+f(b))/2+s)*h;
}
h
a x
1
x
2
x
3
. . . . .x
2 n
x
1 n
b
f(x
)
Figura 6.9. Calculul integralei prin metoda trapezelor
105
void main()
{long int j; double p,q; double eps, d2;double dif;
cout<<"Marg. inf:";cin>>p; cout<<"Marg. sup:";cin>>q;
cout<<"Eroare:";cin>>eps; j=1;
double d1=intrap(p, q, j, functie);
do{
j*=2;
if (j>MAXLONG || j<0) break;
d2=intrap(p, q, j, functie);
dif=fabs(d1-d2); d1=d2;
cout<<"Nr.intervale "<<j<<" Val.integralei "<<d2<<'\n';
}while (dif>eps);
cout<<"\n\n-----------------------------------------------
\n";
cout<<"Val. integralei: "<<d2<<" cu eroare de:"<<eps<<'\n';
}
NTREBRI I EXERCIII
Chestiuni teoretice
1. Asemnri ntre transferul parametrilor unei
funcii prin pointeri i prin referin.
2. Caracteristicile modului de transfer a
parametrilor unei funcii prin pointeri.
3. Caracteristicile variabilelor globale.
4. Caracteristicile variabilelor locale.
5. Care este diferena ntre antetul unei funcii i
prototipul acesteia?
6. Care sunt modurile de alocare a memoriei?
7. Care sunt modurile de transfer a parametrilor
unei funcii?
8. Care sunt operatorii din C++ care permit
alocarea/dezalocarea dinamic a memoriei?
9. Ce clase de memorare cunoastei?
10. Ce este domeniul de vizibilitate a unei
variabile?
11. Ce este prototipul unei funcii?
12. Ce este timpul de via a unei variabile?
13. Ce loc ocup declaraiile variabilelor locale n
corpul unei funcii?
14. Ce reprezint antetul unei funcii?
15. Ce rol are declararea funciilor?
16. Ce se indic n specificatorul de format al
funciei printf ?
17. Ce sunt funciile cu numr variabil de
parametri? Exemple.
18. Ce sunt funciile cu parametri implicii?
19. Ce sunt pointerii ctre funcii?
20. Ce sunt variabilele referin?
21. Cine determin timpul de via i domeniul de
vizibilitate ale unei variabile?
22. Comparaie ntre declararea i definirea
funciilor.
23. Diferene ntre modurile de transfer a
parametrilor prin valoare i prin referin.
24. Diferene ntre modurile de transfer a
parametrilor unei funcii prin pointeri i prin
referin.
25. Din apelul funciei printf se poate omite
specificatorul de format?
26. Din ce este format o funcie?
27. n ce zon de memorie se rezerv spaiu
pentru variabilele globale?
28. O funcie poate fi declarat n corpul altei
funcii?
29. O funcie poate fi definit n corpul unei alte
funcii?
30. Parametrii formali ai unei funcii sunt
variabile locale sau globale?
31. Transferul parametrilor prin valoare.
32. Ce rol au parametrii formali ai unei funcii?
103
Chestiuni practice
1. S se implementeze programele cu exemplele prezentate.
2. S se scrie programele pentru exerciiile rezolvate care au fost prezentate.
3. S se modularizeze programele din capitolul 4 (3.a.-3.g., 4.a.-4.i, 5.a.-5.h.), prin implementarea unor
funcii (funcii pentru: citirea elementelor unui vector, afiarea vectorului, calculul sumei a doi vectori,
calculul produsului scalar a doi vectori, aflarea elementului minim din vector, citire a unei matrici,
afiare a matricii, calculul transpusei unei matrici, calculul sumei a dou matrici, calculul produsului a
dou matrici, calculul produsului elementelor din triunghiul haurat, etc.).
4. S se rescrie programele care rezolv exerciiile din capitolul 3, folosind funcii (pentru calculul
factorialului, aflarea celui mai mare divizor comun, ordonarea lexicografic a caracterelor, etc). Utilizai
funciile de intrare/ieire printf i scanf.
5. S se scrie un program care citete cte dou numere, pn la ntlnirea perechii de numere 0, 0 i
afieaz, de fiecare dat, cel mai mare divizor comun al acestora, folosind o funcie care l calculeaz.
6. Se introduce de la tastatura un numr ntreg. S se afieze toi divizorii numrului introdus. Se va folosi o
funcie de calcul a celui mai mare divizor comun a 2 numere.
7. Secvenele urmtoare sunt corecte din punct de vedere sintactic? Dac nu, identificai sursele erorilor.
void a(int x, y) {cout<<"x="<<x<<" y="<<y<<'\n'; }
void main( ) { int b=9; a(6, 7); }
void main( ) { int x=8; double y=f(x);
cout<<"y="<<y<<'\n';}
int f(int z) {return z+z*z;}
8. Scriei o funcie gsete_cifra care returneaz valoarea cifrei aflate pe poziia k n cadrul
numrului n, ncepnd de la dreapta (n i k vor fi argumentele funciei).
9. Implementai propriile versiuni ale funciile de lucru cu iruri de caractere (din paragraful 4.4).
10. S se calculeze valoarea funciei g, cu o eroare EPS (a, b, EPS citite de la tastatur):
g(x)=
}
+ +
b
a
x x ) 1 (
2
*ln a x + dx +
}
+
b
a
x b b arctg x )) ( ( * dx
11. Implementai funcii iterative i recursive pentru calculul valorilor polinoamelor Hermite H
n
(y), tiind
c: H
0
(y)=1, H
1
(y)=2y, H
n
(x)=2yH
1 n
(y)-2H
2 n
(y) dac n>1. Comparai timpul de
execuie al celor dou funcii.
12. S se scrie un program care genereaz toate numerele palindrom, mai mici dect o valoare dat, LIM. Un
numr palindrom are cifrele simetrice egale (prima cu ultima, a doua cu penultima, etc). Se va folosi o
funcie care testeaz dac un numr este palindrom.
13. Fie matricea C (NXN), N<=10, ale crei elemente sunt date de relaia:
j! +
=
j
k
kx
0
) sin( , dac i<j
C
j i ,
= x
i
, dac i=j
i! +
=0
) cos(
k
kx i , dac i>j
a) S se implementeze urmtoarele funcii: de calcul a elementelor matricii; de afiare a matricii; de
calcul i de afiare a procentului elementelor negative de pe coloanele impare (de indice 1, 3, etc).
b) S se calculeze i s se afieze matricea B, unde: B=C - C
2
+ C
3
- C
4
+ C
5
.
14. S se creeze o bibliotec de funcii pentru lucrul cu matrici, care s conin funciile utilizate frecvent
(citirea elementelor, afisarea matricii, adunare a dou matrici, etc). S se foloseasc aceast bibliotec.
15. S se creeze o bibliotec de funcii pentru lucrul cu vectori, care s conin funciile utilizate frecvent. S
se foloseasc aceast bibliotec.
, unde xe[0,1], x introdus de la tastatur
104
TIPURI DE DATE DEFINITE DE UTILIZATOR
7.1. Tipuri definite de utilizator 7.5. Declaraii typedef
7.2. Structuri 7.4. Uniuni
7.3. Cmpuri de bii 7.6. Enumerri
7.1. TIPURI DEFINITE DE UTILIZATOR
Limbajele de programare de nivel nalt ofer utilizatorului faciliti de a prelucra att datele singulare
(izolate), ct i pe cele grupate. Un exemplu de grupare a datelor - de acelai tip - l constituie tablourile.
Datele predefinite i tablourile (prezentate n capitolele anterioare) nu sunt ns suficiente. Informaia
prelucrat n programe este organizat, n general n ansambluri de date, de diferite tipuri. Pentru a putea
descrie aceste ansambluri (structuri) de date, limbajele de programare de nivel nalt permit programatorului
s-i defineasc propriile tipuri de date.
Limbajul C ofer posibiliti de definire a unor tipurilor de date, cu ajutorul:
structurilor - permit gruparea unor obiecte (date) de tipuri diferite, referite printr-un nume comun;
cmpurilor de bii - membri ai unei structuri pentru care se aloc un grup de bii, n interiorul unui
cuvnt de memorie;
uniunilor - permit utilizarea n comun a unei zone de memorie de ctre mai multe obiecte de diferite
tipuri;
declaraiilor typedef - asociaz nume tipurilor noi de date;
enumerrilor - sunt liste de identificatori cu valori constante, ntregi.
7.2. STRUCTURI
Structurile grupeaz date de tipuri diferite, constituind definiii ale unor noi tipuri de date. Componentele
unei structuri se numesc membrii (cmpurile) structurii. La declararea unei structuri se pot preciza tipurile,
identificatorii elementelor componente i numele structurii.
Forma general de declarare a unei structuri:
struct identificator_tip_structura {
lista_de_declaratii_membrii;
} lista_identificatori_variabile; n care:
struct este un cuvnt cheie (obligatoriu)
identificator_tip_structura reprezint numele noului tip (poate lipsi)
lista_de_declaratii_membri este o list n care apar tipurile i identificatorii membrilor
structurii
lista_identificatori_variabile este