indrumarnew

166
INTRODUCERE Limbajul C++ se consideră atît un limbaj de pr ogramare intermediar – de nivel scăzut datorit ă apropierii sale de limbajele de asamblare cu posibilităţi de manipulare a biţilor, apel de sistem de operare, operaţii cu memoria, etc., cît şi un limbaj de nivel înalt cu proprietăţi caracteristice limbajelor din aceast ă categorie ce permite de a crea aplicaţ ii în baza principiilor programării orientate pe obiect. În drumarul prezint ă lucr ările de laborator pe care studen ţii tr ebuie s ă le execute la disciplina “Programarea în limbajul de programare C++”. Pentru fiecare lucrare de laborator este indicată tema şi scopul lucrării, consideraţii le teoretice necesare, întrebări pentru verificarea cunoştinţelor, temele pentru acasă şi de laborator. Aceste compartimente împreună cu bibliografia vor fi utilizate de studenţi pentru executarea lucrărilor de laborator. Pentru a fi admis la îndeplinirea lucrării de labora tor, fiecare student trebuie să înd epl inească următoarele condiţii:  să execute tema pentru acasă, care const ă din descrierea algoritmului de rezolvare a problemelor lucrărilor de laborator,  să răspundă la întrebările de control puse de către profesor. În perioada efectuării lucr ărilor de laborator studentul compilează şi execută programele corespunzătoare problemelor indicate de către profesor în conformitate cu îndrumarul de laborator, efectuează analiza datelor de intrare şi a rezultantelor obţinute, colectează datele pentru darea de seamă a lucrării. 3

Upload: dima-calugari

Post on 08-Apr-2018

227 views

Category:

Documents


2 download

TRANSCRIPT

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 1/166

INTRODUCERE

Limbajul C++ se consideră atît un limbaj deprogramare intermediar – de nivel scăzut datorităapropierii sale de limbajele de asamblare cuposibilităţi de manipulare a biţilor, apel de sistem deoperare, operaţii cu memoria, etc., cît şi un limbaj denivel înalt cu proprietăţi caracteristice limbajelor dinaceastă categorie ce permite de a crea aplicaţii înbaza principiilor programării orientate pe obiect.

Îndrumarul prezintă lucrările de laborator pe

care studenţii trebuie să le execute la disciplina“Programarea în limbajul de programare C++”.Pentru fiecare lucrare de laborator este indicată temaşi scopul lucrării, consideraţiile teoretice necesare,întrebări pentru verificarea cunoştinţelor, temelepentru acasă şi de laborator. Aceste compartimenteîmpreună cu bibliografia vor fi utilizate de studenţipentru executarea lucrărilor de laborator.

Pentru a fi admis la îndeplinirea lucrării delaborator, fiecare student trebuie să îndeplineascăurmătoarele condiţii:–  să execute tema pentru acasă, care constă din

descrierea algoritmului de rezolvare a problemelorlucrărilor de laborator,

–  să răspundă la întrebările de control puse de către

profesor.În perioada efectuării lucrărilor de laboratorstudentul compilează şi execută programelecorespunzătoare problemelor indicate de cătreprofesor în conformitate cu îndrumarul de laborator,efectuează analiza datelor de intrare şi arezultantelor obţinute, colectează datele pentrudarea de seamă a lucrării.

3

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 2/166

Lucrarea de laborator se consideră executatădupă ce studentul demonstrează profesoruluifuncţionarea corectă a programelor la calculator.

Pentru fiecare lucrare studentul pregăteşte darea

de seamă pe care o susţine în faţa profesorului.Darea de seamă pentru fiecare lucrare de

laborator include: foaia de titlu, tema, scopul lucrării,conţinutul problemei propuse spre rezolvare,descrierea algoritmului de rezolvare a problemeipropuse, listingul programului, datele obţinute înurma executării lucrării respective, bibliografia

utilizată.Temele de laborator pentru studenţi se indicăîn conformitate cu următorul tabel:

1 2 3 4 5 6 71 1 1 1 1 1 1 12 2 2 2 2 2 2 23 3 3 3 3 3 3 3

4 4 4 4 4 4 4 45 5 5 5 5 5 5 56 6 6 6 6 6 6 67 7 7 7 7 7 7 78 8 8 8 8 8 8 89 9 9 9 9 9 9 9

10 10

10

10

10

10

10

10

11 11

11

11

11

11

11

11

12 12

12

12

12

12

12

12

13 13

13

13

13

13

13

13

14 1

4

1

4

1

4

1

4

1

4

1

4

14

4

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 3/166

15 15

15

15

15

15

15

15

Pe verticală este numărul de ordine al studentului în

registru, iar pe orizontală este numărul de ordine allucrării de laborator propuse pentru executare.

5

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 4/166

CUPRINS

Introducere .......................................................................... 3

Lucrarea de laborator nr. 1 ................................................ 6

Lucrarea de laborator nr. 2 ................................................ 61

Lucrarea de laborator nr. 3 ................................................ 81

Lucrarea de laborator nr. 4 ................................................ 10

7

Lucrarea de laborator nr. 5 ................................................ 114

Lucrarea de laborator nr. 6 ................................................ 133

Lucrarea de laborator nr. 7 ................................................ 148

Bibliografie ......................................................................... 153

6

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 5/166

Lucrarea de laborator nr. 1Tema: Reprezentarea tipurilor de date ale limbajului C++ înmemoria calculatorului. Operatorii limbajului C++.Construcţiile elementare ale limbajului C++

(instrucţiunile for, while, do-while, if-else, switch-break, goto).Tipuri de date recursive, operaţii asupra listelor,arborilor. Construirea şi elaborarea programelorrecursive. Fişierele.

Scopul lucrării: familiarizarea studenţilor cureprezentarea tipurilor de date ale limbajului C++ în memoria

calculatorului, operatorii limbajului C++, construcţiileelementare ale limbajului C++ (instrucţiunile for,

while,  do-while, if-else,  switch-break,  goto), tipuri de daterecursive, operaţii asupra listelor, arborilor,construirea şi elaborarea programelor recursive,lucrul cu fişierele.

Consideraţiile teoretice necesare:Tipurile simple şi structurate ale limbajului C+

+ .

Identificatorii limbajului C++ sînt formaţi cuajutorul caracterelor alfanumerice şi caracterul desubliniere  “_”. Primul caracter al unui identificator nupoate fi o cifră.

Pi //legal

mesaj //legalmaxx //legalx3 //legal3x //ILEGALÎn cadrul mulţimii identificatorilor posibili,

remarcăm o clasă aparte, reprezentî nd  cuvintele-cheie. Cele mai frecvente cuvintele-cheie ale limbajul C++sîntauto

break 

delete

do

float

for 

interrupt

long

register 

return

template

this7

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 6/166

casechar classconst

continuedefault

doubleelseenumexport

externfar 

friendgotohugeif 

inlineint

near newoperator private

protectedpublic

shortsignedsizeof static

structswitch

typedef unionunsignedvirtual

voidwhile

Cuvintele-cheie nu trebuie utilizaţi ca nume devariabile.

Declararea variabilelor trebuie efectuată înainte dea fi folosite, la începutul programului sau chiar înfuncţie de contextul problemei în interiorulprogramului nemijlocit înainte de utilizare, cînd aparenecesitarea introducerii variabilei. 0 declaraţiespecifică un tip şi este urmată de o listă de una saumai multe variabile de acel tip, ca în exemplul de maijos:

int i,n;char c, linie[80];Domeniu de acţiune a variabilelor.

Variabilele pot fi iniţializate în momentul declaraţiei lor.Dacă numele este urmat de semnul egal şi de oconstantă, aceasta serveşte la iniţializare, ca înurmătoarele exemple:

char backslash = '\\';int i = 0;float eps = 1.0e-5;Dacă variabila este externă sau statică,

iniţializarea are loc o singură dată, înainte caprogramul să-şi înceapă execuţia. Variabilele automate,iniţializate explicit, sînt iniţializate la fiecare apel alfuncţiei în care sînt conţinute. Variabilele automatepentru care nu există o iniţializare explicită auvaloare nedefinită. Variabilele externe şi statice seiniţializează implicit cu zero, dar este un bun stil de

programare acela de a efectua iniţializarea lor în8

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 7/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 8/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 9/166

*pi=20; // i=20;Deoarece operatorul adresă & furnizează adresa uneivariabile, instrucţiunea pi=&i asignează variabilei piadresa lui i.(de exemplu, adresa 1000). Un alt operator unar

ce însoţeşte clasa pointerilor este * care furnizeazăconţinutul locaţiei de memorie de pe adresa indicatăde către pointer, de exemplu,

*pi=i; //  adică 15;Dacă j este un alt int, atunci j=*pi asignează lui j conţinutullocaţiei indicate de pi. Are loc următoareaechivalenţă: j=*pi; adică j=i;

Pointerii pot apărea în expresii. De exemplu, dacăpi conţine adresa lui i, atunci *pi poate apărea în oricecontext în care ar putea apărea i, cum ar fi

j=*pi+l; // adică j=i+l;printf("%d\n",*pi);d=sqrt((double)*pi);

În expresii ca j=*pi+1; operatorii unari * şi & sînt prioritarifaţă de cei aritmetici, astfel, această expresie adună

1 şi asignează valoarea obţinută lui j ori de cîte oripointerul pi avansează.

Referiri prin pointeri pot apărea şi în membrulstîng al atribuirilor. Dacă pi conţine adresa lui i, atunci*pi=0 îl pune pe i ca 0, iar *pi+=1 îl incrementează pe i, caşi (*pi)++. În ultimul exemplu parantezele sîntnecesare, fără ele se incrementează pi în loc

să incrementeze ceea ce indică pi, deoarece operatoriiunari * şi ++ sînt evaluaţi de la dreapta spre stînga. Deexemplu,

void main(){ int *pi, i=10;float *pf, f=12.5;double *pd, d=0.001;char *pc, c=’a’;

*pi=i; *pf=f; *pd=d; *pc=c;11

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 10/166

printf(“pi=%p, pf=%p, pd=%p, pc=%p”, pi, pf, pd, pc);printf(“*pi=%i, *pf=%f, *pd=%e, *pc=%c”, *pi, *pf, *pd,

*pc);printf(“pi++ =%p, pf++ =%p, pd++ =%p, pc++=%p”,

pi++, pf++, pd++, pc++);printf(“(*pi)++ =%p, (*pf)++ =%p, (*pd)++ =%p,

(*pc)++ = %p”, (*pi)++ , (*pf)++, (*pd)++, (*pc)++);

}Rezultatul îndeplinirii programului:

pi=8F1C, pf=0758, pd=074C, pc=1330*pi=10, *pf=12.500000,*pd=1.000000e-03, *pc=a pi++ =8F1C, pf++ =0758,pd++ =074C, pc++=1330(*pi)++ =1B57, (*pf)++ =0000,(*pd)++ =0000, (*pc)++ = 0000

Deoarece pointerii sînt variabile, ei pot fimanevraţi ca orice altă variabilă.  Dacă pj este un altpointer la int , atunci

pj=pi;copiază conţinutul lui pi în pj, adică pj va indica la

variabila adresa căreia este indicată în pi, astfel că pjse va modifica odată cu pi. Pointerii pot conţineadrese către elemente fără tip, cu void. Putem atribuiunui pointer void valoarea unui pointer non-void fărăa fi necesară o operaţie de conversie de tip typecast.

char *cp; // pointer către un caractervoid *vp; // pointer către void vp=cp; // legal - pointerul la caracter depus în

//pointerul către void cp=vp; // ILEGAL - lipseşte conversia de tipcp=(char*) vp; // legal - pointerul către void depus în

pointerul către caracter cu conversie de tip.Referinţa  prezintă o legătură cu o variabilă,

conţinînd o adresă. Spre deosebire de pointeri, în acăror declarare se utilizează simbolul “*”, pentru a

defini o referinţă, vom folosi simbolul “&”.12

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 11/166

int i; // declararea unui întregint *p=&i; // definirea unui pointer la iint &r=i; // definirea unei referinţe la i

Atît p, cît şi r acţionează asupra lui i. 

i=55; // acţiune asupra lui i*p=13; // acţiune asupra lui ir=20; // acţiune asupra lui i.

Există însă o diferenţă majoră între p şi r , nu numai înmodul de apelare, ci şi datorită faptului că p poate, laun moment dat, să fie în legătură cu o altă variabilă,a cărei locaţie de memorie o va conţine, diferită de

cea a lui i, în timp ce r  nu-şi poate schimba referinţa,acesta nefiind altceva decît o redenumire a variabilei i. Înceea ce priveşte utilizarea referinţelor, va trebui săţinem cont de următoarele restricţii:–  referinţele trebuie iniţializate chiar în momentul

declarării lor,–  odată fiind iniţializate, referinţelor nu li se pot

schimba locaţiile la care se referă,

–  nu sînt permise referinţe la referinţe şi pointericătre referinţe, dar putem avea o referinţă la unpointer.

Referinţele pot fi utilizate drept constante, potfi iniţializate cu constante, funcţii sau chiar structuri.

Tablourile, din rîndul cărora fac parte vectorii şimatricele, sînt tipuri de date foarte apropiate

pointerilor şi referinţelor. Vom vedea că oriceoperaţie, care poate fi rezolvată prin indexareatablourilor, poate fi rezolvată şi cu ajutorul pointerilor.Astfel, declaraţia

char linie[80];defineşte linie ca fiind un şir de 80 de caractere şi, înacelaşi timp, linie va constitui un pointer la caracter.Dacă pc este un pointer la un caracter, declarat prin

char *pc;13

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 12/166

atunci atribuirea pc=&1inie[0]; face ca pc să indice primulelement al tabloului linie (de indice zero). Aceastaînseamnă că pc conţine adresa lui linie[0]. Acumatribuirea

c=*pc;va copia conţinutul lui linie[0] în c. Dacă pc indică unelement al lui linie, atunci, prin definiţie, pc+1 indicăelementul următor şi, în general, pc-i indică cu ielemente înaintea elementului indicat de pc, iar  pc+i cu ielemente după acelaşi element. Dacă pc indicăelementul linie[0],  *(pc+1) indică conţinutul lui linie[1],pc+i este adresa lui linie[i], iar  *(pc+i)

este conţinutul luilinie[i]. Observăm că operatorul de indexare [], de formaE1[E2], este identic cu*((E1)+(E2)). Aceste remarci sîntadevărate indiferent de tipul variabilelor din tabloullinie. Definiţia adunării unităţii la un pointer şi, prinextensie, toată aritmetica pointerilor constă, de fapt,în calcularea dimensiunii memoriei ocupate deobiectul indicat. Astfel, în pc+i i este înmulţit cu

lungimea obiectelor pe care le indică pc, înainte de a fiadunat la pc.

Corespondenţa între indexare şi aritmeticapointerilor este foarte strînsă. Referinţa la un tabloueste convertită de către compilator într-un pointerspre începutul tabloului. Numele acestui tablou este oexpresie de tip pointer.

Evaluînd elementul linie[i], limbajul C++ îlconverteşte în *(linie+i), cele două forme fiind

echivalente. Aplicînd operatorul & ambilor termeni aiacestei echivalenţe, rezultă că linie[i] este identic culinie+i, unde linie+i fiind adresa elementului i din tabloul linie.Dacă pc este un pointer, el poate fi utilizat în expresii cu un indicepc[i] fiind identic cu *(pc+i).  Un pointer este o variabilă.Deci,

pc=linie; // şi14

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 13/166

pc++; sînt operaţii permise. Numele unui tablou este oconstantă şi nu o variabilă, construcţii de tipul linie++fiind interzise. Singurele operaţii permise a fi

efectuate asupra numelor tablourilor, în afara celorde indexare, sînt cele care pot acţiona asupraconstantelor

Aritmetica adreselor  pentru pointeri şi tablouriconstituie unul din punctele forte ale limbajului C++.Se garantează că nici un pointer care conţine adresaunei date nu va conţine valoarea zero, valoare

rezervată semnalelor de eveniment anormal. Aceastăvaloare este atribuită constantei simbolice NULLpentru a indica mai clar că aceasta este o valoarespecială pentru un pointer. În general, întregii nu potfi asignaţi pointerilor, zero fiind un caz special.

Există situaţii în care pointerii pot fi separaţi.Dacă p şi q indică elemente ale aceluiaşi tablou,operatorii  <, >, =, etc. lucrează conform regulilor 

cunoscute. p<q este adevărată, de exemplu, în cazul încare p indică un element anterior elementului pe careîl indică q. Relaţiile == şi != sînt şi ele permise. Oricepointer poate fi testat cu NULL, dar nu există nici oşansă în a compara pointeri situaţi în tablouri diferite.

Este valabilă şi operaţia de scădere apointerilor. Astfel, dacă p şi q indică elementele

aceluiaşi tablou, p-q este numărul de elemente dintrep şi q. O funcţie, deosebit de utilă în lucrul cu şiruride caractere, este strlen(), care returnează lungimeaşirului de caractere transmis ca parametru.

int strlen(char *s){ char *p=s;while (*p!='\0') p++;return p-s; }

Prin declarare p este iniţializat cu s şi indică primul15

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 14/166

caracter din s. În cadrul ciclului while este examinat conţinutulşirului de caractere, indirect, prin intermediulpointerului p, caracter după caracter, pînă cînd seîntîlneşte '\0' ', acesta din urmă semnificînd sfîrşitul

şirului. Dacă while ar testa doar dacă expresia estezero, este posibilă omiterea testului explicit, astfel decicluri fiind deseori scrise sub forma

while (*p) p++;Deoarece p indică şirul de caractere, p++ face ca p săavanseze de fiecare dată la caracterul următor, iar p-sdă numărul de caractere parcurse (lungimea şirului).

Aritmetica pointerilor este consistentă: dacă am filucrat cu float , care ocupă mai multă memorie decîtchar , şi dacă p ar fi fost un pointer la float , p++ ar fi avansatla următorul float . Toate manipulările de pointeri iauautomat în considerare lungimea obiectului referit.

Să implementăm, de exemplu, o funcţie decomparare a două şiruri de caractere. Funcţia strcmp(s,t) compară şirurile de caractere s şi t  şi returnează

valoare negativă, nulă sau pozitivă, în funcţie derelaţia dintre s şi t (care poate fi s<t, s=t sau s>t ). Valoareareturnată este obţinută prin scăderea caracterului depe prima poziţie, unde s diferă de t . Pentru claritateaproblemei, vom prezenta două variante, una utilizîndtablourile, iar cea de a doua utilizînd pointerii.

Varianta cu tablourile:

 strcmp(char s[], char t[]) { int i=0;while (s[i]==t[i])if (s[i++]=='\0') return 0;return s[i]-t[i];}

Varianta cu pointerii:strcmp(char *s, char *t){ for(;*s==*t;s++,t++)

if(*s=='\0') return(0);16

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 15/166

return (*s-*t);}Dacă  ++ şi  - - sînt folosiţi ca operatori prefixaţi, potapărea alte combinaţii de  *, ++ şi - -, deşi mai puţinfrecvente. De exemplu: *++p incrementează pe p înainte

de a aduce caracterul spre care indică p. *- - pdecrementează pe p în aceleaşi condiţii.

Alte operaţii, în afara celor menţionate deja(adunarea sau scăderea unui pointer cu întreg,scăderea sau compararea a doi pointeri), sînt ilegale.Nu este permisă adunarea, împărţirea, deplasarealogică sau adunarea unui float sau double la pointer.

Tablourile multidimensionale  pot fi  definite cu ajutorultablourilor de tablouri, de exemplu.:char ecran [25][80];

excepţie făcînd tablourile de referinţe, acestea dinurmă nefiind permise datorită faptului că nu sîntpermişi pointerii la referinţe.

Dacă E este un tablou n-dimensional de dimensiuni i, j, ...,k, atunci apariţiile lui E în expresii sînt convertite în pointer la

un tablou n-1-dimensional de dimensiuni j, ..., k . Dacă laacesta se aplică explicit sau implicit (prin indexare)operatorul *, rezultatul este tabloul n-1-dimensional indicatde pointer, care, la rîndul său, este convertit imediatîn pointer.

Tablourile sînt memorate pe linii şi, deci, ultimiiindici, de la stînga la dreapta, variază mai repededecît primii. Prima dimensiune a unui tablou sefoloseşte numai pentru a determina spaţiul ocupat deacesta, ea nefiind luată în consideraţie decît ladeterminarea unui element de indici daţi. Estepermisă omiterea primei dimensiuni a unui tablou,dacă tabloul este extern, alocarea făcîndu-se în cadrulaltui modul sau cînd se efectuează iniţializareatabloului în declaraţie, în acest caz fiind determinată

dimensiunea din numărul de elemente iniţializate.17

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 16/166

Iniţializarea tablourilor poate avea loc chiar încadrul declarării acestora

