2.1.Limbajele de programare C şi C++. Elemente de bază. 2.1.1.

Limbajele C şi C++ Limbajul C face parte din familia de limbaje concepute pe principiile programării structurate, la care ideea centrală este ”structurează pentru a stăpâni o aplicaţie”. Limbajul C++ este o variantă de limbaj C îmbunătăţit, mai riguroasă şi mai puternică, completată cu construcţiile necesare aplicării principiilor programării orientate pe obiecte (POO). Limbajul C++ păstrează toate elementele limbajului C, beneficiind de eficienţa şi flexibilitatea acestuia. Un program scris în limbajul C (sau C++) este compus din unul sau mai multe fişiere sursă. Un fişier sursă este un fişier text care conţine codul sursă (în limbajul C) al unui program. Fiecare fişier sursă conţine una sau mai multe funcţii şi eventual, referinţe către unul sau mai multe fişiere header Funcţia principală a unui program este numită main. Execuţia programului începe cu execuţia acestei funcţii, care poate apela, la rândul ei, alte funcţii. 2.1.2.Elemente de bază.
VOCABULARUL

În scrierea programelor în limbajul C/C++ pot fi folosite doar anumite simboluri care alcătuiesc alfabetul limbajului. Acesta cuprinde:  Literele mari sau mici de la A la Z (a-z);  Caracterul subliniere ( _ underscore), folosit, de obicei, ca element de legătura între cuvintele compuse;  Cifrele zecimale (0-9);  Simboluri speciale:  Caractere:  operatori (Exemple: +, *, !=);  delimitatori (Exemple: blank (spaţiu), 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 funcţii sau sunt folosite în expresii pentru schimbarea ordinii de efectuare a operaţiilor (în ultimul caz, fiind operator); {} - Încadrează instrucţiunile compuse; // - Indică începutul unui comentariu care se poate întinde până la sfârşitul liniei; /* */ - Indică începutul şi sfârşitul 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).
UNITĂŢILE LEXICALE

Unităţile lexicale (cuvintele) limbajului C/C++ reprezintă grupuri de caractere cu o semnificaţie de sine stătătoare. Acestea sunt:  Identificatori;  Cuvinte cheie ale limbajului; Identificatorii reprezintă numele unor date (constante sau variabile), sau ale unor funcţii. 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 conţine litere mici sau mari, dar limbajul C++ este senzitiv la majuscule şi minuscule (case-sensitive). Astfel, identificatorii viteza şi Viteza sunt diferiţi. Nu pot fi folosiţi ca identificatori cuvintele cheie. Identificatorii pot fi standard (ca de exemplu numele unor funcţii predefinite: scanf, clear, etc.) sau aleşi de utilizator. Cuvintele cheie sunt cuvinte ale limbajului, împrumutate din limba engleză, cărora 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);  Instrucţiuni (Exemple: if, for, while);  Operatori (Exemplu: sizeof). Sensul cuvintelor cheie va fi explicat pe masură ce vor fi prezentate construcţiile în care acestea apar.

2.2. Descrierea şi prelucrarea datelor (tipuri standard de date, constante, variabile, expresii, operaţii de citire/scriere, funcţii uzuale).
2.2.1. DATE ÎN LIMBAJUL C/C++

Aşa cum s-a văzut în capitolul 1, un program realizează o prelucrare de informaţie. 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 afişarea 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 informaţionale 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, urmând ca de atributul clasă de memorare să ne ocupăm în paragraful 6.8. Numele unei date Numele unei date este un identificator şi, ca urmare, trebuie să respecte regulile specifice identificatorilor. Deasemenea, numărul 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, diferenţiindu-se prin caracterul 33, vor fi consideraţi identici.
2.2.2. TIPURI DE DATE

Tipul unei date constă într-o mulţime de valori pentru care s-a adoptat un anumit mod de reprezentare în memoria calculatorului şi o mulţime de operatori care pot fi aplicaţi 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 biţi), capabil să conţină codul unui caracter din setul local de caractere;

în nici un caz. Astfel. caracter sau şir de caractere. Calificatorul long se aplică tipului double. float număr real. signed şi unsigned. Calificatorii signed (cel implicit) şi unsigned se aplică tipului char. Tabelul 2. cu extensie de semn obligatorie Valoare întreagă Valoare întreagă cu precizie mare Valoare întreagă cu precizie mare Valoare întreagă cu precizie mică Valoare întreagă. double număr real. care se pot aplica tipurilor de bază char. short nu este mai lung decât long. acesta va fi int. simplă precizie (6 ) Valoare numerică cu zecimale. În completare există un număr de calificatori. se obţin tipurile derivate de date. însă. Fiecare compilator este liber să interpreteze short şi long în mod adecvat propriului hardware. CONSTANTE O constantă este un literal (o formă externă de reprezentare) numeric. dublă precizie 2. dublă precizie (10 ) Valoare numerică cu zecimale. int. Numele şi valoarea unei constante sunt identice. long. Valoarea unei constante nu poate fi schimbată în timpul execuţiei programului în care a fost utilizată.3. float sau double: short. Short şi long se referă la mărimea diferită a întregilor. int reflectând mărimea cea mai "naturală" pentru un anumit calculator.2. iar datele de tip unsigned int sunt întotdeauna pozitive. Tipul şi . fară extensie de semn Aceeaşi ca la char. în virgulă mobilă.1. simplă precizie. implicit. poate fi întâlnit în expresii cu extensie de semn Aceeaşi ca la char. Toţi aceşti calificatori pot aplicaţi tipului int. Tip Lungimea zonei de memorie ocupate (în biţi) MSUNIX DOS LINUX 8 8 8 8 16 32 32 16 16 32 32 64 80 8 8 32 64 64 32 32 64 32 64 128 Descriere char unsigned char signed char int long (long int) long long int short int unsigned int unsigned long int float double long double Valoarea unui singur caracter. fără semn Valoare întreagă. fără semn Valoare numerică cu zecimale. în virgulă mobilă. dublă precizie.   int număr întreg. S-a intenţionat ca short şi long să furnizeze diferite lungimi de întregi. reflectă în mod tipic mărimea naturală din calculatorul utilizat. Dacă într-o declaraţie se omite tipul de bază.

tip int  Constante întregi hexagesimale Dacă în faţa numărului apar caracterele zero (0) şi x (sau X).3. D (sau d) cu valoare 13.valoarea ei sunt determinate în mod automat. 2. tipul constantei este unsigned long int. F (sau f) cu valoare 15. Exemple: 056 077 // constante întregi octale. tip int  Constante întregi octale Dacă în faţa numărului apare cifra zero (0). E (sau e) cu valoare 14. A (sau a) cu valoare 10. Exemple: 145677L 897655l // tip decimal long int  Dacă secvenţa de cifre este urmată de U sau u. tip int  Constante întregi.  Constante întregi în baza 10. de tipuri derivate  Dacă secvenţa de cifre este urmată de L sau l. C (sau c) cu valoare 12. fără punct zecimal.2. tipul constantei este long int. acest lucru indică faptul că acea constantă este de tipul int. de către compilator. B (sau b) cu valoare 11. tipul constantei este unsigned int. Exemple: 0x45 0x3A 0Xbc // constante întregi hexagesimale. Exemple: 65555u  Dacă secvenţa de cifre este urmată de U (u) şi L (l). in baza opt (constantă octală). Amintim că în baza 16 cifrele sunt: 0-9.Constante întregi Constantele întregi sunt literali numerici (compuşi din cifre). acest lucru indică faptul că acea constantă este de tipul int. pe baza caracterelor care compun literalul. în baza 16 (constantă hexagesimală). 8 sau 16  Constante întregi în baza 10 Exemple: 45 -78 // constante întregi decimale (în baza 10). .1.

