Sunteți pe pagina 1din 12

Alocarea dinamica a memoriei

Fiecarui program i se aloca trei zone distincte in memoria interna:


y segment de date; y segment de stiva y heap. Def. Prin pointer intelegem adresa unei variabile , iar printr-o variabila de tip pointer vom intelege o variabila care poate retine adresele altor variabile.

Def. Prin alocare dinamica a memoriei vom intelege alocarea unor variabile in Heap, alocare care se face in timpul executarii programului si nu de la inceput. Alocarea dinamica foloseste pointeri si variabile de tip pointer. Avantajele alocarii dinamice: utilizarea memoriei cat are nevoie in Borland C++ memoria din segmentul de date nu este intotdeauna suficienta , e limitata la 64 K, dar apeland la Heap, creste memoria disponibila.

Variabilele de tip pointer in C++


Memoria interna poate fi privita ca o succesiune de octeti care sunt numerotati pentru a-i putea distinge. Def. Numarul de ordine al unui octet se numeste adresa lui. Exemplu. O variabila de tip int ocupa doi octeti. Def. Adresa primului octet al variabilei se numeste adresa variabilei. Memorarea adreselor variabilelor se face cu ajutorul variabilelor de tip pointer. Variabilele de tip pointer se caracterizeaza prin faptul ca valorile pe care le poate memora sunt adrese ale altor variabile. Limbajul C++ face distinctie intre natura adreselor care pot fi memorate. Astfel, exista adrese ale variabilelor de tip int, de tip float, de tip char, etc. Declararea unei variabile de tip pointer: tip *nume. Exemplu: int * adr1, * adr2 float * adresa.

Operatori
1) Adresa unei variabile se obtine cu ajutorul operatorului de referinta & care trebuie sa preceada numele variabilei: &nume_variabila; exemplu: adr1=&numar; -variabilei adr1 i se atribuie adresa variabilei numar

2) Pentru a obtine continutul variabilei a carei adresa este memorata , se utilizeaza operatorul unar *, numit si operator de dereferentiere, are prioritate 2. Exemplu: //variabila a este initializata cu valoarea 7, iar variabila adr este ini// tializata cu adresa lui a, se afiseaza continutul variabilei a(7), // pornind de la adresa ei, retinuta de adr. 3) Operatorul . numit operator de selectie, are prioritate 1(maxima). 4) Operatorul de selectie directa ->- acceseaza un camp al unei structuri pornind de la un pointer catre acea structura. Exemplu: (*adra).nume Sau La tiparire: cout<<adra->nume<< <<adra->prenume; 4) Intre variabilele de tip pointer sunt premise atribuiri doar in cazul in care au acelasi tip de pointer int * adr1,*adr2; float *adr3; // initializari atribuirea: adr1=adr2 corecta atribuirea: adr3=adr2 nu este corecta Cum putem atribui cotinutul unei variabile de tip pointer catre tipul x, altei variabile de tip pointer catre tipul y? Exemplu: Raspuns: se utilizeaza operatorul de conversie explicita: adr3=(float*) adr2 este corect. int a=7, *adr=&a; cout<<*adr;

Alocarea dinamica in C++


In C++, pentru alocarea dinamica se utilizeaza urmatorii operatori: 1. 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 ete 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 sau pana la sfarsitul executarii programului. 2. Operatotul delete elibereaza spatial rezervat pentru variabila a carei adresa este retinuta in P. Dupa eliberare, continutul variabilei P este nedefinit. delete P. exemplu: int *adr1; adr1=new int; //aloc spatiu in Heaap pentru o variabila de tip int *adr1=7; // variabila alocata retine 7 cout<<*adr1; // tiparesc continutul variabilei delete adr1; //eliberez spatiul

Mecanismul alocarii dinamice