int point[2]={10,19};char mesaj1[6]={'S 1,'a','l','u','t','\0'};

char mesaj2[6]="Salut";Observăm că şirurile de caractere se comportăoarecum ciudat. Atît mesaj1, cît şi mesaj2 sînt şiruri de 6caractere avînd drept terminator de şir caracterul nul.Diferenţa între cele două şiruri nu se află înconţinutul lor, ci în cadrul iniţializării lor. În cazuliniţializării prin acolade, { }, caracterul nul nu estesubînţeles, prezenţa acestuia rămînînd la latitudineanoastră, în schimb, adoptînd o iniţializare pringhilimele, “ “, va trebui să dimensionămcorespunzător şirului de caractere, ţinînd cont deprezenţa terminatorului de şir. În exemplul mesaj2 avem5 litere plus caracterul nul, fiind necesare 6 locaţii în vedereamemorării cuvîntului “Salut”.

Dimensionarea tablourilor se realizează în

concordanţă cu necesităţile aplicaţiei. Existăposibilitatea iniţializărilor parţiale, care nu utilizeazăîntreg spaţiu rezervat. În cazul şirurilor de caractere,restul spaţiului rămas neutilizat va conţine numaicaracterul nul. În restul situaţiilor, conţinutul tablouluifiind aleator, se recomandă iniţializarea acestuia încadrul unui ciclu.

Tablouri de pointeri. Pointerii sînt ei înşişi variabile,de aceea ei sînt utilizaţi în tablouri de pointeri. Pentruexemplificare, vom considera un  program caresortează un set de linii de text în ordine alfabetică.Cu toate că algoritmul de sortare este unul comun,deosebirea dintre sortarea unui tablou de numere şi aunuia de şiruri de caractere constă în aceea că liniilede text de lungimi diferite nu pot fi comparate sau

deplasate printr-o singură operaţie. Avem nevoie de18

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 17/166

o reprezentare a datelor care să se poată faceeficient şi potrivit regulilor de gestionare a liniilor detext de lungimi diferite.

Introducem noţiunea de tablou de pointeri. Dacă

liniile de  sortare sînt memorate cap la cap într-un şir decaractere, atunci fiecare linie poate fi accesată printr-un pointer la primul său caracter. Pointerii înşişi pot fimemoraţi într-un  tablou. Două linii pot fi comparateprin transmiterea pointerilor respectivi lui  strcmp().Cînd două linii neordonate trebuie inversate, seinversează pointerii lor în tabelul de pointeri, nu

însăşi liniile. Acest mod de lucru elimină cuplul deprobleme legate de gestionarea memoriei şi poatedeplasa liniile.

Procesul de sortare constă din trei etape:- citirea tuturor liniilor la intrare,- sortarea liniilor,- tipărirea liniilor în ordine.

Împărţim programul în funcţii care efectuează aceste

trei etape. Funcţia de intrare trebuie să colecteze şisă salveze caracterele din fiecare linie şi săconstruiască un tablou de pointeri pe linii. Va trebuisă numere liniile la intrare. Această informaţie estenecesară pentru sortare şi tipărire. Deoarece funcţiade intrare poate opera doar cu un număr finit de linii,ea va returna o valoare, cum ar fi -1, în cazul în care se vor

prezenta mai multe linii. Funcţia de ieşire trebuiedoar să tipărească liniile în ordinea în care apar întabloul de pointeri.

#include <stdio.h>#include <string.h>#include <conio.h>#define LINII 100#define MAXLEN 1000

int citeste_linii(char *s[])19

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 18/166

{ printf("Introdu un text (maxlen=1000)\n");  printf("Pentru introducerea unei linii noi se

utilizează tasta ENTER.\n");printf("Sfîrşitul textului se va marca prin

'*'. \n\n");char c;int i=0, j=0;while((c=getchar())!='*'){ if (c=='\n')

{ s[i][j]='\0'; i++;j=0; }else s[i][j++]=c;}

return i+1; }void scrie_linii (char *linieptr[],int maxlinii){ for( int i=0; i<maxlinii;i++)

printf("%s\n", linieptr[i]); }void sortare_linii(char *v[],int n){ char *temp;for(int k=n/2;k>0;k/=2)

for(int i=k;i<n;i++)for(int j=i-k;j>=0;j-=k){ if (strcmp(v[j],v[j+k])<=0) break;

temp=v[j];v[j]=v[j+k];v[j+k]=temp; } }

void main(){ clrscr();

char *linieptr[LINII];int nlinii;if ((nlinii=citeste_linii(linieptr))>=0)

  { printf("\n Textul pînă la sortare:\n");scrie_linii(linieptr,nlinii);sortare_linii(linieptr,nlinii);printf("\n Textul după sortare \n");

scrie_linii(linieptr,nlinii);20

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 19/166

}else printf("Input prea mare pentru sortare \n"); }

Rezultatul îndeplinirii programului:Introdu un text (maxlen=1000)

Pentru introducerea unei linii noi se utilizeazătasta ENTER.Sfîrsitul textului se va marca prin '*'.ashdgasghddgjahsdgjaghdjhagsdhgdhjgdh*Textul pînă la sortare:

ashdgasghddgjahsdgjaghdjhagsdhgdhjgdh va marca prin'*'.Textul după sortare

ashdgasghddgjahsdgjaghdjhagsdhgdhjgdh va marca prin'*'.

Declararea variabilei linieptr:char *linieptr[LINII];

arată că linieptr  este un tablou de LINII  elemente, fiecareelement fiind un pointer la char.  linieptr[i] este un pointer lacaractere, iar  *linieptr[i] accesează un caracter. Dacă

linieptr  este el însuşi un tablou care este transmis luiscrie_linii(), el poate fi tratat ca un pointer, iar funcţiapoate fi scrisă.

void scrie_linii(char *linieptr[],int nlinii){ while (- - nlinii>=0)

printf("%s\n",*linieptr++); }*linieptr  adresează iniţial prima linie, iar, cu fiecareincrementare, el avansează linia următoare pînă cîndnlinii se epuizează.

Sortarea are loc în cadrul funcţiei  sortare_linii().Dacă orice element individual din v este un pointer lacaractere, temp va fi un astfel de pointer, încît cei doi potfi copiaţi unul în altul.

Fiind date declaraţiileint a[10][10]; int *b[10];

utilizările lui a şi b pot fi similare, în sensul că a[5][5] şi21

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 20/166

b[5][5] sînt referinţe legale ale aceluiaşi int . Toate cele100 celule de memorie ale tabloului a trebuie alocate, iargăsirea fiecărui element se face prin calculul obişnuital indicelui. Pentru tabloul b, prin declararea sa, se alocă

10 pointeri, fiecare dintre aceştia urmînd să indice untablou de întregi. Presupunînd că fiecare indică la 10elemente din tablou, vom obţine 100 celule de memorierezervate, plus cele 10 celule pentru pointeri. Astfel,tabloul de pointeri utilizează mai mult spaţiu şi poatecere un mod explicit de iniţializare. Dar există douăavantaje: accesarea unui element se face indirect

prin intermediul unui pointer, în loc să se facă prinînmulţire şi adunare (cum este în cazul tablouluimultidimensional), iar liniile tabloului pot fi de lungimidiferite. Aceasta înseamnă că nu orice element al luib este constrîns să indice la un vector de 10 elemente,unii pot indica la cîte 2 elemente, alţii la cîte 20 de elementesau chiar la nici unul.

Structura este o colecţie de elemente de tipuri

diferite şi care pot fi referiţi atît separat, cît şiîmpreună.  Definirea unei structuri se realizează cuajutorul cuvîntului-cheie  struct . Ea are următoareasintaxă:

struct [tip structur ă] { tip_1 element_1;………

tip_ n element_n 

} obiect_ de_ tip_ structură;unde tip structur ă descrie organizarea structurii,tip1,..., tipn indică tipul elementelor structurii,element1, ..., element  sunt numele elementelor structurii,obiect_ de_ tip_ structură este una sau o listă de

variabile pentru care se alocă memorie. De exemplu,struct punct { float x,y;} p;

S-a definit o structură p ca fiind de tip punct , punctul fiind

compus din două elemente x şi y reale. Asupra22

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 21/166

componentelor unei structuri putem acţiona prinintermediul operatorului de apartenenţă, “.”, deexemplu:

p.x=10; p.y=30;

Există posibilitatea efectuării operaţiilor cu întreagastructură, atribuirea fiind, de exemplu :

p={10,30);0 declaraţie de structură care nu este urmată de olistă de variabile nu produce alocarea memoriei, ci descrieorganizarea structurii., de exemplu:

typedef struct { char name[25]; int id, age;char prp; } student;

Definirea unei structuri permite determinarea unui nou tip de date.În continuare definind pointeri la această structură,tablouri, ale căror elemente sînt de tipul acesteistructuri, şi elemente de acest tip pot fi definite noistructuri de date mai compuse.

Un alt aspect al utilităţii structurilor îl constituietratarea tablourilor de structuri, de exemplu:

punct hexagon[6]; punct octogon[8];Accesul către membrii componenţi ai fiecăruielement al vectorului se realizează prin combinareaaccesului indexat, caracteristic tablourilor, cu celutilizat în cazul structurilor:

hexagon[i].x=10;În cazul definirii unui pointer la o structură, accesul lacomponentele acelei structuri se va efectua prinexpresii de forma

punct *pptr;pptr->x=10; // Echivalent cu p.x=10;(*pptr) .y=30; // Echivalent cu p.y=30;

Parantezele au rolul de a indica ordinea în careacţionează cei doi operatori “*” şi “.”, prioritar fiind “*”.

Unele elemente ale unei structuri pot fi  cîmpuri de biţi.

Un cîmp de biţi este o configuraţie de biţi adiacenţi, ce23

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 22/166

apar într-un element de tip  int . Cîmpurile sînt declarate detip  unsigned, iar numele cîmpului este urmat de douăpuncte “:” şi un număr ce reprezintă numărul de biţiocupaţi de cîmpul respectiv:

unsigned nume_cîmp:nr_biţi;Cîmpurile pot fi accesate ca orice alt element destructură. Orice cîmp trebuie să aibă toţi biţii îninteriorul unei zone de tip  int  (nu poate avea biţi îndouă cuvinte diferite). Ordinea de alocare a memorieipentru cîmpuri este dependentă de sistem. Unelesisteme fac alocarea de la stînga la dreapta, iar altele

invers. Nu se pot utiliza tablouri de cîmpuri. Cîmpurilenu au adresă şi nu li se poate aplica operatorul deadresare &.

Un caz special de structuri îl constituie  union.  Acesteasînt structuri alternative pentru care dimensiuneaspaţiului necesar memorării lor este egală cu cea maimare dimensiune necesară memorării uneicomponente a acelei structuri. De exemplu, variabila

este de tipulunion un_tip{ int uint; float ufloat; char uchar;punct upunct; // upunct este de tipul structurii punct } variabila;

Toate componentele uniunii ocupă aceeaşi zonă încadrul memoriei. Spre deosebire de structuri, înuniune este accesibilă o singură componentă a uneiuniuni. Uniunea se defineşte în aceeaşi manieră ca şistructurile, cuvîntul-cheie utilizat fiind union.

Operatorii 

Operatori şi expresii. Acţiunile desfăşurate încadrul oricărui program, în marea lor majoritate, seefectuează prin expresiile formate prin combinaţii dedate şi operatori. Limbajul C++ posedă toţi operatorii

limbajului C şi completează această listă cu operatori24

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 23/166

proprii. Din lista operatorilor disponibili ai limbajuluiC++ indicăm operatorii caracteristici lui new – pentrualocarea memoriei, delete – pentru eliberarea memoriei alocate cuoperatorul new, :: – operatorul de scop sau de rezoliţie. 

În funcţie de numărul de operanzi, operatorii sepot clasifica în trei categorii: operatori unari, binari şiternari.

Operatori unari . Formarea expresiilor în care intervinoperatorii unari se produce de la dreapta la stînga.

Operatorul de indirectare: * se poate aplica unei expresiide tip pointer  (*expresie) şi are drept rezultat o valoare(lvalue sau adresă) care se referă la obiectul indicat depointer.

Operatorul de adresare: & poate fi aplicat unei valori(&lvalue) şi are ca rezultat un pointer la obiectul definit delvalue şi are acelaşi tip ca şi tipul lvalue.

Operatorul unar minus: - se aplică unei expresii (-expresie) în vederea inversării semnului acesteia.

Operatorul negaţie logică: ! se poate aplica unei

expresii aritmetice sau unui pointer  (! expresie) şi are carezultat 1, dacă valoarea operandului este 0, şi 0, în cazcontrar, tipul rezultatului fiind int.

Operatorul negaţie pe biţi : ~ se aplică uneiexpresii de tip întreg (~expresie) şi transformă 0 în 1 şi 1în 0 în toţi biţii rezultaţi după conversiile uzuale.

Operatorul de incrementare: ++ incrementează cu 1valoarea operandului.

Operatorul de decrementare: - - decrementează cu 1valoarea operandului.

Operatorul ++, ca şi operatorul - -, poate fi utilizatatît ca prefix, cît şi ca sufix. În cazul utilizării lor caprefix, întîi se acţionează cu operatorul asupra valoriioperandului şi apoi se utilizează noua valoare aacestuia. În cazul utilizării lor ca sufix, întîi se

utilizează valoarea acestuia, apoi se acţionează cu25

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 24/166

26

operatorul asupra valorii operandului.Conversia unei expresii (typecast ): este de tipul (tip)

expresie sau (expresia) şi produce conversia valoriiexpresiei la tipul specificat.

Operatorul dimensiune: sizeof  este de tipul sizeof (expresie) sau sizeof (tip) şi ne indică dimensiunea înocteţi a operandului, determinată din declaraţiileelementelor ce apar în expresie.

Operatorul de alocare a memoriei:  new apare sub formapointer_la_nume = new nume [ iniţializator ]

şi încearcă să creeze un obiect nume prin alocarea unuinumăr egal cu sizeof(nume) de octeţi în memoria heap,adresa acestuia fiind returnată. În cazul în carealocarea nu este efectuată cu succes, se returneazăvaloarea NULL

Operatorul de eliberare a memoriei : delete are sintaxăde forma delete pointer_la_numeşi eliberează memoria alocată începînd de la adresaconţinută de pointer_la_nume.

Operatorul virgulă: , produce expresii de formaexpresie, expresie; 

El efectuează evaluarea expresiilor de la stînga ladreapta şi are ca rezultat şi tip valoarea şi tipulultimei expresii. Gruparea cu paranteze este permisăşi produce o singură valoare. De exemplu:

void main(){int s;for(int i=0,s=0;i<10,i++) s+=I;cout<< “Suma este de ”<<s<<endl;}

Operatori binari 

Operatorii aritmetici : +, -, *, / acţionează respectîndregulile binecunoscute de calculare a expresiilor.Trebuie făcută o observaţie asupra operatorului de

împărţire / . În cazul în care ambii operanzi sînt întregi, rezultatul26

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 25/166

este întreg (prin trunchierea rezultatului real).Operatorul modulo: % furnizează restul împărţirii

primului operand la cel de al doilea. De exemplu, unnumăr este par, dacă este divizibil cu 2. Deci

if (x%2==0) cout « "x este par";else cout « "x este impar";Operatorul de deplasare la stînga: « are ca rezultat

deplasarea către stînga a valorii operandului stîng cuun număr de biţi egal cu valoarea operandului drept,biţii eliberaţi astfel fiind completaţi cu valoarea 0.

Operatorul de deplasare la dreapta: » acţionează înmod similar cu precedentul, singurul element carediferă faţă de operatorul anterior fiind sensuldeplasării. De exemplu, funcţia definită mai jos Biti(x,4,3) returnează 3 biţi din poziţiile 4,3 şi 2, aliniaţi ladreapta.

Biti (unsigned x,unsigned p,unsigned n){return (x»(p+1-n))&~ (~0«n) ; }Operatorii de comparaţie: <, <=, >, >=, =

=(egal), !=(neegal) au ca rezultat o valoare de tip int care este 0 încazul în care condiţia nu este îndeplinită şi 1–  în cazcontrar. Pointerii pot fi comparaţi numai pe aceeaşistructură de date, iar ultimii doi operatori permitcompararea pointerului cu NULL, care corespunde adreseivide.

Operatorii logici binari pe biţi : & (şi), | (sau),^ (sau exclusiv) furnizează un rezultat de tip int  (0 pentruvaloarea false şi 1 pentru valoarea true). De exemplu, funcţianumăr_biti() controlează numărul de biţi pe 1 dintr-unargument întreg

număr_biti (unsigned n){ int b;for (b=0; n!=0; n»=1)if (n&O1) b++;

return b; /}27

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 26/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 27/166

nesemnificative fiind ignorate. Pe o linie de programputem scrie multe instrucţiuni. Instrucţiunile potapărea în diferite forme: de atribuiri, de declaraţii,instrucţiuni condiţionale, de ciclare, de salt,

instrucţiuni compuse.Instrucţiunea compusă (blocul de

instrucţiuni) grupează declaraţii şi instrucţiuni învederea utilizării unui bloc de instrucţiuni echivalentcu o instrucţiune compusă. Forma generală este:

{lista_declaraţii lista_instrucţiuni}Instrucţiunea condiţională if, if-else are una

din formele:if (expr) instrucţiune;if (expr) instrucţiune_l; else instrucţiune_ 2;

Instrucţiunea if evaluează expresia expr . În cazul în carese obţine o valoare nenulă, se trece la executareainstrucţiune_1, iar dacă această valoare este nulă şiexistă instrucţiune_2, se va executa instrucţiune_2. Încazul absenţei variantei else se va trece  la execuţia

instrucţiunii imediat următoare instrucţiunii if. Instrucţiunea de ciclu condiţionată anterior 

while estewhile (expr) instrucţiune;

Atît timp cît valoarea expresiei expr este nenulă, se executăinstrucţiune. De exemplu, 

i=0;while (i<n) a[i++]=0.0;

Evaluarea expresiei are loc înaintea execuţiei instrucţiunii,fapt pentru care această instrucţiune este din clasaciclurilor cu precondiţie. Din acest motiv este posibilca corpul ciclului să nu se execute nici măcar o dată,dacă condiţia ciclului este falsă. Execuţia programuluiva trece la instrucţiunea imediat următoareinstrucţiunii de ciclu.

Instrucţiunea de ciclu condiţionată29

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 28/166

posterior do-while are forma do instrucţiunewhile (expr );instrucţiune se va executa pînă ce valoarea expresieiexpr  devine falsă. Spre deosebire de instrucţiunea

while, în ciclul do-while evaluarea expresiei are loc după fiecareexecutare a corpului ciclului. Datorită acestui faptinstrucţiune se va executa cel puţin o singură dată, iarinstrucţiunea do se încadrează în categoria ciclurilorcu postcondiţie. De exemplu:

i=0;do

{ a[i++]=0.0; }while (i<n);Ciclul do-while este folosit mai puţin decît ciclul for . Cutoate acestea, prezenţa sa se impune î n cazurile în careeste necesar ă executarea corpului unui ciclu cel puţin odată, urmînd ca  ulterior să se execute în funcţie deîndeplinirea condiţiei finale, indicate în contextul  cicluluiwhile.

Instrucţiunea de ciclu aritmetic for  areurmătoarea formă generală for (expr_1;expr_2; expr_3) instrucţiune;şi este echivalentă cu următoarea succesiune deinstrucţiuni:

expr_1;while (expr_2)(  instrucţiune;

expr_3; )Oricare dintre cele trei expresii poate lipsi, absenţaexpresiei expr_2 fiind înlocuită, implicit, cu valoarea 1.De exemplu,

for (int i=0; i<=n; i++) a[i]=0.0;for ( int k=0, number_of_nums=0, number_of_chars=0;

k<strlen(text); k++)

{ cout « text[k] «‘\n’;30

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 29/166

if (is_num(text[k])) number_of_nums++;if (is_alpha(text[k])) number_of_chars++;}

Ciclul for este util de folosit atunci cînd există o simplă

iniţializare şi reiniţializare, deoarece se păstreazăinstrucţiunile de control al ciclului împreună.Instrucţiunea switch face parte din categoria

instrucţiunilor de selectare. Transferul controlului se vaefectua la una din variantele posibile, în funcţie devaloarea unei expresii de control. Sintaxa instrucţiuniieste switch (expr) instrucţiune;unde instrucţiune este o instrucţiune compusă, în carefiecare instrucţiune individuală trebuie etichetată cuo etichetă de forma

case expresie_constanta:unde expresie_constanta trebuie să fie de tip int şi nu pot fidouă etichete egale în aceeaşi instrucţiune switch. Celmult o instrucţiune poate fi etichetată cudefault:

La execuţia unei instrucţiuni switch se evalueazăexpresia expr  şi se compară valoarea obţinută cufiecare constantă ce apare în etichetele asociateinstrucţiunii. Dacă se găseşte o astfel de constantă,controlul este dat instrucţiunii ce urmează ei, în cazcontrar, controlul fiind transferat la instrucţiunea dedupă eticheta default , dacă aceasta există, sauinstrucţiunii imediat următoare instrucţiunii switch.

Pentru a se menţiona sfîrşitul unei instrucţiuniataşate unui caz, se va utiliza una dintreinstrucţiunile goto, break  sau return. La începutul uneiinstrucţiuni switch pot apărea declaraţii, dar nu se vorefectua iniţializări ale variabilelor de tip auto sauregister . De exemplu,

switch (text[k])

{ case ‘ A’ : număr_caractere++; break;31

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 30/166

case ‘ B’: număr_caractere++; break;… // se vor completa toate cazurile posibilecase 'Z' : număr_caractere++; break;case ' a’ : număr_caractere++; break;

… // se vor completa toate cazurile posibilecase ‘z’: număr_caractere++; break;case ‘0’: :număr cifre++;… // se vor completa toate cazurile posibilecase '9':număr cifre++; }

  Instrucţiunea break  are forma break;Are ca efect terminarea execuţiei unui ciclu de tip while,do-while, for  sau switch,

controlul fiind transferat primeiinstrucţiuni din corpul blocului cel mai interior.Instrucţiunea continue  are forma

continue;Are drept efect trecerea controlului următorului cicluîntr-o instrucţiune de tip while sau for  în care apare şinu are nici un efect dacă nu apare în corpul unorastfel de instrucţiuni. Cînd este întîlnită, ea se trece la

următoarea iteraţie a ciclului (while, for, do-while). În cazullui while şi do-while, aceasta înseamnă că partea decontrol se execută imediat. În cazul ciclului for ,controlul va trece la faza de reiniţializare. De obicei,instrucţiunea continue nu se va aplica instrucţiuniiswitch. Ca exemplu, fragmentul următor sumeazănumai elementele pozitive dintr-un tablou a, în care valorilenegative sînt omise.

int s;for (int i=0,s=0; i<N; i++){ if (a[i]<0) continue; //sare indicii elementelor negatives+=a[I]; }Instrucţiunea return  admite următoarele

două formereturn; sau return (expr);

cea din urmă fiind echivalentă cu următoarea32

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 31/166

32

  return expr;Efectul instrucţiunii return este trecerea controlului lafuncţia care a apelat funcţia respectivă fărătransmiterea unei valori în prima variantă sau cu

transmiterea unei valori în ultimele -două variante.Instrucţiunea goto şi etichete. Limbajul C+

+ oferă instrucţiunea goto pentru ramificare. Formal,instrucţiunea goto nu este necesară şi uşor se poatescrie programe fără ea. Cu toate acestea, existăcîteva situaţii î n care goto îşi poate găsi locul. Cea maiobişnuită folosire este aceea de a abandona

prelucrarea în anumite structuri puternic imbricate,de exemplu, de a ieşi afară din două cicluri deodată,instrucţiunea break  nu poate fi folosită, deoarece eapărăseşte numai ciclul cel mai din interior. Astfel:

for(...)for(...)( ...if(dezastru) goto error;}

…error:;O posibilitate de căutare a primului element negativîntr-un tablou bidimensional ar fi:

for (i=0; i<N; i++)for(j=0; j<M; j++)if (v[i][j]<0) goto found;found: // s-a găsit în poziţia i, j 

Programul cu un goto poate fi scris întotdeauna fără goto,chiar dacă preţul pentru aceasta este o variabilăsuplimentară sau nişte controluri repetate. Deexemplu, căutarea în tablou devine:

found=0;for (i=0; i<N && found; i++)

for (j=0; j<M && found; j++) found = v[i][j]<0;if (found) { …….. } // a fost găsit la i-1, j-1 

else {…………..} // nu s-a găsit33

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 32/166

Instrucţiunea vidă are forma “;” şi esteutilizată pentru a evita existenţa unei etichete chiarîn faţa unei acolade de închidere a unui bloc sau încazul în care corpul unui ciclu nu conţine nici o

instrucţiune.

Tipuri de date recursive, operaţii asupralistelor, arborilor.

Listele simplu şi dublu lănţuite, arborii sînt formatedin elemente definite de structuri cu autoreferire. Elesînt consecutivităţi de elemente de acelaşi tip,

numărul cărora se schimbă dinamic în procesul deexecutare a programului. Lista liniară F , care constădin elemente D1, D2,...,Dn, grafic se poate reprezenta înmodul următor:

  D1 D2 D3 ... DnAsupra elementelor listelor se pot efectuaurmătoarele operaţii:

- de căutare a elementului după criteriul dat;

- de determinare a primului element în listaliniară;

- insertarea unui element nou înainte sau dupăo componentă indicată a listei liniare;

- eliminarea unui element din listă;- sortarea componentelor listei.

Metodele de stocare a listelor liniare se divid în metodeconsecutive şi stocare lănţuită. 

Elementele listei liniare, utilizate de metodeleconsecutive, se alocă într-un tablou d  de dimensiunefixă, de exemplu, 100, şi lungimea listei este indicatăde variabila l , adică se declară

float d[100]; int l;Dimensiunea 100 mărgineşte dimensiunea maximală alistei liniare. Lista F  în tabloul d   se formează în modul

următor:34

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 33/166

d[0]=7; d[1]=10; l=2;Lista obţinută se păstrează în memorie în

conformitate cu schema: 

Pentru organizarea elementelor în formă de listăsimplu lănţuită, se utilizează structurile care sîntlegate cîte o componentă în lanţ, începutul căreia(prima structură) este indicat de pointerul dl . Structura caredefineşte elementul listei conţine în afară decomponenta informaţională şi un pointer laurmătorul element din listă. Descrierea acestui tip destructură cu autoreferire şi pointerul în cauză se faceîn modul următor:

typedef struct nod  // structura cu autoreferire{float val; // valoarea componentei

informaţionalestruct nod *urm ; // pointerul la următorul elementdin lanţ 

} DL;DL *p; // pointerul la elementul curent DL *prim; // pointerul la începutul listei

Pentru alocarea memoriei elementelor listei în C++, seutilizează operatorul de alocare: new care apare sub forma

pointer_la_nume = new nume [ iniţializator ];care încearcă să creeze un obiect  nume prin alocareaunui număr egal cu  sizeof(nume) de octeţi în memoriaheap, adresa acestuia este returnată şi asignatăvariabilei pointer_la_nume.  În cazul în care alocarea nueste efectuată cu succes, se returnează valoareaNULL.

Operatorul de eliberare  delete este apelat printr-o

l: 2d :

7 10 ...

[0] [1] [2] [3] [98] [99]

35

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 34/166

instrucţiune de formadelete pointer_la_nume ;

eliberează memoria alocată începînd cu adresaconţinută de pointer_la_nume. De exemplu,

p=new(DL);p->val=10;p->n=NULL;dl=new(DL));dl->val=7;dl->n=p;

În ultimul element al listei pointerul la elementul vecin arevaloarea NULL. Lista are următoarea formă: 

Operaţii asupra listelor simplu lănţuiteFiecare element al listei simplu lănţuite reprezintă o

structură alcătuită din două componente: val  – folositpentru componenta informaţională şi p pentru pointer laurmătorul element din lista lănţuită. Pointerul dl indică adresa de alocare pentru primul element allistei. Pentru toate operaţiile asupra listei se va utilizaurmătoarea descriere a structurii elementelor liste: 

typedef struct nod { float val;struct nod * urm;

} NOD;int i,j;NOD * prim, * r, * p;

Pentru executarea operaţiilor pot fi utilizateurmătoarele fragmente de program:1) formarea listei simplu lănţuite:

float x=5; int n=1;36

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 35/166

p=new(nod);r=p;p->val=x;p->urm=NULL;

prim=p;while (p->val !=0){ p=new(nod); n++;p->val=x-1.0*n;r->urm=p;p->urm=NULL;r=p; }

2) tiparul elementului j: r=prim;j=2;while(r!=NULL && j<n-1){ if (r==NULL) printf("\n nu este elementul %d ",j);else printf("\n elementul %d este egal cu %f ",j++,r->val);r=r->urm; }

3) tiparul ambilor vecini ai elementului determinat de pointerul p :

p=prim;if((r=p->urm)==NULL) printf("\n nu are vecin dindreapta");else printf("\n vecinul din dreapta este %f", r->val);if(prim==p) printf("\n nu are vecin din stînga" );else { r=prim;

while( r->urm!=p ) r=r->urm;printf("\n vecinul de stînga este %f", r->val); }4) eliminarea elementului care este succesorulelementului în cauză, la care indică pointerul р 

p=prim;37

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 36/166

if ((r=p->urm)==NULL) printf("\n nu este succesorul ");p->urm=r->urm; delete(r->urm);

5) insertarea noului element cu valoarea newval=100 dupăelementul determinat de pointerul p:

r=new(NOD);r->urm=p->urm; r->val=100; p->urm=r;

Organizarea listelor dublu lănţuiteLista dublu lănţuită este o listă în care fiecare

element conţine doi pointeri: unul la precedentulelement, altul – la succesorul element din listă. Listadublu lănţuită în program se poate determina cuajutorul următoarelor descrieri:

