Alocare dinamica a memoriei.


Alocarea dinamică a memoriei în C se poate face cu ajutorul funcţiilor malloc, calloc şi
realloc, ale căror definiţii le găsim în fişierul antet malloc.h. Cele 3 funcţii pentru alocare
dinamică returnează toate tipul pointer către void, adică void*. De aceea, în momentul folosirii
acestor funcţii trebuie făcută o conversie de tip. Oricare dintre cele trei funcţii de alocare
returnează valoarea NULL (constanta NULL are valoarea 0) în cazul în care alocarea de memorie
nu s-a putut face (nu este suficientă memorie liberă sau lungimea zonei de memoriei ce se
doreşte a fi alocată nu este validă, adică este negativă).
Funcţia malloc primeşte un parametru de tip întreg, care reprezintă numărul de octeţi de
memorie ce se doreşte a fi alocaţi. De exemplu, pentru un vector de numere întregi scurte trebuie
să definim un pointer către tipul int, pointer care va reţine adresa către zona de memorie alocată.
Cum se face o alocare dinamica pentru vector ?

int i,*a,n,m;
printf("Dati lungimea vectorului: ");
scanf("%d",&n);
a=(int*)malloc(n*sizeof(int)); /* alocare memorie pentru n
elemente de tip int */
if (a==NULL)
{
perror("Memorie insuficienta!"); /* mesaj eroare */
exit(1); /* parasire program cu cod de eroare */
}
for (i=0;i<n;i++)
{
printf("a[%d]=",i);
scanf("%d",&a[i]);
}

Funcţia malloc returnează tipul void*, care trebuie convertit în exemplul de mai sus la
tipul int*, adică la tipul variabilei a.
Funcţia calloc are doi parametri. Primul parametru reprezintă numărul de blocuri ce se
alocă, iar al doilea este lungimea unui bloc. Alocarea memoriei pentru vectorul a din exemplul
de mai sus poate fi rescrisă folosind funcţia calloc astfel:
a=(int*)calloc(n,sizeof(int));
Spre deosebire de funcţia malloc, funcţia calloc iniţializează zona de memorie alocată cu
0, adică toţi octeţii sunt setaţi la valoarea 0.
Funcţia realloc este folosită pentru ajustarea lungimii unei zone de memorie deja alocate,
copiind conţinutul memoriei anterior alocate dacă este necesar la o nouă adresă. Funcţia are doi
parametri. Primul reprezintă adresa zonei de memorie pentru care se doreşte să se facă
realocarea, iar al doilea este noua lungime (în octeţi) a memoriei ce se vrea a fi realocată.
Dacă lungimea memoriei realocate este mai mică sau egală decât lungimea zonei de
memorie iniţiale, atunci adresa rămâne nemodificată (şi este returnată), eventuala diferenţă de
memorie se eliberează.
Dacă memoria realocată este mai mare decât cea iniţială, atunci se alocă o nouă zonă de
memorie în care se copiază informaţia din zona iniţială, după care prima zona de memorie se
eliberează, în final returnându-se noua adresă.
Cum se face realocarea unui vector?

printf("Dati noua lungime a vectorului: ");
scanf("%d",&m);
a=(int*)realloc(a,m*sizeof(int));
if (a==NULL)
{
printf("Memorie insuficienta!");
exit(1);
}
Eliberarea memoriei alocate cu malloc, calloc şi realloc se face cu ajutorul funcţiei free,
care primeşte ca parametru pointerul spre zona de memorie alocată. Pentru exemplele de mai sus
eliberarea memoriei pentru vectorul a se face cu free(a).
Alocarea memoriei pentru o matrice se poate face, de asemenea, atât static cât şi dinamic.
Varianta statică este: tip a[nl][nc];, unde nl reprezintă numărul de linii, iar nc este numărul de
coloane al matricii.
În continuare prezentăm două moduri în care se poate face alocare dinamică de memorie
pentru o matrice a de valori reale (float) de dimensiuni m şi n. În C, o matrice alocată dinamic
este un vector (de lungime m) de vectori (fiecare de lungime n). Pentru aceasta trebuie să definim
variabila a care va fi de tipul float**, adică pointer către pointer către tipul float. Pointerul a va fi
adresa către zona de memorie în care se reţine vectorul cu adresele de început ale fiecărei linii
ale matricii. Întâi va trebui să alocăm memorie pentru vectorul de adrese de lungime m. Apoi
vom aloca memorie necesară stocării celor m x n elemente ale matricii. În final vom face
legăturile între vectorul de adrese şi zona de memorie unde vor fi stocate elementele matricii.
Cum se face alocarea dinamica a unui matrici?