Se va prezenta legatura intre pointeri si masive. Fie un tablou p-dimensional care se declara astfel: tip nume [n]1 [n2][np] Numele tabloului p-dimensional de mai sus este pointer constant catre un tablou p-1 dimensional de forma [n2] [n3 ][np] , care are componentele de baza de acelasi tip cu cele ale tabloului. Exemplu: float A[17][14][12]- tablou cu 3 dimensiuni de tip float - A este pointer constant catre tablouri cu [14][12] componente de tip float Un pointer catre un tablou k dimensional cu [l1][l2][lk] componente de un anumit tip se declara astfel: Tip (*nume ) [l1] [l2][lk] Exemplu: float (*p) [4] [2]; -variabila de tip pointer, numita p, care poate retine pe A. 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).

Aplicatie:
1.Se dau doua matrici. Sa se afiseze suma matricelor. Matricele sunt alocate in Heap. # include <iostream.h> Void * Cit_mat (int m, int n) { int i, j, (* a)[10]=new int[10][10]; For (i=0; i<m;i++) For (j=0; j<n; j++) cin>>a[i][j]; Return a; } Void tip_mat (int m, int n, int (*a) [10]) {int i, j; For (i=0; i<m; i++) { for (j=0; j<n ; j++) cout <<a[i][j]<< ; Cout<<endl; } } Void * Suma_mat( int m, int n, int (*a)[10], int (*b)[10]) { int i, j, (*c)[10]=new int[10][10]; for (i=0; i<m; i++) for (j=0; j<n; j++) c[i][j]=a[i][j]+b[i][j]; return c; } main ( ) { int m, n, i, j, (*c)[10], (*a)[10], (*b)[10];

cout<<m=; cin>>m; cout<<n=; cin>>n; a=(int (*) [10]) Cit-mat(m,n); b=(int (*) [10]) Cit_mat(m,n); c=(int (*) [10]) Suma_mat(m,n,a,b); Tip_mat(m,n,c); }

Liste liniare
Definitia listelor Def. O lista liniara este o colectie de n u 0 noduri, x1, x2, ,xn aflate intr-o relatie de ordine. Astfel, x1, este primul nod al listei,, xn este ultimul nod al listei. Operatiile permise sunt: - accesul la oricare nod al listei in scopul citirii sau modificarii informatiei continute de acesta; - adaugarea unui nod; - stergerea unui nod; - schimbarea pozitiei unui nod in cadrul listei. Un vector poate fi privit ca o lista liniara care este alocata secvential. 1. Liste liniare simplu inlantuite (LLSI) a) Prezentare generala Def: O lista liniara simplu inlantuita este o structura de forma inf1 adr2 inf2 adr3 ........
adr1 adr2 adrn

infn 0

unde : adr1,adr2,...,adrn reprezinta adresele celor n inregistrari; inf1, inf2, ..., infn reprezinta informatiile continute de noduri, de alta natura decat cele de adresa; - 0 are semnificatia nici o adresa- elementul este ultimul in lista. Fiecare nod, cu exceptia ultimului, retine adresa nodului urmator. Accesul la un nod al listei se face prin parcurgerea nodurilor care il preced. b) Crearea si afisarea listelor Intreaga structura memorata in Heap este gestionata printr-un singur pointer memorat in segmentul de date. In cazul listelor, prin acel pointer se poate accesa numai primul element al listei, apoi pornind de la acesta se poate accesa al doilea element al listei s.a.m.d. Ultimul element al listei va avea memorat in campul de adresa o valoare cu semnificatia de nici o adresa. Cu ajutorul acestei valori programele vor detecta sfarsitul listei.Acesta valoare este 0. Crearea listelor Initial o valoare v retine 0. Presupunem ca avem o lista de forma celei de mai jos, iar v retine adresa primului element ( adr1): 12
V adr 1

adr2
adr2

17

adr3
adrn

29

Daca se citeste un nod nou ,atunci acesta se adauga intr-o inregistrare aflata la inceputul listei, in urmatoarele etape:

se aloca spatiu pentru noua inregistrare, se completeaza campul numeric, iar adresa urmatoare este cea din v, deci a primului element al liste. 12 adr2
adr2

17

adr3
adrn

29