typedef struct ndd { float val; //  valoarea informaţională a

componentei struct ndd * succesor; //  pointer la succesorul element

al //listei nstruct ndd *precedent; // pointer la precedentul element al

//listei m} NDD;

NDD * prim, * p, * r;Interpretarea grafică a listei F=< 2,5,7,1 > ca listădublu lănţuită este următoarea:

Insertarea noului element cu valoarea newval  după elementuldeterminat de pointerul p, se efectuează deoperatorii

r=new(NDD);

r->val=newval;38

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 37/166

r->succesor=p->succesor;(p->succesor)->precedent=r;p->=r;

Eliminarea elementului urmat de elementul la care

indică pointerul p se efectuează în modul următor:p->succesor=r;p->succesor=(p->succesor)->succesor;( (p->succesor)->succesor )->precedent=p;delete r;

Lista liniară este ciclică, dacă ultimul element al listeiindică la primul element, iar pointerul  dl  indică laultimul element al listei. Schema listei ciclice pentrulista F=< 2,5,7,1 > este următoarea:

La rezolvarea problemelor pot apărea diferite tipuride liste lănţuite.Stivă şi coadă

În funcţie de metoda de acces la elementelelistei liniare, pot fi cercetate următoarele tipuri deliste liniare: stive, cozi şi cozi de tip vagon.

Stiva  este o consecutivitate de elemente deacelaşi tip – variabile scalare, tablouri, structuri sauuniuni. Stiva reprezintă o structură dinamică,numărul de elemente a căreia variază. Dacă stiva n-are elemente, ea este vidă. 

Asupra elementelor stivei pot fi efectuateurmătoarele operaţii:- verificarea dacă stiva este vidă,- includerea unui element nou în vîrful stivei;- eliminarea elementului din vîrful stivei;- accesarea elementului din vîrful stivei, dacă

stiva nu este vidă.Astfel, operaţia de includere şi eliminare a

39

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 38/166

elementului, de asemenea, accesarea elementuluiare loc numai asupra elementului din vîrful stivei.

Coada este o listă liniară în care elementelelistei se elimină din capul listei şi elementele noi se includ

prin coada listei.Coadă de tip vagon este o listă liniară în care

includerea şi eliminarea elementelor din listă seefectuează din ambele capete (vîrful şi sfîrşitul) alelistei.

Stiva şi coada se organizează atît static prinintermediul tabloului, cît şi dinamic – prin listă

(simplu sau dublu lănţuită).Vom cerceta cum se utilizează lista în formă destivă pentru implementarea calculării expresieiaritmetice în formă inversă poloneză. În astfel demod de prezentare a expresiei operaţiile seînregistrează în ordinea executării lor, iar operanzii seaflă nemijlocit în faţa operaţiei. De exemplu, expresia(6+8)*5-6/2 în forma inversă poloneză are forma: 6 8 +

5 * 6 2 / -Utilizînd noţiunea de stivă, expresia aritmetică

în formă inversă poloneză se execută print-o singurătrecere de examinare a expresiei. Fiecare număr seintroduce în stivă, iar operaţia se execută asupraurmătoarelor două elemente din vîrful stivei,înlocuindu-le cu rezultatul operaţiei efectuate.Dinamica schimbărilor din stivă va fi următoarea:

S = < >; <6>; <6,8>; <14>; <14,5>; <70>;<70,6>; <70,6,2>; <70,3>; <67>.

Mai jos este descrisă funcţia  eval,  care calculeazăvaloarea expresiei indicate în tabloul  m  în formă deexpresie inversă poloneză, m[i]>0  indică numărulnenegativ, iar valoarea m[i]<0 - operaţia. În calitate decoduri pentru operaţiile de adunare, scădere,

înmulţire şi împărţire se aleg numerele: -1, -2, -3, -4.40

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 39/166

Pentru organizarea stivei se utilizează tabloul interior stack . Parametrii funcţiei sînt tabloul de intrare m şilungimea sa l .

float eval (float *m, int l)

{ int p,n;float stack[50],c;for(int i=0; i < l ;i++)if ((n=m[i])<0){ c=st[p--];

switch(n){ case -1: stack[p]+=c; break;

case -2: stack[p]-=c; break;case -3: stack[p]*=c; break;case -4: stack[p]/=c; } }

else stack[++p]=n;return(stack[p]); }

Arbori 

Arborii sînt structuri de date dinamice, cuautoreferire. Prin arbore se înţelege o mulţime finită

şi nevidă de elemente (noduri): A={A1, A2,..., An}, n>0cu următoarele proprietăţi:–  există un nod şi numai unul care se

numeşte rădăcina arborelui,– celelalte noduri formează submulţimi ale lui

A, care formează fiecare cîte un arbore,arborii respectivi se numesc subarbori airădăcinii.

Într-un arbore există noduri cărora nu lecorespund subarbori. Astfel de noduri se numescterminale.

În multe aplicaţii se utilizează noţiunea dearbori binari. Dacă mulţimea de elemente a arboreluibinar este vidă, se consideră că arborele constănumai din rădăcină. Dacă mulţimea de elemente este

nevidă, arborele binar se divide în două submulţimi:41

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 40/166

subarborele drept  şi cel de stînga. Arborele binar esteordonat, deoarece în fiecare nod subarborele stîng seconsideră că precede subarborele drept. Un nod alunui arbore binar poate să aibă numai un

descendent: subarborele drept sau subarborele stîng.De exemplu, un nod al unui arbore binar poate fi ostructură care poate fi definită în felul următor:

typedef struct tnod { int nr, int f; // declaraţiistruct tnod *st; //  este pointerul spre subarborele stîng

al //nodului curentstruct tnod *dr; //  este pointerul spre subarborele drept

al //nodului curent} TNOD;Asupra arborilor binari pot fi definite

următoarele operaţii:– afişarea componentelor informaţionale ale nodului,– specificarea criteriului de determinare a poziţiei încare să se inserteze în arbore nodul curent;

– determinarea echivalenţei a doi arbori;– insertarea unui nod terminal într-un arbore binar;– accesarea unui nod al arborelui,– parcurgerea unui arbore;–  ştergerea unui arbore.

Afişarea componentelor informaţionale alenodului se poate de efectuat prin funcţia:

void prelucrare (TNOD *p){printf(“numărul = %d apariţii= %d \n”, p->nr,p->f);}Criteriul de determinare a poziţiei, în care să se

inserteze în arbore nodul curent, se defineşte defuncţia:

int criteriu(TNOD *p, *q){ if (q->nr < p -> nr )

return –1; // insertarea nodului curent42

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 41/166

  //în subarborele stîng al nodului sprecare indică

//pointerul pif (q->nr > p-> nr )

return 1; // insertarea nodului curent//în subarborele drept al nodului spre

care indică //pointerul p}Insertarea unui nod terminal într-un arbore

binar poate fi efectuată prin următoarea funcţie:TNOD* insert_nod(){ TNOD *parb, *p, *q;

int n=sizeof(TNOD);if (parb ==0){ parb=p; return p; }

int i;q=parb;for(;;)if ((i=criteriu(q,p)) <0) {q->st=p; return p; }

else { q=q->st; continue; }if (i>0)if (q->dr ==0)

{q->dr=p; return p;}else {q=q->dr; continue; }

return eq(q,p); }}if(p==0)

{ printf(“eroare: memorie insuficientă\n”);exit(1);}elibnod(p); return 0; }Accesarea unui nod al unui arbore poate fi realizată prin

următoarea funcţie:TNOD * cauta (TNOD *p){TNOD *parb, *q;

if (parb==0) return 0;43

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 42/166

int i;for (q=parb;q;)

if ((i=criteriu(q,parb))==0) return q;else if(I<0) q=q->st;

else q=q->dr;return 0; }Parcurgerea unui arbore poate fi efectuată în

trei modalităţi: în preordine; în inordine; în postordine.Parcurgerea în preordine presupune accesul la

rădăcină şi apoi parcurgerea celor doi subarbori aisăi: mai întîi subarborele stîng, apoi cel drept.

void preord (TNOD *p){ if (p!=0){ prelucrare(p); preord(p->st); preord(p->dr); }}Parcurgerea în inordine presupune parcurgerea mai întîi a

subarborelui stîng, apoi accesul la rădăcină şi încontinuare se parcurge subarborele drept.

void inord (TNOD *p)

{ if (p!=0){inord(p->st); prelucrare(p); inord(p->dr);}}Parcurgerea în postordine presupune parcurgerea mai

întîi a subarborelui stîng, apoi a arborelui drept şi, înfinal, accesul la rădăcina arborelui.

void postord (TNOD *p){ if (p!=0)

{ postord(p->st); postord(p->dr); prelucrare(p); }}Ştergerea unui arbore poate fi efectuată de

următoarea funcţie:void elib_nod(TNOD *p){ delete(p); }void sterge_arbore (TNOD *p)

{ if (p!=0)44

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 43/166

{ postord(p->st); postord(p->dr); elibnod(p); }}Recursivitatea ca metodă de programareRecursivitatea presupune o repetare. Ea constă

în apelarea unei funcţii de către ea însăşi.Funcţia se numeşte recursivă dacă în momentul

executării sale funcţia se apelează pe ea însăşi, sauindirect, printr-o succesivitate de apeluri ale altorfuncţii.

Funcţie este nemijlocit recursivă dacă ea seapelează din corpul aceleiaşi funcţii. De exemplu:

int a(){.....a().....}Funcţia este indirect recursivă dacă se

efectuează apel recursiv prin intermediul uneisuccesivităţi de apeluri ale altor funcţii. Toatefuncţiile componente ale acestei succesivităţi deapeluri se socot recursive. De exemplu, 

a(){.....b().....}

b(){.....c().....}c(){.....a().....} .Funcţiile a,b,c sînt recursive, deoarece la apelul

unei din funcţii are loc apelul altor funcţii inclusiv şipe ea însăşi.

Execuţia algoritmului recursiv presupunecrearea unui număr (finit) de copii ale algoritmului,care corespund diferitelor valori ale unei variabile. Înconstruirea algoritmului recursiv este inclusă ocondiţie de terminare a apelării recursive de oexpresie; care prin apelări succesive valoarea eicreşte pînă la o valoare ce satisface condiţia definalizare a recursivităţii. La executarea programuluicu funcţii recursive se creează copii ale acestora,fiecare din ele corespunzînd unei valori a expresiei de

recursie. Atît timp cît expresia recursiei se calculează45

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 44/166

pînă cînd creşte pînă la o valoare ce satisfacecondiţia de finalizare a recursivităţii, se spune că areloc recursia înainte. Cînd expresia atinge valoareasoluţiei recursiei, se execută copiile create, astfel

încît se obţine soluţia problemei. În acest caz are locrecursia înapoi. Executarea programelor cu funcţiirecursive necesită multă memorie şi mult timp decalcul, cu o complexitate mai mare decît cele nerecursive.

Recursivitatea ca metodă de programare estemai eficientă, codul programelor cu funcţii recursiveeste mai compact şi mai uşor de înţeles.

În limbajul C++ funcţiile pot să se autoapeleze.Exemplul clasic de funcţie recursivă este calculareafactorialului numărului N! = 1*2*3*...*N.

Vom numi această funcţie factorial().long factorial(int n) {return((n==1)?1: n*factorial(n-1) ); }

Apelul funcţiei recursive creează noi copii alevariabilelor locale şi ale parametrilor pentru clasa dememorie auto  şi register , valorile lor din apelurile

precedente se păstrează. Pentru fiecare moment sîntaccesibile numai valorile apelului curent. Variabileledeclarate cu clasa de memorie static nu necesităcrearea noilor copii. Valorile lor sînt accesibile în oricemoment de executare a programului. În corpul funcţieirecursive este necesar de indicat condiţia de ieşiredin procesul recursiv, în caz contrar sistemul de

calcul poate intra în impas. De exemplu, funcţia detipărire unui număr (ca un şir de caractere): poate fiapelată de ea însăşi, adică să fie recursivă

void print_cifre(int n){ int i;if (n<0){ putchar(‘-’); n=-n; }if ((i=n/10)!=0) print_cifre(i);

putchar(n%10+’0’); }46

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 45/166

Programul de mai jos calculează funcţiaAkkerman cu utilizarea funcţiei recursive ackr   şifuncţiei auxiliare smacc:

// calculul recursiv al funcţiei Аkkerman

# include <stdio.h>int smacc( int n,int x ) //  funcţie auxiliară 

int ackr( int n, int x, int y) // funcţie  recursivă void main () //  funcţia în care se apelează

funcţia{ int x,y,n,t;

int ackr(int, int, int);scanf("%d %d %d",&n,&x,&y);t=ackr(n,x,y);printf("%d",t); }

int smacc( int n,int x ) //  funcţie auxiliară 

{ switch (n ){ case 0: return(x+1);

case 1: return (x);case 2: return (0);

case 3: return (1);default: return (2); }}

int ackr( int n, int x, int y) // funcţie  recursivă { int z;

int smacc( int,int);if(n==0 || y==0) z=smacc(n,x);else { z=ackr(n,x,y-1); // apeluri  recursive ackr(...)

z=ackr(n-1,z,x); }return z; }

Rezultatul îndeplinirii programului:1 4 6  // datele iniţiale

-10 // rezultatul obţinut

Fişierele input/output ale limbajul C++.

47

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 46/166

Deschiderea şi închiderea fişierelor. Citirea şi scrierea în fişiere.

Limbajul C++ include în sine funcţiile standardinput/output ale limbajului C de prelucrare a fişierelor

la nivelul jos, inferior şi superior.Funcţiile de prelucrare a fişierelor de nivel

inferior pot fi utilizate prin includerea fişierelor io.h,fcntl.h şi stat.h.

Pentru deschiderea unui fişier se utilizeazăfuncţia open care are următoarea formă sintactică:

df = open(…);

unde df este variabilă de tip int (descriptorul de fişier).Funcţia open are următorii parametri: se indicăcalea de acces la fişier şi modalitatea de accesare acomponentelor fişierului. Modalitatea de accesare acomponentelor se indică prin una din următoareleconstante:

O_RDONLY fişierul se deschide numai pentrucitirea componentelor lui

O_WRONLY fişierul se deschide numai pentruînregistrarea componentelor lui

O_RDWR  fişierul se deschide pentrucitirea şi înregistrareacomponentelor lui

O_APPEND fişierul se deschide pentruadăugarea componentelor noi la

sfîrşitul luiO_BINARY fişierul se prelucrează binarO_TEXT fişierul se prelucrează textual

Pentru a crea un fişier, se utilizează funcţia creat  cuurmătorii parametri: calea de acces la fişierul creat şimodalitatea de utilizare a fişierului. Al doilea parametru seindică de una din următoarele constante:

S_IREAD fişierul va fi creat numai pentru

citire48

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 47/166

S_IWRITE fişierul va fi creat numai pentruînregistrare

S_IEXE fişierul va fi creat numai pentru executareCitirea dintr-un fişier se efectuează prin funcţia

read indicîndu-se următorii parametri:read(df, buf, lung)

unde df  este descriptor de fişier; buf  – pointer sprezona de memorie în care se va păstra înregistrareacitită din fişier; lung – lungimea în octeţi a înregistrăriicitite.

Înregistrarea în fişier se efectuează prin funcţia

write. Această funcţie are aceiaşi parametri ca şifuncţia read .Poziţionarea într-un fişier se efectuează prin

funcţia fseek(df, deplasare, origine). Această funcţie areurmătorii parametri: df  – descriptorul fişierului,deplasarea indică numărul de octeţi pentru a deplasacapul de citire sau scriere al discului, origine areurmătoarele valori pentru efectuarea deplasării: 0 –

faţă de începutul fişierului, 1- faţă de poziţia curentăa capului de citire sau înregistrare, 2 – faţă de sfîrşitulfişierului.

Închiderea fişierului se efectuează de funcţiaclose (df).

Exemplu de utilizare ale acestor funcţii:char nfis[]=”fisier1.dat”;int df; char *p;df=open(nfis,O_RDONLY);read(df,p,80);close(df);Prototipurile funcţiilor de prelucrare a fişierelor

de nivel superior pot fi utilizate prin includereafişierului stdio.h.

Fişierele input/output standard se efectuează

prin intermediul funcţiilor scanf şi printf, gets, getc, getch şi49

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 48/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 49/166

\n avans la început de linie nouă;\r  poziţionare la începutul liniei curente;\t  tabulator;\a emite un semnal sonor .

Fiecare semn % este interpretat ca începutul descrieriicaracteristicilor de tipărire a unei valori. Cele mauutilizate semne sînt următoarele:Semnul Descrierea%d,% i

un întreg zecimal este aşteptat la intrare;argumentul corespunzător trebuie să fie unpointer la întreg;

%o un întreg octal este aşteptat la intrare;argumentul corespunzător trebuie să fie unpointer la întreg;

%x un întreg hexazecimal este aşteptat laintrare;argumentul corespunzător trebuiesă fie un pointer la întreg;

%h un întreg short este aşteptat la intrare;argumentul trebuie să fie un pointer la un

întreg short;%u un întreg fără semn zecimal este aşteptat

la intrare; argumentul să fie pointer laîntreg;

%f  un număr în virgulă flotantă este aşteptat;argumentul corespunzător trebuie să fie unpointer la un cîmp float. Caracterul de conversie e este*f. Formatul prezentat la intrare pentru unfloat este alcătuit dintr-un semn opţional;

%e un număr în virgulă flotantă este aşteptat;argumentul corespunzător trebuie să fie unpointer la un cîmp double. Caracterul de conversiee este *e. Formatul prezentat la intrarepentru un double este alcătuit dintr-unsemn opţional, un şir de numere care pot

să conţină şi un punct zecimal şi un cîmp51

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 50/166

de exponent care este format din E  sau e,urmat de un întreg cu semn;

%c un singur caracter este aşteptat la intrare;argumentul corespunzător trebuie să fie un

pointer la caracter. În acest caz, ignorareacaracterelor albe este suprimată; pentru aciti următorul caracter, altul decîtcaracterele albe se va utiliza %1s;

%s un şir de caractere este aşteptat;argumentul corespunzător trebuie să fie unpointer al unui tablou de caractere, destul

de mare pentru a încăpea şirul şi unterminator ‘\0’, care va fi adăugat.Caracterele de conversie d, u, i ,o, şi x pot fi precedate de

litera l , pentru a indica un pointer la long , mai degrabă decîtla int , care apare în lista de argumente. Similar, litera l înaintea luie sau f  indică un pointer la double în lista deargumente. De exemplu:

int i;

float x;char nume[50];scanf (“%d%f%s”,&i,&x,nume) ;

cu linia de intrare25 244.32E-1 Mircea

va asigna lui i valoarea 25, lui x valoarea 244.32E-1, iar lui numevaloarea “Mircea”. Cele trei cîmpuri de la intrare potfi separate de oricîte spaţii, taburi şi caractere delinie nouă. Apelarea

int i;float x;char nume[50];scanf (“%2d%4.2f%2s”,&i,&x,nume) ;

cu linia de intrare25 244.32E-1 Mircea

va asigna 25 lui i, 44.32 lui x, iar nume va obţine52

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 51/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 52/166

un comentariu legat de valoarea care urmează să fieintrodusă. De exemplu, în programul de mai jos amafişat mesajul “număr real”, după care urmeazăapelul funcţiei scanf  care aşteaptă introducerea unei

valori de tip real sau întreg:#include<stdio.h>void main(){ float a;int i;

printf ("Introdu un număr real: ");//utilizatorul vaintroduce, //lascanf("%f", &a); // tastatura, un număr urmatde Enter.printf("\n Introdu un număr intreg: "); // la fel seprocedează //în cazul variabilei iscanf ("%i,", &i); //  afişarea textului "număr intreg"printf("\n Număr întreg: %6i \n Număr real:%9.3f", i, a);

} // va fi urmată de introducerea, la tastatură, anumărului //dorit.Rezultatul îndeplinirii programului:Introdu un număr real: 3.14Introdu un număr intreg: 20Număr întreg: 20Număr real: 3.140Funcţiile de scriere şi citire anterioare pot fi

folosite şi în cazul fişierelor. Biblioteca stdio.h, specificălimbajului C, conţine definiţia unui tip de date FILE .Accesul la un fişier se face printr-un pointer de tipFILE . Etapele care trebuie să fie parcurse sîntdefinirea unui pointer de tip FILE  şi asocierea unuifişier fizic. Pointerul va primi drept valoare adresaunei variabile de tip FILE , obţinută prin intermediul

funcţiei fopen(). Această funcţie are două argumente:54

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 53/166

un şir de caractere care conţine numele fişierului fizicrecunoscut de sistemul de operare şi un alt şir decaractere care conţine indicaţii relativ la modul deutilizare al fişierului. Ultimul parametru poate conţine

caracterulR pentru fişiere deschise pentru citire,W  pentru fişiere deschise pentru creare sau

scriere,T  pentru fişiere de tip text sauB pentru fişiere binare

În exemplul de mai jos am creat un fişier prin

intermediul unui pointer de tipul FILE  şi o iniţializareprin funcţia fopen(). Pointerul p conţine o valoare de tipFILE fumizată de funcţia fopen(), care deschide pentruînregistrare fişierul disk.dat . Am scris în acest fişier douăvalori în acelaşi mod cum am făcut afişarea la ieşireastandard.

#include<stdio .h>void main()

{ FILE *p;p = fopen("disk.dat","wt");fprintf(p,"%6i\n%9.3f", 29, 2.71);fclose (p) ;

}Rezultatul îndeplinirii programului:

s-a format fişierul “disc.dat” (pentru înregistrare) cuurmătorul conţinut:

292.710

Întrebările pentru verificarea cunoştinţelor:1. Enumeraţi tipurile de date fundamentale înlimbajul C++?2. Pentru ce se utilizează variabilele în limbajul C++?

3. Prin ce se deosebesc variabilele descrise ca extern de cele55

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 54/166

descrise ca static?4. Prin ce se deosebeşte o referinţă de un pointer?5. De ce nu este permisă definirea unui vector dereferinţe?

6. Prin ce se deosebeşte noţiunile union şi struct?7. Care sînt operaţiile aritmetice admise asuprapointerilor?8. Definiţi un tablou tridimensional, elementele

cărora sînt de tip point .9. Daţi exemple de utilizare a operatorilor unari,binari şi ternari.

10. Prin ce se deosebeşte operatorii de incrementareşi decrementare prefixate de cele sufixate?Exemple de expresii.

11. Explicaţi acţiunea instrucţiunilor de ciclu.Exemple de utilizare.12. De ce fiecare variantă a instrucţiunii switch se

poate termina cu instrucţiunea break ? Exemple deutilizare a instrucţiunii switch cu şi fără

instrucţiunea break .13. Corectaţi programul de mai jos care efectuează

sortarea parţială a listei simplu lănţuite, dupăsortare pointerul v indică la elementul k1. 

NOD *v;float k1;k1=prim->val;r=prim;while( r->urm!=NULL ){ v=r->urm;

if (v->val; v=v->urm;v->n=prim;

prim=v; }56

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 55/166

else r=v; }14. Alcătuiţi un program care organizează o listă

ciclică Fi (1<I) dintr-o consecutivitate de numere întregiB1, B2,..., Bn din intervalul de la 1 pînă la 9999,

sortate crescător.Indicaţie: La rezolvarea acestei probleme avem o listă

sortată crescător Fi. La introducerea unui nou elementBi+1, acest element se insertează la locul său înlista Fi. Pentru insertarea elementului nou în lista Fi, să secerceteze trei cazuri:

- lista Fi este vidă,

- elementul se insertează la începutul listei,- elementul se insertează la sfîrşitul listei.15. Cercetaţi programul de mai jos

typedef struct str1{ float val;struct str1 *n;} NOD;

void main()

{ NOD *arrange(void); NOD *p;p=arrange();while(p!=NULL){ cout<< p->val<<endl;p=p->n; }

}NOD *arrange() //  formarea listei sortate { NOD *dl, *r, *p, *v; // dl - începutul listei, p,v – pointeri

la //două elemente vecine,float in=1; // r  – fixează pointerul la

elementul curent //careconţine valoarea în

char *is;dl=new(NOD);dl->val=0; //  primul element 

dl->n=r=new(NOD);57

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 56/166

r->val=10000; r->n=NULL; //  ultimul element while(1){ cin>> is;

if(* is=='q') break;

in=atof(is);r=new(NOD);r->val=in;p=dl;v=p->n;while(v->valn);}r->n=v;p->n=r; }

return(dl); }16. Inversaţi consecutivitatea de simboluri introduse.

De exemplu,s-a introdus consecutivitatea ABcEr-1, consecutivitateainversată va fi 1-rEcBA. Utilizaţi noţiunea de listăsimplu lănţuită.

17. Cercetaţi operaţiile efectuate asupra stivei înprogramul de mai jos: typedef struct st // declararea tipului STACK 

{ char ch;struct st *ps;} STACK;

main(){ STACK *p,*q;

char a;p=NULL;do // completarea stivei { a=getch();q=new(STR1);q->ps=p; p=q;q->ch=a;

} while(a!='.');58

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 57/166

do // tiparul stivei { p=q->ps; delete (q); q=p;cout<< p->ch;

} while(p->ps!=NULL);

}18. Scrieţi un program în care numerele din baza 10

din lista dublu lănţuită dată se înlocuiesc cu celedin baza 2.

19. Scrieţi un program care ar efectua următoareleoperaţii. Se creează o listă dintr-un şir de numereîntregi, care se termină cu zero. Din listă se ştergmai întîi elementele negative, apoi numerelepare.

20. Scrieţi un program care din trei cozi se selecteazăo coadă nouă mai întîi numerele negative,zerourile, apoi numerele pozitive.

21. Analizaţi ce efectuează programul de mai jos:typedef struct nod 

{ float val;

struct nod *n;} NOD;int index (NOD *x[100]){ NOD *p;

int i,j=0;float inp;for (i=0; i<100; i++) x[i]=NULL;cin>> inp;while (inp!=0)

{ j++;p=new(NOD);i=inp%100+1;p->val=inp;p->n=x[i];x[i]=p;

cin>>inp; }59

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 58/166

64

return j; }Valoarea returnată de funcţia index va fi numărul deelemente cercetate din listă.22. Scrieţi un program care să extragă în lista L2

