Alocarea dinamica a memoriei
Anumite variabile pot fi alocate dinamic. Asta inseamna ca: Spatiul necesar memorarii este rezervat intr-un segment special destinat acestui scop, numit HEAP. In memorie se rezerva spatiu in timpul executarii programului, atunci cand se utilizeaza un anumit operator. Atunci cand variabila respectiva nu mai este utila, spatiul din memorie este eliberat, pentru a fi rezervat, daca este cazul, pentru alte variabile. Mecanismul alocarii dinamice este urmatorul: 37522cpz35cve6c Se declara o variabila pointer, s-o numim p, care permite memorarea unei adrese. Se aloca variabila dinamica prin operatorul new aplicat asupra unui tip, iar rezultatul este atribuit variabilei p. In urma acestor operatii variabila p retine adresa variabilei alocata dinamic. Orice acces la variabila alocata dinamic se face prin intermediul variabilei p. Variabila alocata dinamic Adresa variabilei alocata dinamic pv522c7335cvve p segment de date HEAP In C++, pentru alocarea dinamica se utilizeaza urmatorii operatori: Operatorul new aloca spatiu in HEAP pentru o variabila dinamica. Dupa alocare, adresa variabilei se atribuie lui p, unde p este o variabila de tip pointer catre tip: p=new tip numarul de octeti alocati in HEAP este, evident, egal cu numarul de octeti ocupat de o variabila de tipul respectiv. durata de viata a unei variabile alocate in HEAP este pana la eliberarea spatiului ocupat (cu delete) sau pana la sfarsitul executarii programului. Operatorul delete elibereaza spatiul rezervat pentru variabila a carei adresa este retinuta in p. Dupa eliberare, continutul variabilei p este nedefinit. delete p Exemple: Variabile de tip pointer catre variabile de tip int. Variabila adr1 poate retine adrese ale variabilelor de tip int. . . . int* adr1; adr1=new int; // aloc spatiu in HEAP pentru o variabila de tip int *adr1=7; // variabila alocata retine 7 cout<<*adr1; // tiparesc continutul variabilei delete adr1; // eliberez spatiul Variabile de tip pointer catre variabile de tip float. Variabila adresa, poate retine adrese ale variabilelor de tip float. float* adresa; // sau float* adresa=new float; adresa=new float; *adresa=7.65; cout<<*adresa; Variabile de tip pointer catre variabile de tip inreg, care la randul lor, sunt de tip struct. Variabila adr, poate retine adrese ale variabilelor de tipul inreg. #include<iostream.h> struct inreg { char nume[20], prenume[20]; int varsta; }; main() { inreg* adr; adr=new inreg; cin>>adr->nume>>adr->prenume>>adr->varsta; cout<<adr->nume<<endl<<adr->prenume<<endl<<adr->varsta; } Alocarea dinamica a masivelor Pentru inceput, vom prezenta, pe scurt, legatura intre pointeri si masive. Un tablou p-dimensional se declara astfel: tip nume[n1][n2]. . .[np] Exemple: float A[7][4][2]; am declarat un tablou cu 3 dimensiuni, unde tipul de baza este float. long b[9][7][8][[5]; am declarat un tablou cu 4 dimensiuni, unde tipul de baza este long. Numele tabloului p dimensional de mai sus este pointer constant catre un tablou p-1 dimensional de forma [n2]. . .[np], care are componentele de baza de acelasi tip cu cele ale tabloului. A este pointer constant catre tablouri cu [4][2] componente de tip float. b este pointer constant catre tablouri cu [7][8][5] componente de tip long. Un pointer catre un tablou k dimensional cu [l1][l2]. . .[lk] componente de un anumit tip se declara astfel: tip (*nume)[l1][l2]. . .[lk] variabila de tip pointer, numita p, care poate retine pe A se declara: float (*p)[4][2]; variabila de tip pointer, numita q, care poate retine pe b se declara: long (*q)[7][8][5]; De ce se folosesc parantezele rotunde? Operatorul de tip array ([]) are cea mai mare prioritate (mai mare decat operatorul *). Declaratia: float *p[7][8][5]; este interpretata ca masiv cu [7][8][5] componente de tip float*. In concluzie, este masiv cu componente de tip pointer si nu pointer catre masive. Atentie! Aici se fac multe confuzii! Intrucat numele unui masiv p dimensional este pointer catre un masiv p-1 dimensional, pentru a aloca dinamic un masiv se va utiliza un pointer catre masive p-1 dimensionale (ultimele p-1 dimensiuni). Exemple. Alocam in HEAP un vector cu 4 componente de tip int. Numele unui astfel de vector are tipul int* (pointer catre int). Prin urmare, variabila a are tipul int*. Dupa alocare, ea va contine adresa primului element al vectorului din HEAP. Din acest moment, pornind de la pointer (retinut in a) vectorul se adreseaza exact cum suntem obisnuiti. int *a=new int[4]; a[3]=2; Observati modul in care a fost trecut tipul in dreapta operatorului new. Practic, declararea tipului se face intocmai ca declaratia masivului, insa numele a fost eliminat. Declaram in HEAP o matrice (masiv bidimensional) cu 3 linii si 5 coloane, cu elemente de tip double: double (*a)[5]=new double [3][5]; a[1][2]=7.8; In cazul masivelor, trebuie atentie la eliberarea memoriei (cu delete). Trebuie tinut cont de tipul pointerului, asa cum rezulta din exemplele urmatoare: Fie vectorul alocat in HEAP int *a=new int[4]; Daca incercam dezalocarea sa prin: delete a; ii dezalocam prima componenta, pentru ca pointerul este de tip int*. Corect, dezalocarea se poate face prin: delete [4] a – eliberam spatiul pentru toate componentele (in acest caz avem 4). Observati ca operatorul delete se poate utiliza si ca mai sus. Fie matricea alocata in HEAP: double (*a)[5]= new double [3][5]; Eliberarea spatiului ocupat de ea se face prin delete [3] a; Programul urmator citeste si afiseaza o matrice. Nou este faptul ca matricea este alocata in HEAP. #include <iostream.h> main() { int m, n, i, j, (*adr)[10]; adr=new int [10][10]; cout<<”m=”; cin>>m; cout<<”n=”; cin>>n; for(i=0; i<m; i++) for(j=0; j<n; j++) cin>>adr[i][j]; for(i=0; i<m; i++) { for(j=0; j<n; j++) cout<<adr[i][j]<<” “; cout<<endl; } } Alocarea in HEAP nu este lipsita de importanta. De obicei, matricele ocupa mult spatiu in memorie. Faptul ca, de aceasta data ele sunt rezervate in HEAP, conduce la economisirea memoriei din segmentul de date sau acela de stiva. In acest fel programul dispune de mai multa memorie, pentru ca HEAP-ul este oricum rezervat. Este cunoscut faptul ca functiile nu pot intoarce masive. In schimb, o functie poate intoarce un pointer catre orice tip (void*). Reamintim ca unei variabile de tipul void* I se poate atribui orice tip de pointer, dar atribuirea inversa se poate face doar prin utilizarea operatorului de conversie explicita. Programul urmator citeste doua matrice si afiseaza suma lor. Matricele sunt rezervate in HEAP. #include <iostream.h> void* Cit_Mat(int m, int n) { int i, j, (*adr1)[10]=new int[10][10]; for(i=0; i<m; i++) for(j=0; j<n; j++) cin>>adr1[i][j]; return adr1; } void Tip_Mat(int m, int n, int(*adr1)[10]) { int i, j; for(i=0; i<m; i++) { for(j=0; j<n; j++) cout<<adr1[i][j]<<” “; cout<<endl; } } void* Suma_Mat(int m, int n, int(*adr1)[10], int(*adr2)[10]) { int i, j, (*adr)[10]=new int[10][10]; for(i=0; i<m; i++) for(j=0; j<n; j++) adr[i][j]=adr1[i][j]+adr2[i][j]; return adr; } main() { int m, n, i, j, (*adr)[10], (*adr1)[10], (*adr2)[10]; cout<<”m=”; cin>>m; cout<<”n=”; cin>>n; adr1=(int(*)[10])Cit_Mat(m,n); adr2=(int(*)[10])Cit_Mat(m,n); adr=(int(*)[10])Suma_Mat(m,n,adr1,adr2); Tip_Mat(m,n,adr); } Pentru fiecare dintre cele n materiale, aflate intr-o magazie, se cunoaste: denumirea materialului, unitatea de masura (bucati, kg.,etc.) si cantitatea care se gaseste in magazie, exprimata in unitatea de masura inscrisa. Programul de mai jos citeste informatiile si le organizeaza astfel: segmentul de date contine un vector cu n componente, unde fiecare componenta retine un pointer catre inregistrarea cu datele citite pentru fiecare material; datele citite pentru fiecare material se organizeaza ca struct, alocat in HEAP. cuie kg 12 Clesti buc 987 Cuie kg. 12000 pv522c7335cvve pv522c7335cvve #include <iostream.h> struct material { char denumire[20], unit_mas[5]; float cantitate; }; void Cit_Material(int i, material* v[100]) { v[i]=new material; cout<<”Denumire “; cin>>v[i]->denumire; cout<<”Unitate de masura “; cin>>v[i]->unit_mas; cout<<”Cantitate “; cin>>v[i]->cantitate; } void Tip_Material(int i, material* v[100]) { cout<<v[i]->denumire<<endl<<v[i]->unit_mas<<endl<<v[i]->cantitate; } main() { int n, i; material* v[100]; cout<<”n=”; cin>>n; for(i=0; i<n; i++) Cit_Material(i,v); for(i=0; i<n; i++) Tip_Material(i,v); }