adr 1

34
adrn+1

adr1

variabila v va memora adreasa noii iregistrari: 12 Adr2


adr2

17

Adr3
adrn

29

adr 1

34
adrn+1

adr1

Programul este urmatorul: #include <iostream.h> struct Nod { int info; Nod * adr_urm; }; Nod * v; int nr; void Adaug (Nod*& v, int nr) { Nod* c=new Nod; c-> info=nr; c->adr_urm=v; v=c; } void Tip(Nod* v) { Nod* c=v; while ( c ) { cout<<c->info<<endl; c=c-> adr_urm; } } main( ) { cout<<numar=; cin>>nr; while (nr) { Adaug(v, nr); cout<<numar=; cin>>nr; }; Tip (v); } Programul recursiv de creare a listei este prezentat mai jos: #include <iostream.h> struct Nod { int info; Nod * adr_urm;

}; Nod * v; Nod * Adaug() { Nod* c; int nr; cout<<numar=; cin>>nr; if (nr) { c=new(Nod); c->adr_urm=Adaug( ); c->info=nr; return c; } else return 0; } void Tip( Nod* v) { Nod* c=v; while ( c ) {cout<<c->info<<endl; c=c->adr_urm; } } main ( ) { v=Adaug( ); Tip(v); } Mai jos este prezentat un subprogram recursiv care tipareste informatiile in ordine inversa fata de modul in care se gasesc in lista: void Tip_inv( Nod* v) { if (v) { Tip_inv(v->adr_urm); cout<<v->info<<endl; } } c) Operatii asupra unei liste liniare Orice lista va fi retinuta prin doua informatii de adresa: a primului nod (v) si a ultimului nod ( sf ).Structura unui nod al listei este: struct Nod { int info; Nod* adr_urm; };

A.Adaugarea unui nod Se poate face avand: 1)lista vida v retine 0; Vrem sa adaugam un nod pe care il alocam zonei Heap, adresa nodului va fi in v, si cum are un singur nod, adresa primului nod este si adresa ultimului , deci continutul lui v va coincide cu acela a lui sf. 13 0

v sf 2) lista este nevida Fie lista: 13 adr2

27

adr3

39

v sf Se adauga un nod cu informatia 6.Initial se aloca spatiu pentru nod.

13

27

39

V sf c Campul de adresa al ultimului nod, cel care are adresa in sf, va retine adresa nodului nou creat, dupa care si sf va retine aceeasi valoare. 13 27 39 0

V sf Daca nu am fi utilizat varaibila sf pentru a retine adresa ultimului nod, ar fi fost necesar sa parcurgem intreaga lista , pornind de la v, pentru a obtine adresa ultimului. Void Adaugare (Nod*& v, Nod*& sf, int val) { Nod* c; if (v= =0) { v=new( Nod); v->info=val; v->adr-urm=0; sf=v; } else { c=new(Nod);

sf->adr_urm=c; c->info=val; c->adr_urm=0; sf=c; } } B. Inserarea unui nod, dupa un altul, de informatie data Initial se face identificarea nodului dupa care se face adaugarea. Se aloca spatiu pentru noul nod. Se completeaza adresa si anume adresa nodului care urmeaza dupa nodul ales.

13

27

39

46

sf 5 Campul de adresa al nodului cu informatia 3 va retine adresa nodului nou creat: 13 27 39 0 46 0

sf

55 un caz aparte apare atunci cand nodul de informatie val este ultimul in lista. In acest caz sf retine adresa nodului nou creat pentru ca acesta va fi ultimul. void Inserare_dupa( Nod* v, Nod*& sf, int val, int val1) { Nod* c=v, *d; while (c->info!=val) c=c->info=adr_urm; d=new Nod; d->info=val1; d->adr_urm=c->adr_urm; c->adr_urm=d; if (d->adr_urm= =0) sf=d; } C.Inserarea unui nod , inaintea altui nod, de informatie data Void Inserare_inainte(Nod*& v, int val, int val1) {Nod* c, *d; if (v->info= = val) { d=new Nod; 9

d->info=val1; d->adr_urm=v; v=d; } else {c=v; while (c->adr_urm-> infi!=val) c=c->adr_urm; d=new Nod; d->info=val1; d->adr_urm=c->adr_urm; c->adr_urm=d; } } D. Stergerea unui nod de informatie data Algoritmul este diferit in functie de pozitia in lista a nodului care va fi sters- daca este primul sau ultimul. 1) nodul nu este primul. Pentru nodul care va fi sters, informatia de adresa a predecesorului va retine adresa nodului succesor: 13 55 27 .......... 39 0