elementele cu numere impare din lista L1. Lista L1 conţinenumere întregi.

23. Cum se utilizează funcţiile standard de citire avalorilor variabilelor de la tastatură şi din fişier?

24. Cum se utilizează funcţiile standard de tipar la ecranşi înregistrare într-un fişier a valorilor variabilelor?

25. Care sînt caracterele de control şi specificare a

tiparului variabilelor la ecran?Temele pentru acasă:1. Care dintre exemplele de declaraţie şi/sau iniţializaresînt corecte:

int r;int 25;int p=25;

int i;int r=i;r=25;const int j=25;int r=j;

2. Scrieţi o versiune de funcţie cu pointeri pentrustrcat() concatenare a două şiruri de caractere.

3. Scrieţi variante de programe cu pointeri care arefectua funcţiile citeşte_linie(), reverse_linie().

4. Care dintre exemplele de declaraţie şi/sauiniţializare sînt corecte:

int &r;int &r=25;int *p=25;int i;

int &r=i;60

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 59/166

r=25; |const int j=25;int &r=j;

5. Scrieţi un program pentru a număra biţii de la

dreapta spre stînga pentru un număr dat.6. Scrieţi un program care roteşte întregul n la dreaptacu b poziţii.

7. Scrieţi un program care inversează cei n biţi ai săicare încep de la poziţia p, lăsîndu-i pe ceilalţineschimbaţi.

8. Scrieţi un program care converteşte literele mari înlitere mici utilizînd o expresie condiţională.

9. Scrieţi un program care converteşte numărulîntreg n în baza zecimală într-un şir de caractere.

10. Scrieţi un program care converteşte întregii fărăsemn n într-o reprezentare binară s.

11. Scrieţi un program care converteşte un întregîntr-un număr hexazecimal.

12. Scrieţi un program de convertire a unui şir de

caractere într-un întreg.13. Scrieţi un program care inversează un şir de

caractere s.14. Scrieţi un program pentru a număra biţii de la

dreapta spre stînga pentru fiecare număr cititdintr-un fişier.

15. Scrieţi un program care roteşte un întreg n (cititdintr-un fişier) la dreapta cu b poziţii. b este unnumăr aleator de la 1 la 16.

16. Scrieţi un program care în fiecare număr cititdintr-un fişier inversează cei n biţi ai săi careîncep de la poziţia p, lăsîndu-i pe ceilalţineschimbaţi, p ia valoare de la 1 la 10.

17. Scrieţi un program care converteşte literele mariîn litere mici dintr-un fişier textual.

18. Scrieţi un program care converteşte numărul61

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 60/166

întreg n în baza zecimală, citit dintr-un fişier într-un şir de caractere.

19. Scrieţi un program de convertire a fiecăruielement dintr-o stivă într-un şir de caractere.

Temele pentru lucrări de laborator:I.

1. Scrieţi un program care compară două stivedate.

2. Scrieţi un program care generează o mie deseturi de cinci numere aleatoare cuprinse între

1 şi 40, în final afişînd frecvenţa cu care a fostgenerat fiecare număr.3. Scrieţi un program pentru a număra biţii de la

dreapta spre stînga pentru un număr introdusde la tastatură.

II.1. Scrieţi un program care calculează numărul de

elemente dintr-o listă simplu lănţuită care sîntmai mici ca valoarea medie aritmetică a tuturor elementelor acestei liste.

2. Scrieţi un program care efectuează înmulţireacifrelor unui număr dat.

3. Scrieţi un program care converteşte numărulîntreg n în baza zecimală într-un şir decaractere.

III.1. Scrieţi un program care determină un număr

obişnuit din inversul cifrelor numărului dat.2. Scrieţi un program care permite crearea unui

arbore binar şi traversarea lui în inordine,preordine, postordine.

3. Scrieţi un program care converteşte întregii

fără semn  dintr-o listă dublu lănţuită în62

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 61/166

reprezentare binară.IV. 1. Scrieţi un program care din 100 de numere

aleatoare se determină numărul maximal şi cel

minimal. Să se determine diferenţa dintre numărulmaximal şi cel minimal determinat

2.  Scrieţi un program care converteşte întregii fărăsemn  n selectaţi dintr-un fişier într-o reprezentarebinară.

3. Scrieţi un program care converteşte un întreg într-un număr hexazecimal.

V.1. Scrieţi un program care determină numărul de

ordine a numărului minimal dintr-o consecutivitatede numere aleatoare. Cantitatea de numerealeatoare ale consecutivităţii este aleatoare (N = 1,…,100). Valorile numerelor aleatoare aleconsecutivităţii sînt din intervalul 0 …100000.

2. Scrieţi un program de convertire a unui întreg într-

un şir de caractere.3. Scrieţi un program cu o funcţie recursivă care

calculează cel mai mare divizor comun alelementelor dintr-o consecutivitate.

VI.1. Scrieţi un program care determină numărul

maximal şi cel minimal într-o listă circulară de 100de numere aleatoare. Să se determineconsecutivitatea de elemente ce se află întrenumerele maximal şi cel minimal determinate.

2. Scrieţi un program care calculează suma cifrelorpentru fiecare număr din consecutivitatea de 100 denumere aleatoare.

3. Scrieţi un program care inversează un şir decaractere s.

VII.63

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 62/166

1. Scrieţi un program care formează o listă nouăsimplu lănţuită după următoarea legitate: din treiliste simplu lănţuite mai întîi se selecteazănumerele divizibile la 3, 5 şi 7, apoi – cele pozitive pare.

2. Scrieţi un program care generează un fişier alcăror valori ale elementelor sînt cuprinse între 1 şi100. Să se determine frecvenţa cu care a fostgenerat fiecare element în fişierul creat.

3. Scrieţi un program care inversează cei n biţi aielementelor unei liste simplu lănţuită care încep depe poziţia p, lăsîndu-i pe ceilalţi neschimbaţi.

VIII.1. Scrieţi un program care atribuie unei liste simplulănţuite elementele altei liste în ordine inversă.

2. Scrieţi un program cu funcţie recursivă carecalculează cel mai mare divizor comun dintr-un şirde numere date.

3. Scrieţi un program care din două fişiere ordonatedescrescător se unesc în unul nou păstrîndu-i-se

ordinea descrescătoare de sortare.IX.1. Scrieţi un program care determină cîte numere din

consecutivitatea de 100 de numere aleatoare sîntmai mari ca “vecinii” săi.

2. Scrieţi un program care înlocuiesc numerele dinbaza 10 din consecutivitatea dată cu cele din baza2.

3. Scrieţi un program care decide dacă o valoare xaparţine unei liste dublu lănţuite v. Elementele lui vtrebuie să fie în ordine crescătoare. Se tipăreştenumărul elementului din listă (un număr între 0 şin-1), dacă x apare în v, şi –1, dacă nu apare.

X.1. Scrieţi un program care va tipări în ordine inversă

subconsecutivitatea de numere dintre valoarea64

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 63/166

minimă şi maximă ale unei liste simplu lănţuită.2. Scrieţi un program care determină un număr

obişnuit din inversul cifrelor numărului dat.3. Utilizînd funcţia recursivă, scrieţi  un progr am care

converteşte un întreg citit dintr-un fişier în numerehexazecimale.

XI.1. Scrieţi un program care formează o listă dublu

lănţuită nouă din cea dată după următoarealegitate: elementele listei noi se obţine din inversulcifrelor numărului din lista dată.

2. Să se scrie un program care ar conţine douăfuncţii: una - recursivă, a doua - nerecursivă pentrunumărarea elementelor unei liste.

3. Scrieţi un program care inversează fiecare elementde tip şir de caractere dintr-o listă simplu lănţuită.

XII.1. Scrieţi un program care converteşte literele mari în

litere mici utilizînd din elementele unei stive.

2. Să se scrie un program care din lista L1 ce conţinenumere întregi să se extragă în lista L2 elementele cunumere impare din lista L1.

3. Scrieţi un program care converteşte întregii fărăsemn  dintr-o listă simplu lănţuită  n, într-oreprezentare binară.

XIII.1. Scrieţi un program care calculează suma

cifrelor pentru fiecare număr dinconsecutivitatea de 100 de numerealeatoare.

2. Scrieţi un program care roteşte fiecare element allistei dublu lănţuite n la dreapta cu b poziţii.3. Scrieţi un program care atribuie unui fişier

elementele altui fişier în ordine inversă.

XIV.65

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 64/166

1. Scrieţi un program care creează o listă circulară acăror valori ale elementelor sînt cuprinse între 1 şi100. Să se determine frecvenţa cu care a fostgenerat fiecare element al listei create.

2. Scrieţi un program care calculează suma cifrelorpentru fiecare număr din consecutivitatea de 100 denumere aleatoare.

3. Scrieţi  un program care converteşte fiecareelement al listei dublu lănţuite într-un numărhexazecimal.

XV.1. Scrieţi un program care determină cîte numere ale

unei cozi de 100 de numere aleatoare sînt maimari ca “vecinii” săi.

2. Scrieţi un program care formează un fişier nou dincel dat după următoarea legitate: elementelefişierului nou se obţine din inversul cifrelornumărului din fişierul dat.

3. Alcătuiţi un program care ar efectua următoarele

operaţii asupra listei dublu lănţuite:–  iniţializarea listei;– cãutarea elementului dupã criteriul dat;– insertarea unui element nou înainte sau dupã o componentã

indicatã a listei;– eliminarea unui element din listã; sortarea componentelor 

listei.

66

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 65/166

Lucrarea de laborator nr. 2Tema: Clase (constructori, destructori).Funcţii şi claseprietene.

Scopul lucrării: familiarizarea studenţilor cunoţiunea de clase, utilizarea constructorilor,destructorilor, cu funcţii şi clase prietene.

Consideraţiile teoretice necesare:Clase

Sintaxa simplificată a declarării unei clase este

următoarea:class NumeClasă{...declaraţii variabile membri...declaraţii funcţii membri...}

Din definirea clasei se poate observa că clasa esteasemănătoare cu o structură. Ea are în componenţa

sa membri atît de tip variabilă, cît şi de tip funcţie.Pentru datele din interiorul clasei se utilizează, deregulă, termenul de date membri, iar pentru funcţii –denumirea de funcţii sau metode. O clasă permiteincapsularea în interiorul sau a datelor şi a codului.

Pentru a putea utiliza efectiv un tip de date (încazul de faţă o clasă), trebuie sa definim o variabilă

de acel tip. Într-un mod similar declaraţieiint i;putem scrie:

NumeClasă variabilăVom considera că variabilă este un obiect . Expr imareauzuală este că un obiect este instanţierea unei clase.

O clasă este compusă din două părţi: declaraţiaşi implementarea ei. Declaraţia clasei prezintă

membrii clasei. Membrii clasei sînt variabile de67

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 66/166

instanţiere şi funcţii membri indicate prin prototipullor (tipul returnat, numele funcţiei, lista deparametri). Implementarea funcţiilor membri are locprin implementarea clasei. Gradul de accesibilitate la

elementele componente ale clasei este indicat princuvintele: private sau protected  – elementele clasei sîntaccesate numai prin intermediul funcţiilor membrisau prietene friend, public – toate elementele sînt disponibile înexteriorul clasei. De exemplu:

#include<iostream.h>class myclass //  se declară un nou tip de datemyclass{private: int a; //  componenta int a se declară

implicit în //zona privatepublic: // funcţiile membri declarate mai joc

sînt din //zona publicvoid set_a (int num); //  prin intermediul acestorfuncţii se

// accesează componenta a

int get_a ();};void myclass::set_a(int num) { a=num;}

//  această funcţie atribuie valoarecomponentei a

int myclass::get_a(){return a; }//  această funcţie furnizează valoarea

componentei avoid main () // funcţia de bază a programului{ myclass ob1, ob2; // se declară două obiecte ob1

şi ob2 //de tipul myclassob1.set_a (10); // pentru obiectul ob1 se atribuie

//valoare componentei a egală cu 10ob2.set_a (99); // pentru obiectul ob2 se atribuie

//valoare componentei a egală cu 99

cout << ob1.get_a ()<<“ \n”; //  pentru obiectul ob168

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 67/166

se //furnizează valoareacomponentei a/ /care apoi se tipăreşte la ecran

cout << ob2.get_a () << “ \n”; //  pentru obiectul ob2

se //furnizează valoareacomponentei a// care apoi se tipăreşte laecran

}Rezultatul îndepliniri programului:1099

Funcţiile set_a şi get_a, pentru setarea şi furnizareavalorii pentru componenta a, nu sînt necesare,dacăcomponenta a va fi inclusă în zona public,. Componenta ava fi explicit accesată şi i se va iniţializa sau atribuivaloare. Exemplul de mai sus se va modifica în felulurmător:

#include<iostream.h>

class myclass //  se declară un nou tip de datemyclass{public:

int a; // componenta int a se declară explicit în//zona public

// funcţiile membri declarate mai sus nusînt necesare

};void main (){ myclass ob1, ob2; // se declară două obiecte ob1

şi ob2 // de tipul myclassob1.a =10; //  pentru obiectul ob1 se

iniţializează //valoareacomponentei a în mod//explicit cu valoarea 10

ob2.a = 99; // pentru obiectul ob2 se iniţializează69

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 68/166

//valoarea componentei  a înmod// explicit cu valoarea 99

cout << ob1.a << “\n”; // pentru obiectul ob1

// se tipăreşte valoareacomponentei a

cout << ob2.a << “\n”; // pentru obiectul ob2// se tipăreşte componentei a

}Rezultatul îndepliniri programului:1099Constructorii  sînt un tip special de funcţie

membru, avînd acelaşi nume ca şi numele clasei, nureturnează rezultat şi sînt apelaţi automat lainstanţierea unei clase, fie ea statică sau dinamică. Eiau scopul de a atribui valori iniţiale elementelormembri, dar pot efectua şi unele operaţii, cum ar fi,alocarea dinamică de memorie, deschiderea unui

fişier ş.a. De exemplu:class persoana{ private:char nume[40];long int telefon;

public:persoana() {nume=’\0’; telefon =0;};// constructorul iniţializează valori nule

elementelor membripersoana(char*p, long int t) {strcpy(nume,p); telefon=t;}// constructor iniţializează valori concrete pentruelementele //membri ale claseipersoana(char* nume) {return nume; };//aceste  funcţii atribuie valori pentru elementele

membri nume 

persoana(long int telefon) {return telefon;}; //şi telefon70

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 69/166

persoana persoana_ input (char *n, long int t=0){persoana p;strcpy(p.nume,n); p.telefon=t;return p; };

};Apelul constructorului se efectuează în momentuldeclarării unui obiect. Dacă declarăm o variabilă detipul persoana,  fie

persoana p = persoana (“Vasilina”, 743567);sau

persoana p (“Vasilina”, 743567);constructorul va iniţializa elementele membri nume şitelefon ale clase persoana respectiv cu valorile “Vasilina” şi743567. Dacă se va declara un obiect de tipul persoana fărădate iniţiale, constructorul va completa elementelemembri nume cu stringul vid ‘\0’ şi telefon cu valoarea 0.

Destructorii  dezactivează toate funcţiile unuiobiect, îl distruge şi sînt apelaţi automat laeliminarea unui obiect, la încheierea timpului de viaţă

în cazul static, sau la apelul unui delete în cazuldinamic. De regulă, destructorii sînt utilizaţi în cazul,cînd constructorii efectuează alocări dinamice dememorie. Destructorul are acelaşi nume ca şiconstructorul, f iind precedat de semnul “~”. De exemplu:

#include<iostream.h>#include<string.h>#include<stdlib.h>#define Size 255class strtype{ private:char *p;int len;public:strtype() // constructorul

{ p=new char;71

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 70/166

if (!p){cout << “Eroare la alocarea memoriei \n”;exit(1);}*p=’\0’; len=0; };~strtype() {cout << “Eliberarea memoriei\n”; delete p; }

// destructorulvoid set (char*ptr){ if (strlen(ptr)> Size )cout<<”Stringul conţ ine mai mult de 255 de caractere

\n”; strcpy(p,ptr); len=strlen(p);};void show(){ cout << p << “- lungimea “<< len << “\n”;}};void main(){ strtype s1,s2;s1.set (“Test”); s2.set(“Program C++”);s1.show(); s2.show();}Rezultatul îndeplinirii programului:Test- lungimea 4

Program C++- lungimea 11Eliberarea memorieiEliberarea memoriei

Destructorii obiectelor membri sînt apelaţi, după cedestructorul obiectului principal a fost executat. Dacăobiectul membru este compus din alte obiecte, atuncise va proceda la executarea destructorilor obiectelorincluse. Destructorii obiectelor membri sînt apelaţi în

ordine inversă, în care aceştea apar în declaraţiaclasei.

Din punct de vedere cronologic, constructoruleste apelat după alocarea memoriei necesare, deci înfaza finală a creării obiectului, iar destructorulînaintea eliberării memoriei aferente, deci în fazainiţială a distrugerii sale.

Constructorii şi destructorii se declară şi se72

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 71/166

definesc similar cu celelalte funcţii membri, darprezintă o serie de caracteristici specifice:

–  numele lor coincide cu numele clasei căreiaii aparţin; destructorii se disting de

constructori prin faptul că numele lor esteprecedat de caracterul

– nu pot returna nici un rezultat–  nu se pot utiliza pointeri către constructori

sau destructori–  constructorii pot avea parametri, destructorii

insa nu. Un constructor fără parametri

poartă denumirea deconstructor implicit .

în care o clasa nu dispune de constructori saudestructori, compilatorul de C++ generează automatun constructor, respectiv destructor, implicit.

Membrii unei clase

Accesarea membrilor unei clase se face în felulurmător:obiect.VariabiăMembru = valoare;

pentru accesul la o variabilă membru, şiobiect.FuncţieMembru();

pentru apelarea unei funcţii membri.Pentru exemplificare să consideram o

implementare a noţiunii de punct . Ca variabile membriavem nevoie doar de coordonatele x şi y care definesc poziţiaîn spaţiu a unui punct. Am mai declarat o funcţie care

calculează aria dreptunghiului avînd punctele(0, 0)

şi(x, y).class Point {unsigned x, y;unsigned long Arie() {return x * y;};unsigned GetX();unsigned GetY();void SetX(unsigned X);

void SetY(unsigned Y);73

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 72/166

};unsigned Point::GetX() {return x;}unsigned Point::GetY(){return y; }void Point::SetX(unsigned X){ x = X; }

void Point::SetY(unsigned Y) { y = Y; }Am folosit un operator nou, specific C++, ::, numit operator derezoluţie, numit şi operator de acces sau de domeniu. Elpermite accesul la un identificator dintr-un bloc în care acesta nueste vizibil datorită unei alte declaraţii locale. Unexemplu de folosire este următorul:

char *sir = "variabilă globală";void funcţie(){ char *sir = "variabilă locală";printf("%s\n", ::sir); // afişează variabila globalăprintf("%s\n", sir); // afişează variabila locală}

Pentru definiţiile funcţiilor membri aflate în afaradeclaraţiei clasei este necesară specificarea numeluiclasei urmat de acest operator, indicînd faptul că

funcţia are acelaşi domeniu cu declaraţia claseirespective şi este membru a ei, deşi este definită înafara declaraţiei.

Cuvîntul-cheie this. Toate funcţiile membri ale uneiclase primesc un parametru ascuns, pointer-ul this,care reprezintă adresa obiectului în cauză. Acestapoate fi utilizat în cadrul funcţiilor membri. De exemplu:

unsigned long Point::Arie(){return this->x * this->y; }Crearea şi distrugerea obiectelor. Să

considerăm următorul program C++:void main(){Point p; }În momentul definirii variabilei p, va fi alocat automat

spaţiul de memorie necesar, acesta fiind eliberat la

terminarea programului. În exemplul de mai sus, variabila p este74

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 73/166

de tip static. În continuare vom modifica acestprogram pentru a folosi o variabilă dinamică(pointer).

void main()

{ Point *p;p = new Point;p->x = 5; p->y = 10;printf("Aria = %d\n", p->Aria());delete p; }Operatorul new este folosit pentru alocarea memoriei, iar 

sintaxa acestuia este:variabila = new tip;variabila = new tip(valoare_iniţială);variabila = new tip[n];

Prima variantă alocă spaţiu pentru variabilă dar nu oiniţializează, a doua variantă ii alocă spaţiu şi oiniţializează cu valoarea specificată, a treia alocă untablou de dimensiune n. Acest operator furnizează carezultat un pointer conţinînd adresa zonei de

memorie alocate, în caz de succes, sau un pointer cuvaloarea NULL (practic 0) cînd alocarea nu a reuşit.Eliminarea unei variabile dinamice şi eliberarea

zonei de memorie aferente se realizează cu ajutoruloperatorului delete. Sintaxa acestuia este:

delete variabilă;Deşi aceşti doi operatori oferă metode flexibile degestionare a obiectelor, există situaţii în care aceastanu rezolvă toate problemele. De aceea, pentrucrearea şi distrugerea obiectelor în C++ se folosescnişte funcţii membri speciale, numite constructori şidestructori, despre car e s-a menţionat mai sus.

Să completăm în continuare clasa Point  cu unconstructor şi un destructor:

Point::Point() // constructor implicit

{ x = 0; y = 0; }75

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 74/166

Point::Point(unsigned X, unsigned Y){ x = X; y = Y; }Point::~Point() { }

Aţi remarcat cu această ocazie modul de marcare a

comentariilor în C++: tot ce se află după caracterul//  este considerat comentariu.

Definiţii de formaPoint p; // sauPoint *p = new Point();

duc la apelarea constructorului implicit.O întrebare care poate apare este motivul pentrucare am realizat funcţiile GetX(), GetY(), SetX(),SetY(), cînd puteam utiliza direct variabilele membri xşi y. Deoarece una din regulile programării C++ estede a proteja variabilele membri, acestea pot fiaccesate numai prin intermediul unor funcţii, care aurolul de metode de prelucrare a datelor incapsulate îninteriorul clasei.  Funcţii şi Clase friend. Conceptul friend

permite abateri controlate de la ideea proiecţieidatelor prin incapsulare. Mecanismul de friend (sauprietenie) a apărut datorita imposibilităţii ca ometodă să fie membru a mai multor clase.

Funcţiile prietene sînt funcţii care nu sîntmetode ale unei clase, dar care au totuşi acces lamembrii privaţi ai acesteia. Orice funcţie poate fiprietenă a unei clase, indiferent de natura acesteia.

Sintaxa declarării unei funcţii prietene în cadruldeclaraţiei unei clase este următoarea:

friend NumeFuncţieDe exemplu:class Point { friend unsigned long Calcul(unsigned X, unsigned Y);

public:

friend unsigned long AltăClasă::Calcul(unsigned76

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 75/166

X,unsigned Y);

... };unsigned long Calcul(unsigned X, unsigned Y)

{return X * Y / 2; }unsigned long AltăClasă::Calcul(unsigned X,unsigned Y)

{ ... }Funcţii membri ca prietene. Orice funcţie membru

nu poate fi prietenă aceleiaşi clase, dar, posibil, să fieprietena altei clase. Astfel, funcţiile friend constituie o

punte de legătură între clase. Există două moduri dea face ca o funcţie membru a unei clase să fieprietena altei clase. Prima variantă este specificareafuncţiei membru a unei clase, ca fiind prietenă alteiclase. Deci, în cea de-a doua clasă, vom declarafuncţia membru în prima clasă ca fiind de tip friend.

class B;class A

{…..void Al (B &x) ;…..);class B{ friend void A::A1(B &x); );

A doua variantă este declararea unei clase prietenă,astfel, că toate funcţiile sale membri, sînt, de fapt,prietene clasei în care un obiect de tipul primei claseeste declarat friend .

class B;class A{ void Al (B &x) ; );class B{…

friend A;77

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 76/166

…};Indiferent de metodă, se impune predeclarareaclasei, care va fi prietenă sau va conţine funcţii, caresînt prietene unei alte clase.

Clasele prietene sînt clase care au acces la membriiprivaţi ai unei clase. Sintaxa declarării unei claseprietene este:

friend class NumeClasăPrietenăDe exemplu:class PrimaClasă {...};class ADouaClasă {...friend class PrimaClasă;};Clasa PrimaClasă are acces la membrii privaţi ai

clasei ADouaClasă.Relaţia de prietenie nu este tranzitivă. Daca o

clasa A este prietena a clasei B, şi clasa B esteprietenă a unei clase C, aceasta nu înseamnă ca Aeste prietenă clasei C. De asemenea, proprietatea deprietenie nu se moşteneşte în clasele derivate. Claseprietene sînt utile în situaţia în care avem nevoie declase, care să comunice între ele deseori, acesteaaflîndu-se pe acelaşi nivel ierarhic. Pentruexemplificare, presupunem că vom implementa ostivă de caractere ca o listă simplu înlănţuită. Vomutiliza două clase, una ataşată nodurilor din listă şiuna – stivei propriu-zise.

#include<conio.h>#include<stdio.h>class stiva;class nod 

{ private:78

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 77/166

friend stiva;nod(int d, nod *n);int data;nod *anterior;

};class stiva{ private:

nod *virf;public:stiva () { virf=NULL; }~stiva() { delete virf; }

void push (int c);int pop ();};nod::nod (int d, nod *n) {data=d; anterior=n;}void stiva::push (int i) {nod *n=new nod(i, virf); virf=n; }int stiva::pop ()

{ nod *t=virf;if (virf)

{ virf=virf->anterior;int c= t->data;delete t;return c; }return -1;

}void main(){ int c;

stiva cs;printf("Introdu un sir de caractere, ce se termina in *");

while ((c=getch ())!='*'){ cs.push (c);

putch(c); }putch(c);

while ((c=cs.pop ())!=-1)

{ putch (c); }79

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 78/166

c='\n'; putch(c);}Rezultatul îndeplinirii programului:

Introdu un sir de caractere, ce se termina in *ertyuioppoiu*uiop

poiuytrePrototipul unei funcţii friend cu o clasă se află, de regulă,în cadrul clasei respective. Funcţia friend  nu estemembru a acestei clase. Indiferent de poziţiadeclaraţiei unei asemenea funcţii, în cadruldeclaraţiei clasei funcţia va fi publică. De exemplu:

class punct 

{ private:int x, y;

public:punct (int xi, int yi) {x=xi; y=yi; };friend int compara (punct &a, punct &b);};int compara (punct &a, punct &b){  //returnează <0, dacă a este mai aproapede origine

// >0, dacă b este mai aproape deorigine

// =0, dacă a şi b sînt egaldepărtate.

return a. x*a. x+a. y*a. y-b. x*b. x-b. y*b. y; }void main()

{ punct p (14,17), q(57,30);if(compara(p,q)<0) printf("p este mai apropiat deorigine\n");

else printf (“q este mai apropiat de origine. \n") ; }Orice funcţie friend a unei clase poate fi transformatăîntr-o funcţie membru a acelei clase, renunţîndu-seînsă la gradul de “prietenie”. Exemplul de mai sus semodifică în felul următor:

80

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 79/166

8

#include<stdio.h>class punct { private:

int x,y;

public:punct (int xi, int yi) { x=xi; y=yi; }int compara (punct &b);};int punct:: compara (punct &b){ return x*x+y*y-b.x*b.x-b.y*b.y; }void main (){ punct p(14,17), q(57,30);

if (p.compara (q)<0)printf ("p este mal apropiat deorigine\n");

else printf ("q este mai apropiat de origine.\n");} Rezultatul îndeplinirii programului:p este mal apropiat de origine

Întrebările pentru verificarea cunoştinţelor:1. Ce se va afişa la ecran?#include <iostream.h>int a=1,b=2, c=43;class numere{ public:

int a,b;void Actiune(int b)

};void numere:: Actiune(int b) { a=14; b=56; c=3; }void main (){numere doua_numere;doua_numere.Actiune(56); }

2. Care este deosebirea dintre constructor şi un destructor alunei clase? Cum sînt activaţi constructorii şi

destructorii?81

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 80/166

2. Ce se numesc clase prietene?3. Ce se numesc funcţii prietene?

Temele pentru acasă:

1. Introduceţi şi lansaţi în execuţie următorulprogram. Ce rezultat furnizează?

#include <stdio.h>class număr {public:int n;număr(int i) { printf( "num() %d \n",n); };-număr() { printf("-num() %d \n",n); };};class numere{ public:număr a,b,c;numere(int x, int y, int z);-numere();};

numere::numere(int x, int y, int z) : c(z), a(x), b(y){ printf("A fost apelat un constructor \n"); }numere::~numere {printf("A fost apelat un destructor\n"); }void main (){numere bon(1, 2, 3);)

2. Introduceţi şi lansaţi în execuţie următorulprogram. Ce rezultat se afişează?

#include. <stdio.h>class 0_clasa{public:o_clasa (){ printf("Apel constructor\n"); }:

~o_clasa() { printf("Apel destructor \n"); }};class alta_clasa2

