1 / 35

ALOCAREA DINAMIC Ă A MEMORIEI

ALOCAREA DINAMIC Ă A MEMORIEI. Prof. ADINA-ELENA P IŢIGOI. GENERALITĂŢI. Definiţii Prin pointer înţelegem adresa unei variabile, iar printr-o variabila de tip pointer vom înţelege o variabilă care poate reţine adresele altor variabile

thai
Download Presentation

ALOCAREA DINAMIC Ă A MEMORIEI

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. ALOCAREA DINAMICĂ A MEMORIEI Prof. ADINA-ELENA PIŢIGOI

  2. GENERALITĂŢI Definiţii • Prin pointer înţelegem adresa unei variabile, iar printr-o variabila de tip pointer vom înţelege o variabilă care poate reţine adresele altor variabile • Prin alocarea dinamică a memoriei vom înţelege alocarea unor variabile în Heap, alocare care se face în timpul executării programului şi nu de la început, aşa cum am fost obişnuiţi până acum. Mecanismul alocării dinamice a memoriei necesită utilizarea pointerilor şi evident, a variabilelor de tip pointer.

  3. Avantajele alocării dinamice sunt: Programul va utiliza atâta memorie cât are nevoie. Nu întotdeauna se poate cunoaşte, de la început, de câtă memorie are nevoie, aceasta se decide în timpul executării, în funcţie de datele de intrare. Dacă o variabilă nu mai este necesară, există posibilitatea să eliberăm memoria ocupată de aceasta. O astfel de abordare conduce la micşorarea substanţială a necesarului de memorie a unui program.

  4. Variabile de tip pointer Definiţii • Numărul de ordine al unui octet se numeşte adresa lui • Adresa primului octet al variabilei se numeşte adresavariabilei.

  5. Observaţii • Nu trebuie confundată adresa unei variabile cu valoarea pe care aceasta o memorează! • Pointerul este adresa unei variabile. Memorarea adreselor variabilelor se face cu ajutorul variabilelor de tip pointer. Variabilele de tip pointer se caracterizează prin faptul că valorile pe care le pot memora sunt adrese ale altor variabile.

  6. Limbajul C++ face distincţie între natura adreselor care pot fi memorate. Astfel, există adrese ale variabilelor de tip int, adrese ale variabilelor de tip float, adrese ale variabilelor de tip char, etc. Din acest motiv şi tipul variabilelor de tip pointer este diferit.

  7. Declararea tipului unei variabile de tip pointer: tip *nume; • Variabile de tip pointer către variabile de tip int. Variabilele adr1 şi adr2 pot reţine adrese ale variabilelor de tip int. int *adr1, *adr2; • Variabile de tip pointer către variabile de tip float. Variabila adresa poate reţine adrese ale variabilelor de tip float: float* adresa;

  8. Declararea tipului unei variabile de tip pointer: Variabile de tip pointer către variabile de tip elev, care la rândul lor sunt de tip struct. Variabilele a şi b, pot reţine adrese ale variabilelor de tipul elev. struct elev { char nume[20], prenume[20] ; float nota_mate, nota_info; int varsta; }; elev *a,*b;

  9. Observaţii • Caracterul "*" poate fi aşezat în mai multe feluri, după cum se observă: int* adr1; int * adr1; int *adr1; • Pentru a declara mai multe variabile de acest tip, caracterul "*" se trece de fiecare dată: int *adr1, *adr2, *adr3; • Declaraţia int* adr1, adr2; are semnificaţia că adr1 este de tip pointer către int, şi adr2 este de tip int.

  10. Adresa unei variabile se obţine cu ajutorul operatorului de referenţiere "&", care trebuie să preceadă numele variabilei: &Nume_variabilă; Ex: adr1=&număr; - variabilei adr1 i se atribuie adresa variabileinumăr.

  11. Fiind dată o variabilă de tip pointer către variabile de un anume tip, care memorează o adresă a unei variabile de acel tip, pentru a obţine conţinutul variabilei a cărei adresă este memorată, se utilizează operatorul unar "*", numit şi operator de dereferenţiere.

  12. int a=7, *adr=&a; cout<<*adr; Variabila a este iniţializată cu 7, iar variabila adr este initializată cu adresa lui a. Secvenţa afişează conţinutul variabilei a (7), pornind de la adresa ei, reţinută de adr.

  13. struct elev { char nume[20], prenume[20]; }; … elev a, *adra=&a; strcpy(a. nume,"Bojian") ; strcpy(a.prenume, "Andronache"); cout<< (*adra) .nume«" “; cout<< (*adra) .prenume<<endl; Variabila a de tip elev este iniţializată, iar variabila adra, de tip pointer către variabile de tip elev este iniţializată cu adresa variabilei a.

  14. Evaluarea expresiei (*adra).nume • Operatorul"." - numit operator de selecţie, are prioritatea 1, deci maximă. • Operatorul "*" - unar, numit şi operator de dereferenţiere, are prioritatea 2, mai mică. Prin urmare, în absenţa parantezelor rotunde, se încearcă mai întâi evaluarea expresiei "adra.nume", expresie care n-are sens! Parantezele schimbă ordinea de evaluare, se evalueaza mai întâi "*adra", expresie care are sens.

  15. Observaţie În loc să folosim trei operatori, se poate utiliza unul singur, operatorul de selectie indirecta: "->". Acesta accesează un câmp al unei structuri pornind de la un pointer (adresă) către acea structură. El are prioritatea maximă. Tipărirea se face: cout<<adra->nume<<" "<<adra->prenume;

  16. Între variabile de tip pointer sunt permise atribuiri doar în cazul în care au acelaşi tip pointer (reţin adrese către acelaşi tip de variabile). Ex: int *adr1, *adr2; float *adr3; ... // initializari Atribuirea "adr1=adr2"este corectă, iar atribuirea "adr3=adr2"nu este corectă. În acest caz, se utilizează operatorul de conversie explicită. "adr3= (float*) adr2" este corectă.

  17. Alocarea dinamică a memoriei Operatorul new alocă spaţiu în heap pentru o variabilă dinamică. După alocare, adresa variabilei se atribuie lui p, unde p este o variabilă de tip pointer către tip: p=new tip

  18. Observaţii • Numărul de octeţi alocaţi în heap este egal cu numărul de octeţi ocupat de o variabilă de tipul respectiv. • Durata de viaţă a unei variabile alocate în heap este până la eliberarea spaţiului ocupat (cu delete) sau până la sfârşitul executării programului.

  19. Operatorul delete eliberează spaţiul rezervat pentru variabila a cărei adresă este reţinută în p. După eliberare, conţinutul variabilei p este nedefinit. delete p;

  20. Variabile de tip pointer către variabile de tip int int* adr1; adr1=new int; // aloc spaţiu în HEAP pentru o variabilă de tip int *adr1=7; //variabila alocată reţine 7 cout<<*adr1; // tipăresc conţinutul variabilei delete adr1; // eliberez spaţiul

  21. Variabile de tip pointer către variabile de tip float float* adresa; // sau float* adresa=new float; adresa=new float; *adresa=7.65; cout<<*adresa;

  22. Variabile de tip pointer către variabile de tip inreg, care la rândul lor, sunt de tip struct #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; cout<<adr->varsta; }

  23. Mecanismul alocării dinamice Un tablou p-dimensional se declară astfel: tip nume [n1] [n2] . . . [np] Ex: float a[7][4][2]; - am declarat un tablou cu 3 dimensiuni, unde tipul de bază este float. long b[9] [7] [8] [5]; - am declarat un tablou cu 4 dimensiuni, unde tipul de bază este long.

  24. tip nume [n1] [n2] . . . [np] Numele tabloului p dimensional de mai sus este pointer constant către un tablou p-1 dimensional de forma [n2]... [np], care are componentele de baza de acelaşi tip cu cele ale tabloului. a este pointer constant către tablouri cu [4] [2] componente de tip float; b este pointer constant către tablouri cu [7] [8] [5] componente de tip long. float a[7][4][2]; long b[9] [7] [8] [5];

  25. Un pointer către un tablou k dimensional cu [l1] [l2] …[lk] componente de un anumit tip se declară astfel: tip (*nume) [l2] …[lk] Ex: - variabila de tip pointer, numită p, care poate reţine pe a, se declară: float (*p)[4] [2]; - variabila de tip pointer, numită q, care poate reţine pe b, se declară: long (*q) [7] [8] [5]; float a[7][4][2]; long b[9] [7] [8] [5];

  26. Operatorul de tip [] are cea mai mare prioritate (mai mare decât operatorul "*"). Declaraţia float *p[7][8][5]; este interpretată ca masiv cu [7] [8] [5] componente de tip float*. Deci este masiv cu componente de tip pointer şi nu pointer către masive.

  27. Intrucât numele unui masiv p dimensional este pointer către un masiv p-1 dimensional, pentru a aloca dinamic un masiv se va utiliza un pointer către masive p-1 dimensionale (ultimele p-1 dimensiuni).

  28. Alocăm în heap un vector cu 4 componente de tip int. Numele unui astfel de vector are tipul int* (pointer către int). Prin urmare, variabila a are tipul int*. După alocare, ea va conţine adresa primului element al vectorului din heap. Din acest moment, pornind de la pointer (reţinut în a) vectorul se adresează exact cum suntem obişnuiţi. int *a =new int[4]; a[3]=2; Observaţi modul în care a fost trecut tipul în dreapta operatorului new. Practic, declararea tipului se face întocmai ca declaraţia masivului, însă numele a fost eliminat.

  29. Declaram în heap o matrice (masiv bidimensional) cu 3 linii şi 5coloane, cu elemente de tip double: double (*a) [5] = new double [3] [5]; a[1] [2]=7.8;

  30. În cazul masivelor, la eliberarea memoriei (cu delete) trebuie ţinut cont de tipul pointerului. Fie vectorul alocat în heap, int *a =new int [4]; Daca încercăm dezalocarea sa prin: delete a; îi dezalocăm prima componentă, pentru că pointerul este de tip int*. Dezalocarea se poate face prin delete [4] a; eliberam spaţiul pentru toate componentele (în acest caz avem 4).

  31. Fie matricea alocată în heap: double (*a)[5]=new double [3] [5]; Eliberarea spaţiului ocupat de ea se face prin delete [3] a;

  32. Citirea şi afişarea unei matrice alocate în 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;} }

  33. Funcţiile nu pot întoarce masive. O funcţie poate întoarce un pointer către orice tip (void*). 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 explicită. Programul următor citeşte două matrice şi afişează suma lor. Matricele sunt alocate în heap.

  34. #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>>adrl[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; } }

  35. 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); }

More Related