Exemplu: Constantă caracter Valoare .codul 66.2.  Valorile ordinale ale literelor mari sunt ordonate şi consecutive ('A' are codul ASCII 65.codul 50. 'b' . etc. În acest caz. numărul din faţa literei E reprezintă mantisa.3. constante este de tip float.45f //tip float 9.  Valorile ordinale ale cifrelor sunt ordonate şi consecutive ('0' are codul ASCII 48.788L //tip long double Constante reale în format ştiinţific Numărul poate fi urmat de caracterul e sau E şi de un număr întreg.codul 67. iar numărul întreg care urmează caracterului E reprezintă exponentul. Constante caracter Constantele caracter sunt încadrate între apostroafe.). etc. 'C' . ea este de tipul double. este de tip long double. '2' . reale     Dacă o constantă numerică conţine punctul zecimal. Exemplu: 3. Exemplu: 'a' //tip char O constantă caracter are ca valoare codul ASCII al caracterului pe care îl reprezintă.Exemple: 7899UL //tip decimal unsigned long int 2. În această formă externă de reprezentare.1459 //tip double Dacă numărul este urmat de F sau f. Acest set de caractere are următoarele proprietăţi:  Fiecărui caracter îi corespunde o valoare întreagă distinctă (ordinală). cu sau fără semn.codul 99.3. Dacă numărul este urmat de L sau l.  Valorile ordinale ale literelor mici sunt ordonate şi consecutive ('a' are codul ASCII 97. '1' codul 49.2. deci valoarea constantei va fi dată de mantisa × 10 exponent .codul 98. baza de numeraţie este 10.).). etc. constanta este în notaţie ştiinţifică. 'B' . 2. Exemplu: 0.Constante numerice.  Constante caracter corespunzătoare caracterelor imprimabile O constantă caracter corespunzătoare unui caracter imprimabil se reprezintă prin caracterul respectiv inclus între apostroafe. In forma externă de reprezentare.2.3. 'c' .

Lungimea unui şir este practic nelimitată.2. O dată izolată este o variabilă simplă. Dacă datele se grupează întrun anumit mod (în tablouri . Dacă o dată nu are legături cu alte date (de exemplu. sau schimbarea valorii sale. mai mare cu 1 decât numărul de caractere din şir. caracter care reprezintă marcatorul sfârşitului de şir. tip. În componenţa unui şir de caractere. variabilele sunt date (obiecte informaţionale) ale căror valori se pot modifica în timpul execuţiei programului. După ultimul caracter al şirului.2. . compilatorul stabilea. tipul constantei. deci şi caracterele escape. matrici . compilatorul plasează automat caracterul NULL (\0). Numele unei variabile ne permite accesul la valoarea ei. automat. În cazul constantelor. la o variabilă ne vom referi prin numele ei. În cazul variabilelor este necesară specificarea tipului fiecăreia. se foloseşte caracterul backslash. deci. relaţia de ordine). vom spune că este o dată izolată. dacă este necesar acest lucru. Şi variabilele sunt caracterizate de atributele nume.vectori. variabilele sunt compuse (structurate).4. Numărul de octeţi pe care este memorat un şir va fi. VARIABILE Spre deosebire de constante. Dacă la o constantă ne puteam referi folosind caracterele componente.4. Dacă se doreşte continuarea unui şir pe rândul următor. trebuie respectate regulile enumerate în secţiunea identificatori. Pentru fiecare caracter se memorează codul ASCII al acestuia. Numele unei variabile este un identificator ales de programator. încadrate de ghilimele.3.‘A’ ‘a’ ‘0’ ‘*’ 2.sau structuri). în funcţie de componenţa literalului. Ca urmare. valoare şi clasă de memorare. poate intra orice caracter. Caracterele componente ale unui şir sunt memorate într-o zonă continuă de memorie (la adrese succesive). Variabilele sunt nume simbolice utilizate pentru memorarea valorilor introduse pentru datele de intrare sau a rezultatelor. Constante şir de caractere 65 97 48 42 Constanta şir este o succesiune de zero sau mai multe caractere. 2.

în memorie se rezervă numărul de locaţii corespunzător tipului variabilei respective. de tip int.4. /* declararea variabilei simple a. pi=3. În acest caz. să fie depusă (memorată. . se rezervă în memorie un număr de octeţi corespunzător tipului variabilei. 2. în acea zonă de memorie. Se rezervă un octet. Într-un program în limbajul C++.14. Iniţializarea variabilelor în declaraţii În momentul declarării unei variabile.1.4.la declararea acesteia. Exemple: int a=7*9+2. atribui) o anumită valoare. /* declararea variabilei simple c. char LinieNoua=’\n’. j. Se specifică tipul variabilei(lor) şi o listă formată din unul sau mai mulţi identificatori ai variabilelor de tipul respectiv./*declararea var. /* declararea variabilei simple lungime. pi*/ short int z=3. simple i. se rezervă 4 octeţi */ 2./*declararea variabilei radiani. j. trebuie declarate înainte de utilizare. Toate variabilele care vor fi folosite în program.8. y=0. double x=9. acesteia i se poate da (asigna. de tip char. La declararea variabilelor. Se evaluează expresia.2. declaraţiile de variabile pot apare în orice loc în programul sursă.2. Declararea variabilelor Modul general de declarare a variabilelor este: tip_variabile listă_nume_variabile. Forma unei declaraţii de variabile cu atribuire este: tip_variabilă nume_variabilă=expresie. iar rezultatul acesteia este asignat variabilei specificate. urmând ca ulterior.2. iar valoarea va fi depusă (memorată) în acele locaţii. Se rezervă pentru i şi j câte 16 biţi (2octeţi)*/ char c. */ float lungime. Exemple: int i. //declararea şi iniţializarea variabilei simple z char d=’\011’. înregistrată) o anumită valoare.declararea şi iniţializarea var. de tip int şi iniţializarea ei cu valoarea 65*/ float radiani.

acesta este considerat tipul implicit. volatile g. Transferul informaţiei se realizează cu operatorul >> pentru intrare şi operatorul << pentru ieşire. //permis b=4/5. prin aşa-numiţii calificatori. de tipul: . În limbajul C++ sunt predefinite următoarele dispozitive logice de intrare/ieşire: cin .dispozitivul de ieşire (monitorul).console input . /* citeşte valoarea variabilei var de la tasatatură */ Sunt posibile operarţii multiple. Aceştia sunt:  const. prin program (printr-o atribuire).terminator=’@’. Utilizarea dispozitivelor de intrare/ieşire cu operatorii corespunzători determină deschiderea unui canal de comunicaţie a datelor către dispozitivul respectiv. Exemple: cout << var. de fapt.Operaţii de intrare/ieşire Limbajele C/C++ nu posedă instrucţiuni de intrare/ieşire. fără ca proprietăţile anterioare să dispară).2. obiecte (predefinite).terminator=’*’. După operator se specifică informaţiile care vor fi citite sau afişate.Compilatorul C++ furnizează mecanisme care permit programatorului să influenţeze codul generat la compilare. în momentul de faţă. fiind. Calificatorul volatile (cel implicit) are efect invers calificatorului const. //w.8.  volatile. Dacă după calificator nu este specificat tipul datei. iar în limbajul C++ prin supraîncărcarea operatorilor (definirea unor noi proprietăţi ale unor operatori existenţi. mai precis a operatorilor >> şi << . mai simplă.dispozitivul de intrare (tastatura). g de tip int. cin şi cout sunt. Aşa cum se va vedea în capitolul 9. Vom folosi în continuare abordarea limbajului C++. În limbajul C aceste operaţii se realizează cu ajutorul unor funcţii (de exemplu.5. Calificatorul const asociat unei variabile. printf şi scanf). implicit 2. volatile char terminator. nu va permite modificarea ulterioară a valorii acesteia. cout . //nepermisa modificarea valorii variabilei b const w.console output . de exemplu). adică int. /* afişează valoarea variabilei var pe monitor*/ cin >> var. Exemple: const float b=8. deci de citire/scriere (ca limbajul PASCAL.

//citirea valorii variabilei c. se efectuează succesiv. Operanzii operatorului extractor (>>) pot fi doar nume de variabile. //afişarea constantei şir de caractere. double cout<<"a="<<a<<"Valoarea expresiei a+b este:"<<a+b<<'\n'. cin >> var1 >> var2 >> var3. int. Operatorii pot fi:  unari (necesită un singur operand). Exemple: char c. Operanzii operatorului insertor (<<) pot fi nume de variabile (caz în care se afişează valoarea variabilei). conform tipului acestora). d de tip int. e. respectiv citirea valorilor variabilelor var1. OPERATORI ŞI EXPRESII Datele (constante sau variabile) legate prin operatori. Tipurile de date transferate către ieşire pot fi: toate tipurile numerice.6. Operatorii care pot fi aplicaţi datelor (operanzilor) depind de tipul operanzilor. cout<<"Astept un caracter:". b. Tipurile de date citite de la tastatură pot fi toate tipurile numerice.Exemple: cout << var1 << var2 << var3. de tip caracter int a. . Utilizarea dispozitivelor şi operatorilor de intrare/ieşire în C++ impune includerea fişierului iostream.4). var2 şi var3. de la stânga la dreapta. double d.  binari (necesită doi operanzi). cin>>a>>b>>e>>d. scrierea. constante sau expresii. formează expresii (figura 2. iar operatorul << se numeşte operator insertor (inserează valori în fluxul datelor de ieşire. Operatorul >> se numeşte operator extractor (extrage valori din fluxul datelor de intrare. caracter sau şir de caractere. 2.h. caracter sau şir de caractere. datorită faptului că tipul unei date constă într-o mulţime de valori pentru care s-a adoptat un anumit mod de reprezentare în memoria calculatorului şi o mulţime de operatori care pot fi aplicaţi acestor valori.  ternari (trei operanzi). int. conform tipului acestora).2. b. e. În acest caz. deci a mesajului cin>>c. //citirea valorilor variabilelor a.

au tip şi valoare.  Operatori aritmetici unari: Operator Semnificaţie Minus unar -a ++ Operator de incrementare a++ (adună 1 la valoarea operandului) -Operator de decrementare (scade 1 din valoarea operandului)  Exemple sau ++a a---a sau Operatorul . Asociativitatea operatorului are loc de la dreapta la stânga. int s. prezentate în paragraful 2. a=b=10.7. cout<<"Adresa la care este memorata variabila a este:"<<&a. apoi a=b. x=9. //rezultat s=11. Expresiile. se pot realiza anumite conversii. int a. mai întâi b=10. Dacă tipurile membrilor stâng şi drept diferă. 2.2. .  Operatorul de atribuire (de asignare) este un operator binar care se aplică tuturor tipurilor de variabile. Este folosit sub formele următoare: nume_variabilă=expresie.O expresie este o combinaţie corectă din punct de vedere sintactic. formată din operanzi şi operatori. s=a+20*5.6. furnizează adresa la care este memorată aceasta. sau: expresie1=expresie2. Exemplu: int a. deoarece s este int. //rezultat: s=110 s=x+2.unar schimbă semnul operandului. Poate fi aplicat oricărui tip de date şi se mai numeşte operator de referenţiere.18. iar valoarea acesteia este atribuită variabilei din membrul stâng. Se evaluează expresia din membrul drept.  Aşa cum se observă în linia a 2-a din exemplul precedent. operatorul de atribuire poate fi utilizat de mai multe ori în aceeaşi expresie.b. OPERATORI Operatorul unar adresă &. Exemplu: float x. aplicat identificatorului unei variabile. ca şi operanzii.1. Astfel.

Operatorul de decrementare -.  Operatori aritmetici binari compuşi Operator Semnificaţie += a=a+b -= a=a+b *= a=a*b Exemple a+=b a-=b a*=b .care poate fi folosit în formă prefixată (--a) sau postfixată (a--).  Utilizarea acestor operatori în expresii. înaintea operandului. x=x+1. Ambii operatori pot fi folosiţi în formă prefixată. caracter. astfel: y=++x y=x++ y=--x y=x-este echivalent cu: x=x+1. determină evaluarea acestora în moduri diferite.  Operatori aritmetici binari: Operator Semnificaţie Exemple + Adunarea celor doi operanzi a+b Scăderea celor doi operanzi a-b * Înmulţirea celor doi operanzi a*b / Împărţirea celor doi operanzi a/b % Operatorul modulo (operatorul rest) a%b (furnizează restul împărţirii operatorului stâng la operatorul drept). după operand (a++. y=x. respectiv --a) sau postfixată. respectiv a--). Operatorul . x=x-1. cout<<”b=”<<b<<’\n’.b.Exemplu: int a. reale. b=-a. este echivalent cu: y=x. y=x. este echivalent cu: y=x. (++a.unar poate fi aplicat datelor întregi. cout<<”a=”<<-a<<’\n’. este echivalent cu: x=x-1. Operatorii de incrementare şi decrementare pot fi aplicaţi datelor numerice sau caracter. în formă prefixată sau postfixată.

dacă relaţia este adevărată.  Operatori logici pe cuvânt Operator Semnificaţie Exemple ! Not (negaţie logică) !(a==b) && And (conjuncţie. Regulile de precedenţă şi asociativitate ale acestor operatori sunt prezentate în tabelul 2. Rezultatul unei expresii în care apare unul din operatorii relaţionali binari este întreg şi are valoarea zero (0) dacă relaţia este falsă.4. Operatorii relaţionali servesc la compararea valorilor celor doi operanzi şi nu modifică valorile operanzilor. real sau char.   Operatori logici pe bit . înmulţirea sau împărţirea acestuia prin valoarea operandului drept. Operatorii aritmetici binari compuşi au aceeaşi prioritate şi asociativitate ca şi operatorul de atribuire. Aceşti operatorii pot fi aplicaţi datelor de tip întreg./= a=a/b a/=b %= a=a%b a%=b Aceşti operatori se obţin prin combinarea operatorilor aritmetici binari cu operatorul de atribuire şi sunt folosiţi sub forma următoare: expresie1 operator= expresie2. real sau caracter. Operatori relaţionali binari Operator Semnificaţie Exemple == Egal cu a==b != Diferit de a!=b < Mai mic decât a<b <= Mai mic sau egal a<=b > Mai mare decât a>b >= Mai mare sau egal a>=b Primii doi operatori mai sunt numiţi operatori de egalitate. sau logic) (a>b) || (b>c) Aceşti operatori pot fi aplicaţi datelor de tip întreg. scăderea. şi logic) (a>b) && (b>c) || Or (disjuncţie. Observaţiile referitoare la operatorii aritmetici binari sunt valabile şi pentru operatorii aritmetici binari compuşi. Rezultatul obţinut este acelaşi cu rezultatul obţinut prin: expresie1 = expresie1 operator expresie2. Toţi aceşti operatorii modifică valoarea operandului stâng prin adunarea. sau valoarea unu (1) (sau diferită de 0 în cazul compilatoarelor sub UNIX). Construcţia x+=1 generează acelaşi rezultat ca expresia x=x+1.

Astfel. El furnizează complementul faţă de unu al unui întreg. sau logic pe bit) a | 0377 XOR (Sau exclusiv logic pe bit) a^b Deplasare stânga 0377 << 2 Deplasare dreapta 0377 >> 2 Aceşti operatori nu se aplică numerelor reale. şi logic pe bit a & 0377 OR (Disjuncţie. se obţin operatorii: &=. Primul operator este unar. cu numărul de biţi indicaţi de operandul drept. Operatorul & este adesea utilizat în expresii ca x&0177. ci numai datelor de tip întreg sau caracter. unde setează pe unu biţii care în x şi masca MASK sunt setaţi pe unu. Operatorii logici pe bit & şi | sunt diferiţi de operatorii logici && şi || (pe cuvânt).Operator ~ & | ^ << >> Semnificaţie Exemple Negaţie (cod complementar faţă de unu) ~a AND (Conjuncţie. Operatorul binar ^ îşi găseşte o utilizare tipică în expresii ca: x&^077. >>=. adică va schimba fiecare bit de pe 1 în zero şi invers. Operatorii de deplasare pe bit (<< şi >>) efectuează deplasarea la stânga sau la dreapta a operandului stâng. cu două poziţii. cu excepţia celor de ordin inferior din x. introducând zero pe poziţiile rămase vacante. ceilalţi binari. Combinând operatorii logici pe bit cu operatorul de atribuire. Operatorul ~ are aceeaşi prioritate ca şi ceilalţi operatori unari. Deplasarea la stânga a unei date cu n poziţii este echivalentă cu înmulţirea valorii acesteia cu 2 n . care maschează ultimii 6 biţi ai lui x pe zero. Operatorul condiţional Este un operator ternar (necesită 3 operanzi). ^=. Deplasarea la dreapta a unei date fără semn cu n poziţii este echivalentă cu împărţirea valorii acesteia cu 2 n . |=. unde setează toţi biţii pe zero. utilizat în construcţii de forma: expresie1?expresie2:expresie3  . <<=. x<<2 deplasează biţii din x la stânga. Operatorul | este utilizat în expresii ca: x&MASK .

daca da. care are ca rezultat numărul de octeţi pe care este memorată o dată de un anumit tip. Operatorul virgulă este folosit în instrucţiunea for. de octeţi pe care este memorată constanta şir ”ab6*”   Operatorul (tip) . Altfel (dacă expresie1 are valoarea zero). Deci operatorul condiţional este folosit pentru a atribui întregii expresii tipul şi valoarea expresiei2 sau a expresiei3. 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. Exemple: cout<<sizeof(int).// afişează 5. atunci tipul şi valoarea întregii expresii vor fi aceleaşi cu tipul şi valoarea expresiei2. Tipul şi valoarea întregii expresii este dată de tipul şi valoarea expresiei2. x=(c=y. y--. tipul şi valoarea întregii expresii vor fi aceleaşi cu tipul şi valoarea expresiei3. Dacă aceasta are o valoare diferită de zero. nr. y:”. c<=5). altfel semn=1. Operatorul virgulă Este utilizat în construcţii de forma: expresie1 . // afişează numărul de octeţi pe care este memorat un întreg (2) cout<<sizeof(”ab6*”). c. cout<<”Astept val. Operatorul virgulă are cea mai mică prioritate. în funcţie de o anumită condiţie. expresie2 Operatorul virgulă forţează evaluarea unei expresii de la stânga la dreapta. ptr. x=0. Operandul este un tip sau o dată (constantă sau variabilă) de un anumit tip. y. Exemplu: int x. /* c va primi valoarea lui y (citită). apoi este decrementat y  Operatorul sizeof() Este un operator unar.Se evaluează expresia1. cin>>y. atunci semn=-1. x=1 sau x=valoare diferită de zero)*/ x++. se verifică dacă c este mai mic sau egal cu 5. Daca nu. //întâi este incrementat x.

Operatorii de indexare Operatorii de indexare sunt parantezele pătrate []. La alcătuirea expresiilor.6. La apelul funcţiilor. Operatori de acces la membri structurilor Operatorii ::. se realizează conversii ale tipului operanzilor. parantezele rotunde sunt numite şi operatori de apel de funcţie. numit şi operator de deferenţiere. 2. Acestea includ expresii întregi care reprezintă indici ai unui tablou.3. Conversiile sunt: . parantezele rotunde încadrează lista parametrilor efectivi. Operatorii & (adresă) şi * sunt complementari. pe care îi vom enumera în continuare. (float) a.. când cunoştinţele acumulate vor permite acest lucru.// converteşte operandul a (care era de tip întreg) în float În afara operatorilor prezentaţi. Din acest motiv. La evaluarea unei expresii se aplică regulile de prioritate şi asociativitate a operatorilor din expresie. . Operatorul unar * Este operator unar. Despre aceşti operatori vom discuta în capitolele viitoare. există şi alţii. Ordinea de aplicare a operatorilor poate fi schimbată prin folosirea parantezelor.7. Se aplică unei expresii de tip pointer şi este folosit pentru a accesa conţinutul unei zone de memorie spre care pointează operatorul. Tipul unei expresii este dat de tipul rezultatului obţinut în urma evaluării acesteia.EXPRESII   Prin combinarea operanzilor şi a operatorilor se obţin expresii. este indicată evitarea expresiilor în care un operand apare de mai multe ori. 2.   Operatorii paranteză Parantezele rotunde ( ) se utilizează în expresii. sau la apelul funcţiilor. ->. Exemple: int a. Exemplu: Expresia *a este înlocuită cu valoarea de la adresa conţinută în variabila pointer a. CONVERSII DE TIP La evaluarea expresiilor. Ei vor fi studiaţi în capitolul 7.Este un operator unar care apare în construcţii numite ”cast” şi converteşte tipul operandului său la tipul specificat între paranteze.2. pentru schimbarea ordinii de efectuare a operaţiilor. .* şi ->* permit accesul la componentele unei structuri.

float y. Exemplu: int x=3.   Automate.  Dacă un operand este de tipul double.5. rezultatul împărţirii este întreg. Înainte de a se efectua împărţirea celor 2 operanzi. short int -> int Ele sunt realizate de fiecare dată când într-o expresie apar operanzi de tipul char sau short int. celălalt este convertit la acelaşi tip. operandul x (întreg) este convertit în număr real simplă precizie. Conversiile cerute de evaluarea expresiilor sunt efectuate în cazurile în care în expresii apar operanzi de tipuri diferite. bidimensionale) Algoritmul proiectat pentru rezolvarea unei anumite probleme trebuie implementat într-un limbaj de programare. . 2. Cerute de programator (prin construcţiile cast). Instrucţiunea descrie un proces de prelucrare pe care un calculator îl poate executa. explicite. O instrucţiune este o construcţie validă (care respectă sintaxa limbajului) urmată de .3. tipul expresiei este double. deci y ar fi avut valoarea 1. . prelucrarea datelor se realizează cu ajutorul instrucţiunilor. y=(float)x/2. Conversiile explicite (cerute de programator) se realizează cu ajutorul construcţiilor cast. valoarea lui y va fi 1. se realizează conversia unuia sau a ambilor operanzi:  Dacă un operand este de tip long int. Tipuri structurate de date (tablouri unidimensionale. Conversiile automate sunt realizate de către compilator: char. Ordinea în care se execută instrucţiunile unui program defineşte aşa-numita structură de control a programului. Înaintea aplicării operatorilor. După atribuire. Dacă nu ar fi fost folosit operatorul de conversie în expresia y=x / 2. celălalt este convertit la acelaşi tip. tipul expresiei este float. celălalt este convertit la acelaşi tip.  Dacă un operand este de tipul float. Cerute de evaluarea expresiilor. operanzii x şi 2 fiind întregi. tipul expresiei este long int.

dar nu se execută nimic (de obicei. instr2. . IMPLEMENTAREA STRUCTURII SECVENŢIALE Structura secvenţială este o înşiruire de secvenţe de prelucrare (instrucţiuni).): Reprezentarea structurii secvenţiale cu ajutorul pseudocodului: instr1. Bohm şi G. IMPLEMENTAREA STRUCTURII DE DECIZIE (ALTERNATIVE. Schema logică pentru structura secvenţială Implementarea structurii secvenţiale se realizează cu ajutorul instrucţiunilor:  Instrucţiunea vidă Sintaxa: .  structura repetitivă (ciclică). Se vor prezenta în continure doar instrucţiunile care le implementează. S1 S2 Sn Figura 3.Limbajele moderne sunt alcătuite pe principiile programării structurate. . Conform lui C. DE SELECŢIE) Reprezentarea prin schemă logică şi prin pseudocod a structurilor de decizie şi repetitive sunt descrise în capitolul 1. Se utilizează în construcţii în care se cere prezenţa unei instrucţiuni. . orice algoritm poate fi realizat prin combinarea a trei structuri fundamentale:  structura secvenţială. . . plasate una după alta. Instrucţiunea vidă nu are nici un efect. Jacobini. de selecţie).  structura alternativă (de decizie. Reprezentarea structurii secvenţiale cu ajutorul schemei logice ( figura 3.1. în instrucţiunile repetitive). .1. în ordinea în care se doreşte execuţia acestora.

se evaluează expresie (care reprezintă o condiţie) din paranteze.Instrucţiunea if: Sintaxa: if (expresie) instrucţiune1. Instrucţiunea switch În unele cazuri este necesară o decizie multiplă specială. La întâlnirea instrucţiunii if. [ieşire. ]  Ramura else este opţională. instrucţiune_n Figura 3. După execuţia instrucţiunii if se trece la execuţia instrucţiunii care urmează acesteia.] Altfel dacă expresie=expr_const_2 instrucţiune2. Instrucţiunea switch permite acest lucru.2): test_expresie instrucţiune1 break instrucţiune2 break Dacă expresie=expr_const_1 instrucţiune1.] Altfel instrucţiune_n.] Altfel dacă expresie=expr_const_n-1 instrucţiune_n-1. dacă valoarea expresiei este 0 (condiţia nu este îndeplinită). Dacă valoarea expresiei este 1 (condiţia este îndeplinită) se execută instrucţiune1. se execută instrucţiune2. Decizia multiplă .2. Deci. la un moment dat. [ieşire. fie instrucţiune2. [ieşire. Reprezentare prin pseudocod:  Reprezentare prin schema logică (figura 3. se execută doar una dintre cele două instrucţiuni: fie instrucţiune1. [ else instrucţiune2.

Break-ul cauzează deci. expresie=expr_const_2. . se execută cazul marcat cu eticheta default (când acesta există). IMPLEMENTAREA STRUCTURILOR REPETITIVE (CICLICE) Există două categorii de instrucţiuni ciclice: cu test iniţial şi cu test final. . . ] } Este evaluată expresie (expresie aritmetică). . expr_const_2. În cazul în care valoarea expresiei nu este găsită printre valorile expresiilor constante. . [break.etc. . Dacă nu este întâlnită instrucţiunea break. . .] case expresie_const_2: instructiune_2. [break. (expresii constante=expresii care nu conţin variabile). .) şi se execută instrucţiunea de pe ramura corespunzătoare. . ..] . . . [break. . . . . . . iar valoarea ei este comparată cu valoarea expresiilor constante 1. . . 2. În exemplul următor. . etc. . . trebuie să fie întregi. . etc. case expresie_const_n-1: instructiune_n-1. parcurgerea continuă. . ele sunt de tip char. Implementarea structurilor ciclice cu test iniţial Structura ciclică cu test iniţial este implementată prin instrucţiunile while şi for. deci se va trece la execuţia primei instrucţiuni de după switch. În situaţia în care valoarea expresie este egală cu valoarea expr_const_k. .] [ default: instructiune_n. Expresiile expresie.Se testează dacă valoarea pentru expresie este una dintre constantele specificate (expr_const_1. ieşirea imediată din switch. . . . În schema logică test_expresie este una din condiţiile: expresie=expr_const_1. Dacă se întâlneşte instrucţiunea break. .  Instrucţiunea while Sintaxa: . expresie_const_2. expresie_const_1. dar o dată de tip char este convertită automat în tipul int. etc. se execută instrucţiunea corespunzătoare acelei ramuri (instrucţiune_k). parcurgerea este întreruptă. . . Sintaxa: switch (expresie) { case expresie_const_1: instructiune_1.

sau o altă instrucţiune ciclică.  Reprezentare prin schema logică (figura 3. // ciclu infinit. În cazul în care la prima evaluare a expresiei. Este de dorit ca instrucţiunea din corpul ciclului while să modifice valoarea expresiei. În momentul în care expresie ia valoarea 0 (condiţie neîndeplinită).3. Instrucţiune din corpul ciclului while poate fi compusă (un bloc).while (expresie) instructiune. Dacă aceasta are valoarea 1 sau diferită de 0 . instrucţiunea (corpul ciclului) se repetă atât timp cât expresie are valoarea 1.d. 3. Exemplu: int a=7. 2. La întâlnirea acestei instrucţiuni. Structura ciclică cu test iniţial 0 Reprezentare în pseudocod: evaluare expresie1 CÂT TIMP expresie2 REPETĂ ÎNCEPUT instrucţiune evaluare expresie3 SFÂRŞIT . Astfel. se repetă instrucţiune. se execută instrucţiune. corpul instrucţiunii while nu va fi executat niciodată. Se revine apoi în punctul în care se evaluează din nou valoarea expresiei. În limbajul C instrucţiunea for poate fi utilizată într-un mod mult mai flexibil.a. ş. Dacă nu se realizează acest lucru. se evaluează expresie.): evaluare expresie1 (particular iniţializare contor) expresie2 1 instrucţiune evaluare expresie3 (particular incrementare contor) Figura 3. Observaţii: 1. Dacă ea este tot 1. se iese din ciclu şi se trece la următoarea instrucţiune de după while. aceasta are valoarea zero.3. se repetă la infinit afişarea mesajului Instrucţiunea for În majoritatea limbajelor de programare de nivel înalt.m. corpul instrucţiunii while se repetă de un număr infinit de ori.(condiţie îndeplinită). instrucţiunea for implementează structura ciclică cu număr cunoscut de paşi (vezi reprezentarea prin schema logică şi pseudocod din capitolul 1). while (a==7) cout<<”Buna ziua!\n”.

Ca şi variabilele simple. deoarece grupează mai multe elemente. Implementarea structurilor ciclice cu test final Instrucţiunea do-while Sintaxa: do instructiune. expresie3) instructiune. Tablouri unidimensionale şi bidimensionale DECLARAREA TABOURILOR Numim tablou o colecţie (grup. . Tablourile sunt variabile compuse (structurate). iar tipul tabloului este dat de tipul elementelor sale. Elementele tabloului pot fi referite prin numele tabloului şi indicii (numere întregi) care reprezintă poziţia elementului în cadrul tabloului. Se repetă instrucţiune cât timp valoarea expresiei este 1 (condiţia este îndeplinită).  Se execută instrucţiune. while(expresie).Sintaxa: for (expresie1. expresie2. se execută instrucţiune. Se evaluează apoi expresie. situate într-o zonă de memorie continuă (elementele tabloului se află la adrese succesive). Nu este obligatorie prezenţa expresiilor. variabilele tablou trebuie declarate înainte de utilizare. corpul ciclului se execută cel puţin o dată. Se testează din nou valoarea expresiei. Modul de declarare: tip nume_tablou[dim_1][dim_2]…[dim_n]. de acelaşi tip. mulţime ordonată) de date. În cazul instrucţiunii do-while. ci doar a instrucţiunilor vide. În funcţie de numărul indicilor utilizaţi pentru a referi elementele tabloului. putem întâlni tablouri unidimensionale (vectorii) sau multidimensionale (matricile sunt tablouri bidimensionale). Variabilele tablou au nume. Dacă aceasta are valoarea 1.

1.. de maximum 20 de elemente. // declararea tabloului vect. tip double double matrice[2][3]. .tab[10]. // Iniţializarea elementelor tabloului vector[0]=100. Se pot efectua operaţii asupra fiecărui element al tabloului. Un element al unui tablou poate fi utilizat ca orice altă variabilă (în exemplul următor. La întâlnirea declaraţiei unei variabile tablou. vector[5]=105. atribuirea de valori elementelor tabloului vector). vector[2]=102. vector[4]=104.q.. TABLOURI UNIDIMENSIONALE Tablourile unidimensionale sunt tablouri cu un singur indice (vectori). de maximum 10 elemente. // maximum 2 linii şi maximum 3 coloane. Exemple: //1 int vect[20]. dim_1-1].dim_2. char*/ //4 /*declararea tabloului tabc. nu asupra întregului tablou. de tipul int. // Se rezervă 20*sizeof(int)=20 * 2 = 40 octeţi //2 double p. vector 100 101 102 103 104 105 vector[0] vector[1] vector[2] vector[3] vector[4] vector[5] Figura 4. de maximum MAX (10) elemente de tip // declararea tabloului matrice (bidimensional).. compilatorul alocă o zonă de memorie continuă (dată de produsul dintre dimensiunea maximă şi numărul de octeţi corespunzător tipului tabloului) pentru păstrarea valorilor elementelor sale. vector[3]=103.dim_n sunt numere întregi sau expresii constante întregi (a căror valoare este evaluată la compilare) care reprezintă limitele superioare ale indicilor tabloului. Exemplu: // Declararea tabloului vector int vector[6].. Dacă tabloul conţine dim_1 elemente. tip double //3 #define MAX 10 char tabc[MAX]. 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ă. // declararea variabilelor simple p. vector[1]=101. dim_1. q şi a vectorului tab.unde:tip reprezintă tipul elementelor tabloului. indicii elementelor au valori întregi din intervalul [0.

tab ’A’ ’B’ 1 ’C’ ’D’ [0] [3] float data[5]={ 1. cin>>a[i]. //3 Afişarea elementelor unui vector în ordine inversă: cout<<”Elementele vectorului în ordine inversă:\n”. =”. //citirea valorii elementului de indice i } //Sau: double a[20]. ’D’. caz în care compilatorul determină automat mărimea tabloului. numărul maxim de elemente ale tabloului poate fi omis. ’C’.3. i<n. for (i=0. . 2. for (i=0. i++) { cout<<”a["<<i<<”]=”.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 Exerciţii: //1 Citirea elementelor unui vector: double a[5]. în funcţie de numărul elementelor iniţializate. i<n i++) cout<<a[i]<<’ ’. ’C’}. cout<<”Dim.4 }.2. 3. Max. data 1. i++) { cout<<”a[“<<i<<”]=”. int i. //afişarea unui mesaj prealabil citirii fiecărui element cin>>a[i].2 2. Exemplu: char tab[]={ ’A’.3 3. int i. } //2 Afişarea elementelor unui vector: cout<<”Vectorul introdus este:\n”. for (i=0.La declararea unui vector cu iniţializarea elementelor sale. i<5. cin>>n. n.

. . . . . . . .2 . . cu acelaşi număr de elemente: p= ∑ai ∗bi i =0 n −1 double p=0. . . q 1n q 21 q 22 q 23 . . . i<n i++) c[i]=a[i] . . cu acelaşi număr de elemente: for (i=0. //5 Produsul scalar (p) a vectorilor a şi b. //3 Vectorul sumă (c) a vectorilor a şi b.1 q m− .q[m-1][0] . . q[0][0] q[0][1] q[0][2] . q[m-1][n-1] . . q 1. . . . tip În memorie. . . . cu maxim3 linii şi 2 coloane. . . . . . double // declararea matricii q. . . q[0][n-1] q[1][0] . .b[i]. . . În matematică: q 11 q 12 q 13 . valoarea lui k = i ∗ m + j (unde m este numărul maxim de linii. elementele unei matrici sunt memorate pe linii: q 00 q 01 q 10 q 11 q 20 q 21 .n − Q m×n Q= . . . q 2 n Q= . . . . . . . . . .n − 1 q 10 q 11 q 12 . . . . . . q mn În limbajele C/C++ (indicii de linie şi de coloană pornesc de la 0): 1 q 00 q 01 q 02 . elementele unui tablou bidimensional sunt plasate în spaţiu pe două direcţii. Q m×n q m1 q m2 q m3 . . . . . . . . 0 q m− . . q m − . . . //4 Vectorul diferenţă (c) a vectorilor a şi b. cu acelaşi număr de elemente: for (i=0. . Dacă notăm cu k poziţia în memorie a unui element. . . . for (i=0. . . . i este indicele de linie. .n − Exemplu: double q[3][2]. 1 1 1 1 1 q m− . . i<n i++) c[i]=a[i]+b[i]. . i<n i++) p += a[i] ∗ b[i].for (i=n-1. j este indicele de coloană). . . . . . . . i>=0 i++) cout<<a[i]<<’ ’. . TABLOURI BIDIMENSIONALE Din punct de vedere conceptual. . . . Matricea reprezintă o aplicaţie naturală a tablourilor bidimensionale. q 0 .

mat[0][1]=-50. {7. mat[3][2]=19 La declararea unei matrici şi iniţializarea elementelor sale. mat[0][2]=3 mat[1][0]=32. -50. {50. {-1. ale cărei elemente se iniţializează astfel: mat[0][0]=1. {3. 30}. 1}. elementele matricii mat se iniţializează în modul următor: mat[0][0]=10. Construcţia are acelaşi efect ca precedenta. 2. mat[2][1]=1. 4}}. -1}. . {32. -2}. -8. -2}. se poate proceda astfel: int mat[4][3] = { {10. {1. 19} }. în schimb. mat[1][2]=1 mat[2][0]=-1. 20. 1}}. 1}. int mat[][3] = { {1. { {20. -40}. {3. mat[2][2]=1 Elementele mat[0][2]. mat[2][0]=3. mat[1][1]. mat[2][2]=-2 mat[3][0]=7. 20. {11. Exemplu: int a[2][2][3]={ { {10. se poate omite numărul maxim de linii. {32. 9} }. trebuie specificat numărul maxim de coloane: int mat[][3] = { {10. 1. mat[1][1]=20. 3}. 12}} }. {-1. cu mai mult de doi indici. Prin această construcţie. 1}. {7.Dacă se doreşte iniţializarea elementelor unei matrici în momentul declarării acesteia. -8. mat[1][2] nu sunt initalizate. Construcţiile utilizate la iniţializarea tablourilor bidimensionale se extind pentru tablouri multidimensionale. -5. 20}. mat[3][1]=-8. mat reprezintă o matrice 3 ∗ 3. mat[1][0]=-1. mat[0][1]=1. Ele au valoarea zero dacă tabloul este global şi valori iniţiale nedefinite dacă tabloul este automatic. mat[2][1]=2. { -1}. 3}. datorită modului de memorare. 1.

caracterul null (zero ASCII). se trece pe linia următoare } } ŞIRURI DE CARACTERE Şirurile de caractere sunt tablouri de caractere. Să se afişeze matricea citită.h> void main(void) {int A[10][10]. ’d’. ’\0’. j++) { cout<<"A["<<i<<". cout<<"Nr. int nr_lin. j<nr_col. i++) { for (j=0.int i. linii:". ’e’}. // tablou de caractere char sc[5] = {’a’. coloane:". j. ’b’. ’c’. care include automat caracterul null. nr_col. cout<<'\n'. cin>>nr_lin. //sau cu char sc[] = ”abcd”. #include <iostream. cout<<"Nr.h>. FUNCŢII PENTRU OPERAŢII CU ŞIRURI DE CARACTERE Funcţiile pentru operaţii cu şiruri se găsesc în header-ul <string. i<nr_lin. ’\0’}. ’d’. } //afişarea elementelor matricii for (i=0. //afişarea unui mesaj prealabil citirii cin>>A[i][j]. Exemplu: char tc[5] = {’a’. ’c’. // şirul de caractere cu elementele abcd Limbajul C/C++ permite iniţializarea unui tablou de caractere printr-o constantă şir (şir între ghilimele). j<nr_col. //citirea elementelor unei matrici for (i=0. cin>>nr_col. . j++) cout<<A[i][j]<<'\t'. Deci ultima iniţializare este echivalentă cu: char sc[5] = ”abcd”. care au ca ultim element un terminator de şir. i++) for (j=0. ’b’. i<nr_lin.Exerciţiu: Să se citească de la tastatură elementele unei matrici de maxim 10 linii şi 10 coloane. // după afişarea elementelor unei linii."<<j<<"]=".

Din punct de vedere conceptual. efectuează prelucrările descrise în corpul funcţiei asupra acestora şi pot returna o valoare (rezultatul. 2. şir_2) Funcţia compară cele două şiruri date ca argument şi returnează o valoare întreagă egală diferenţa dintre codurile ASCII ale primelor caractere care nu coincid.strlen (nume_şir) Returnează un număr întreg ce reprezintă lungimea unui şir de caractere. cu valori în mulţimea C (C=mulţimea de valori. Implementarea funcţiilor în C/C++. STRUCTURA UNEI FUNCŢII Un program scris în limbajul C/C++ este un ansamblu de funcţii. Pentru a fi posibilă copierea. fiecare dintre acestea efectuând o activitate bine definită. şir_sursă) Funcţia copie şirul sursă în şirul destinaţie. asamblarea lor realizându-se cu ajutorul linkeditorului de legături. datele de ieşire). Funcţiile pot fi descrise în cadrul aceluiaşi fişier. Funcţiile comunică prin argumennte: ele primesc ca parametri (argumente) datele de intrare. domeniul de definiţie). Execuţia programului începe cu funcţia principală. care îndeplineşte condiţia că oricărui element din D îi corespunde un unic element din C. strcpy (şir_destinaţie. funcţia reprezintă o aplicaţie definită pe o mulţime D (D=mulţimea. strcmp (şir_1.4. strcat (şir_destinaţie. şir_sursă) Funcţia concatenează cele două şiruri: şirul sursă este adăugat la sfârşitul şirului destinaţie. altfel pot apare erori grave. fără a număra terminatorul de şir. lungimea şirului destinaţie trebuie să fie mai mare sau egală cu cea a şirului sursă. . numită main. sau în fişiere diferite. codomeniul). care sunt testate şi compilate separat. Tabloul care conţine şirul destinaţie trebuie să aibă suficiente elemente.

numele acesteia şi lista declaraţiilor parametrilor formali. se revine în funcţia apelantă. în antet. La execuţie. Dacă funcţia întoarce o valoare. La fel ca un operand sau o expresie. despărţite prin virgulă. Declaraţia conţine antetul funcţiei şi informează compilatorul asupra tipului. care implementează algoritmul de calcul folosit de către funcţie. Nume_funcţie este un identificator. se foloseşte instrucţiunea return valoare. numelui funcţiei şi a listei parametrilor formali (în care se poate indica doar tipul parametrilor formali. Tipul unui parametru poate fi oricare. apar doar parantezele ( ). Declaraţiile de funcţii se numesc prototipuri. că acesta este int. O formă învechită a antetului unei funcţii este aceea de a specifica în lista parametrilor formali doar numele acestora. sau (void). în locul tip_vali_return se specifică void. Lista_declaraţiilor_param_formali (încadrată între paranteze rotunde) constă într-o listă (enumerare) care conţine tipul şi identificatorul fiecărui parametru de intrare. se consideră. care este dat de tipul valorii returnate de funcţie în funcţia apelantă. În corpul funcţiei apar (în orice ordine) declaraţii pentru variabilele locale şi instrucţiuni. la întâlnirea acestei instrucţiuni. Această libertate în omiterea tipului parametrilor constituie o sursă de erori. Dacă lista parametrilor formali este vidă. după numele funcţiei. o funcţie are un tip. implicit. Corpul funcţiei este un bloc. chiar şi tipul pointer. din care pot lipsi numele parametrilor formali. şi sunt constituite din antetul funcţiei. în care se indică: tipul funcţiei. Dacă tip_val_return lipseşte. Nu este admisă definirea unei funcţii în corpul altei funcţii. Dacă funcţia nu întoarce nici o valoare. Definiţia conţine antetul funcţiei şi corpul acesteia. nu şi tipul. .O funcţie este formata din antet si corp: antet_funcţie { corpul_funcţiei } Sau: tip_val_return nume_func (lista_declaraţiilor_param_ formali) { declaraţii_variabile_locale instrucţiuni return valoare } Prima linie reprezintă antetul funcţiei. În limbajul C/C++ se utilizează declaraţii şi definiţii de funcţii. nu şi numele acestora).

controlul este redat funcţiei apelante. Aceste variabile sunt numite variabile locale şi nu pot fi accesate din alte funcţii. Parametrii efectivi trebuie să corespundă cu cei formali ca ordine şi tip. la execuţie. Acest lucru este posibil doar în cazul în care funcţia returnează o valoare.). ci numai ţin locul acestora pentru a putea exprima procesul de calcul realizat prin funcţie. Deci. Variabilele declarate în interiorul unei funcţii.8. Exemplu: . efectivi. La apel. cât şi parametrii formali ai acesteia nu pot fi accesaţi decât în interiorul acesteia. pentru a sublinia faptul că ei nu reprezintă valori concrete. Acest mod de programare se numeşte programare procedurală şi realizează un proces de abstractizare prin parametri. O altă posibilitate de a apela o funcţie este aceea în care apelul funcţiei constituie operandul unei expresii. Utilizarea parametrilor formali la implementarea funcţiilor şi atribuirea de valori concrete pentru ei. din funcţia apelantă. şi execuţia continuă cu instrucţiunea următoare instrucţiunii de apel. numită instrucţiune de apel. folosită în calculul expresiei. La revenirea din funcţie. iar valorile lor vor fi atribuite parametrilor formali. reprezintă un prim nivel de abstractizare în programare. concreţi. Domeniul de vizibilitate a unei variabile este porţiunea de cod la a cărei execuţie variabila respectivă este accesibilă. de forma: nume_funcţie (lista_parametrilor_efectivi). domeniul de vizibilitate a unei variabile locale este funcţia în care ea a fost definită (vezi şi paragraful 6. se atribuie parametrilor formali valorile parametrilor efectivi. Ei se concretizează la execuţie prin apelurile funcţiei. după care se execută instrucţiunile din corpul funcţiei.tipul_valorii_returnate nume_funcţie formali) declararea_parametrilor_formali { declaraţii_variabile_locale instrucţiuni return valoare } (lista_parametrilor_ APELUL ŞI PROTOTIPUL FUNCŢIILOR O funcţie poate fi apelată printr-o construcţie urmată de punct şi virgulă. la execuţie. Parametrii folosiţi la apelul unei funcţii sunt parametri reali. Parametrii declaraţi în antetul unei funcţii sunt numiţi formali.

return c. . c nedeclarat . se transmit valorile partametrilor efectivi. . Aceste valori vor fi atribuite. .  Transfer prin pointeri. . Există următoarele moduri de transfer (transmitere) a parametrilor către funcţiile apelate:  Transfer prin valoare. cout << "a=”<<a<<” b=”<<b<<” c=”<<c’\n’. . . . . int c. . Exemplu: void main() { int a=1. b. parametrii de la funcţia apelantă la funcţia apelată au fost transmişi prin valoare. b=2.b. cout << "a=”<<a<<” b=”<<b<<’\n’. c . . . . . . . . la apel. // variabile a şi b nu sunt accesibile în main() } Dacă în interiorul unei funcţii există instrucţiuni compuse (blocuri) care conţin declaraţii de variabile. TRANFERUL PARAMETRILOR PRIN VALOARE În exemplele anterioare. aceste variabile nu sunt vizibile în afara blocului. . .  Transfer prin referinţă. . . . vizibile doar în corpul funcţiei } void main() { . // a=1 b=6. . . } cout << "a=”<<a<<” b=”<<b<<” c=”<<c’\n’. int c=9. { int a=5. . . . // a=1 b=2. prin apel. De la programul apelant către funcţia apelată. .variabile locale. // a. b=6. . . . reali. // a=5 b=6 c=9 . .int f1(void) { double a. . . . } TRANSFERUL PARAMETRILOR UNEI FUNCŢII Funcţiile comunică între ele prin argumente (parametrii). c nedeclarat .

z=psi ( 3*x+9. iar valoarea este atribuită parametrului formal corespunzător. parametrii formali. O modificare a valorii parametrului formal în interiorul funcţiei (printr-o operaţie din corpul funcţiei). ci doar valoarea parametrului formal. Exemplu: double psi(int a. nu va modifica valoarea parametrului efectiv. poate constitui un mijloc util de protecţie. o copie locală a acestei valori va fi memorată în parametrul formal. 3 sunt parametri efectivi cout<<”data=”<<data<<’\n’.cu cei formali. double y=12.6. void f1(float intr.int nr)// intr.ca ordine şi tip . În schimb. // apelul funcţiei f1. Param. valoarea parametrului efectiv (data) din funcţia apelantă. Acestea sunt evaluate.1. } . deci a copiei locale a parametrului efectiv (figura 6. y-5) + 28. } void main() { int x=4.parametri formali { for (int i=0.5. în funcţia f1. valoarea parametrului formal intr este modificată (alterată) prin instrucţiunea ciclică for. intr=”<<intr<<’\n’. În interiorul funcţiei. Exerciţiu: Să se scrie următorul program (care ilustrează legătura dintre pointeri şi vectori) şi să se urmărească rezultatele execuţiei acestuia. cout<<”Val. f1(data. cout<<”z=”<<z<<’\n’.i++) intr *= 2.5 (nemodificat) } Fiecare argument efectiv utilizat la apelul funcţiei este evaluat.). la apel. Deci procedeul de transmitere a parametrilor prin valoare constă în încărcarea valorii parametrilor efectivi în zona de memorie a parametrilor formali (în stivă). i<nr.parametrilor formali. nr .3). z. rămâne nemodificată. Astfel. Faptul că variabila din programul apelant (parametrul efectiv) şi parametrul formal sunt obiecte distincte.// intr=12 } void main() { float data=1. else return -a+3*b. double b) { if (a > 0) return a*b*2. parametrii efectivi pot fi chiar expresii. În cazul transmiterii parametrilor prin valoare. iar valoarea lor va iniţializa. data. // data=1.0. La apelul unei funcţii. parametrii reali trebuie să corespundă .

funcţia apelată poate modifica conţinutul locaţiilor spre care pointează argumentele (pointerii). Funcţii care returnează pointeri Valoarea returnată de o funcţie poate fi pointer. cout<<"Adr. . /*incrementeaza pointerului w cu 2(val. specificate de programator. dacă valoarea parametrilor formali (iniţializaţi cu valorile parametrilor efectivi) se modifică în interiorul funcţiei apelate. int). b.8. o copie a parametrilor efectivi. // w= adr.1. aşa cum se observă în exemplul următor: Exemplu: #include <iostream. parametrii transmişi unei funcţii pot fi pointeri (variabile care conţin adrese). b). de fapt.5.6. În aceste cazuri. float h=f1( (double) a. parametrii formali ai funcţiei apelate vor fi iniţializaţi cu valorile parametrilor efectivi. lui a .*w = a[0]=10 return w+=k. Astfel. de fiecare dată când o funcţie transmite argumente unei funcţii apelate.h> double *f (double *w. În acest mod.4.9}. prin operatorul ”cast”. int i=2. int k) { // w conţine adr.7.2. float g=f1(a. Exemplu: float f1(double. } // conversie automată: int a -> double a // conversie explicită Limbajul C este numit limbajul apelului prin valoare. TRANSFERUL PARAMETRILOR PRIN POINTERI În unele cazuri. void main() { int a. lui a este:"<<a. este transmisă. de început a vectorului a cout<<"w="<<w<<" *w="<<*w<<'\n'.3. sau sunt conversii explicite. lui k). b). deoarece.Transferul valorii este însoţit de eventuale conversii de tip. valorile parametrilor efectivi din funcţia apelantă nu vor fi afectate. în urma verificării apelului de funcţie. pe baza informaţiilor despre funcţie. Aceste conversii sunt realizate automat de compilator. deci cu valorile unor adrese. deci w pointează către elementul de indice 2 din vectorul a*/ } void main() {double a[10]={10.

cout<<"c="<<c<<'\n'. b este:"<<&b<<'\n'. a + 2 * sizeof(double). cout<<"pa="<<pa<<" *pa="<<*pa<<'\n'. În exemplul următor definim variabila br. variabilă referinţă către variabila b. b este:0xfff4 b=12. int &br=b.c. se poate observa: . lui a[2]. } TRANSFERUL PARAMETRILOR PRIN REFERINŢĂ În acest mod de transmitere a parametrilor. br 7 12 #include <stdio. //br=12 cout<<"b="<<b<<'\n'. //br=7 cout<<"Adr.h> 12 c void main() { Figura 6. unui parametru formal i se poate asocia (atribui) chiar obiectul parametrului efectiv. // double *pa. Astfel.double *pa=a. pa=a.4.i).h> #include <iostream. cout<<"pa="<<pa<<'\n' // pointerul pa conţine adresa de început a tabloului a // a[i] = * (a + i) // &a[i] = a + i pa=f(a. //br referinţă la altă variabilă (b) br=7. la aceeaşi adresă şi sunt variabile sinonime. Variabilele b şi br se găsesc. cout<<"b="<<b<<'\n'. Variabilele referinţă b. adica adr. în memorie. *pa=2. //b=7 cout<<"br="<<br<<'\n'. //Adr. //Adr. cout<<"br="<<br<<'\n'. br este:"<<&br. // pa conţine adr. br int b. parametrul efectiv poate fi modificat direct prin operaţiile din corpul funcţiei apelate. br este:0xfff4 printf("Adr. Exemplu: b. //b=12 c=br. //c=12 } Comparând cele trei moduri de transmitere a parametrilor către o funcţie.

si anume la varful stivei. aşa cum ilustrează exemplele următoare: 2. struct nod { int info: nod *adr_urm. Stiva functioneaza pe principiul LIFO (Last In First Out). ca parametrii efectivi pot apare expresii sau nume de variabile. Limbajul C este numit limbajul apelului prin valoare. ca parametri efectivi pot apare expresii de pointeri. 3.. ci doar nume de variabile. Arbori binari LISTE LINIARE O lista liniara este o colectie de n noduri unde n>=0. La apelul prin referinţă transferul datelor este bidirecţional. STIVE O stiva este o structura liniara deschisa ale carei extremitati se numesc baza si varf si in care accesul se face la un singur capat. 4. *sf. si anume constanta Null. struct nod { int info.5. însă. care sunt sinonime (au nume diferite. La apelul prin valoare transferul datelor este unidirecţional.1.4. La transmiterea parametrilor prin referinţă. } *v. Daca stiva este vida varful coincide cu baza si vor avea aceeasi adresa. sau aşa cum vom vedea în paragraful 6. adică valorile se transferă numai de la funcţia apelantă către cea apelată. Liste. COADA . nod *adr_inapoi. ce poate fi si vida. ca parametri efectivi nu pot apare expresii. dar referă aceleaşi locaţii de memorie). Alocarea dinamica a stivei necesita cunoasterea in orice moment a pointerului pentru varful stivei. tipul de apel: prin valoare sau prin referinţă. pentru fiecare parametru. Liste liniare. Listele se pot aloca dinamic sau secvential. Transmiterea parametrilor unei funcţii prin referinţă este specifică limbajului C++. folosind pointeri. Arbori. stive şi cozi (reprezentarea grafică. La transmiterea parametrilor prin pointeri. Cozi. deoarece o modificare a parametrilor formali determină modificarea parametrilor efectivi. apel prin referinţă în cazul variabilelor simple. Apelul poate deveni. La transmiterea parametrilor prin valoare. 5. În limbajul C++ se poate alege. în cazul în care parametru efectiv este un tablou. Stive. 2. operaţii specifice). } nod *v.

Algoritmii pentru implementarea operaţiilor de bază (în pseudocod) sunt: adaugare(elem. obţinerea primului element fără extragerea acestuia. În cazul în care stiva este vidă. Ambele structuri au două operaţii de bază: adăugarea şi extragerea unui element. Ultimul element al masivului va fi utilizat pentru memorarea numărului de elemente ale stivei. Cele mai utilizate implementări sunt cele folosind masive şi liste. Noţiuni generale Cozile şi stivele sunt structuri de date logice (implementarea este făcută utilizând alte structuri de date) şi omogene (toate elementele sunt de acelaşi tip). operaţiile de bază se pot implementa în timp constant (O(1)). În afara acestor operaţii se pot implementa şi alte operaţii utile: test de structură vidă. n) . iar coada o disciplină de tip FIFO (First In First Out). atunci elementul Vn-1 va avea valoarea 0. Stiva foloseşte o disciplină de acces de tip LIFO (Last In First Out). … Diferenţa fundamentală între cele două structuri este disciplina de acces. Cozi şi stive 1. Ambele abordări au avantaje şi dezavantaje: Avantaje Dezavantaje Masive • implementare simplă • consum redus de memorie • viteză mare pentru operaţii • numărul de elemente este limitat • risipă de memorie în cazul în care dimensiunea alocată este mult mai mare decât numărul efectiv de elemente Liste • număr oarecare de elemente • consum mare de memorie pentru memorarea legăturilor Pentru implementarea unei stive folosind masive avem nevoie de un masiv V de dimensiune n pentru memorarea elementelor. Moduri de implementare Stivele şi cozile pot fi implementate în mai multe moduri. Folosind această reprezentare. Coada functioneaza pe principiul FIFO (First In First Out) struct nod { int info. 2. } *v. V. nod *adr_urm.O coada este o lista liniara deschisa la care operatiile au loc la ambele capete. *sf.

1] //extragem elementul din masiv v[n-1] = v[n-1] + 1 //decrementăm numărul de elemente return elem Coada se poate implementa folosind un vector circular de dimensiune n (după elementul n-4 urmează elementul 0). Stiva vidă este reprezentată printr-un pointer nul. Grafuri (orientate şi neorientare). n) if v[n-1] = 0 //verificam dacă stiva nu e goală return "stiva goala" elem = v[v[n-1] . vom folosi o listă simplu înlănţuită organizată ca în figura următoare: Fiecare nod este format din informaţiile utile şi o legătură către elementul următor. Elementele sunt adăugate înaintea primului element (cu deplasarea varfului stivei). V. Grafurile .n) if v[n-1] = v[n-2] //verificare coadă goală return "coada goala" v[n-1] = (v[n-1] + 1) mod (n-2) //deplasăm indicele de sfârşit return V[V[n-1]] //întoarcem elementul Cea de-a doua modalitate de implementare a stivelor şi cozilor este cea folosind liste alocate dinamic. Algoritmii care implementează operaţiile de bază pentru o coadă memorată in forma prezentată sunt: adaugare(elem. iar antepenultimul element este un marcaj folosit pentru a putea diferenţia cazurile de coadă goală şi coadă plină. Tipul informaţiilor stocate în stivă este indicat de utilizator prin definirea tipului TipStiva. 2. Ultimele două elemente conţin indicii de start şi sfârşit ai cozii. În cazul stivei. parcurgere.6.if v[n-1] = n-1 //verificam dacă stiva nu e plină return "stiva plina" v[v[n-1]] = elem //adaugăm elementul în masiv v[n-1] = v[n-1] + 1 //incrementăm numărul de elemente return "succes" stergere(V. operaţii. Extragerea se face tot din vărful stivei. n) v[n-2] = (v[n-2] + 1) mod (n-2) //deplasăm capul cozii if v[n-1] = v[n-2] //verificare coada plină return "coada plina" V[V[n-1]] = elem //adăugăm elementul return "succes" stergere(V. Definire.

u4.Graf orientat Un graf orientat reprezinta o pereche ordonata de multimi G=(X. 4. (4. (3. numita multimea nodurilor. 5. Exemplu In graful din fig. 1 multimea nodurilor este X={1. u6. . u7.5)}.4).2).7). (7.5).6). (7. 7} si multimea arcelor este U={u1. si U este o multime formata din perechi ordonate de elemente ale lui X. u8. u10}={(1.3). u2. (3.1).U). (6. 2. u3. u9. (2. numita multimea arcelor.6). 3.3). u5. (5. unde X este o multime finita si nevida. 6. (5.

exista un lant care le leaga. u3 .2) stabilind lantul {u6. dar si pe traseul de noduri (4. u 2. …. fara a tine cont de orientarea arcelor componente. Exemplu Graful este conex pentru ca oricum am lua doua noduri putem ajunge de la unul la celalalt pe un traseu de tip lant. un} cu proprietatea ca oricare doua arce consecutive au o extremitate comuna. Un lant intr-un graf orientat este un sir de arce {u1. de la nodul 4 la nodul 2 putem ajunge pe traseul de noduri (4.2) stabilind astfel lantul {u5. u3}.1. daca oricare ar fi doua varfuri ale sale. u2} . De exemplu. un lant este un traseu care uneste prin arce doua noduri numite extremitatile lantului.Conexitate in grafuri orientate Un graf G este conex. Altfel spus.3.

Plecand dintr-un nod al primei submultimi si deplasandu-ne pe arce. putem spune ca intre oricare doua noduri din aceasta submultime exista cel putin un lant. de exemplu lantul {u1.2. u1}. .6}. De exemplu plecand din nodul 1 putem ajunge in nodul 2 pe traseul {u3. nu avem cum sa trecem in a doua submultime pentru ca nu exista nici un arc direct care sa lege cele doua submultimi. deci nu exista lant de la 2 la 4. Luand submultimea de noduri {1. Dar nu ptuem gasi un lant intre un nod din prima submultime si un nod din a doua submultime. dar de aici nu putem ajunge mai departe in nodul 4.Acest graf nu este conex. La fel stau lucrurile cu submultimea de noduri {4..3}. u2}. u2} sau {u3.5.

Pentru a demonstra acest lucru.3}. Exemplu Graful cu n=3 din fig. u2.2. y apartin multimii {1. U1).3} si U1={u1. si G2=(X2. U). exista un drum de la x la y precum si un drum de la y la x. u5}. De exemplu graful din fig. U2). . u3}. U). cu proprietatea ca nu exista nici un lant care sa lege un nod din X 1 cu un nod din X-X 1 (pentru orice nod. nu exista un lant intre acel nod si nodurile care nu fac parte din subgraf). 4 este tare conex. si pentru fiecare astfel de pereche cautam un drum de la x la y si un drum de la y la x. insa in el distingem doua componente conexe: G1 =(X1. 3 nu este conex . reprezinta un subgraf G1=(X1. Graf tare conex Graful tare conex este un graf orientat G=(X. unde X1={1.Componenta conexa Componenta conexa a unui graf G=(X. U1) conex.5. daca pentru oricare doua noduri x si y apartin lui X. a lui G.6} si U2={u4.2. y) cu x. formam toate perechile posibile de noduri distincte (x. unde X2={4.

pe arcele (2.3). Exemplu .3) si (3.2.3]. U1) al grafului G=(X. Fie un subgraf tare conex G1=(X1. pe arcele (3. De la 3 la 2 – drumul [3. U). pe arcele (3.1]. Componenta tare conexa Un subgraf se obtine dintr-un graf G= (X.2].2].1).x=1.2).2) si (2. De la 3 la 1 – drumul [3. Daca acest subgrafnu mai este tare conex.1. Adaugam la subgraf un nod x care nu face parte din multimea nodurilor sale (x apartine X-X1). Obtinem astfel multimea de varfuri X1 reunit cu {x}.2).1.2.2) si (2. atunci el se numeste componenta tare conexa.1). x=1. y=3 De la 2 la 3 – drumul [2. x=2. y=3 De la 1 la 3 – drumul [1.1) si (1.1) si (1.3) si (3. pe arcele (1. y=2 De la 1 la 2 – drumul [1.3. pe arcele (2. pe arcele (1.1].3).3.3]. Subgraful indus pe multimea X1 reunit cu {x} se obtine luand si arcele care trec prin nodul x. U) eliminand niste varfuri si pastrand doar acele muchii care au ambele extremitati in multimea varfurilor ramase. De la 2 la 1 – drumul [2.

Acestui graf ii adaugam un nod x care nu face parte din multimea nodurilor subgrafului G1. Problema Stabiliti daca graful de mai jos este sau nu conex. Graful obtinut este componenta tare conexa. Am obtinut astfel subgraful tare conex G1=(X1.Acesta este graful G=(X. . U1).U) tare conex. Din el eliminam nodul 4.

2].5] sau [4.1. De la 3 la 4 – pe drumul [ 3. u6. u14.1).2). u9.4]. u13. (5.4]. u11.3. u16}={(1.5. De la 2 la 5 – pe drumul [2.3].1). (5.5].3]. 5}. De la 1 la 4 – pe drumul [1. De la 4 la 5 – pe drumul [4.5. (2.5).2.4] sau [2. u8. u5. etc. etc.5].5. (1.5). (2.5] sau [1.etc. u3.4]. (5.X= {1.5. u7. 4.4). De la 2 la 4 – pe drumul [2. etc. etc.5.4. u10. De la 1 la 3 – pe drumul [1. etc.5. etc. U= {u1.3] sau [1. (4.2. (3. (3.3.4] sau [1. etc.3. (3.3).2. (2.3.4).4).5.3). 2.5] sau [2.5.3.1. (4.2. De la 1 la 2 – pe drumul [1.4. u12.3).2] sau [1.2.5].5.3] sau [2.5].4] sau [3. De la 3 la 5 – pe drumul [3.5). etc. (1.4.5). 3. u2.1.5. (5.5.5.2). u4.1)}.2). De la 1 la 5 – pe drumul [1. etc. De la 2 la 3 – pe drumul [2. Grafuri neorientate . (4.5] sau [3. u15.

unde G=(V.4.3].w) presupune că w este adiacent cu v şi v adiacent cu w.2].3. [1. [2.3.Graf = orice mulţime finită V prevăzută cu o relaţie binară internă E. Muchie = element al mulţimii E ce descrie o relaţie existentă între două vârfuri din V.2].4].6}. 1 6 5 3 4 2 In figura alaturata: V={1. E) este un graf neorientat. Muchia (v.2.4]. [1.[3.6} sunt noduri E={[1. E). este un număr natural ce reprezintă numărul de noduri adiacente cu acesta (sau numarul de muchii incidente cu nodul respectiv) Nod izolat = Un nod cu gradul 0. Graf neorientat = un graf G=(V. Nodul 6 este izolat (gradul 0) 2 3 4 . Incidenţă = o muchie este incidentă cu un nod dacă îl are pe acesta ca extremitate.4.v) ∈E. În exemplul din figura de mai sus vârful 1 este adiacent cu 4 dar 1 şi 3 nu reprezintă o pereche de vârfuri adiacente.[3. E) în care relaţia binară este simetrică: (v.5. Nod terminal= un nod cu gradul 1 1 6 5 Nodul 5 este terminal (gradul 1). [2. Notăm graful cu G=(V.5]}) Adiacenta: Într-un graf neorientat existenţa muchiei (v.5.w) este incidentă în nodul v respectiv w.5]} sunt muchii G=(V.3].4]. E) este un graf neorientat. Grad = Gradul unui nod v. {[1.[3.2. unde G=(V.w)∈E atunci (w.[3.4]. Nod = element al mulţimii V. E)=({1. dintr-un graf neorientat.

E’⊂ E se numeşte graf parţial al lui G. wi+1)∈E pentru 1≤ i<n.E) se suprimă cel puţin o muchie atunci noul graf G’=(V. Lanţ = este o secvenţă de noduri ale unui graf neorientat G=(V. Ciclul este elementar dacă este format doar din noduri distincte. Lungimea unui ciclu nu poate fi 2. Lungimea unui lanţ = numărul de muchii din care este format. w2. excepţie făcând primul şi ultimul.E). 5 Lanţul 5 3 4 5 6 este simplu 2 dar nu este elementar. 3. . 1 6 5. 1 6 5 3 4 1 6 5 3 4 2 2 . 2. cu proprietatea că oricare două noduri consecutive din lant sunt adiacente: L=[w1. Lanţul 3 4 5 3 reprezintă un ciclu elementar Graf partial = Dacă dintr-un graf G=(V. w3. . 3 4 Lanţul 5 3 4 5 3 2 este compus şi nu este elementar.Nodurile 1. 4 au gradele egale cu 2. Lanţ simplu = lanţul care conţine numai muchii distincte Lanţ compus= lanţul care nu este format numai din muchii distincte Lanţ elementar = lanţul care conţine numai noduri distincte Ciclu = Un lanţ în care primul nod coincide cu ultimul. 6 reprezintă un lanţ simplu şi elementar de lungime 3.E’).wn] cu proprietatea că (wi. Succesiunea de vârfuri 2..

w) există un lanţ care le uneşte. Nr de noduri: 4x(4-1)/2 = 6 Graf conex = graf neorientat G=(V. 1 6 5 3 4 6 5 3 2 2 G partial al lui G G1 este graf Graf regulat = graf neorientat în care toate nodurile au acelaşi grad. Numărul de muchii ale unui graf complet este: nr*(nr-1)/2. 1 6 5 3 4 2 Graf complet = graf neorientat G=(V.Unde nr este numarul de noduri 1 2 graf complet. E’⊂ E si V’⊂ V se numeşte subgraf al lui G.E’).E) se suprimă cel puţin un nod împreună cu muchiile incidente lui. atunci noul graf G’=(V’.E) în care pentru orice pereche de noduri (v.E) în care există muchie între oricare două noduri. 1 6 5 3 4 1 6 5 3 4 3 4 2 2 graf conex nu este graf conex .G G G1 este graf partial al lui Subgraf = Dacă dintr-un graf G=(V.

6 Lanţ hamiltonian = un lanţ elementar care conţine toate nodurile unui graf 1 6 5 3 4 2 L=[2 .1. maximal în raport cu proprietatea de conexitate (între oricare două vârfuri există lanţ). 5. 3] este lant hamiltonian Ciclu hamiltonian = un ciclu elementar care conţine toate nodurile grafului 1 6 5 3 4 2 C=[1. 5. 1 6 5 3 4 2 graful nu este conex. 2 si 3.6.2. Lanţ eulerian = un lanţ simplu care conţine toate muchiile unui graf .3.5. 4. 6. Are 2 componente conexe: 1.4.1] este ciclu hamiltonian Graf hamiltonian = un graf G care conţine un ciclu hamiltonian Graful anterior este graf Hamiltonian.Componentă conexă = subgraf al grafului de referinţă. 4.

1

6 5 3 4

2

Lantul: L=[1.2.3.4.5.3.6.2.5.6] este lant eulerian Ciclu eulerian = un ciclu simplu care conţine toate muchiile grafului Ciclul: C=[1.2.3.4.5.3.6.2.5.6.1] este ciclu eulerian Graf eulerian = un graf care conţine un ciclu eulerian. Condiţie necesară şi suficientă: Un graf este eulerian dacă şi numai dacă oricare vârf al său are gradul par.

Reprezentarea grafurilor neorientate
Fie G=(V, E) un graf neorientat. Exista mai multe modalitati de reprezentare pentru un graf neorientat, folosind diverse tipuri de structuri de date. Reprezentarile vor fi utilizate in diversi algoritmi si in programele care implementeaza pe calculator acesti algoritmi. Matricea de adiacentã matricea booleanã Matricea de adiacentã asociatã unui graf neorientat cu n noduri se defineste astfel: A = (ai j) n x n cu 1, daca [i,j]∈E a[i,j]= 0, altfel Observatii:
-

Matricea de adiacenta asociatã unui graf neorientat este o matrice simetricã Suma elementelor de pe linia k reprezintã gradul nodului k

-

k

Suma elementelor de pe coloana k reprezintã gradul nodului

Fie graful din figura urmatoare:

1

2

0 1 0 1 0 0 nodul 1 are gradul 2 1 0 1 0 0 0 nodul 2 are gradul 2 A = 0 1 0 1 1 0 nodul 3 are gradul 3 5 1 0 1 0 0 0 nodul 4 are gradul 2 0 0 1 0 0 0 nodul 5 are gradul 1 3 4 0 0 0 0 0 0 nodul 6 are gradul 0 Numarul de noduri este 6 si numarul de muchii este 4 Matricea este simetrica si patratica avand 6 linii si 6 coloane Diagonala principala contine numai valori nule
6

Pentru a prelucra graful se citesc: 6- reprezentand n, numarul de noduri 4- reprezentand m, numarul de muchii 4 perechi x-y reprezentand extremitatile celor 4 muchii: 1-2 => a[1,2]=a[2,1]=1 1-4 => a[1,4]=a[4,1]=1 2-3 => a[2,3]=a[3,2]=1 3-4=> a[3,4]=a[4,3]=1 3-5 => a[3,5]=a[5,3]=1

Listele de adiacenta a nodurilor
Reprezentarea in calculator a unui graf se poate face utilizand listele de adiacenta a varfurilor, adica pentru fiecare varf se alcatuieste lista varfurilor adiacente cu el. Fie graful din figura urmatoare:

1

6 5 3 4

2

Lista vecinilor nodului 3: 2, 4, 5 (noduri adiacente)
1 6 5 3 4

2

Nodul 6 nu are vecini (este izolat) Pentru intreg graful vom avea mai multe liste : Nodul 1 : 2 4 Nodul 2 : 1 Nodul 3 : 2 Nodul 4 : Nodul 5 : Ordinea nodurilor in cadrul unei liste nu este importanta Pentru a genera o astfel de lista vom defini tipul nod : struct nod {int nd; nod *next;}; Toate listele se vor memora utilizand un vector de liste : nod *L[20]; Datele de intrare : numarul de noduri si muchiile se vor citi din fisier : O solutie de implementare este urmatoarea : #include<conio.h> #include<fstream.h> struct nod
1 3 3 4 3 5

i++) afisare(i). nod *next. //citirea datelor din fisier clrscr(). while(c) {cout<<c->nd<<" ".open("graf. for(i=1. //se adauga i in lista vecinilor lui j q->nd=i.txt". L[i]=p. //se adauga j in lista vecinilor lui i p->nd=j. nod *L[20].{int nd. f. L[j]=q. f>>n.n.j. while(f>>i>>j) {p=new nod. q=new nod.ios::in). .} cout<<endl. q->next=L[j]. } f.}. nod *c=p.*q.} } void main() {fstream f.i<=n.close(). else {cout<<"lista vecinilor lui "<<nr_nod<<endl. if(p==0) cout<<nr_nod<<" este izolat "<<endl. c=c->next. void afisare(int nr_nod) //afiseaza lista vecinilor nodului nr_nod {nod *p=L[nr_nod]. cout<<endl<<"listele de adiacente ". nod *p. p->next=L[i].int i.

pentru a se face economie de memorie. e. daca in problema se doreste un acces frecvent la muchii. E1)este o componenta conexa daca: . Adica. Aceste doua moduri de reprezentare (prin matrice de adiacenta si prin liste de vecini) se folosesc dupa natura problemei. unde V are n elemente (n noduri) si E are m elemente (m muchii). 1. Parcurgand listele de adiacenta rezolvati urmatoarele cerinte : a. Sa se determine daca graful contine noduri izolate Sa se determine fradul unui nod citit de la tastatura Sa se determine nodul cu cel mai mare grad Sa se determine daca nodurile x si y sunt adiacente Sa se verifice daca graful este regulat Sa se determine daca graful este complet Componente conexe Fie G=(V. b. } Observatie : In exemplul anterior adaugarea unui nou element in lista se face inainte celorlalte din lista corespunzatoare. c. daca numarul de muchii care se reprezinta este mult mai mic dect nxn. b.pentru orice pereche x. atunci se va folosi matricea de adiacenta. e. Probleme propuse : 1. E2) care sa indeplineasca prima conditie si care sa-l contina pe G1 .getch(). f. d. Definitie: G1=(V1. E) un graf neorientat.y de noduri din V1 exista un lant de la x la y (implicit si de la y la x) .nu exista alt subgraf al lui G. este de preferat sa se folosesca listele de adiacenta. a. d. G2=(V2. Sa se memoreze un graf neorientat utilizand liste de adiacente. c. f.

E)este conex daca pentru orice pereche x. .subgraful care contine nodurile: 67 Observatie: subgraful 1. operaţii.y de noduri din V exista un lant de la x la y (implicit si de la y la x). 4 nu este componenta conexa pentru ( chiar daca pentru orice pereche x.y de noduri exista un lant de la x la y) deoarece exista subgraful 1. Nodul in care nu intra nici un arc se numeste radacina.subgraful care contine nodurile: 12345 . iar cele de pe ultimul nivel se numesc frunze sau noduri terminale.7. Definire. Observatii: .Graful anterior nu este conex pentru ca admite doua componente conexe Graful urmator este conex: 1 6 7 5 3 4 2 2. modele de reprezentare. 2.Un graf este conex daca admite o singura componenta conexa. 3. Definitie: Un graf G=(V. 5 care il contine si indeplineste aceeasi conditie. 3. Nodurile sunt organizate pe nivele. ARBORI Un arbore este un graf conex fara nici un ciclu (n varfuri si n-1 arce). 4.1 6 7 5 2 3 4 Graful alaturat are doua componente conexe: . Nodurile pot contine informatii utile ce poarta denumirea de chei ale arborelui. Un nod in care intra un arc se numeste succesor sau fiu. 2. iar cel din care iese un arc sau mai multe se numeste predecesor sau parinte. . Arbori. Legaturile existente intr-un arbore sunt de tip parinte-fiu.

sunt identice.2.k se transforma în arbore binar având radacina A1..i1 pentru 2<=i<=k.1. care daca nu este vida. contine un nod numit radacina. restul nodurilor formând doi arbori disjuncti numiti subarborele stâng si subarborele drept. . Un arbore generalizat A cu radacina A1 si subarborii A1. astfel incât secventele de noduri pentru parcurgerea inpreordine sa fie identice in cazul ambilor arbori. iar A1.. orice arbore putând fi transformat în arbore binar .A1. se obtine arborele binar reprezentat. A1.i devin fiii drepti ai lui A1.1 fiul sau stâng. Secventele de noduri în parcurgerea în preordine a arborelui generalizat si a celui binar obtinut prin transformare. . Implementarea arborilor binari Un arbore binar poate fi descris cu ajutorul urmatoarei structuri de date dinamice: typedef int TCheie. Aplicând regula descrisa.ARBORI BINARI Definitie Un arbore binar este o multime de n >= 0 noduri. A1.. Exemplu: Se considera arborele generalizat de mai sus. Aceasta structura de date e importanta pentru ca e usor de reprezentat si prelucrat. Tehnica transformarii unui arbore generalizat în arbore binar Un arbore generalizat poate fi transformat intr-un arbore binar.

cele 3 posibilitati de traversare sunt: o o o preordine . returnând true la gasire. Are proprietatea ca daca un nod oarecare al arborelui are cheia c. respectiv drept.insereaza cheia X în arborele A. Arbori binari ordonati. respectiv toate cheile din subarborele drept au cheile mai mari sau egale cu c. daca exista.face vid arborele A. prin trecerea la fiul stâng sau drept de la nodul curent.cauta cheia X.*dr. TRAVERSEAZA(A) . . secventa cheilor este monoton crescatoare. CAUTA(X. De aici rezulta procedeul de cautare foarte simplu. TNodAB *stg. B inordine . toate nodurile din subarborele stâng al nodului au cheile mai mici decât valoarea c. Operatorii arborelui binar INITIALIZEAZA(A) . TNodAB(TCheie k) { cheie=k. SUPRIMA(X. R. R.lista A. Arbori binari de înaltime minima Arborele binar ordonat e arborele binar cu proprietatea ca parcurgând nodurile în inordine.parcurge toate cheile arborelui A Traversarea arborilor binari Pentru un arbore binar.lista A.suprima cheia X. notând cu R radacina si cu A si cu B subarborele sau stâng.A) .lista R. B. Cele trei metode de traversare se concretizeaza în trei functii recursive în care Prelucrare este operatia ce trebuie facuta asupra fiecarui nod.class TNodAB { public: TCheie cheie.A) . A. INSEREAZA(X. functie de relatia dintre cheia cautata si cea a nodului curent. B postordine. } }.A) . stg=dr=NULL.

Algoritmi fundamentali pentru prelucrarea datelor (algoritmi de sortare.De aceea se impune sa gasim cei mai convenabili algoritmi si sa prezentam avantajele si dezavantajele acestora. astfel încât dupa insertie el sa ramâna ordonat. usor de gasit si de inteles. Se repeta pâna când se ajunge la un pointer nil care se inlocuieste cu pointerul spre noul nod creat. Cateva din cele mai cunoscute sunt sortarea rapida (QuickSort). sortarea prin interclasare (MergeSort) si sortarea cu micsorarea incrementului( Shell Sort ). sortarea prin insertie ( InsertSort ) si sortarea cu bule ( BubbleSort ). Metodele avansate se bazeaza pe algoritmi putin mai complicati. fata de n/2 comparatii într-o lista liniara. Tehnica de creare a arborilor binari ordonati Procesul de creare consta în insertia câte unui nod într-un arbore binar ordonat. Pentru ca sortarea sa fie stabila.Cum înaltimea minima a unui arbore binar ordonat cu n noduri este hmin=[log2 (n+1)]. pana la limbi( realizarea unor dictionare ). algoritmi de căutare. algoritmi de interclasare) Sortarea reprezinta una dintre cei mai utilizate metode de programare.8. care initial este vid. Metodele de sortare se clasifica in metode directe si metode avansate. 2. se trece la fiul drept chiar daca valoarea cheii e egala. Are utilizari de la domenii precum matematica( statistica matematica ). dupa cum cheia de inserat e mai mica sau mai mare decât a nodului parcurs. rezulta ca o cautare într-un arbore binar ordonat necesita aproximativ log2n comparatii de chei. dar care nu necesita unostinte avansate de algoritmica. Pentru aceasta se traverseaza arborele începând cu radacina si se selecteaza fiul stâng sau drept. Ne vom rezuma la cei mai importanti ( in cartea lui Donald Knuth –“ Algoritmi de sortare” sunt prezentati peste 30 asemenea metode de programare). La fiecare metoda voi descrie algoritmul. Metodele directe pe care le vom lua in considerare sunt sortarea prin selectie ( SelectSort ). Metodele directe se bazeaza„ pe algoritmi de dificultate redusa. il voi exemplifica in Pseudocod si C++( la .

nu folosesc memorie suplimentarã. in altele cele avansate sunt mai bune. intrucat nu exista un algoritm perfect. cu exceptie poate o micã tabelã sau stivã.1 BubbleSort Acesta metoda se rezuma la a compara fiecare element cu celelalte. In unele cazuri metodele directe sunt mai economicoase( mai putine elemente de comparat ). Algoritmul este urmatorul: simple-sort (a[Nmax+ 1]) pentru iÅ 1 pana la n pentru j Å i+1 pana la n daca a[i]>a[j] interschimba(a[i]. cei care au o reprezentare de listã înlãntuitã deci folosesc N cuvinte de memorie în plus pentru pointerii listei. Trebuie sã folosim mai multe criterii pentru evaluarea timpului de executie al algoritmului de sortare cum ar fi. voi analiza complexitatea algoritmilor si voi propune un set de probleme. a[j]) Algoritmul in C++ (neparamatrizat) este : void BubbleSort(Tip a[Nmax+1]. 1.int Size) . facandu-se interschimbarea daca elementul mai mare are indexul mai mic. Recomand ca lucrarea sa fie parcursa pas cu pas. Metodele se împart în trei tipuri: cei care sorteazã pe loc. cei care au nevoie de memorie suplimentarã pentru o copie a tabelei initiale. Poate fi folosita cu succes de catre incepatori. De asemenea recomand incepatorilor ca sa utilizeze fiecare metoda. Este cea mai simpla metode de sortare si nu necesita cunoasterea detaliata a limbajului de programare. numãrul de pasi(de atribuiri) ai algoritmului si numãrul de comparatii dintre elemente necesare pentru a sorta N elemente Al doilea factor important este cantitatea (volumul) de memorie suplimentarã folositã de un algoritm de sortare. Metode directe 1.unele metode si parametrizat). Analizând complexitatea algoritmilor factorul cel mai important este timpul de executie exprimat în "O-mare".

2. Exemplu de sortare (sirul initial este {6. Nu necesitã foate multã memorie. dar nu pentru tabele mari.i<size.i++) if (a[i]>a[i+1]) {interschimba(a[i]. a[i]=a[j].} for(int i=0.a[i+1]). În cazul cel mai nefavorabil sunt necesare N ×(N-1)/2 comparãri si N × (N-1)/2 interschimbãri. 1}): Nr interschinbari .( Algoritmul in C++ (parametrizat) este : Void Bubblesort_para(Tip a[Nmax+1]. 3.} }while (ok==1).j<=Size. adicã N-1 comparãri.i. Timpul de executie depinde de input. adicã de ordinea initialã al elementelor. { { Bubble sort este o metodã de sortare simplã. Complexitatea timpului al Bubble sortului este O(N 2 . Dacã tabela este deja sortatã e nevoie de un singur pas. eficientã pentru un numãr mic de elemente (mai putin de 15). 4. do{ for( i=1. a[j]=aux. {In acest caz in cazul cel mai defavorabil numarul de comparatii este tot NC=n(n1)/2 dar spre deosebire de celalalt algoritm este mai rapid in cazurile medii.) BubbleSort nu foloseste alte structuri de date si din aceasta cauza este recomandabil in cazurile cu putine elemente de sortat si in cazul in care memoria este limitata.i++) for(int j=i+1. 5.j++) if(a[i]>a[j]) } Tip aux=v[i]. dar este de douã ori mai lentã decât InsertionSort în aproape orice situatie.int size) } int ok=0.i<Size.ok=1. (daca nu mai gaseste doua elemente de interschimbat algoritmul se opreste. Performanta algoritmului în caz general este mai greu de analizat dar este asemãnãtor cazului nefavorabil.

. Considerãm elementele A[1]. parcurgem tabela si le inserãm fiecare element în locul propriu între celelalte elemente considerate sortate. Algoritmul este : Insertion(a[nmax+1]) Pentru iÅ2 pana la n JÅi pana cand (a[j-1]>a[i]) a[j]Åa[j-1] jÅ j-1 . dar poate mai flexibil. Tabela este sortatã complect când indexul ajunge la capãtul drept al tabelei.N .A[i-1] fiind sortate... inserãm elementul A[i] în locul ce îi revine. Elementele aflate în stânga indexului sunt în ordine sortatã dar nu sunt în pozitia lor finalã. elementele A[1]…A[i] sunt sortate prin inserarea lui A[i] între lista elementelor sortate: A[1]…A[i-1].3 InsertionSort Insertia directã apartine familiei de tehnici de sortare care se bazeazã pe metoda "jucãtorului de bridge". Este un algoritm aproape la fel de simplu ca Selection sort.6 5 4 3 2 1 1 5 6 4 3 2 1 2 5 4 6 3 2 1 3 5 4 3 6 2 1 4 5 4 3 2 6 1 5 5 4 3 2 1 6 6 4 5 3 2 1 6 7 4 3 5 2 1 6 8 4 3 2 5 1 6 9 4 3 2 1 5 6 10 3 4 2 1 5 6 11 3 2 4 1 5 6 12 3 2 1 4 5 6 13 2 3 1 4 5 6 14 2 1 3 4 5 6 15 1 2 2 3 4 5 1. Fiind dat o tabelã A cu N elemente nesortate. Pentru fiecare i = 2.

Strategia de bazã folositã este "divide et impera". type v. Necesitã numai în jur de NlogN operati în cazul general pentru a sorta N elemente. lucreazã destul de bine în diferite situatii si consumã mai putine resurse decât orice altã metodã de sortare în multe situatii. j. } A[j] = v. care foloseste partitionarea ca idee de bazã. Este mai rapidã decât orice metodã de sortare simplã. i <= size. For ( i = 2. j = i. 2. liniar: O(N) pentru tabele care contin N elemente aproape sortate. se executã bine pentru fisiere sau tabele mari.1 QuickSort În practicã algoritmul de sortare cel mai rapid este Quicksort numitã sortare rapidã. Metoda QuickSort presupune gasirea pozitiei finale pe care o ocupa elemenetul de pe prima pozitie comparandu-l cu elementele din cealalta partitie a tabelului. int size ) } int i. While ( A[j-1] > v )// mut elementele cu o pozitie in fata { A[j] = A[j-1].2 MergeSort Algoritmul de sortare prin interclasare se bazeazã pe urmãtoarea idee: pentru a . decât una mare.a[j]Åa[i]Algoritmul in C++ este : Insertion ( type A[ ]. Algoritmul este usor de implementat. i++ ) } v = A[i]. deci de ordinea initialã al elementelor. j --. Timpul de executie al algoritmului depinde de numãrul inversãrilor.// pun elem in poz lui { { Insertion sort este un algoritm de sortare simplu. acest algoritm realizandu-se pana cand partitia are 1 element. dar ineficient pentru cele mici. 2. pentru cã este mai usor de sortat douã tabele mici.

Sorteaza a doua jumatate a tabelului 4. Tabelul se imparte in n/2. sã obtinem o tabelã sortatã.sorta o tabelã cu N elemente îl împãrtim în douã tabele pe care le sortez separat si le intrclasãm. Astfel spunem cã tabela este h-sortatã. va produce o tabelã sortatã. Este o metodã de sortare care foloseste strategia de bazã "divide et impera". dupa aceea tabelele se impart in jumatate. Algoritmul presupune : 1. h-sortatã este formatã din h subtabele sortate independent. Ideea de bazã o constituie rearanjarea elementelor din tabela A în asa fel încât.3 ShellSort Sortarea cu micsorarea incrementului (shellsort) este o extensie simplã al Insertion sortului care câstigã vitezã permitând schimbarea elementelor aflate departe. Afla mijlocul tabelului 2. Imbina cele 2 jumatati Algoritmul in Pseudocod este: 2. conform cãreia problema se descompune în alte douã subprobleme de acelasi tip si dupã rezolvarea lor rezultatele se combinã. intercalate. tot asa pana cand tabelele formate au mai putin sau cel mult de k elemente(in cazul nostru k=2este cel mai usor sa compari 2 elemente). Sorteaza prima jumatate a tabelului 3. luând fiecare a h-a element (începând de oriunde). O tabelã . Folosind astfel o procedurã pentru fiecare secventã a valorii lui h care se terminã în 1. Algoritmul sorteazã elementele în ordine crescãtoare. Algoritmul este : shell-sort (a) h←1 pana cand h<n/9 h ← 3*h+1 pana cand h>0 pentru i ← h+1 pana la n t ← a[i] j←i pana cand (j>h si a[j-h] > t) .

v. h = 3*h+1). j . h. acţiunile fiind determinate doar de organizarea datelor. i += 1) } v = A[i]. . Această disciplină care are la bază ideea unificării datelor cu modalităţile de prelucrare a acestora şi manevrează entităţi reprezentate sub formă de obiecte (obiect=date+cod de tratare a acestor date). h > 0. Abordarea obiectuală a structurilor de date în aplicaţii complexe (definirea de clase şi obiecte în C++.  Rezolvarea orientată pe date.= h. destructori. în care organizarea datelor este neesenţială.. h /= 3 ) for (i = h+1. moşteniri). a[j-h]) j ← j-h h ← h/3 Algoritmul in C++ este : Shellsort(int A[]. { { Exemplu : sirul initial este {1 11 8 10 12 4 7 3 1 13 1 6 9 5 2 } 2. h <= n/9. while ( j>h && A[j-h]>v ) } A[j] = A[j-h]. int n) } int i.9. Termenul "OOP" ("Object Oriented Programming") desemnează disciplina programării obiectuale (orientate-obiect). i <= n. { A[j] = v.3. for ( .interschimba(a[j].  Rezolvarea orientată obiect. constructori. j. care combină tendinţele primelor două abordări. for (h = 1. Aşa cum s-a subliniat în capitolul 1. j = i. rezolvarea unei probleme se poate face pe 3 direcţii:  Rezolvarea orientată pe algoritm (pe acţiune).

Instanţa este un obiect dintr-o clasă (A. el poate folosi tipul matrice în mod similar unui tip predefinit: matrice A. Câteva exemple de limbaje de programare orientată obiect: SIMULA(1965). 4. Pentru o clasă definită. Astfel. O clasă se caracterizează prin: numele clasei. 3. B. încapsularea (ascunderea) informaţiei. atribute. Obiectele care reprezintă aceeaşi idee sau concept sunt de acelaşi tip şi pot fi grupate în clase (concrete sau abstracte). Java (în plus. C sunt obiecte. instanţe ale clasei matrice) şi are proprietăţile definite de clasă. adaptabil.Programarea obiectuală oferă posibilităţi de modelare a obiectelor. un fenomen implică tipuri diferite de obiecte. Comportamentul unui obiect este determinat de care acţiunile pe care obiectul poate să le execute (metodele). un tip de date înseamnă o mulţime de valori pentru care s-a adoptatat un anumit mod de reprezentare şi o muţime de operatori care pot fi aplicaţi acestor valori). moştenirea. matrice C=A+B. De exemplu. Cele mai multe limbaje orientate obiect fac următoarea distincţie între atribute:  atribute ale clasei (au aceeaşi valoare pentru toate instanţele clasei). a proprietăţilor şi a relaţiilor dintre ele. deci şi operatorii destinaţi manipulării acestora: Clasă = Date + Operaţii. ABSTRACTIZAREA DATELOR Obiectele sunt componente software care modelează fenomene din lumea reală. SIMULA-2(1967). programarea orientată obiect (conform lui Pascou) sunt: abstractizarea datelor. Toate obiectele au o stare şi un comportament. reciclabil). etc). Facilităţile oferite de 1. funcţii şi relaţii cu alte clase. Atributele specificate în definiţia unei clase descriu valoric proprietăţile obiectelor din clasă. Smalltalk. Tipul unui obiect (şablon al obiectului) este o clasă. programatorul îşi poate defini tipul (clasa) matrice şi operatorii care pot fi aplicaţi matricilor (* pentru înmulţirea a două matrici. + pentru adunarea a două matrici. Java poate fi considerat un limbaj de programare orientată eveniment). . legarea dinamică (“târzie”). Clasele implementează tipuri de date (aşa cum s-a subliniat în capitolul 2.pentru scăderea a două matrici. dar şi posibilitatea de a descompune o problemă în componentele sale (soft mai mentenabil. B. se pot crea mai multe instanţe ale acesteia. C++. În general. 2. . sub diferite aspecte. Starea unui obiect se referă la elementele de date conţinute în obiect şi la valorile asociate acestora (datele membre).

gradul de abstractizare este. structurile şi uniunile reprezintă cazuri particulare ale claselor.constă în modul de acces la membrii: la structuri şi uniuni membrii (datele şi metodele) sunt implicit publici. La crearea unui obiect. În limbajul C++ atributele se numesc date membre. dar şi funcţii membre. private. Clasa conţine atât structurile de date necesare descrierii unui obiect. Astfel. cât şi metodele care pot fi aplicate obiectului. Atributele de clasă se pot obţine în cazul datelor membre statice (aceeaşi adresă de memorare pentru orice instanţă a clasei). numite constructori). cât şi operaţiile asupra datelor (funcţiile membre.pe cealată parte . Eliberarea memoriei se realizează cu ajutorul unor funcţii membre speciale. modul de acces la membrii tipului de date (în scopul protejării acestora) poate fi schimbat prin utilizarea modificatorilor de control ai accesului: public. câmpuri de date (vezi capitolul 8).implicit privaţi (membrii sunt încapsulaţi). fiecare instanţă având propria copie a atributului).  Metode (funcţii membre). în momentul încheierii existenţei obiectului respectiv. iar la clase . alocarea memoriei se poate fi face static sau dinamic (cu ajutorul unor funcţii membre speciale. depanat sau întreţinut. pentru memorarea valorilor datelor membre se foloseşte aceeaşi zonă de memorie. face ca tipurile de date introduse prin structuri sau uniuni să nu poată fi strict controlate în ceea ce priveşte operaţiile executate asupra lor. dar şi de instanţele altor clase (prin mecanismul moştenirii). Toate datele membre sunt atribute instanţă. metode). Lipsa unor modalităţi de protecţie a datelor. În limbajul C++. protected.pe de o parte . DEFINIŢIA CLASELOR ŞI ACCESUL LA MEMBRII LEGĂTURA CLASĂ-STRUCTURĂ-UNIUNE Aşa cum s-a subliniat în capitolul 9. . DECLARAREA CLASELOR . putând avea nu numai date membre. mult mai ridicat. Singura diferenţă între structuri şi uniuni constă în faptul că la uniuni. Fiecare obiect are acces la un set de funcţii care descriu operaţiile care pot fi executate asupra lui. Deosebirea esenţială între structuri şi uniuni . iar programele devin mult mai uşor de înţeles. Metodele pot fi folosite de instanţele clasei respective.şi clase .atribute ale instanţei (variază de la o instanţă la alta. În cazul claselor. La definirea unei clase se definesc şi metodele acesteia (numite şi funcţii membre). numite destructori. o clasă reprezintă un tip abstract de date. care încapsulează atât elementele de date (datele membre) pentru care s-a adoptat un anumit mod de reprezentare.

implicit. Exemplu: class masina{ char *culoare. Clasa reprezintă un tip de date (definit de utilizator). până la sfârşitul declaraţiei clasei sau al întâlnirii altui modificator de acces (exemplele 1. Observaţiile legate de prezenţa nume_tip sau lista_variabile (din capitolul 8) sunt valabile şi în cazul claselor.4. Specificatorii modului de acces pot apare în declararea clasei de mai multe ori. private sau protected (eventual friend.). private int capacit_cil. în plus.Modul de declarare a unei clase este similar celui de declarare a structurilor şi a uniunilor: class nume_tip{ modificator_control_acces: lista_membrilor. Membrii cu acces private pot fi accesaţi numai prin metodele clasei (sau prin funcţiile prietene.4. se pot aplica modificatorii de acces. capitolul 10. Modificatorul de acces public se utilizează pentru membrii care dorim să fie neprotejaţi. Dacă nu se specifică. // dată membru la care accesul este. Domeniul unui modificator de acces ţine din punctul în care apare modificatorul respectiv. Cei cu acces protected posedă caracteristicile celor privaţi. ultimii doi modificatori asigurând protecţia membrilor din domeniul de acţiune a lor.).datele declarate în cadrul clasei. private . accesul implicit (public) nu poate fi modificat. // dată membru la care accesul este. este considerat cel implicit (private). Membrii unei clase sunt:  Datele membre . vezi paragraful 10.2). Observaţie: În cazul tipurilor de date definite cu ajutorul structurilor. Pentru membrii care apar în lista_membrilor se poate preciza un anumit mod de acces. Modificator_control_acces poate fi public.funcţiile membre. definiţiile putând fi făcute oriunde în fişier. Se admite că în cadrul declaraţiei de clasă să se specifice doar prototipurile funcţiilor membre. funcţiile declarate sau definite în cadrul clasei. implicit. În cazul tipurilor definite cu ajutorul uniunilor. sau în alt fişier. Variabilele din lista_variabile sunt de tipul nume_tip şi se numesc instanţe (obiecte) ale clasei. } lista_variabile.  Metodele . în orice ordine. putând fi accesaţi şi din clasele derivate.

la t Figura 10. Alocarea memoriei pentru datele membre nestatice .Lun g d.la t Lung d lat d. b. Se pot declara oricâte obiecte (instanţe) ale clasei. care permite introducerea datelor despre o instanţă a clasei int ret_capacit(). //dată membru privată }.la t Lung lat b g b. //metodă cu acces public. c.Lun Lung Lung lat a g a. dreptunghi b.Lun comun. se declară obiectul (variabila) a de tip dreptunghi. vezi figura 10. Spunem că obiectul a este o instanţă a clasei dreptunghi. care există într-un singur exemplar.1.1. //dată membru privată public: void citire_inf_pers(). În exerciţiul anterior. //metodă cu acces public }. punctul c. c. Excepţia de la această regulă o constituie datele membru statice. în funcţia main.Lun a. //metodă publică private: int varsta. d de tip dreprunghi. MEMBRII UNEI CLASE Datele membru se alocă distinct pentru fiecare instanţă (atribute ale instanţei) a clasei (pentru declararea obiectelor a.).public: void citire_date(). Exemple: dreptunghi a. Exemplu: class persoana{ char *nume. d. c.la t c lat g c. Aşa cum se observă din exemplu. declararea obiectelor de un anumit tip are o formă asemănătoare celei pentru datele de tip predefinit: nume_clasa lista_obiecte. OBIECTE Un obiect este o dată de tip definit printr-o clasă. b. Membrii culoare şi capacitate_cil (accesul private) pot fi accesaţi doar prin intermediul metodelor clasei. pentru toate instanţele clasei.

folosind operatorul de rezoluţie (::). metoda seteaza_dimen este doar declarată în interiorul clasei. De fapt. double ). prin care obiectul va avea acces la metoda respectivă.Metodele figurează într-un singur exemplar. transparentă utilizatorului. după cum obiectul este desemnat prin nume sau prin pointer (vezi exemplu). Legătura dintre obiect şi funcţia membră se face prin operatorul . Accesul la o metodă presupune o activitate de adresare. în interiorul obiectului creat se află doar punctatori la clasa din care provin. Excepţia de la această regulă o constituie metodele virtuale (capitolul 12). O funcţie membru se apelează totdeauna în strânsă dependenţă cu un obiect din clasa respectivă. . fiind abia apoi definită. lat. În interiorul definiţiei clasei se alocă o singură copie a fiecărei funcţie membră şi punctatorii respectiv. deoarece. oricâte instanţe ale clasei ar exista. double arata_Lung(). Operatorul cuplează nume_clasa::nume_functie_membru şi defineşte domeniul (scopul) în care acea funcţie va fi recunoscută. În plus. metodele statice pot fi apelate independent de un obiect al clasei. sau operatorul ->. class dreptunghi{ double Lung. double l)) s-a folosit operatorul :: (scope resolution operator) care specifică relaţia de apartenenţă a metodei la tipul dreptunghi. Exemplu: Fie clasa dreptunghi din exerciţiul anterior. double arata_Lat(). Prezenţa numelui clasei în faţa funcţiei membru este obligatorie. care aparţin unor clase diferite. La definirea funcţiei (void dreptunghi::seteaza_dimen(double L. În exemplul anterior. altfel nu s-ar putea face distincţia între metode cu nume identice. double calcul_arie(). public: void seteaza_dimen(double.

Moştenirea poate fi: unică sau multiplă. //…………………………………………………………………… cout<<"Aria dreptunghiului:"<<a. care permite refolosirea codului şi extinderea funcţionalităţii claselor existente. un obiect poate prelua proprietăţile obiectelor din clasa de bază. Clasa A reprezintă clasa de bază (este o generalizare) şi conţine informaţiile comune (disponibile prin moştenire şi subclaselor acesteia). Clasa B reprezintă clasa derivată (este o particularizare. domeniul de vizibilitate al unui nume coincide cu domeniul numelui. au sânge cald.. îşi alăptează puii. Sau: B este clasă. Mecanismul moştenirii permite crearea unei ierarhii de clase şi trecerea de la clasele generale la cele particulare. void main() { dreptunghi a. aşa cum prezintă tabelul 6. //……………………………………………………………………………. iar B reprezintă clasa animalelor domestice. } Vizibilitate Domeniul de vizibilitate a unei variabile (obiect) este determinat de clasa de memorare a variabilei (obiectului). iar A este o superclasă a clasei B. aceasta moşteneşte toate caracteristicile clasei A. dreptunghi *pa. rămânând de specificat doar trăsăturile distinctive. Prin moştenire. pa=&a. De obicei.1.1. Procesul implică la început definirea clasei de bază care stabileşte calităţile comune ale tuturor obiectelor ce vor deriva din bază (ierarhic superioară)(figura 9. Este bine ca informaţia comună unor clase să fie specificată o singură dată (conceptul de clasă/subclasă. o specializare a clasei A) care extinde funcţionalitatea clasei de bază şi conţine informaţiile specifice. (capitolul 6).1. dar şi multe asemănări. A este clasă de bază. Să presupunem că A reprezintă clasa mamiferelor (cu proprietăţile caracteristice: nasc pui vii. etc). double arie=pa->calcul_arie(). În momentul definirii clasei derivate B. În acest caz. MOŞTENIREA Moştenirea este o caracteristică a limbajelor de programare orientate obiect.calcul_arie()<<'\n'.). Relaţia clasă de bază-clasă derivată . A B Figura 9. Între două clase pot exista multe diferenţe.}. iar B clasă derivată (subclasă a clasei A). superclasă/clasă în OOP).

una pentru fiecare drum. MOŞTENIREA MULTIPLĂ În situaţia moştenirii multiple. care să ajute doar la organizarea structurii (reţelei) de moştenire. este posibilă o moştenire repetată. Moştenirea multiplă Moştenirea multiplă este utilă. moştenirea clasei va fi multiplă (rezultând o structură de reţea). MOŞTENIREA UNICĂ În cazul moştenirii unice. Aşa cum vedea în capitolele următoare. A A B C D B C D E F G H E F Figura 9. fiecare clasă are doar o superclasă.. în care o clasă ajunge să moştenească de la aceeaşi clasă.3. pe drumuri diferite în reţea (vezi figura 9. Există mai multe strategii de rezolvare a conflictului (părintele cel mai apropiat. în aceste situaţii. dar poate crea ambiguităţi (când pentru acelaşi atribut se moştenesc valori diferite). Ideea moştenirii multiple poate duce la utilizarea unor clase pentru care nu există instanţe. cel mai depărtat. Deasemenea.). iar A este clasă virtuală de bază şi pentru C şi pentru B. limbajul C++ oferă programatorului două strategii: 1) clasa E poate avea două copii ale lui A. . 2) clasa E are o singură copie. o clasă are mai multe superclase. Moştenirea simplă (unică) Figura 9. Există două modalităţi de specializare a unei clase de bază:  introducerea de extra-atribute şi extra-metode în clasa derivată (particulare doar clasei derivate). în care clasa E moşteneşte de la aceeaşi clasă A.. Astfel. A-C-E) . etc. pe drumurile AB-E.  redefinirea membrilor în clase derivate (polimorfism).2.3.

Figura 9. Această tehnică de "plasare" a valorilor în datele membre private ale obiectului. clasă friend: aceşti membri pot fi accesaţi prin Clasa B derivată funcţiile membre ale funcţiei prietene specificate. protected: aceşti membri pot fi accesaţi prin funcţiile membre ale clasei şi funcţiile membre ale clasei derivate. deoarece toate datele şi funcţiile membre sunt caracterizate printr-un nivel de acces (rezultând astfel o mare flexibilitate). În limbajul C++ încapsularea poate fi forţată prin controlul accesului.În plus. Vom spune că metodele şi atributele unui obiect sunt “private”. fiind partajate între toate instanţele clasei. Obiectul deţine controlul asupra atributelor instanţă. Accesul la membrii unei clase În limbajul C++.4. Interfaţa cu obiectul relevă foarte puţin din ceea ce se petrece în interiorul lui. încapsulate în obiect. . ÎNCAPSULAREA (ASCUNDEREA) INFORMAŢIEI Încapsularea (ascunderea) informaţiei reflectă faptul că atributele instanţă şi metodele unui obiect îl definesc doar pe acesta. reprezintă un mecanism de ascundere a datelor. limbajul C++ permite un control puternic asupra atributelor şi metodelor care vor fi moştenite. nivelul de acces poate preciza şi tipul de moştenire (capitolul 12).): public     Clasa A private: membrii (date şi metode) la care protected accesul este private pot fi accesaţi doar prin private metodele clasei (nivel acces implicit). Excepţia de la această observaţie o reprezintă doar atributele de clasă care nu sunt încapsulate. public: membrii la care accesul este public pot fi accesaţi din orice punct al domeniului de existenţă a clasei respective. unde în clasa derivată nivelul de acces al membrilor este acelaşi ca în clasa de bază.4. care nu pot fi alterate de către alte obiecte. Nivelul de acces la membrii unei clase poate fi (figura 9.  Publică. unde membrii protected şi public din clasa bază devin private în clasa derivată.  Privată.