( public:82

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 81/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 82/166

(copiere, includere a unui substring, concatenare şieliminare a unui substring) pentru clasa:

class sir 

{ private:char continut[80];int lungime;public:sir ();char *contine() (return continut;}};

Temele pentru lucrări de laborator:1. Să se scrie un program care să definească un nou

tip de variabile - tipul complex şi să construiascăfuncţii adecvate pentru operaţiile de bază cu acesttip de date (adunare, scădere, înmulţire, calcululmodulului numărului complex).

2. Să se scrie un program care ar evalua o funcţie, a

cărei expresie analitică se introduce de laterminalul calculatorului ca un şir de caractere.3. Să se scrie un program în care se defineşte o clasă

stivă elementele căreia sînt de un tip abstract dedate cu următoarele funcţii:

–  empty(Q) care curăţă stiva Q,–  if_is_empty(Q) care verifică dacă stiva Q este vidă,–  in_query(Q,x) care adaugă elementul x în stiva Q,–  out_query(Q,x) care scoate elementul x din stiva Q,–  error (k) care indică eroarea cu numărul k (k=1 dacă

stiva este supraîncărcată, k=2 dacă stiva estevidă).

4. Scrieţi un program care determină pentru o clasălistă simplu lănţuită cu următoarele funcţii:

–  member(x,L) care determină apartenenţa

elementului x listei L;84

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 83/166

–  equal(L1,L2) care determină echivalenţa a două listeL1 şi L2;

–  print(L) care tipăreşte toate elementele listei L;–  readlist(L,fin) care citeşte elementele din fişierul fin

în lista L.5. Scr ieţi un program care determină o clasă coadă în

care sînt determinate următoarele funcţii:–  empty(Q) care curăţă coada Q,–  if_is_empty(Q) care verifică dacă coada Q este vidă,–  in_query(Q,x) care adaugă elementul x în coada Q,–  out_query(Q,x) care scoate elementul x din coada Q,

–  error (k) care indică eroarea cu numărul k (k=1 dacăcoada este supraîncărcată, k=2 dacă coada estevidă).

6. Scrieţi un program care la o singură trecere prinfişierul fin fără utilizare a fişierelor suplimentare vatipări elementele fişierului fin în următoarea ordine:

– toate elementele mai mici ca valoarea a,– elementele din segmentul [a,b],

–  restul elementelor păstrînd aceeaşi ordine dinfişierul fin. (a<b, a şi b sînt cunoscute şi sînt deacelaşi tip ca şi elementele fişierului fin).

7. Scrieţi un program care determină o clasă stivă încare sînt determinate următoarele funcţii:

–  empty(S) care curăţă stiva S,–  if_is_empty(S) care verifică dacă stiva S este vidă,

–  pop(S,x) care adaugă elementul x în stiva S,–  push(S,x) care scoate elementul x din stiva S,–  error (k) care indică eroarea cu numărul k  (k=1 dacă

stiva este supraîncărcată, k=2 dacă stiva estevidă).

8. Scrieţi un program care efectuează asupraelementelor fin - fişierului de tip text - următoareleoperaţii:

–  tipăreşte inversat conţinutul fiecărui cuvînt al liniei85

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 84/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 85/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 86/166

– adunarea,–  înmulţirea cu un coeficient,–  scăderea,–  împărţirea la un coeficient,

–  valoarea numerică a unităţilor de greutate să setipărească cu cuvinte.

15. Scrieţi un program care efectuează următoareleoperaţii asupra unităţilor de timp (de exemplu, anul, luna,ziua, ceasul, minutul, secunda):

– adunarea,–  înmulţirea cu un coeficient,– 

scăderea,–  împărţirea la un coeficient,–  valoarea numerică a unităţilor de timp să se

tipărească cu cuvinte.

Lucrarea de laborator nr. 3Tema: Clase derivate, funcţii virtuale, supraîncărcareafuncţiilor şi operatorilor.

Scopul lucrării: familiarizarea studenţilor cunoţiunile de clase derivate, funcţii virtuale şiredefinite, operatori supraîncărcaţi, obiecte

Consideraţiile teoretice necesare:

Clase derivate.Moştenirea este o relaţie între clase,

caracterizată prin trecerea atributelor de la o clasă,de bază, la alta, derivată. Clasele derivate posedătoate caracteristicile clasei de bază. Ele pot fiîmbogăţite atît structural, cît şi funcţional. Totodatăse observă o ierarhizare datorită faptului că existăposibilitatea ca o clasă derivată să aibă mai multe

88

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 87/166

clase de bază, ordinea importanţei nivelelor rămînîndaceeaşi.

Noţiunea de derivare este o abstractizare a noţiuniide moştenire. O clasă care adaugă proprietăţi noi la o

clasă deja existentă vom spune ca este derivata claseide bază. Clasa derivată moşteneşte toate datele şifuncţiile membri ale clasei de bază; ea poate adăuganoi date la cele existente şi poate suprascrie sauadăuga funcţii membri. Clasa de bază nu esteafectată în nici un fel în urma acestui proces dederivare şi, ca urmare, nu trebuie recompilată.

Declaraţia şi codul obiect sînt suficiente pentrucrearea clasei derivate, ceea ce permite reutilizareaşi adaptarea uşoară a codului deja existent, chiardacă fişierul sursă nu este disponibil. Astfel, nu estenecesar ca programatorul unei clase derivate săcunoască modul de implementare a funcţiilor membridin componenta clasei de bază.

În funcţie de necesităţi, derivarea claselor va fi

un proces cu durată variabilă. În acest sens, sepreferă conceperea unor clase de bază simple, înlocul unora dezvoltate.

Dintr-o clasă de bază pot fi derivate mai multeclase şi fiecare clasă derivată poate servi mai departeca bază pentru alte clase derivate. Se poate astfelrealiza o ierarhie de clase, care să modeleze adecvat

sisteme complexe. Pornind de la clase simple şigenerale, fiecare nivel al ierarhiei acumuleazăcaracteristicile claselor "părinte" şi le adaugă unanumit grad de specializare. O clasă poate sămoştenească simultan proprietăţile mai multor clase,procedură numită moştenire multiplă. Construireaierarhiei de clase reprezintă activitateafundamentală în realizarea unei aplicaţii orientate

obiect. Sintaxa simplificată a derivării este:89

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 88/166

class NumeClasăDerivată : NumeClasaDeBazăÎn continuare vom deriva din clasa Point o clasă

specializată, GraphicPoint, care va "şti" să desenezepunctul pe ecran:

class GraphicPoint : public Point {unsigned color;GraphicPoint(unsigned X, unsigned Y, unsigned Color);~GraphicPoint();void Draw();void SetX(unsigned X);void SetY(unsigned Y);};GraphicPoint::GraphicPoint(unsigned X, unsigned Y,unsigned Color) : Point(X, Y) {color = Color; }GraphicPoint::~GraphicPoint() {}GraphicPoint::Draw(){……// apelarea funcţiilor grafice pentru desenareapunctului

}GraphicPoint::SetX(unsignedX){Point::SetX(); //  funcţia SetX() este membru aclasei de bazăDraw();}GraphicPoint::SetY(unsigned Y){Point::SetY();

Draw();}În exemplul de mai sus s-a adăugat o variabilă

nouă faţă de clasa Point , color , pentru a putea memoraculoarea cu care se face desenarea punctului. Deasemenea, s-a suprascris constructorul şidestructorul clasei părinte. În constructorul derivat s-

a apelat constructorul original folosind construcţia:90

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 89/166

ClasaDerivată::ClasaDerivată() : ClasaDeBază()În clasa GraphicPoint  s-a adăugat o funcţie membru

nouă, Draw(), care desenează punctul pe ecran. Amsuprascris funcţiile SetX() şi SetY(), apelînd în ambele

funcţiile originale, utilizînd sintaxa:ClasaDeBază::FuncţieMembru()

apelînd apoi funcţie de desenare, Draw().Regulile de funcţionare ale constructorilor şi

destructorilor, descrise în lucrarea de laborator nr. 2,rămîn valabile şi în cazul claselor derivate, ţinîndu-secont de următoarele observaţii privind ordinea de

apelare a acestora:–  la instanţierea clasei derivate, seapelează mai întîi constructorul clasei debază, apoi se apelează propriulconstructor.

– la distruger ea unui obiect al unei clasederivate, este apelat mai întîi propriuldestructor, şi apoi destructorul clasei de

bază (în ordine inversă creăriiobiectului).

Controlul accesului la clase

Limbajul C++ permite controlul accesului la membriiclaselor. În acest scop s-au creat trei specificatori de control alaccesului:

–  public, membrul poate fi accesat de orice funcţiedin domeniul declaraţiei clasei;

–  private, membrul este accesibil numai funcţiilormembri şi prietene ale clasei;

–  protected , similar cu private, însă accesul se extindeşi la funcţiile membri şi prietene ale claselorderivate.

O funcţie membru a unei clase are acces la toţimembrii clasei, indiferent de specificatorul de acces.

Aşa dar, sintaxa declaraţiei unei clase derivate,91

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 90/166

incluzînd controlul accesului, este:class NumeClasăDerivată : SpecificatorAcces

NumeClasaDeBazăunde SpecificatorAcces poate fi public sau private.

Atributuldin clasade bază

Modificator de acces

Accesulmoştenit declasaderivată

Accesul dinexterior 

privateprotectedpublic

privateprivateprivate

inaccesibilprivateprivate

inaccesibilinaccesibilinaccesibil

privateprotectedpublic

publicpublicpublic

inaccesibilprotectedpublic

inaccesibilinaccesibilaccesibil

Pentru a oferi clasei derivate acces la unmembru al clasei de bază, acesta trebuie declaratprotected sau public. Elementele declarate cu specificatorul publicîn clasa de bază sînt accesibile elementelor în clasaderivată. Elementele declarate cu specificatorul private

sau protected  în clasa de bază nu sînt accesibile în moddirect elementelor din clasa derivată, ele pot fiaccesate doar prin unele funcţii declarate special(care returnează valorile elementelor din clasa debază descrise cu specificatorul private sau protected ).Pentru respectarea principiului incapsulării datelor,datele membri pentru care se oferă acces claselorderivate se declară în clasa de bază cu atributulprotected . De asemenea, pentru a conserva dreptul deacces în urma derivării, se utilizează derivarea public.Accesul poate fi stopat pe orice nivel al ierarhiei de clase printr-oderivare cu specificatorul de acces private.

Stabilirea atributelor de acces ale membrilorunei clase, precum şi ale derivărilor, dezvoltareaierarhiei de clase, trebuie să se facă astfel ca să nu

afecteze incapsularea datelor.92

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 91/166

Să cercetăm exemplul următor, completat cuspecificatori de acces:

class Point { protected:

unsigned x, y;public: Point();Point(unsigned X, unsigned Y);~Point();unsigned long Arie();unsigned GetX();unsigned GetY();void SetX(unsigned X);void SetY(unsigned Y);};class GraphicPoint : public Point {unsigned color;public: GraphicPoint(unsigned X, unsigned Y, unsigned Color);~GraphicPoint();

void Draw();void SetX(unsigned X);void SetY(unsigned Y);};

Variabilele membri x şi y sînt declarate protected , aşaîncît vor fi vizibile şi vor avea acelaşi atribut în clasaGraphicPoint (deşi nu sînt utilizate). În mod normal, xşi y ar trebui sa fie declaraţi private, întrucît nu sînt

utilizaţi decît în interiorul clasei Point . Funcţiile dinGraphicPoint  nu accesează aceşti doi membri direct, ciprin intermediul metodelor publice de accesare a loroferite de clasa Point .

Implicit, dacă nu este utilizat nici un specificatorde acces, membrii sînt consideraţi private.

void main()

{Point *p;93

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 92/166

p = new Point;p->x = 5; // operaţie imposibilă: x este membru privat p->y = 8; // operaţie imposibilă: y este membru privat p->SetX(5); // corect: acces la variabila x prin

intermediul //funcţiei SetX() p->SetY(8); // corect: acces la variabila x prin

intermediul //funcţiei SetY() printf("Aria = %d\n", p->Aria());delete p;}

Deci din exteriorul unei clase nu pot fi accesate datele membriprivate sau protected .

Atunci cînd funcţiile unei clase de bază sîntrescrise într-una derivată, spunem că aceste clasesînt polimorfe, vom avea o singură denumire şi maimulte acţiuni, adică, o singură interfaţă cu metodemultiple. Această noţiune legată de derivare este ceade supraîncărcare sau suprascriere a funcţiilor membri. Ease referă la redefinirea unor funcţii a clasei de bază în

clasa derivată. Funcţiile din clasa părinte sînt încontinuare accesibile în clasa derivată.Să vedem cum arată obiectele polimorfe.

Pentru aceasta, determinăm clasele de bază Punct  şicea derivată Cerc şi funcţia membru Aria(), ce va avea caefect determinarea ariei obiectului respectiv:

#include <stdio.h>class Punct { float x,y;public:void Incarc_punct(float xi,float yi) {x=xi;y=yi;};virtual float Aria() { return 0.0; };};const float pi=3.14159;class Cerc : public Punct 

{float raza;94

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 93/166

public: void Incarc_raza (float r) { raza=r; }float Aria(){ return pi*raza*raza; } ; // funcţieredefinită

};

void main(){ Punct p;float a=p.Aria();printf("Aria unui punct este: %5.2f\n",a);Cerc c;c.Incarc_raza(3.65637);a=c.Aria();printf("Aria cercului este: %5.2f\n",a);}Rezultatul îndeplinirii programului:Aria unui punct este: 0.00Aria cercului este: 42.00

Clasa Cerc este derivată de la clasa Punct.  Cerc şiPunct  sînt obiecte din aceeaşi categorie, sîntpolimorfe. Pentru a obţine obiecte polimorfe, va

trebui să construim o ierarhie de clase şi apoi săredefinim funcţiile, aparţinînd clasei de bază înclasele derivate. Această operaţie poate fi realizată îndouă moduri:–  rescriind funcţiile respective, efectuînd, deci o

nouă implementare a acestora,–  utilizînd funcţiile virtuale.

Să vedem cum are loc rescrierea funcţiilor. Esteevident că funcţia membru Aria() a clasei Punct  estemoştenită de clasa Cerc, dar nu convine din punctul de vedere alvalorii returnate. Astfel, s-a impus reimplementarea acesteia.

Punct *p;Cerc c;p=&c;float aria=p->Aria ();

În instrucţiunea în care este apelată funcţia Aria()95

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 94/166

este apelată funcţia Cerc::Aria(), p indică spre obiectul cde tipul Cerc. 

Ataşarea codului unei funcţii la numele săupoate fi efectuată static sau dinamic. Acest proces

poartă denumirea de identificare a funcţiilor, existînd,deci două metode de identificare: statică şi dinamică.

Identificarea statică are loc la un apel normal defuncţie. Compilatorul preia numele funcţiei,argumentele sale şi, în cazul în care aceasta estemembru, numele clasei obiectului.

Identificarea dinamică se va realiza în momentul

execuţiei, funcţia nefiind identificată. Cum? Oposibilitate ar fi de a utiliza pointeri la funcţii, astfel,că doar în momentul rulării vom şti funcţia, spre carea indicat acel pointer. Vom defini un pointer îninteriorul clasei Punct , ce va indica spre funcţia Aria(). 

Reţinem că acest pointer va fi moştenit de cătreCerc. După crearea unui obiect de tip Punct  sau Cerc,vom iniţializa pointerul spre funcţia corectă.

O a doua posibilitate este aceea de a utilizafuncţiile virtuale.

Funcţiile virtuale sînt utilizate pentrureimplementarea unor funcţii membri ale unor clase debază, astfel, încît această redefinire de funcţii săfuncţioneze în ambele situaţii.

const float pi=3.14159;class Cilindru : public Cerc{ float inaltime;public:void Incarca_ inaltime(int h) {inaltime =h;};float Aria() ; };float Cilindru::Aria(){return 2*pi*raza*inaltime +2 *Cerc::Aria(); }

În implementarea noii versiuni a funcţiei membri

Cilindru::Aria() se utilizează versiunea anterioară96

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 95/166

moştenită de la clasa de bază Punct.Evident că Punct::Aria() nu va modifica rezultatulfurnizat, aportul său la aceasta fiind nul, dar sesugerează că este permisă apelarea funcţiilor

moştenite pentru oricare nivel al ierarhiei, ţinînd contde nivelurile de protecţie ( private, protected şi public).

În procesul de lucru cu clase derivate putem foarteuşor greşi, transformînd o funcţie virtuală în funcţieredefinită datorită faptului că cele două categorii seaseamănă. Totuşi, există cîteva diferenţe dintreaceste două categorii de funcţii:

–  funcţiile membri redefinite sînt ataşate obiectului,urmînd procedura statică (la compilare), în timp cefuncţiile virtuale fac parte din cea de– a douacategorie, legăturile cu obiectele fiind realizatedinamic (în timpul execuţiei);

–  funcţiile membri redefinite pot avea liste diferitede parametri, în timp ce funcţiile virtuale trebuiesă posede aceeaşi listă de parametri.

Dacă, în cadrul ierarhiei de clase, funcţiile nu secomportă exact cum vrem noi, va trebui să verificămtoate funcţiile virtuale, pentru a ne asigura că, într-adevăr, sînt virtuale şi nu redefinite.

# include <stdio.h>class scade{public:virtual int executa (unsigned char c) { return --c; };

};class aduna : public scade{ public:

int executa ( char c) { return ++c; };};void main(){scade *p=new aduna;

int k=p->executa(43);97

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 96/166

printf(“k = %d \n”,k);}Rezultatul îndeplinirii programului:k = 42

În acest exemplu programul va afişa răspunsul42. Versiunea clasei scade acceptă un argumentunsigned char , iar versiunea clasei aduna –  un argument de tipchar . Datorită acestei schimb de tip, a doua versiune afuncţiei executa() nu este virtuală, ea este redefinită.Chiar dacă prin intermediul lui p acţionăm asupraunui obiect aduna, apelînd funcţia executa(), ne referim laversiunea scade. Deci programul va afişa valoarea 42.

O funcţie operator  are aceleaşi componente pecare le are orice funcţie, include un nume, un tipreturnat, argumente, corp şi, eventual, apartenenţala o clasă. Există trei elemente care trebuie stabilitela declararea operatorului, şi anume, este operatorunar sau binar, este postfixat sau prefixat ca poziţieşi este funcţie membru sau nu – domeniu de acţiune.

Funcţiile operator  membri vor avea cu unargument mai puţin decît cele non-membri. Apelul unui astfelde operator membru va fi

p+=5;sau

p. operator+=(5);Redefinirea operatorilor 

Limbajul C++ permite programatorilor sădefinească operatori pentru a lucra cu propriileclase. Sintaxa supraîncărcării unui operator este:

operator Simbol unde Simbol  este simbolul oricărui operator C++,exceptînd: . *- adresare la componenta prin pointer, ::-operatorul de rezoluţie, ()  ?:- operatorul condiţional,operatorul sizeof, etc.. Această definire se face în cadrul

clasei, întocmai ca o funcţie membru (vezi Tabelul 1.)98

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 97/166

Există două variante de definire a operatorilor:–  ca funcţie membru a clasei;–  ca funcţie prietenă a clasei.

Tabelul 1.

Tipuloperatorului

Simboluloperatorului

Asociativitate Observaţii

Binar  () [] -> ->Se definesc cafuncţii membri

Unar  + - ~ * & (tip) <-

Unar  ++ -- <-Nu se poate dis-tinge între pre- şi

postfixare

Unar  new, delete <-Poate fi supra-definit şi pentru oclasă

Binar  -> * / % + - &| && || ->

Binar  << >> < <=> >= == != ->

Binar 

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

<- Se definesc cafuncţii membri

Binar  , ->Pentru exemplificare, vom extinde clasa Point cu utilizarea

unor operatori.

class Point {// ...Point& operator += (Point p);Point& operator -= (Point p);Point operator + (Point p);Point operator - (Point p);Point& operator = (Point p);int operator == (Point p);

int operator != (Point p);99

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 98/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 99/166

clase prezintă o restricţie majoră: primul operandeste obligatoriu să fie de tipul clasa respectiv.

În limbajul C++ supradefinirea operatorilor estesupusă unui set de restricţii:

– nu este permis introducerea de noi simboluri deoperatori;

– patru operatori nu pot fi redefiniţi (vezi maisus);

–  caracteristicile operatorilor nu pot fischimbate: pluralitatea (nu se poatesupradefini un operator unar caoperator binar sau invers), precedenţaşi asociativitatea, prioritatea lor;

–  funcţia operator  trebuie sa aibă cel puţinun parametru de tipul clasa căruia îi esteasociat operatorul supradefinit.

Programatorul are libertatea de a alege naturaoperaţiei realizate de un operator, însă esterecomandat ca noua operaţie să fie apropiată de

semnificaţia iniţială.Redefinirea operatorului +=. Acţiunea acestuia este

aceea de a adăuga o valoare unui număr de tip char,int, float sau double. Putem redefini acest operator, pentru a operaasupra obiectelor, de exemplu, de tip persoana.

# include <stdio.h># include <string.h>class persoana{ private:char nume[40];long int telefon;int virsta;public:persoana () {strcpy(nume,'\0');telefon=0; virsta=0;};persoana(long int Telefon) { telefon= Telefon; };

persoana(char *Nume) { strcpy(nume,Nume); };101

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 100/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 101/166

predefinit în C++, pentru operanzi de tip clasă. Dacănu este supradefinită, atribuirea se face membru cumembru în mod similar cu iniţializarea obiectuluiefectuată de către compilator. În caz de o atribuire

specifică a clasei, operatorul = poate fi supradefinit.Point& Point::operator = (Point p){x = p.x; y =p.y; return *this;}

Redefinirea operatorului [].Operatorul de indexare [] sedefineşte astfel:

int &operator[](int)De exempluPoint Array_Point::operator []= (Point *p, int j) {returnp[j];}Redefinirea operatorilor new şi delete poate

fi efectuată pentru a realiza operaţii specializate dealocare/eliberare dinamică a memoriei. Funcţiaoperator new trebuie sa primească un argument detipul size_t  care să precizeze dimensiunea în octeţi aobiectului alocat şi să returneze un pointer de tip void 

conţinînd adresa zonei alocate:void *operator new(size_t)cu menţiunea că size_t este definit în stdlib.h. Chiar dacăparametrul de tip size_t  este obligatoriu, calcululdimensiunii obiectului în cauză şi generarea sa seface de către compilator.

Funcţia operator delete trebuie sa primească ca primparametru un pointer de tipul clasei în cauză sauvoid , conţinînd adresa obiectului de distrus, şi un aldoilea parametru opţional de tip size_t . Funcţia nuîntoarce nici un rezultat.

void operator delete(void *, size_t)Operatorii new şi delete supradefiniţi păstrează

toate proprietăţile operatorilor new şi delete standard.Redefinirea operatorilor unari  poate fi efectuată

utilizînd o funcţie membru fără parametri sau o103

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 102/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 103/166

tip clasă, funcţia operator  trebuie să aibă acces ladatele membri ale clasei de la care se faceconversia, deci trebuie declarată prietenă a claseirespective.

Conversiile de tip folosind constructori  constă îndefinirea unui constructor ce primeşte ca parametrutipul de la care se face conversia. Constructorulîntoarce întotdeauna ca rezultat un obiect de tipulclasei de care aparţine, ca urmare, folosind aceastămetodă se pot realiza numai conversii dintr-un tip debază sau un tip clasă într-un tip clasă.

În cazul conversiei dintr-un tip clasă într-un alttip clasă, constructorul trebuie să aibă acces la datelemembri ale clasei de la care se face conversia, decitrebuie declarată prietenă a clasei respective.

Constructorul de copiere. O situaţie care poateapărea deseori este iniţializarea unui obiect cu datelemembri ale unui obiect de acelaşi tip. Exista totuşisituaţii în care operatorul de atribuire nu poate fi

utilizat, de exemplu, la transferul unui obiect caparametru sau la crearea unei instanţe temporare aunei clase, cînd copierea membru cu membru nu esteadecvată. Pentru a rezolva aceste situaţii, în limbajulC++ a fost introdus un constructor special, numitconstructorul de copiere. Sintaxa este:

NumeClasă::NumeClasă (NumeClasă

&NumeObiectSursă)În continuare vom completa clasa Point  cu un constructor decopiere:

Point::Point(Point &p){p.x = x;p.y = y;}

În cazul în care clasa nu dispune de constructor decopiere, compilatorul generează automat un

constructor de copiere care realizează copierea105

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 104/166

membru cu membru.Clase abstracte. În limbajul C++ există

posibilitatea de a defini clase generale, care sîntdestinate creării de noi clase prin derivare. Ele nu pot

fi instanţiate şi utilizate ca atare. Acest gen de clase senumesc clase abstracte. Ele se constituie ca bază în cadrulelaborării de ierarhii de clase, putînd fi folosite, deexemplu, pentru a impune anumite restricţii înrealizarea claselor derivate.

În vederea construirii unor astfel de clase, s-a introdusconceptul de funcţie virtuală pură. O astfel de funcţie

este declarată în cadrul clasei, dar nu este definită. Oclasă care conţine o funcţie virtuală pură esteconsiderată abstractă. Sintaxa definirii acestor funcţiieste:

virtual TipData NumeFunctieMembru() = 0Funcţiile virtuale pure trebuie definite în clasele

derivate, altfel şi acestea vor fi considerate abstracte.Membrii statici ai unei clase. În mod normal, datele

membri ale unei clase sînt alocate în cadrul fiecăruiobiect. În C++, se pot defini date membri cu ocomportare specială, numite date statice. Acestea sîntalocate o singură dată, existînd sub forma uneisinguri copii, comună tuturor obiectelor de tipul claseirespective, iar crearea, iniţializarea şi accesul la acestedate sînt independente de obiectele clasei. Sintaxa este:

static DeclarareMembruFuncţiile membri statice efectuează, de asemenea,operaţii care nu sînt asociate obiectelor individuale, ciîntregii clase. Funcţiile exterioare clasei pot accesamembrii statici ale acesteia astfel:

NumeClasă::NumeMembruObiect::NumeMembruFuncţiile membri statice nu primesc ca

parametru implicit adresa unui obiect, aşadar, în106

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 105/166

cadrul lor cuvîntul-cheie this nu poate fi utilizat. Deasemenea, membrii normali ai clasei nu pot fi referiţi decîtspecificînd numele unui obiect.

Întrebările pentru verificarea cunoştinţelor:1. Care dintre instrucţiunile de mai jos sînt legale?a: class sir 

{private:static char eos;char *continut;int dimensiune;public:sir(int sz);void copy(sir &s);};

b: char sir::eos=Ox1A;void sir::copy(sir 63)delete continut;continut = new char[3.dimensiune];

char *p=continut;char *q=s.continut;while <*qt=eos)

c: *p++=*q++;*p=eos;void main(){sir s(80);}

d: sir::eos=0;e: s.eos='$';2. După cum ştim, atunci cînd redefinim funcţii,

listele de argumente trebuie să difere de laimplementare la implementare. De ce acest lucrunu se impune atunci cînd redefinim funcţia Aria()din cadrul claselor Punct şi Cerc?

3. Dacă redefinim operatorul+ ataşat clasei persoana şi

facem această funcţie membri, cîte argumente107

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 106/166

108

explicite va avea aceasta?4. Scrieţi o funcţie operator membru a clasei persoana pentru

a rescrie operatorul ==. Există mai multe variante aleacestei funcţii?

Temele pentru acasă:1. Ce va afişa programul următor?

#include<iostream.h>class Bunic{ public :

virtual void sfat(){ cout<< “Distrează-te”; }

};class Tata : public Bunic{ public:void sfat(){ cout « "Fă-ţi lecţ iile'\n"; }

}

