indrumarnew
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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.