Memoria ocupata de nodul care urmeaza a fi sters este eliberata:

13 2) nodul este primul. Fie lista: 13 55

27

39

27

..........

39

v Variabila v va retine adresa celui de-al doilea nod:

13

55

27

39 0

v Spatiul ocupat de primul nod va fi eliberat

55 v Programul este urmatorul: Void Sterg ( Nod*& v, Nod*& sf, int val) { Nod* c, *man; if (v->info= = val) { man=v; v=v->adr_urm;

27

39 0

10

} else { c=v; while (c->adr_urm->info!=val) c=c->adr_urm; man=c->adr_urm; c-> adr_urm=man->adr_urm; if (man= = sf) sf=c; } delete man; } Urmatorul subprogram ne afiseaza lista liniara: Void Listare(Nod* v) { Nod* c=v; while ( c ) { cout<< c->info<<endl; c=c->adr_urm; } cout<<endl; } In urma tuturor operatiilor facute putem testa aplicatia: Nod* v, *sf; int i; main( ) { for (i=1;i<=10;i++) Adaugare (v, sf, i); Listare (v); Inserare_dupa(v, sf, 7, 11); Inserare_dupa(v, sf, 10, 12); Inserare_dupa(v, sf, 1, 13); Listare( v ); Inserare_inainte(v, 13,14); Inserare_inainte(v, 1,15); Listare (v); Sterg(v, sf,15); Sterg(v, sf,13); Sterg(v, sf,12); Listare (v); }

Aplicatie
Sortarea prin insertie Se citesc de la tastatura n numere naturale. Se cere ca cestea sa fie sortate crescator prin utilizarea metodei de sortare prin insertie.

11

Metoda consta in a considera primele k valori sortate , urmand sa inseram valoarea k+1 in sirul deja sortat. Lista va contine valoarea maxima MaxInt alocata deja in lista, deci vom porni de la o lista nevida. Alocam spatiu in Heap pentru o valoare , apoi aceasta este citita.Distingem doua cazuri: a) valoarea citita este mai mica decat prima valoare a listei. Aceasta inseamna ca ea este cea mai mica si va fi introdusa prima in lista. b) valoarea citita nu este cea mai mica din lista, deci ea va trebui introdusa in interiorul listei. Odata gasita adresa acestei valori, avem nevoie de adresa precedenta (pentru aputea lega in lista noul nod) vom merge cu doi pointeri, c si c1, unde c1 retine adresa inregistrarii cu valoarea mai mare decat inregistrarea citita, iar c adresa inregistrarii precedente. #include <iostream.h> const MaxInt =32000; struct Nod { int info; Nod* adr_urm; }; int n,i; Nod *v, *adr, *c, *c1; main( ) { cout<<n=; cin>>n; v=new Nod; v->info=MaxInt; v->adr_urm=0; for (i=1;i<=n;i++) { adr=new Nod; cout<<numar=; cin>>adr->info; if (adr->info<=v->info) // primul din lista { adr->adr_urm=v; v=adr; } else // nu e primul din lista { c=v; c1=v->adr_urm; while (c1->info<adr->info) { c=c->adr_urm; c1=c1->adr_urm; } c->adr_urm=adr; adr->adr_urm=c1; } } //tiparesc c=v; while (c->info!=MaxInt) { cout<<c->info<<endl; c=c->adr_urm; } }

12

S-ar putea să vă placă și