class Fiu : public Tata{ public:void sfat()

{ Bunic::sfat(); }};void main()( Fiu lon; lon.sfat(); }

2. Ce se va afişa la ecran după executareaprogramului următor?

#include <iostream.h>class Mesaje_bune{ public:virtual void act1()

{ cout«"Prinţul vede prinţesa\n";

act2(); }108

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 107/166

void act2(){ cout«"Prinţul o sărută\n"; act3();

}virtual void act3()

  { cout«"Prinţesa se trezeşte\n"; act4();}virtual void act4 ()

{ cout«"Si au trăit fericiţi . . . \n" ;act5(); )

void act5(){ cout « "Sfîrşit '\n"; }

};class Mesaje rele : public Mesaje bune{ public:void act3()

{ cout«"Prinţesa rămîne ţeapănă\n" ;act4() ; }void act4()

{ cout«"Prinţul fuge îngrozit\n";act5();

}void act5(){ cout«"Un sfîrşit, nefericit' \n" ; }

};void main (){ char c;

Mesaje bune *mes;cout«"Care variantă doriţii să vedeţi(L/B) ?\n" ;cin»c;if (p=='L') | | (c=='l’)) mes=new Mesaje_bune;else mes=new Mesaje rele;mes->act1();delete mes;}

Temele pentru lucrări de laborator:109

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 108/166

1. Scrieţi un program care ar defini clasa de bază num.În această clasă determinaţi un număr întreg şifuncţia shownum(). Creaţi două clase derivate outhexşi outoct care moştenesc num. Funcţia shownum() se va

redefini în clasele derivate astfel ca ea să afişeze ladisplay respectiv, valorile din sistemele denumeraţie hexazecimală şi octală, să se efectuezetoate operaţiile aritmetice asupra numerelor dinaceste sisteme de numeraţie.

2. Scrieţi un program care care ar defini clasa de bazănum. În această clasă determinaţi un număr întreg

şi funcţia shownum(). Creaţi clasa derivată outbin caremoşteneşte num. Funcţia shownum() se va redefini înclasa derivată astfel ca ea să afişeze la displayvalorile din sistemul de numeraţie binar, să seefectueze toate operaţiile aritmetice şi logiceasupra numerelor binare.

3. Scrieţi un program care defineşte clasa de bazădistance pentru a păstra în variabila de tipul double

distanţa dintre două puncte. În clasa distance să secreeze funcţia virtuală trav_time(), care afişeazăvaloarea timpului necesar pentru a parcurgedistanţa măsurată în mile, viteza fiind de 60mile/oră. În clasa derivată metric se va redefinifuncţia trav_time(), astfel ca ea să afişeze timpulnecesar pentru parcurgerea distanţei măsurată în

kilometri, viteza fiind de 100 km/oră.4. Scrieţi un program care ar defini clasa de bazăvector . În această clasă determinaţi un vector denumere întregi şi funcţia showvector(). Creaţi clasaderivată array care moşteneşte vector . Funcţiashowvector() se va redefini în clasa derivată, astfel caea să afişeze la display valorile tabloului pe linii şipe coloane. Să se calculeze suma elementelor

tabloului, să se efectueze operaţiile algebrice110

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 109/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 110/166

–  să se compare două şiruri de biţi,–  să se extragă un subşir de biţi din şirul de biţi dat,–  să se lichideze un subşir de biţi din şirul de biţi dat

din poziţia dată,

–  să se inverseze un şir de biţi dat,–  să se caute un subşir de biţi din şirul de biţi dat.8. Scrieţi un program care ar defini clasa de bază

set_bit . În această clasă determinaţi funcţiashowset_bit(). Creaţi clasa derivată mulţime caremoşteneşte set_bit. Funcţia showset_bit() se va redefiniîn clasa derivată, astfel ca ea să afişeze la display

valorile unei mulţimi. Să se efectueze următoareleoperaţii asupra mulţimii:–  să se determine numărul de elemente a mulţimii–  să se determine spaţiul pentru mulţimea dată,–  să se compare două mulţimi,–  să se extragă o submulţime din mulţimea dată,–  să se adauge un nou element la mulţime,–  să se şteargă un element din mulţime,

–  să se caute o submulţime din mulţimea dată.9. Scrieţi un program care ar defini clasa de bază int.

În această clasă determinaţi valorile întregi şifuncţia showint(). Creaţi clasa derivată longint  caremoşteneşte int. Funcţia showint() se va redefini înclasa derivată, astfel ca ea să afişeze la displayvalorile unui număr de tip longint ..Să se efectueze

următoarele operaţii asupra tipului longint:–  să se determine numărul de cifre din numărul dat,–  să se compare două numere longint ,–  să se extragă numerele de tip int din numărul

longint (partea inferioară şi partea superioară),–  să se efectueze operaţiile algebrice asupra

numerelor date,–  să se inverseze un număr de tip longint  (partea

inferioară cu cea superioară).112

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 111/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 112/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 113/166

listei şi funcţia showlist(). Creaţi clasa derivată stivacare moşteneşte list. Funcţia showlist() se va redefiniîn clasa derivată, astfel ca ea să afişeze la displayvalorile unei stive. Să se efectueze următoarele

operaţii asupra stivei:–  empty(S) care curăţă stiva S ,–  if_is_empty(S) care verifică dacă stiva S este vidă,–  pop(S,x) care adaugă elementul x în stiva S ,–  push(S,x) care scoate elementul x din stiva S ,–  error (k) care indică eroarea cu numărul k (k=1 dacă

stiva este supraîncărcată, k=2 dacă stiva este vidă).

15. Scrieţi un program care ar defini clasa de bază int.În această clasă determinaţi valorile întregi şifuncţia showdate().  Creaţi clasa derivată date caremoşteneşte int . Funcţia showdate() se va redefini înclasa derivată, astfel ca ea să afişeze la displayvalorile unei date. Să se efectueze următoareleoperaţii asupra datei:

– adunarea,

–  înmulţirea cu un coeficient,–  scăderea,–  împărţirea la un coeficient,–  valoarea datei calendaristice să se tipărească cu

cuvinte.

115

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 114/166

Lucrarea de laborator nr. 4.Tema: Clase derivate cu moştenire multiplă.

Scopul lucrării: familiarizarea studenţilor cu clasele

derivate cu moştenire multiplă.

Consideraţiile teoretice necesare:Moştenirea multiplă

Limbajul C++ permite crearea de clase care moştenescproprietăţile mai multor clase de bază. Dintr-o clasăde bază pot fi derivate mai multe clase şi fiecare

clasă derivată poate servi mai departe ca bazăpentru alte clase derivate. Se poate astfel realiza oierarhie de clase, care să modeleze adecvat sistemecomplexe. Pornind de la clase simple şi generale,fiecare nivel al ierarhiei acumulează caracteristicileclaselor "părinte" şi le adaugă un anumit grad despecializare. O clasă poate să moştenească simultanproprietăţile mai multor clase, procedură numită

moştenire multiplă. Construirea ierarhiei de clasereprezintă activitatea fundamentală de realizare aunei aplicaţii orientate obiect.

Moştenirea multiplă permite formarea uneiierarhiei de clase. Dacă derivarea normală duce laconstruirea unei ierarhii de tip arbore, derivareamultiplă va genera ierarhii de tip graf. Sintaxa

completă pentru operaţia de derivare esteurmătoarea:class NumeClasăDerivată : ListaClaseDeBază

unde ListaClaseDeBază este:SpecificatorAcces NumeClasaDeBază, ...Clase virtuale. Utilizarea moştenirii multiple se

poate complica odată cu creşterea dimensiuniiierarhiei de clase. O situaţie care poate apare este

derivarea din două clase de bază, Clasa1 şi Clasa2, care116

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 115/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 116/166

virtual virtual class B1 class B2

class C 

Întrebările pentru verificarea cunoştinţelor:1. Ce se numeşte moştenire multiplă? Daţi exemple.2. Ce se numeşte clasă virtuală? Daţi exemple.

Temele pentru acasă:1. Ce se va afişa la ecran după rularea programului

următor? #include <iostream.h>cassBl { public :Bl() { cout « "Constructorul B1 \n";}~B1() { cout « "Destructorul B1 \n";}class B2

{ int b;public :B2 ( ) { cout « "Constructorul B2\n"; }~B2 ( ) { cout « "Destructorul B2 \n"; }};// Moştenirea a două clase de bază

class D : public Bl, public B2

{ public:

KOHCTp

 

( cout « " 

cout «main (){ C ob;return 0;

118

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 117/166

D() { cout « "Constructorul D \n";}~D() { cout « "Destructorul D\n";}};void main()

{ D obj; }2. Care va fi rezultatul lansării programului de maijos? Corectaţi greşelile din program.

 #include <iostream.h>class A{ int i;public :Al(int a=0) { i=a;cout « "Constructorul A \n";}~B1() { cout « "Destructorul B1 \n";class B{ int j;public :B2 (int a=0 ) { j=a; cout « "Constructorul B2\n"; }~B2 ( ) { cout « "Destructorul B2 \n"; }};

// Moştenirea a două clase de bază

class C : public Bl, public B2{ int k,public:/* Scrieţi constructorul pentru clasa C astfel cael să activeze constructorii claselor de bază A şiB*/

c() { cout « "Constructorul D \n";

KOHCTp 

( cout « " cout «main (){ C ob;return 0;

119

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 118/166

~C() { cout « "Destructorul D\n";};void main(){ C obj; }

Temele pentru lucrări de laborator:1. La un depozit a fost adusă marfă de export =

{denumire, ţara de exportare, cantitatea, preţul,data livrării}. şi anume, procesor = {tip, viteza de lucru},monitor = {tipul, diagonala}, wincester = {firma, dimensiune}.Să se determine suma de bani necesară pentruachitarea mărfii aduse. Plata se efectuează în leiţinînd cont de cursul valutar  {valuta, data, vînzarea,cumpărarea}.

2. Să se efectueze următoarele operaţii asuprafigurilor geometrice: de rotire a figurii, de mutarepe ecran, de colorare, de decupare a unei părţi dinobiect, de a scrie text în figură. Figurile geometriceau următoarele structuri:. triunghi = {vîrfl, vîrf2, vîrf3},

dreptunghi ={vîrfl, vîrf2}, cerc = {centru, raza}, elipsa =(centru, raza1, raza2}.

3. Să se calculeze cît timp a trecut de la începutul ereinoastre. Structurile de bază sînt deceniu = {veac, era},timp = {ora, minutul, secunda}, data = {zi, luna, an}}.

4. Să se efectueze operaţii algebrice şi conversiiasupra următoarelor structuri: număr complex={partea reală, partea imaginară}, număr raţional= {numărător, numitor}, punct din plan ={coordonata x, coordonata y}.

5. Să se efectueze operaţii de conversie aurmătoarelor structuri: punct din scatiu ={ coordonata x, coordonata y. coordonata z} şicoordonate polare = {raza, unghiul}, unde unghi ={grad, minuta, secunda),

6. Într-un oraş a fost construit un centru de prestare a120

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 119/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 120/166

unde rulează filme. Filmele sunt înregistrate înbaza de date cu următoarea structură: film ={denumire, ţara, regizor, gen, anul filmării}.Fiecare cinematograf este înregistrat cu

următoarea structură = {denumire, telefon, adresa,numărul de locuri}. Să se determine care gen defilme este mai solicitat de vizitatoriicinematografele din Chişinău.

10. Hotelurile din Chişinău prestează servicii pentrumai multe persoane din mai multe ţări. Pentrufiecare hotel în baza de date se va introduce

următoarea structură {denumirea, adresa,numărul de telefon, numărul de stele}. Fiecarenumăr la hotel are structura: {număr , numelelocatarului, data sosirii, data plecării, costul}.Fiecare persoană este înregistrată la hotel: {ţara,strada, numărul casei, scara, apartamentul,numărul de telefon}. Să se determine din ce ţarăne vizitează mai mult.

11. La depozitele unor farmacii a fost adusă marfă deexport = {denumire, tara de exportare,cantitatea, preţul mărfii, data livrării}. Medicamentele

sînt înregistrate în baza de date cu următoareastructură: {denumire, tip, ambalaj, cantitate, cost}.Fiecare farmacie este pusă la evidenţă cuurmătoarea structură farmacie={număr, telefon,

adresă, deschiderea, închiderea farmaciei} . Mediculprescrie reţetă pacientului. Pacientul este înregistratla policlinică după următoarea structură: {nume,adresă, diagnostică, data îmbolnăvirii}. Pacientuldoreşte să cumpere aceste leacuri. Să se afleadresele farmaciilor unde sînt depozitatemedicamentele solicitate. Să se determine frecvenţade solicitare a medicamentelor.

12. Se se afle ruta cea mai optimală (din punct de vedere122

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 121/166

al costului, orei sosirii la destinaţie, timpului) dintredouă oraşe. Comunicarea între aceste două oraşeare loc cu autocarele ( autocar ={model, datafabricării, punctul de destinaţie, costul rutei ), cu trenul

(mersul trenurilor ={număr, destinaţie, ora plecării ,ora sosirii, categoria}), cu avionul (ruta de avion ={număr, destinaţia, ora decolării, ora aterizării} ).

13. La Universitatea Tehnică din Moldova sînt specialităţi lacare se învaţă obiecte ce ţin de informatică:specialitatea={facultatea, catedra, obiectul}, obiect ={denumire, an, tipul lecţiei, număr ore). Să se

determine din punct de vedere geografic cîţi studenţidin diferite judeţe la facultăţi au ore de informatică(studentul = {numele, grupa, data şi locul naşterii,media }.)

14. În Chişinău sînt multe muzee. Informaţia despre unmuzeu poate fi introdusă în următoarea structură:muzeu ={ denumire, adresa, telefon, î nceputul lucrului,sfîrşitul lucrului} . Pentru diferite categorii de vizitatori

(pensionari, studenţi, oameni maturi, copii mici,elevi) costul biletului de intrare este diferit. Să sedetermine frecvenţa de vizitate a muzeului ţinîndcont de numărul de bilete de intrare vîndute.Informaţia despre bilet are următoarea structurăbilet_de_intrare={muzeu, tip_bilet, costul}.

15. La aeroportul din Chişinău, la depozitul de lucruri

pierdute, se află bagaje uitate de pasageri. Fiecarebagaj este etichetat cu următoarea informaţie: bagaj= {număr rută, stăpîn, data, greutate}. Pentrurecuperarea bagajului uitat pasagerul trebuie săprezinte paşaportul (buletinul de identitate). Să sedetermine persoanele a cărei ţări mai des uităbagajul în aeroportul din Chişinău .

16. La o casă de vindere a imobilului se duce evidenţa

caselor (casa.={adresa, telefon, număr camere,123

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 122/166

cost, comodităţi}} şi a apartamentelor de vînzare(apartament.={adresa, telefon, număr camere, etaj,cost}). Să se determine cele mai solicitate tipuri devînzări efectuate de casa de vindere a imobilului.

Lucrarea de laborator nr. 5.Tema: Fluxurile Input şi Output standard şi definite deutilizatori. Formatarea fluxurilor numerice şi textuale.Fluxurile stringuri şi de memorie.

Scopul lucrării: familiarizarea studenţilor cu fluxurile

input şi output standard şi definite de utilizatori, cuformatarea fluxurilor numerice şi textuale, cufluxurile stringuri şi de memorie. 

Consideraţiile teoretice necesare:Noţiune de Fluxuri 

Limbajul C++ foloseşte conceptul abstract de stream(flux) pentru realizarea operaţiilor input/output. Dinpunctul  de vedere al limbajului C++, fluxul este oclasă în sens obişnuit. El oferă metode de scriere şicitire a datelor independente de dispozitivul I/O.Operaţiile de input/output se fac prin intermediul obiectelor detip flux. Acestea pot fi clasificate în funcţie dedispozitivul fizic asociat respectivei operaţii. Din acestpunct de vedere, limbajul C++ distinge trei categorii

de fluxuri:– input/output standard (de exemplu, tastatura şi ecranul);– input/output prin intermediul fişierelor;– input/output în memorie.

Fluxurile incapsulează (ascund) problemelespecifice dispozitivului cu care se lucrează, subbiblioteca standard iostream.h.. Biblioteca iostream.h. estescrisă însăşi în limbajul C++ şi este o bibliotecă aclaselor.

124

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 123/166

Alt avantaj al utilizării fluxurilor se datoreazăimplementării bibliotecii iostream.h, care utilizează unsistem de zone tampon. Operaţiile de intrare/ieşire cudispozitivele periferice sînt consumatoare de timp.

Informaţiile trimise către un flux nu sînt scriseimediat în dispozitivul în cauză, ci sînt transferateîntr-o zonă de memorie tampon, din care sîntdescărcate către dispozitiv în momentul umpleriiacestei zone de memorie.

In limbajul C++ fluxurile au fost implementateutilizînd clase, după cum urmează:

clasa streambuf  gestionează zonele tampon,clasa ios este clasa de bază pentru clasele defluxuri de intrare şi de ieşire. Clasa iosare ca variabilă membru un obiect detip streambuf,

clasele istreamşi ostream

sînt derivate din ios,

clasa iostream este derivată din istream şi ostream şi

oferă metode pentru lucrul cuterminalul,

clasa fstream oferă metode pentru operaţii cufişiere.

.Obiecte standard. La lansarea în execuţie a unuiprogram C++, care include iostream.h, in mod automatcompilatorul limbajului C++ creează şi iniţializează

patru obiecte:cin gestionează intrarea de la intrarea standard(tastatura),

cout  gestionează ieşirea către ieşirea standard(ecranul),

cerr  gestionează ieşirea către dispozitivul standardde eroare (ecranul), neutilizînd zone tampon,

clog  gestionează ieşirea către dispozitivul standard

de eroare (ecranul), utilizînd zone tampon125

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 124/166

Expresia "cout «" se utilizează pentru afişareadiverselor valori. De fapt, cout  este un obiect de tip flux, şianume obiectul “flux standard output ”. Operaţia output (afişare) se realizează prin intermediul operatorului

supraîncărcat «.Obiectul de tip flux standard input  este cin, iar operaţia

input (citirea) se realizează prin intermediul operatoruluisupraîncărcat ». Obiectele cout  şi cin sînt declarate înbiblioteca iostream.h.

Redirectări. Dispozitivele standard de intrare,ieşire şi eroare pot fi redirectate către alte dispozitive.

Erorile sînt, de obicei, redirectate către fişiere, iarintrarea şi ieşirea pot fi conduse ("piped ") către fişiereutilizînd comenzi ale sistemului de operare (utilizareaieşirii unui program ca intrare pentru altul). Sintaxapentru operaţii de ieşire, cout :

cout << InformatieDeTrimisLaIesire;Respectiv pentru intrare, cin:

cin >> NumeVariabilă;

De fapt, cin şi cout sînt nişte obiecte definite global, careau supraîncărcat operatorul >> respectiv << de mai multeori, pentru fiecare tip de parametru în parte (int , char *, etc.):

istream &operator >> (TipParametru &)De exemplu:#include <iostream.h>void main(){int IntegerNumber=50;cout << "IntegerNumber = "; cin >> IntegerNumber;cout<<"\nWhat you entered = "<<IntegerNumber<<endl;}Rezultatul îndeplinirii programului:IntegerNumber = 200What you entered = 200

Acest scurt program citeşte de la intrarea standard o

valoare întreagă, pe care o trimite apoi către ieşirea126

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 125/166

standard. Se observă posibilitatea de a utilizasimbolurile '\n', '\t ', s.a.m.d (ca la printf , scanf , etc.). Utilizareasimbolului endl  va forţa golirea zonei tampon, adicătrimiterea datelor imediat către ieşire.

Atît operatorul >>, cît şi << returnează o referentăcătre un obiect al clasei istream. Deoarece cin, respectivcout, este şi el un obiect istream, valoarea returnată de ooperaţie de citire/scriere din/în stream poate fi utilizatăca intrare/ieşire pentru următoarea operaţie deacelaşi fel.

Operaţia de intrare cin. Funcţia cin.get()

poate fi utilizată pentru a obţine un  singur   caracter dinintrare, apelînd-o fără nici un parametru, caz în carereturnează valoarea utilizată, sau ca referinţă la uncaracter.

get(); // fără parametriÎn această formă, funcţia întoarce valoareacaracterului găsit. Spre deosebire de operatorul >>,funcţia nu poate fi utilizată pentru a citi mai multe

intrări, deoarece valoarea returnată este de tipîntreg, nu un obiect istream. Un exemplu de utilizare:

#include <iostream.h>void main(){char c;while((c = cin.get()) != ‘*’){cout << "c = " << c << endl;}}Rezultatul îndeplinirii programului:asdfgh*c = ac = sc = d c = f c = g 

c = h127

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 126/166

Citirea de şiruri de caractere utilizînd get(). Operatorul >> nu poate fi utilizat pentru a citicorect şiruri de caractere de la intrare, deoarecespaţiile sînt interpretate ca separator între diverse

valori de intrare. În astfel de cazuri trebuie folosităfuncţia get(). Sintaxa de utilizare a funcţiei get  în acestcaz este următoarea:

cin.get(char *PointerLaSirulDeCaractere, int Lungime Maximă, char Sfîrşit);

Primul parametru este un pointer la zona de memorieîn care va fi depus şirul de caractere. Al doilea

parametru reprezintă numărul maxim de caractere cepoate fi citit plus unu. Cel de-al treilea parametrueste caracterul de încheiere a citirii, care esteopţional (implicit considerat '\n').

În cazul în care caracterul de încheiere esteîntîlnit înainte de a fi citit numărul maxim decaractere, acest caracter nu va fi extras din flux.Există o funcţie similară funcţiei get(), cu aceeaşi

sintaxă, numită getline(). Funcţionarea sa este identicăcu get(), cu excepţia faptului că acel ultim caractermenţionat mai sus este şi el extras din flux.

Funcţia cin.ignore() se utilizează pentru atrece peste un număr de caractere pînă la întîlnireaunui anume caracter. Sintaxa sa este:cin.ignore(int NumărMaximDeCaractere, char Sfîrşit);

Primul parametru reprezintă numărul maxim decaractere ce vor fi ignorate, iar al doilea parametru –caracterul care trebuie găsit.

Funcţia cin.peek() returnează următorulcaracter din flux, fără însă a-l extrage.

Funcţia cin.putback() inserează în flux uncaracter.

cout . Funcţii membri ale cout 

Funcţia cout.flush()) determină trimiterea128

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 127/166

către ieşire a tuturor informaţiilor aflate în zona dememorie tampon. Această funcţie poate fi apelată şiîn forma cout << flush.

Funcţia cout.put()) scrie un caracter către

ieşire. Sintaxa sa este următoarea:cout.put(char Caracter);

Deoarece această funcţie returnează o referinţă detip ostream, pot fi utilizate apeluri succesive ale acesteia, ca înexemplul de mai jos:

#include <iostream.h>void main(){cout.put('H').put('i').put('!').put('\n');}Funcţia cout.write() are acelaşi rol ca şi

operatorul <<, cu excepţia faptului că se poatespecifica numărul maxim de caractere ce se dorescscrise. Sintaxa funcţiei cout.write() este:

cout.write(char *SirDeCaractere, int CaractereDeScris);Formatarea ieşirii Funcţia cout.width() permite modificarea

dimensiunii valorii trimise spre ieşire, care impliciteste considerată exact mărimea cîmpului în cauză. Eamodifică dimensiunea numai pentru următoareaoperaţie de ieşire. Sintaxa este:

cout.width(int Dimensiune);Funcţie cout.fill() permite modificarea

caracterului utilizat pentru umplerea eventualuluispaţiu liber creat prin utilizarea unei dimensiuni maimari decît cea necesară ieşirii, cu funcţia cout.width().Sintaxa acesteia este:

cout.fill(char Caracter);Opţiuni de formatare a ieşirii. Pentru

formatarea ieşirii sînt definite două funcţii membri alecout , şi anume:

Funcţia cout.setf() activează o opţiune de

formatare a ieşirii, primită ca parametru:129

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 128/166

cout.setf(ios::Opţiune);unde Opţiune poate fi:

Showpos determină adăugarea semnului plus(+) în faţa valorilor numerice pozitive;

left , right ,internal 

schimbă alinierea ieşirii (la stînga. Ladreapta, centrează);

dec, oct , hex schimbă baza de numeraţie pentruvalori numerice;

showbase determină adăugarea identificatoruluibazei de numeraţie în faţa valorilornumerice.

Funcţia cout.setw() modifică dimensiuneaieşirii, fiind similară funcţiei cout.width(). Sintaxa sa este:cout.setw(int Dimensiune);

În continuare vom exemplifica utilizarea funcţiilorpentru formatarea ieşirii:

#include <iostream.h>#include <iomanip.h>void main()

{int number = 783;cout << "Număr = " << number<<endl;cout.setf(ios::showbase);cout<<"Număr în sistem hexazecimal =

"<<hex << number<<endl;cout.setf(ios::left);cout << "Număr în sistemul octal, aliniat la

stînga = " << oct << number<<endl;}Rezultatul îndeplinirii programului:

Număr = 783Număr î n sistem hexazecimal = 0x30f Număr în sistemul octal, aliniat la sîinga = 01417

Redefinirea operatorilor de intrare şi ieşire pentru fluxul standard. Operatorii de

intrare şi ieşire pentru fluxul standard pot fi redefiniţi130

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 129/166

pentru citirea şi înregistrarea obiectului de tipul claseidefinite de utilizator.

Operatorul de intrare a fluxului standard pentru un obiectdin clasa obj se redefineşte în modul următor:

istream & operator >> (istream &s, class obj){ / /citirea componentelor din clasa objreturn s; }Operatorul de ieşire a fluxului standard pentru

un obiect din clasa obj se redefineşte în modulurmător:

ostream & operator<< (ostream &s, class obj){ // tipărirea componentelor din clasa objreturn s; }

De exemplu, vom redefini operatorii menţionaţi pentruclasa persoana.

# include <stdio.h># include <iostream.h># include <string.h>class persoana

{ private:char nume[40];char prenume[40];long int telefon;int virsta;

public:persoana(char *Nume=NULL, char *n=NULL, int v=0,

long int t=0)

{strcpy(nume,Nume); strcpy(prenume,n);virsta=v; telefon= t; }

friend istream & operator >> (istream &s, persoana &P);friend ostream & operator<< (ostream &s, persoana &P);void set(char* Nume, char *n, int v, long int t)

{strcpy(nume,Nume); strcpy(prenume,n);virsta=v; telefon= t; };

};131

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 130/166

istream & operator >> (istream &s, persoana &P){ if((s >>P.nume) && (s >>P.prenume) &&

(s >>P.virsta) && (s >>P.telefon))P.set(P.nume,P.prenume,P.virsta, P.telefon);

return s; }ostream & operator << (ostream &s, persoana &P){return(s<<P.nume<<' '<<P.prenume<<' '<<P.virsta<<

' '<<P.telefon);}void main(){ persoana p;

cout<<"Introdu datele despre persoana:"<<endl;cin >>p; cout<< p;

}Rezultatele îndeplinirii programului:

Introdu datele despre persoana:BraduMaria20

123456 Bradu Maria 20 123456 Operaţii de intrare/ieşire cu fişiere. În

afară de fluxurile standard input/output se pot defini fluxuri aleutilizatorului definite prin:ifstream nume pentru un flux input (citire),ofstream nume pentru un flux output (scriere),fstream nume flux utilizat şi pentru citire şi

pentru scriere în oricare din cazurile de maisus.

Numele va fi un obiect de tipul claseicorespunzătoare. Lucrul cu fişierele se face prinintermediul clasei ifstream pentru citire, respectiv ofstreampentru scriere. Pentru a utiliza fişiere, aplicaţiiletrebuie să includă fstream.h. Clasele ofstream şi ifstream sînt

derivate din clasa iostream, ca urmare toţi operatorii şi132

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 131/166

toate funcţiile descrise mai sus sînt moştenite şi deaceastă clasă.

Definirea fluxurilor se poate face numai prinincluderea în program a fişierului fstream.h. ifstream,

ofstream şi fstream sînt clase. Declararea unui flux alutilizatorului este o declarare a unui obiect din clasarespectivă. Clasele pot conţine atît date, cît şimetode (funcţii). Operaţiile input/output se fac prinintermediul unor funcţii membri ale claselorrespective. Sintaxele pentru constructorii acestordouă clase sînt:

ofstream Variabila(char *NumeFişier, ios::Mod);ifstream Variabila(char *NumeFişier);Funcţia de deschidere a unui stream este funcţia

open. Fiind o funcţie membru, ea va fi apelată numaiprin intermediul unui obiect declarat de tipul uneiadin clasele de mai sus. De exemplu:

#include<fstream.h>void main()

{ ofstream scriere;scriere.open(“disk.dat");scriere.close();}

Programul de mai sus exemplifică faptul, că nu existănici o diferenţă între lucrul obişnuit cu clase şidefinirea unui flux output. Astfel, variabila scriere a fostdeclarată ca fiind de tipul (clasa) ofstream. Definiţiaclasei ofstream poate fi găsită în fişierul fstream.h.Funcţia membru open, apelată prin intermediulobiectului scriere, creează un fişier cu numele disk.dat .În continuare acesta este închis prin apelul funcţieimembru close(), prin intermediul obiectului scriere. Execuţiaprogramului va determina crearea unui fişier, care,însă nu va conţine nimic. Scrierea propriu-zisă se face

cu operatorul (supraîncărcat) «, iar citirea cu operatorul », – 133

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 132/166

la fel ca în cazul fluxurilor standard input/output.Ideea de a utiliza noţiunea abstractă de flux s-a

impus din dorinţa de a asigura independenţaoperaţiilor input/output faţă de calculator sau de

sistemul de operare. Producătorii de compilatoarelivrează (împreună cu compilatorul) biblioteci, careconţin clase, funcţii, variabile, care permit ca, în maremăsură, această independenţă să fie asigurată.

Funcţia open are primul parametru de tip şir decaractere modificată prin modificatorul const. Acestareprezintă numele fişierului, care va fi asociat

fluxului. Al doilea parametru specifică modul de accesla fişierul asociat fluxului şi poate avea următoarelevalori:ios:: app; accesul se face prin adăugare la

sfîrşitul fişierului,ios:: ate; poziţionarea se face la sfîrşitul

fişierului,ios:: binary; fişierul este interpretat ca fişier binar,

ios::in; se asociază unui flux de intrare,ios::out; se asociază unui flux de ieşire,ios::nocreate; fişierul trebuie să existe deja,ios::noreplace; fişierul trebuie să nu existe,ios::trunc; distruge un fişier preexistent, avînd

acelaşi nume.Aceşti constructori au rolul de a deschide fişierul

specificat ca parametru.Valorile de mai sus sînt constante definite în clasa ios,definite în fişierul ifstream.h. Al treilea parametru este ignoratîn cazul în care parametrul al doilea este ios :: nocreate.

Caracteristicile de tip text  şi binary (binar) trebuieprivite în legătură cu operatorii folosiţi în operaţiileinput/output. Operatorii, pe care i-am folosit pînăacum ( « şi »), utilizează codificarea ASCII a datelor.

De exemplu:134

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 133/166

#include<fstream.h>void main(){ofstream s1;s1.open("dl.dat",ios::binary);

s1<<"text \n"<<12<<"\n"<<4.2;s1.close();ofstream s2("d2.dat");s2<<"text \n"<<12<<"\n"<<4.2;s2.close ();}Rezultatul îndeplinirii programului:Conţinutul fişierului “d1.dat”:text 124.2Conţinutul fişierului “d2.dat”:text 124.2

Funcţiile specializate pentru operaţii input/output,care realizează copii ale memoriei, sînt read şi write.Funcţiile read şi write.

Funcţia write scrie într-un fişier conţinutul uneizone de memorie, care trebuie să fie adresată printr-un pointer de tip caracter. 0 zonă de memorie poate fiprivită ca un şir de octeţi, indicat prin adresă deînceput şi lungime. De exemplu:

#include<fstream.h>void main (){ofstream s1;int i;s1. open ("d1. dat", ios:: binary) ;s1.write((char *) &i, sizeof(i)) ;s1.write("\n",4) ;

s1.close();135

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 134/166

ofstream s2;s2.open("d2.dat");s2.write((char *) &i, sizeof(i));s2. write (" \n", 4);

s2. close ();}

Funcţia de conversie (char *) se utilizează pentru aconverti adresele oricăror obiecte la tipul adresă decaracter. Astfel, se poate de interpretat orice adresădin memorie ca fiind adresa unui şir de caractere.Operatorul sizeof  se utilizează pentru determinarealungimii acestei zone de memorie.

Citirea unui fişier, utilizînd funcţia read , se facerespectînd aceleaşi principii ca în cazul funcţiei write.

Diferenţa între fişierele de tip text  şi binary sepăstrează şi în cazul utilizării funcţiilor read  şi write şiconstă în reprezentarea diferită a caracterelor decontrol. De exemplu:

#include<fstream.h>

void main(){char *p=''\n";ofstream s1;s1.open("d1.dat",ios::binary);s1.write(p,sizeof(p));s1.close();ofstream s2;s2.open("d2.dat") ;s2,write(p,sizeof(p));s2.close() ;}Reprezentarea datelor într-un fişier depinde

exclusiv de funcţiile care se utilizează pentruînregistrarea (<< sau write) respectiv, citirea acestora (>> sauread ).

De cîte ori citim un fişier, despre care ştim cum a136

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 135/166

fost creat, este bine să-l citim cu aceleaşicaracteristici şi cu aceeaşi operatori. Cînd vrem săcitim din fişier, despre care nu ştim cum a fost creat,este bine să-l citim în mod binar, caracter cu

caracter. De exemplu:#include<fstream.h>void main(){int i,j; float k;char p[10];ofstream s1;s1.open("d1.dat") ;s1« 122 « "\n" « 147;s1« "\n abcd\n" « 9.3;s1.close();ofstream s2;s2.open("d.dat",ios::binary);s2 « i « 3 « p « k;s2.close();}

Rezultatul îndeplinirii programului:În fişierul textual “d1.dat” s-a înscrisurmătoarele

122147 abcd 9.3

În fişierul binar s-a înscris următoarele:102273BO39¤ _3.138909e-42În alt exemplu:

#include<fstream>.h>void main(){ char p[20];ifstream s;s.open("d.dat",ios::binary);

s.read(p,19);137

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 136/166

s.close();p[19]=NULL; cout « p;}

fişierul creat poate fi citit în mod binar, utilizînd

funcţia read . În acest mod conţinutul fişierului esteconsiderat copia unei zone de  memorie. Deoarecefişierul a fost creat printr-o codificare ASCII,conţinutul acestuia se ia ca un şir de caractere.Instrucţiunea read copie conţinutul fişierului în şirul decaractere p. Ultima instrucţiune din programul de maisus afişează la ieşirea standard conţinutul vectoruluip. Atribuirea explicită p[19]=NULL este obligatoriepentru a marca sfîrşitul şirului de caractere.

Pentru a închide aceste fişiere, trebuie apelatăfuncţia membru close().

Fluxuri în memorie constituie o interfaţă întreprogram şi un dispozitiv fizic. Am utilizat fluxurilestandard şi operatorii «, » şi, de asemenea, fluxurileasociate cu fişiere. Există posibilitatea de definire a unor 

fluxuri în memorie. Acestea sînt fişiere, care fizic sîntlocalizate în memorie. Un flux în memorie este un şirde caractere, care are exact aceeaşi structură ca unfişier obişnuit. Clasele, care definesc aceste fluxuri,sînt:istrstream(input string stream); flux input,ostrstream(output string stream); flux output,strstream (string stream); flux input/output.

Funcţii de formatare. Clasele bazate pefluxuri conţin o serie de funcţii, care oferă o mareflexibilitate a operaţiilor de scriere cu formatare.Pentru datele numerice cele mai importante sîntfuncţiile, care permit tipărirea într-un cîmp delungime fixă, alinierea (la stînga sau la dreapta) şiprecizia, cu care se face afişarea.

Funcţia width stabileşte dimensiunea cîmpului,138

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 137/166

calculată în caractere, pe care se va face scrierea.Funcţia are un singur parametru de tip întreg şitrebuie apelată prin intermediul unui obiect de tipflux. Astfel, obiectul de tip flux în memorie, declarat

prin simbolul a, va avea funcţia asociată a. width, princare am cerut ca fiecare dată, să fie înregistrată într-un cîmp format din 8 caractere.

Funcţia setf  are, de asemenea, un singur parametru încazul dat ios::right , avînd semnificaţia de aliniere ladreapta.

Funcţia precision are un singur parametr u de tip

întreg, prin care se specifică numărul de poziţii, scrisedupă punctul zecimal. De exemplu:#include<fstream.h>#include<strstream.h>void main (){ float a[4][5];int i, j;for ( i=0; i<4; i++)

for ( j=0; j<5; j++)a[i][j]=(float) (i+2)/(j+1);

char s[200];ostrstream scrie(s,sizeof(s));for ( i =0; i<4; i++){for ( j=0; j<5; j++){scrie.width(8);scrie.setf(ios::right);scrie.precision(2);scrie << a[i][j];}scrie << "\n";};s[164]=NULL;cout << s;

}

Rezultatul îndeplinirii programului:139

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 138/166

2 1 0.67 0.5 0.43 1.5 1 0.75 0.64 2 1.33 1 0.85 2.5 1.67 1.25 1

În programul de mai sus parametrul funcţiei precisioneste 2, deci numerele vor fi scrise cu două semnezecimale. Programul reprezintă un bun exemplu, princare putem scoate în evidenţă utilitatea fluxurilor dememorie.

Rezultatul operaţiilor de intrare/ieşire poate fitestat prin intermediul a patru funcţii membri:

–  eof() verifică dacă s-a ajuns la sfîrşitulfişierului;

–  bad() verifică dacă s-a executat o operaţieinvalidă;

–  fail() verifică dacă ultima operaţie a eşuat;–  good() verif ică dacă toate cele trei rezultate

precedente sînt false.Funcţiile de formatare pot fi aplicate oricărui

obiect de tip flux, fie că este un flux standard, un fluxde tip fişier sau un flux în memorie.

Întrebările pentru verificarea cunoştinţelor:1. Care sînt tipurile de fluxuri standard

definite de utilizator?2. Scrieţi un exemplu de

utilizare a funcţiilor read  şiwrite a conţinutului unei zonede memorie.

3. Definiţi parametrii funcţieimembru open ale unei clase flux.

4. Cum se definesc fluxurile dememorie?

5. Care sînt funcţiile de

formatare pentru fluxuri?140

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 139/166

Temele pentru acasă:1. Corectaţi greşelile şi lansaţi următoarele exemplela execuţie. Ce rezultate vor apărea pe ecran?

Exemplul 1:#include <iostream.h>define N 80void main(0{ inc c;int cnt=0; charcnt=0;While(1)

{ c=cin.get();if (c==EOF) break;if (c=’/’ && cin.peek() ==’/’)

{ cnt++;cin.ignore(n,”\n”);charcnt++=cin.gcount();charcnt++;}

}cout<<”In” << cnt << “ comentarii avem ” << charcnt << “caractere”;}

Exemplul 2 .#include <iostream.h>void main(){While(1)

{ char c; cin.get©;if(cin.eof()) break;cout.put( c);

}Exemplul 3.

#include <iostream.h>void main()

{cout <<setfill(‘%’}<<setw(4)<< 17;}141

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 140/166

Exemplul 4.#include <iostream.h>#include <fstream.h>void main()

{ int I=42;fstream f (“dat.txt”,ios::out|ios::binary);f.seekp(17,ios::beg);f.write((const char*)&I,2) ;f.close();f.open(“dat.txt”, ios::in|ios::binary);f.seekg(17,ios::beg);f,read((char*)&I,2);f.close();cout<<I;}

Exemplul 5.#include <iostream.h>#include <strstream.h>void main()

{char buffer [80];strstream s (buffer,80,ios::out);float pret=123.45;s<<”Preţ ul stocului este de”;s;;serw(6)<<setprecision(2) ;}

Temele pentru lucrări de laborator:

1. Scrieţi un program care compară două fişiere date.2. Scrieţi un program care calculează numărul de

elemente ale unui fişier care sînt mai mici cavaloarea medie aritmetică a tuturor elementeloracestui fişier.

3. Scrieţi un program care tipăreşte toate cuvintelediferite de ultimul cuvînt dintr-un fişier. Cuvintele

din fişier sînt separate prin virgulă, iar.după142

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 141/166

ultimul cuvînt se pune punct.4. Scrieţi un program care determină numărul

maximal şi cel minimal dintr-un şir de 100 denumere aleatoare dintr-un fişier.

Subconsecutivitatea de elemente dintre numărulmaximal şi cel minimal determinat să seînregistreze într-un nou fişier.

5. Scrieţi un program care formează un fişier noudupă următoarea legitate: din trei fişiere date maiîntîi se selectează numerele divizibile la 3, la 5 şi la7, apoi numerele pozitive pare de pe locuri impare.

6. Scrieţi un program care formează un fişier noudupă următoarea legitate: din trei fişiere date maiîntîi se selectează numerele negative, zerourile,apoi numerele pozitive.

7. Scrieţi un program care ordonează lexicografic oconsecutivitate de înregistrări (dintr-un fişier) detipul 

struct { char nume [30];

int ani} înregistrare;Rezultatul ordonării să se înscrie într-un nou fişier.

8. Scrieţi un program care din două fişiere ordonatedescrescător se va forma unul în care se va păstraordinea descrescătoare de sortare.

9. Scrieţi un program care sortează lexicograficcuvintele dintr-un text. Pentru fiecare element

sortat să se indice numărul de repetări alecuvîntului în textul dat.10. Scrieţi un program care calculează suma înmulţirii

numerelor vecine pe pe locuri pare dintr-un fişierdat.

11. Scrieţi un program care va tipări în ordine inversăsubconsecutivitatea de numere dintre valoareaminimă şi maximă ale unei consecutivităţi de

numere citite dintr-un fişier.143

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 142/166

12. Scrieţi un program care formează un fişier nou dincel dat după următoarea legitate: elementelefişierului nou se obţine din inversul numerelor dinfişierul dat.

13. Scrieţi un program care determină frecvenţa cucare a fost generat fiecare element în fişieruluicreat. Valorile elementelor sînt cuprinse între 1 şi100.

14. Scrieţi un program care determină numărulmaximal şi cel minimal din numerele unui fişierdat. Să se determine elementele mai mari ca cel

minimal şi mai mici ca numărul maximal.15. Scrieţi un program care efectuează reformatareaunui fişier textual în felul următor. Lungimearîndului de caractere în fişierul nou are lungimeade 60 de caractere. Dacă în rîndul dat sedepistează punctul, restul rîndului din fişierul dat sescrie din rînd nou.

16. Scrieţi un program care din două fişiere date

ordonate crescător se va forma unul nou, în carese va păstra ordinea crescătoare de sortare.

Lucrarea de laborator nr. 6.Tema:Templates: Template pentru clase şi funcţii. 

Scopul lucrării: familiarizarea studenţilor cu clase şi

funcţii generice.

Consideraţiile teoretice necesare:Clase şi funcţii generice

Template-ul  implementează aşa-zisul concept de"tip parametrizat " ("parametrized type"). Un templatereprezintă o familie de tipuri sau funcţii, cu altecuvinte, un şablon sau model. Acest concept a fostintrodus, în primul rînd, pentru a creşte gradul de

144

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 143/166

reutilizare a codului. De exemplu, pentru aimplementa o listă de numere întregi este necesarărealizarea unei clase speciale (să spunemListOfIntegers), iar pentru o listă de şiruri altă clasă (să

spunem ListOfStrings). Conceptul de template permiterealizarea unei clase generale (să spunem List ), caresă accepte orice tip de element, inclusiv tipurinecunoscute la momentul implementării acesteia.Tipul template este stabilit în momentul instanţieriisale. Template-urile sînt foarte utile pentru realizareade biblioteci care trebuie să ofere metode generice

de prelucrare a datelor. Sintaxa generală dedeclarare a unui template este următoarea:template < ListaDeParametri > Declaraţie

unde Declaraţie reprezintă declararea sau definireaunei clase sau unei funcţii, definirea unui membrustatic al unei clase template, definirea unei clase saufuncţii membri al unei clase template, sau definireaunui membru template al unei clase.

Clasele parametrizate (sau clasele template) sedeclară astfel:template <class NumeParametru>class NumeClasa{ // ...// definirea clasei}

Stabilirea tipului clasei template se face prin intermediulunei construcţii de genul:

NumeClasa <NumeParametru>unde NumeParametru reprezintă tipul obiectului.

Funcţiile template se declară astfel:template <class NumeParametru>// ...

// decl araţia funcţiei145

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 144/166

Să considerăm în continuare ca exempluimplementarea unei stive generice folosind template-uri.

#include <iostream.h>

template <class T> class StackItem{ public:

StackItem *Next;Tip *Data;StackItem(Tip Data_new, StackItem <Tip> *Next_new){ Data = new Tip(Data_new);

Next = Next_new; }};template <class Tip> class Stack {public:

Tip pop(){ Tip result = *(Data->Data);

StackItem <Tip> *temp = Data;Data = Data->Next;delete temp;

return result;}Tip top(){ return *(Data->Data); }void push(Tip Data_new){ Data = new StackItem <Tip>(Data_new, Data); }int isEmpty(){ return Data == 0; }

Stack(){ Data = 0; }

private:StackItem <Tip> *Data;

};void main(){ Stack <int> anIntegerStack;

anIntegerStack.push(5);146

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 145/166

anIntegerStack.push(7);if(anIntegerStack.isEmpty())

cout << "Stiva goala" << endl;else

cout << anIntegerStack.pop() << endl;cout << anIntegerStack.top() << endl;

}Rezultatul îndeplinirii programului:7 5În exemplul următor a fost implementată o listă

generică (List ). Ca elemente a listei s-au folosit obiecte de tipPoint. Pentru parcurgerea uşoară a listei a fostimplementată o clasă de tip "iterator ", care poate ficonsiderată ca fiind un "cursor" care străbate lista.Funcţia List.begin() returnează un iterator poziţionat peprimul element al listei, List.end() pe ultimul element allistei. Saltul la următorul element al listei se face cuajutorul operatorului ++ din clasa Iterator .

#include <iostream.h>class Point {friend ostream& operator << (ostream& output, Point p);protected:unsigned x, y;public:Point() {x = 0;y = 0;}Point(unsigned X, unsigned Y) {x = X;y = Y;}~Point() {}unsigned GetX() {return x;}unsigned GetY() {return y;}void SetX(unsigned X) {x = X;}void SetY(unsigned Y) {y = Y;}};ostream& operator << (ostream& output, Point p){output<<"(" << p.x <<", " << p.y << ")"; return

output;}147

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 146/166

template <class Tip> class Item{public:Item *Next;Tip *Data;

Item(Tip __Data, Item <Tip> *__Next){Data = new Tip(__Data); Next = __Next;}};template <class Tip> class List {public:Tip pop_front(){Tip result = *(Data->Data);Item <Tip> *temp = Data;Data = Data->Next;delete temp;return result;}Tip front() {return *(Data->Data);}void push_front(Tip __Data){Data = new Item <Tip>(__Data, Data);}int empty() {return Data == 0;}

List() {Data = 0;}class Iterator { friend class List <Tip>;protected:Item <Tip> *Current;Iterator(Item <Tip> *x) {Current = x;}public:Iterator() {}

int operator == (Iterator& x){return Current ==x.Current;}int operator != (Iterator& x){return Current != x.Current;}Tip operator *(){return *(Current->Data);}Iterator& operator ++(int){Current = Current->Next; return *this;}};

Iterator begin(){return Iterator(Data);}148

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 147/166

Iterator end(){Item <Tip> *temp;for(temp = Data; temp; temp = temp->Next);return Iterator(temp);}

private:Item <Tip> *Data;};void main(){List <Point> anPointList;List <Point>::Iterator index, end;anPointList.push_front(Point(1, 1));anPointList.push_front(Point(3, 14));index = anPointList.begin(); end = anPointList.end();if(anPointList.empty()) cout << "Lista vida" << endl;elsefor(; index != end; index++)cout << *index << " ";cout << endl;}

Rezultatul îndeplinirii programului:(3, 14 ) (1, 1)Clasele template pot avea trei tipuri de prieteni (friends):

–  o clasă sau funcţie care nu este de tiptemplate;

–  o clasă sau funcţie template;–  o clasă sau funcţie template avînd tipul

specificat.

Dacă este necesară particularizarea unei funcţiitemplate sau a unei funcţii membri a unei clasetemplate pentru un anumit tip, funcţia respectivăpoate fi supraîncărcată pentru tipul dorit.

Trebuie de remarcat, de asemenea, că în cazulîn care o clasă template conţine membri statici, fiecareinstanţă a template-ului în cauză va conţine propriile

date statice.149

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 148/166

Întrebările pentru verificarea cunoştinţelor:1. Ce

reprezintă

untemplate?Daţiexemple defuncţietemplate,clasătemplate.

2. Care estecorelaţiadintre clasederivate şiclasetemplate?

3. Pot oare fi

redefinitefuncţiiletemplate?

4. Clasele template pot avea trei tipuri de prieteni (friends). Caresînt ele? Daţi exemple.

Temele pentru acasă:1. Ce efectuează următoarea funcţie template?

template <class X> void swap(X &a, X &b){X temp; temp=a; a=b; b=temp;}void main(){int 1=10, j=20;float x=10.1, y=23.3;cout<<”Valorile i, j sînt:”<< i << ' '<< j << endl;cout<<”Valorile х, у sînt”<< x<< ' '<< у <<endl;

swap(i,j); swap (x,y); // schimb de variabile150

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 149/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 150/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 151/166

Această problemă poartă denumirea de problemăde sortare a consecutivităţii care poate fi aranjatăşi în ordine descrescătoare: a1 ≥  a2 ≥  …≥  an.; dacănumerele două cîte două sînt diferite,consecutivitatea poate fi aranjată în creştere saudescreştere. Să se cerceteze consecutiv a2, …, an şifiecare element nou ai inclus la locul potrivit înconsecutivitatea deja sortată a1, …, ai-1. Acest loc sedetermină prin compararea consecutivă aelementului ai cu elementele sortate a1, …, ai-1 .

4. Să se cerceteze şi să se calculeze numărul decomparări şi de schimbări (adică permutări dintr-unloc în altul) ale elementelor a1, …, an în procesul deutilizare a algoritmilor descrişi în varianta 1. Să sedemonstreze că numărul de schimbări pentrualgoritmul de sortare prin selectare este mărginitde o funcţie liniară de n. În acelaşi timp şi numărulde comparări pentru algoritmul de sortare prin

selectare şi pentru algoritmii de sortare prininterclasare şi prin inserţie, în unele cazuri, (deexemplu, dacă consecutivitatea iniţială este detipul a1>a2>…>an) sînt funcţii pătratice de n.

5. Din definiţia problemei din punctul 1 rezultă căalgoritmul de sortare prin selectare se deosebeştede celălalţi algoritmi în acele cazuri cînd

schimbarea locului elementului este cu mult maidificilă decît compararea elementelor. Să seutilizeze acest fapt la executarea următoarelorprobleme. Se dă un obiect matrice de numerereale de dimensiunea n× m; să se sorteze (să seschimbe cu locul) liniile matrice:

а) după creşterea valorilor primelor elemente aleliniilor matricei;

b) după descreşterea sumelor elementelor liniilor153

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 152/166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 153/166

schimbare hotarul de jos, iar hotarul de sus seschimbă cu s. Cînd valorile hotarelor coincid, fiindegale cu careva număr t , executarea algoritmuluidescris se finalizează cu rezultatul t . (Numărul de

comparări necesare pentru acest algoritm nuexcedă [log 2 (n +1)]+1)

a) Sunt date numere reale a1, …, an, b1, …, bm (a1 ≤ 

a2≤  …≤  an). Să se obţină numerelenaturale k 1, …, k m astfel, încît k i – să fie soluţiaproblemei căutării locului bi printre a1, …, an

(i= 1, ..., m). Să se utilizeze algoritmulcăutării binare.

b) Tabelul de cîştiguri a loteriei este reprezentat printabelul de numere cîştigătoare a1, …, an şi tabelul decîştiguri în lei p1, …, pn (pi este cîştigul pentrunumărul ai (i = 1, ..., n)). Să se determine sumacîştigurilor pentru biletele cu numerele b1, …, bm. Să

se utilizeze algoritmul căutării binare.c). Fie locul numărului b printre cele aleconsecutivităţii sortate crescător a1, … , an se vaalege ca cel mai îndepărtat loc de la începutulconsecutivităţii neafectînd legitatea sortăriicrescătoare. Să se introducă schimbări îndescrierea algoritmului de împărţire în jumătăţi şirespectiv să se rezolve problema a).