int i,j,m,n;
float **a;
printf("Dati dimensiunile matricii: ");
scanf("%d%d",&m,&n);
…. a[m-1]
a
…. …. ….
a[0]
a[0][0] a[0][n-1] a[1][0]
a[0] a[1]
Fig. 1: Prima schemă de alocare dinamică a memoriei pentru o matrice
a[m-1][0] a[m-1][n-1]
a[1] a[m-1]
26
a=(float**)calloc(m,sizeof(float*));
if (a==NULL)
{
printf("Memorie insuficienta!");
exit(1);
}
a[0]=(float*)malloc(m*n,sizeof(float));
if (a[0]==NULL)
{
printf("Memorie insuficienta!");
exit(1);
}
for (i=1;i<m;i++) a[i]=a[i-1]+n; /* adresele de inceput ale
liniilor */
....
free(a[0]); /* eliberarea memoriei ocupata de matrice */
free(a);

Întâi se alocă memorie pentru vectorul de adrese al liniilor (a este un vector de elemente
de tipul float*). Apoi se alocă memorie necesară stocării tuturor elementelor matricii a (se alocă
m x n blocuri de lungime sizeof(float)), iar adresa către zona alocată se depune în a[0]. a[1] va fi
adresa către zona de memorie aflată cu n căsuţe (fiecare de lungime sizeof(float)) după a[0] etc.
Cu alte cuvinte la adresa a[0] se găsesc elementele primei linii, apoi în continuare elementele
celei de-a doua linii care încep să fie memorate de la adresa a[1], apoi a treia linie la adresa a[2]
ş.a.m.d., iar la sfârşit la adresa a[n-1] avem elementele ultimei linii.
Eliberarea zonei de memorie ocupate de matricea a se face în doi paşi: întâi se eliberează
vectorul cu cele m x n elemente de tip float (aflat la adresa a[0]), iar apoi se eliberează memoria
ocupată cu vectorul de adrese (vector aflat la adresa a).
Dezavantajul alocării dinamice de mai sus constă în faptul că se încearcă alocarea unei
zone continue de memorie de lungime totală m x n x sizeof(float) şi s-ar putea să nu dispunem de
o zonă continuă de memorie liberă de o asemenea dimensiune. Acest dezavantaj în prezent nu
poate fi considerat major, pentru că astăzi calculatoarele dispun de memorie RAM de capacităţi
mari. Marele avantaj al alocării dinamice de mai sus este dat de viteza mare de execuţie datorată
faptului că se fac numai două alocări şi tot atâtea eliberări de memorie.
O alternativă la alocarea de mai sus este alocarea separată a memoriei pentru fiecare linie
a matricii:
int i,j,m,n;
float **a;
printf("Dati dimensiunile matricii: ");
scanf("%d%d",&m,&n);
a = (float**)calloc(m,sizeof(float*));
if (a==NULL)
{
printf("Memorie insuficienta!");
exit(1);
}
for (i=0;i<m;i++)
{
a[i] = (float*)calloc(n,sizeof(float));
if (a[i]==NULL)
27
{
printf("Memorie insuficienta!");
exit(1);
}
}
....
for (i=0;i<m;i++) free(a[i]); */ eliberarea memoriei */
free(a);
În exemplul de mai sus se fac m+1 alocări de memorie pentru m+1 vectori. Primul vector
alocat (de lungime m), ca şi la prima variantă de alocare a memoriei pentru o matrice, va reţine
adresele către fiecare din cele m linii ale matricii. Apoi se încearcă m alocări de vectori de
lungime n, vectorii cu elementele fiecărei linii a matricii. Astfel, a[0], a[1], … , a[m-1] sunt
adresele către fiecare linie obţinute în urma alocărilor. Eliberarea memoriei alocate pentru
matricea a se face tot în m+1 paşi: întâi se eliberează cele m zone de memorie în care sunt
reţinute elementele matricii şi în final se eliberează zona de memorie ocupată de vectorul cu
adresele de început ale liniilor.

Procedând în mod asemănător cu alocarea dinamică a unei matrici putem aloca memorie
pentru vectori de vectori, în sensul că fiecare dintre vectorii de la adresele a[0], a[1], … ,
a[m-1] pot avea lungimi diferite:

int i,j,m,*n;
float **a;
printf("Dati numarul de vectori: ");
scanf("%d",&m);
n=(int*)calloc(m,sizeof(int));
if (n==NULL)
{
printf("Memorie insuficienta!");
exit(1);
}
printf("Dati numarul de elemente al fiecarui vector:\n");
for (i=0;i<m;i++)
{
printf("n[%d]=",i+1);
scanf("%d",&n[i]);
}
a=(float**)calloc(m,sizeof(float*));
if (a==NULL)
{
printf("Memorie insuficienta!");
exit(1);
}
for (i=0;i<m;i++)
{
a[i]=(float*)calloc(n[i],sizeof(float));
if (a[i]==NULL)
{
printf("Memorie insuficienta!");
exit(1);
}
}
printf("Dati elementele vectorilor:\n");
for (i=0;i<m;i++)
for (j=0;j<n[i];j++)
{
printf("a[%d,%d]=",i+1,j+1);
scanf("%f",&a[i][j]);
}
....
29
for (i=0;i<m;i++) free(a[i]); /* eliberarea memoriei */
free(a);
free(n);
}






1 comentarii:

Anonim spunea...

foarte bun ma ajutat sa trec clasa bravo

Trimiteți un comentariu