Alocarea Dinamica A Memoriei

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

Sunteți pe pagina 1din 13

Alocarea dinamica a memoriei

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


segment de date;
segment de stiva
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:
int a=7, *adr=&a;
cout<<*adr;

//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
Exemplu:

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?
Raspuns: se utilizeaza operatorul de conversie explicita:

adr3=(float*) adr2 este corect.

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

infn 0
adrn

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

adr1

adr2

17
adr2

adr3

29

adrn

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

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

adr1

34

17

adr3

adr2

29

29

adrn

adr1

adrn+1

variabila v va memora adreasa noii iregistrari:


12

Adr2

adr1

34

17
adr2

Adr3
adrn

adr1

adrn+1

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:
6

#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

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

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;
8

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

46

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;
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
Memoria ocupata de nodul care urmeaza a fi sters este eliberata:

39

39

2) nodul este primul. Fie lista:


13

55

27

..........

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

55

27

39 0

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)
10

{ Nod* c, *man;
if (v->info= = val)
{ man=v;
v=v->adr_urm;
}
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
11

Se citesc de la tastatura n numere naturale. Se cere ca cestea sa fie sortate crescator prin
utilizarea metodei de sortare prin insertie.
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;

12

c=c->adr_urm;
}
}

13

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