7. Căutare binară. Fie T[1..n} un vector sortat crescătorşi x un obiect care se află printre obiectele lui T. Săse determine locul lui x în T. Consecutivitatea seorganizează în formă de listă dublu lănţuită. Să sefolosească algoritmul de sortare a vectorului T[1..n], divizîndu-lîn doi vectori F  şi V, sortîndu-i pe aceştia şi apoiinterclasîndu-i (amestecîndu-i).

8. Se presupune că numerele a1, …, an sînt elementele155

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 154/166

unui fişier. Valoarea n nu se cunoaşte. Să serezolve următoarele probleme: să se afle valoareamaximală din consecutivitatea dată a1, …, an, dupăce se elimină din ea:

a) un element cu valoarea mах (a1, …, an);b) toate elementele cu valoarea max(a1, …, an). Se subînţelege

că nu toate numerele a1, …, an sînt egale între ele.c) să se afle max (a1, …, an) şi min (a1, …, an) utilizînd

următorul algoritm. Pas cu pas să se obţinăperechile max(a1, …, ai), min(a1, …, ai) (i= 1, ..., n). Ca săse obţină max(a

1

, …, ai+1

), min(a1

, …, ai+1

), se comparăai+1 cu max(a1, …, ai), apoi, dacă ai+1 < max(a1, …, ai),suplimentar se compară ai+1 cu min(a1, …, ai).

9. Se presupune că numerele a1, …, an sînt elementeleunui fişier. Valoarea n nu se cunoaşte. Să serezolve următoarele probleme: să se afle valoareamaximală din consecutivitatea dată a1, …, an,, după

ce se elimină din ea:a) un element cu valoarea mах (a1, …, an);b) toate elementele cu valoarea max(a1, …, an). Se subînţelege

că nu toate numerele a1, …, an sînt egale între ele.c) să se afle max (a1, …, an) şi min (a1, …, an) utilizînd

următorul algoritm. Fie n este un număr par,adică n = 2k . Atunci pas după pas să se obţină max

(a1, …, a2l ), min(a1, …, a2l ) (l=1,..., k ). Ca să se obţinămax(a1, …, a2l+2), min(a1, …, a2l+2), mai întîi se comparăîntre ele a2l+1,  a2l+2  şi max(a2l+1, a2l+2) se compară cumах(a1, …, a2l ), iar min(a2l+1, a2l+2) cu min(a1, …, a2l ). Dacă neste un număr impar, se va efectua încă un passuplimentar: compararea ultimului element an cumax(a1, …, an-1) şi, posibil, cu min(a1, …, an-1).

10.  Algoritmul de insertare simplă poate fi schimbat156

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 155/166

astfel. Locul unde trebuie insertat înconsecutivitatea sortată a1, …, an, se determină prinalgoritmul împărţirii în jumătăţi (V. 4). Se obţine unnou algoritm de sortate care se numeşte algoritm

de sortate prin insertare binară (îmbinarea decuvinte “insertarea binară” se subînţelege ca “insertare prin împărţirea în jumătăţi”). Acestalgoritm necesită aproximativ n*⋅ log2 n comparăriale elementelor consecutivităţii. Să se scrieprogramul care realizează acest algoritm.

11. Sunt date obiectele a1, …, an. Să se obţină în ordine

crescătoare toate numerele diferite ce intră în a1,…, an. Pentru aceasta să se folosească algoritmul desortare prin insertare binară. În procesul de sortaresă se elimine elementele care se repetă. Dacă înurma căutării locului ai în consecutivitatea dejasortată a1, …, ak  (k < i) se va depista că printre a1, …,ak  este deja un element egal cu ai, trebuie de cercetat

următorul ai+1 fără schimbarea consecutivităţii a1, …,ak .

12.  Algoritmul von Newmann de sortare a tabelului a1, …, an înordine nedescrescătoare (algoritm de sortare prinunire) se bazează pe unirea de mai multe ori alegrupelor de elemente deja sortate ale tabelului dat.Mai întîi tabelul este privit ca o totalitate de grupesortate ce conţin cîte un element. Unirea grupelorvecine ne dau noi grupe deja sortate care conţincîte două elemente (poate, posibil, cu excepţiaultimei grupe pentru care nu s-a găsit pereche).Apoi grupele se măresc prin aceeaşi metodă, pînăcînd obţinem o grupă care conţine toateelementele consecutivităţii iniţiale deja sortate.

Pentru sortare, la etapele intermediare, se157

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 156/166

utilizează nu numai tabelul a1, …, aт , dar şi unulauxiliar b1, …, bn. Figura 1 ne ilustrează

Fig.1.cum se unesc două etape ale tabelelor a1, …, an şi b1,…, bn reprezentîndu-le în formă de segmenteîmpărţite în părţi corespunzătoare grupelor de

elemente sortate. Numărul de grupe sortate semicşorează. Deci se va obţine acel moment cîndtabelul a1, …, an sau b1, …, bn va conţine o grupă deelemente deja sortate. Aceasta înseamnă cătabelul este sortat. Pentru unirea a două grupesortate, care conţine corespunzător р şi q elemente,este suficient de a produce nu mai mult de p+q comparări.Rezultă că pentru o singură etapă de sortare estesuficient de a efectua nu mai mult de n comparărişi tot atîtea permutări. Demonstraţi că algoritmullui fon Newmann necesită aproximativ n log2  ncomparări şi tot atîtea permutări. Spre deosebitede alţi algoritmi de sortare numai algoritmul deinsertare binară necesită acelaşi număr decomparări. Însă algoritmul lui fon Newmann se

deosebeşte de cel menţionat prin utilizarea a maipuţine permutări ale elementelor a1, …, an (cu toatecă necesită un tabel suplimentar b1, …, bn). De scrisprogramul care realizează algoritmul lui vonNewmann.

13 Fie se dă tabelul de obiecte a1, …, an. Pentrusortarea tabelului să se utilizeze următoarea

procedură. Să se aranjeze elementele tabelului a1,158

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 157/166

…, an astfel, ca la începutul tabelului să fie grupa deelemente valorile cărora sînt mai mari caelementul de pe primul loc, urmează valoareaprimul element al consecutivităţii date şi apoi vor

urma elementele cu valori mai mici sau egale caprimul element. Astfel, pas cu pas efectuîndprocedura descrisă, să se obţină tabelul sortat.Numărul de comparări fiecare etapă nu trebuie săîntreacă n – 1.

14. Fie a şi b sînt fişiere, k  este un  număr natural. Vomspune că fişierele а şi b sînt corelate k -sortate, dacă:

a) în fiecare din fişierele a şi b primele k componente, următoarele după ele k componente etc. formează grupe sortate;ultima grupă a componentelor din fişier(tot sortată) poate conţine mai puţin de kelemente, dar numai un singur fişierpoate avea o grupă necompletă;

b) numărul grupelor sortate a fişierului a se

deosebesc de numărul grupelor sortate afişierului b nu mai mult decît cu o unitate;

c) dacă într-un fişier numărul grupelorsortate sînt mai puţin cu o unitate decît încelălalt fişier, grupul incomplet deelemente (mai puţin de k  elemente)poate fi numai în fişierul cu mai multe

componente.d) componentele a două fişiere а şi b corelatek -sortate pot fi alocate în fişierele g  şi hastfel, încît g  şi h să fie corelate 2k -sortate.Aceasta se efectuează prin intermediulunirii grupelor sortate. Rezultatele uniriise aranjează alternativ cînd în fişierul g ,cînd în fişierul h. Fig.2 ilustrează acest

proces la primele uniri ale grupelor159

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 158/166

Fig.2.

sortate. Fişierele se prezintă în formă desegmente, componentele cărora seprezintă ca grupe sortate cu număruldeterminat de componente. Să se

finalizeze descrierea acestui algoritmcercetînd etapa finală. Să se demonstrezecă fişierele g  şi h într-adevăr vor fi corelate2k - sortate.

Să se realizeze acest algoritm în formă deprogram.

15. Fie dat tabelul a1, …, an. Trebuie de permutat elementele a1, …,

an astfel, ca la început de tabel să fie grupa de elementemai mari decît elementul care se află pe primulloc în tabelul iniţial, apoi însăşi acest element,după care urmează cele mai mici sau egale cu el.Numărul de comparări şi permutări nu trebuie săîntreacă n - 1. Algoritmul recursiv de sortate(algoritmul de sortare rapidă) care se bazează petransformările descrise mai sus este următorul.Dacă tabelul conţine nu mai mult de un element,tabelul se consideră sortat. În caz contrar,efectuăm transformarea descrisă în V..10 şideterminăm rezultatele de utilizare a algoritmuluide sortare rapidă pentru tabelul a1, …, an în felulurmător: mai întîi se formează prima grupăsortată cu ajutorul algoritmului de sortare rapidă,

apoi fără schimbare acel element care împarte160

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 159/166

grupa întîi şi doi, după care urmează grupa doi deelemente, sortată cu ajutorul algoritmului desortare rapidă. Acest algoritm nu utilizeazătabelul suplimentar şi necesită aproximativ n log2 n

comparări şi tot atîtea permutări de elemente.Acestea sînt caracteristicele numerice medii.Pentru cel mai rău caz, numărul de comparăripoate ajunge la n(n—1)/2. În afară de aceasta,acest algoritm necesită recursie. Să se scrie unalgoritm care realizează algoritmul de sortarerapidă.

161

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 160/166

Lucrarea de laborator nr. 7.Tema: Prelucrarea excepţiilor. Blocul try{…} throw()catch()…

Scopul lucrării: familiarizarea studenţilor cuprelucrarea excepţiilor, lucrul cu blocul try{…} throw ()catch()…

Consideraţiile teoretice necesare:Tratarea excepţiilor Excepţiile sînt situaţiile neaşteptate apărute în

cadrul sistemului care rulează un program.Programele trebuie să conţină proceduri de tratare aacestor situaţii excepţionale.

In C++ s-a realizat un mecanism de tratare aexcepţiilor. Astfel, o excepţie este un obiect a căruiadresă este trimisă dinspre zona de cod, unde aapărut problema, către o zonă de cod, care trebuie s-o rezolve.

Paşii care trebuie, în general, urmaţi în vedereatratării excepţiilor în cadrul programelor C++ sînt:

–  se identifică acele zone din program, încare se efectuează o operaţie desprecare se cunoaşte că ar putea genera oexcepţie şi se marchează în cadrulunui bloc de tip try. In cadrul acestui

bloc, se tastează condiţia de apariţie aexcepţiei, şi în caz pozitiv sesemnalează apariţia excepţiei prinintermediul cuvîntului- cheie throw;

–  se realizează blocuri de tip catch, pentrua capta excepţiile atunci cînd acesteasînt întîlnite.

Blocurile catch urmează un bloc try, în cadrul cărora sînt

tratate excepţiile.162

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 161/166

Sintaxa pentru try:try { // codthrow TipExcepţie;

}Sintaxa pentru throw:throw TipExcepţie;Sintaxa pentru catch:catch(TipExcepţie){// cod tratare excepţie}

Dacă TipExcepţie este "...", este captată orice excepţieapărută.

După un bloc try, pot urma unul sau mai multe blocuricatch. Dacă excepţia corespunde cu una dindeclaraţiile de tratare a excepţiilor, aceasta esteapelată. Dacă nu este definită nici o funcţie detratare a excepţiei, sistemul apelează funcţia

predefinită, care încheie execuţia programului încurs. După ce funcţia este executată, programulcontinuă cu instrucţiunea imediat următoare bloculuitry.

TipExcepţie nu este altceva decît instanţiereaunei clase vide (care determină tipul excepţiei), carepoate fi declarată ca:

class TipExcepţie {};În continuare vom prezenta un exemplu de programcare utilizează tratarea excepţiilor.

#include <iostream.h>#define MAXX 80#define MAXY 25

class Point 

{ public:163

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 162/166

class xZero {};class xOutOfScreenBounds {};Point(unsigned x1, unsigned y1){ x =x1; y =y1; }

unsigned GetX() { return x; }unsigned GetY() { return y; }void SetX(unsigned x1){ if(x1 > 0)

if(x1 < = MAXX) x =x1;else throw xOutOfScreenBounds();

else throw xZero();}

void SetY(unsigned y1){ if( y1 > 0)if( y1 < = MAXY) y =y1;else throw xOutOfScreenBounds();

else throw xZero();}

protected:

int x, y;};void main(){ Point p(1, 1);try{ p.SetX(5);

cout<<"p.x successfully set to "<<p.GetX()<<"."<<endl;

p.SetX(100);}

catch(Point::xZero){ cout << "Zero value!\n"; }

catch(Point::xOutOfScreenBounds){ cout << "Out of screen bounds!\n"; }

catch(...)

{ cout << Unknown exception!\n"; }164

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 163/166

}Rezultatul îndeplinirii programului:p.x successfuly set to 5.

Datorită faptului că excepţia este instanţierea unei

clase, prin derivare pot fi realizate adevărate ierarhiide tratare a excepţiilor. Trebuie de avut însă învedere posibilitatea de apariţie a unor excepţii chiarîn cadrul codului de tratare a unei excepţii, situaţiicare trebuie evitate.Întrebările pentru verificarea cunoştinţelor:1. Cum sînt realizate excepţiile în cadrul programelor C++ ? Daţi exemple. 

Temele pentru acasă:1. Ce rezultate vor fi obţinute la rularea următoruluiprogram:

void main(){ cout<<”Început”;try{  // începutul blocului try

cout<<”interiorul blocului try \n”;throw 10; // generarea eroriicout<<”Aceasta nu se va executa”;}catch (int i) { cout<<”Este prelucrat ă eroarea: ”;cout<<I<<”\n”;}cout << “Sfîrşit”; }

Teme pentru lucrări de laborator:1. Scrieţi un program care calculează numărul de

elemente ale unui fişier care sînt mai mici cavaloarea medie aritmetică a tuturor elementeloracestui fişier.

2. Scrieţi un program care compară două fişiere date.

3. Scrieţi un program care determină numărul165

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 164/166

maximal şi cel minimal dintr-un şir de numerealeatoare dintr-un fişier. Subconsecutivitatea deelemente dintre numărul maximal şi cel minimaldeterminat să se înregistreze într-un nou fişier.

4. Scrieţi un program care tipăreşte toate cuvintelediferite de ultimul cuvînt dintr-un fişier. Cuvinteledin fişier sînt separate prin virgulă, iar.după ultimulcuvînt se pune punct.

5. Scrieţi un program care formează un fişier nouselectîndu-se din trei fişiere date mai întîi numerelenegative, zerourile, apoi numerele pozitive.

6. Scrieţi un program care ordonează lexicografic oconsecutivitate de înregistrări (dintr-un fişier) detipul 

struct { char nume [30];int ani} înregistrare;

7. Scrieţi un program care formează un fişier nou dintrei fişiere date după următoarea legitate: seselectează mai întîi numerele divizibile la 3, la 5 şi

la 7, apoi numerele pozitive pare de pe locuriimpare.

8. Scrieţi un program care sortează lexicograficcuvintele dintr-un text. Pentru fiecare elementsortat să se indice numărul de repetări alecuvîntului în textul dat.

9. Scrieţi un program care din două fişiere ordonate

descrescător se vor uni în unul nou în care se vapăstra ordinea descrescătoare de sortare.10. Scrieţi un program care va tipări în ordine inversă

subconsecutivitatea de numere dintre valoareaminimă şi maximă ale unei consecutivităţi denumere citită dintr-un fişier.

11. Scrieţi un program care calculează suma înmulţiriinumerelor vecine pe locuri pare dintr-un fişier dat.

12. Scrieţi un program care determină frecvenţa cu166

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 165/166

care a fost generat fiecare element în fişieruluicreat. Valorile elementelor sînt cuprinse între 1 şi100.

13. Scrieţi un program care determină numărul

maximal şi cel minimal din numerele unui fişierdat. Să se determine elementele mai mari ca celminimal şi mai mici ca numărul maximal.

14. Scrieţi un program care formează un fişier nou dincel dat după următoarea legitate: elementelefişierului nou se obţine din inversul numerelor dinfişierul dat.

15. Scrieţi un program care să formeze un fişier noucare conţine elementele a două fişiere ordonatecrescător.Elementele fişierului format va păstraordinea crescătoare de sortare.

16. Scrieţi un program care efectuează reformatareaunui fişier textual în felul următor. Lungimearîndului de caractere în fişierul nou are lungimeade 60 de caractere. Dacă în rîndul dat se

depistează punctul, restul rîndului din fişierul datse scrie din rînd nou.

Bibliografia1. D. Somnea, D. Turturea. Introducere în C++. Programarea

obiect orientata. – Bucureşti, ed. Teora, 1993.2. O. Catrina, L. Cojocaru. Turbo C++.– Bucureşti, ed.

Teora, 1994.3. D. Costea. Iniţiere î n limbajul C. – Bucureşti, ed. Teora,

1996.4. D. M. Popovici, I. M. Popovici, I. Tănase. C++.

Tehnologia orientată pe obiecte. Aplicaţii. –Bucureşti, ed. Teora, 1996.

5. L. Negrescu. Iniţiere î n limbajul C, C++. – Cluj, 1996.6.

А. Голуб. С и С++ . Правила программирования.167

8/7/2019 indrumarnew

http://slidepdf.com/reader/full/indrumarnew 166/166

– Москва, Радио и cвязь, 19967. Г. Шилдт. Самоучитель С++. – Пер. с  англ.,

Санкт Петербург, BHV, 1997.8. Дж. Крис. Учимся программировать на языке

С++. – Москва, Радио и cвязь, 1997.9. G. D. Mateescu. C++ limbaj de programare. –

Bucureşti, ed. Petrion, 1998.10.L. Negrescu. Limbajele C, C++ pentru începători. – 

Cluj–Napoca, ed. Albastra, 2000, v.II.11.Бьерн Страустрап. Язык Программирования

С++. М.-BINOM, 2000.

12.D. M. Popovici, I. M. Popovici, I. Tănase. C++.Tehnologia orientată pe obiecte. Aplicaţii. –Bucureşti, ed. Teora, 2002.