tip_date* a=(tip_date*)malloc(n*sizeof(tip_date));
Daca pentru un tablou unidimensional putem aloca dinamic memorie in C folosind malloc
sau calloc
, pentru tablouri multidimensionale (de dimensiune cel putin 2) nu exista functie standard de alocare dinamic. In schimb, alocarea dinamica pentru vector de mai sus poate fi folosita pentru a aloca dinamic memorie pentru un tablou multidimensional in mai multi pasi.
O matrice bidimensionala poate fi considerata ca fiind un vector de vectori m
= nr de vectori (linii) si n
= lungimea unui vector (coloane)
Pentru o matrice vom considera un pointer catre pointer catre tip_date a
:
tip_date** a;
Asa cum am vazut, pointerul este un tip de date format dintr-un tip de date existent urmat de asterisc. Un astfel de pointer poate retine adresa de inceput a zonei de memorie alocata pentru un vector. In scrierea de mai sus, a
este un pointer catre tip_date*
, adica a
poate retine adresa de inceput a unui vector avand componente de tipul tip_date*
, adica a
este un vector de pointeri. Fiecare pointer din acest vector va retine adresa de inceput a unei linii avand elemente de tipul tip_date
.
a=(tip_date**)malloc(m*sizeof(tip_date*));
//alocare memorie pentru vectorul de pointeri
for(int i=0;i<m;i++)
a[i]=(tip_date*)malloc(n*sizeof(tip_date));
//alocare memorie pentru linia i+1
a[i][j]=*(a[i]+j);
Pentru a aloca memorie in stilul de mai sus avem nevoie de m+1
alocari dinamice de vectori
tip_date** a;
void matralloc(int m, int n, tip_date** a)
{
a=(tip_date**)malloc(m*sizeof(tip_date*));
for(int i=0;i<m;i++)
a[i]=(tip_date*)malloc(n*sizeof(tip_date));
}
In exemplul de mai sus, variabila a
este transmisa prin valoare, deci este o copie a pointerului transmis prin functie la apel. In prima linie, a
se initializare cu adresa catre vectorul de pointeri, valoare, care evident nu este returnata de functia matralloc
.
void main()
{
int m, n;
scanf("%d%d",&m,&n);
tip_date** a;
matralloc(m,n,a);
}
Apelul este corect, dar variabila a
din main
nu se va initializa cu adresa vectorului alocat, deci este incorect.
void matralloc(int m, int n, tip_date*** a)
{
*a=(tip_date**)malloc(m*sizeof(tip_date*));
for(int i=0;i<m;i++)
(*a)[i]=(tip_date*)malloc(n*sizeof(tip_date));
}
void main()
{
int m, n;
scanf("%d%d",&m,&n);
tip_date** a;
matralloc(m,n,&a);
}
Din cauza ca alocarea dinamica se face in m+1
pasi, eliberarea, evident, se va face in prin m+1
apeluri ale functiei free()
.
void matrfree(int m,tip_date** a)
{
for(int i=0;i<m;i++)
free(a[i]);
free(a);
}
Pentru o matrice putem gandi diverse metode de a aloca dinamic memorie, pastrand insa ideea de variabila pointer de pointer de tip_date
pentru a retine matricea alocata dinamic.
Prezentam in continuare, o alta metoda consacrata. In aceasta metoda vom face numai doua alocari dinamice, una pentru vectorul de pointeri pentru linii si a doua pentru a retine consecutiv in memorie toate elementele matricei, incepand cu elemetele de pe prima linie, apoi de pe a doua linie... In final, trebuie ca pointerii din vectorul a
sa retina adresele de inceput ale liniilor.
tip_date** a;
a=(tip_date**)malloc(m*sizeof(tip_date*));
a[0]=(tip_date*)malloc(m*n*sizeof(tip_date));
for(int i=1;i<m;i++)
a[i]=a[i-1]+n;
void matralloc2(int m, int n, tip_date*** a)
{
*a=(tip_date**)malloc(m*sizeof(tip_date*));
(*a)[0]=(tip_date*)malloc(m*n*sizeof(tip_date));
for(int i=1;i<m;i++)
(*a)[i]=a[i-1]+n;
}
La metoda a doua de alocare dinamica, am alocat o zona de memorie continua de lungime m*n
casute de tipul elementelor matricei. Adresa acestei zone am retinut-o in pointerul a[0]
, care practic retine adresa de inceput si a primei linii. Adresa de inceput a celei de-a doua linii (a[1]
) este data de adresa a[0]
de la care ne deplasam n
casute la dreapta pentru a regasi inceputul celei de-a doua linii. In mod similar, a[i]
adresa celei de-a i+1
linii este adresa liniei precedente (a[i-1]
) de la care ne deplasam spre dreapta n
casute. Eliberarea matricei alocate in stilul al doilea se va face prin doua apeluri de functie free()
.
void matrfree2(tip_date** a)
{
free(a[0]);
free(a);
}
Prima metoda este „mai fireasca, mai usor de inteles”, in consecinta, metoda 1 poate fi usor generalizata pentru matrice 3D, 4D, ... (pentru o matrice k
dimensionala alocam un vevtor de pointeri catre m
matrici k-1
dimensionala, unde m
este prima dimensiune a matricei k
dimensionala, dupa care facem m
alocari dinamice pentru matrici k-1
dimensionale).
Metoda a doua este mai rapida, atat la alocare cat si la eliberare. Putem trimite/primi o matrice si citi/scrie din/in memorie intr-un singur pas, trimiterea/primirea facandu-se intr-un/dintr-un flux de date (ex. din fisier).
#define matalloc(m,n,a,t) a=(t**)malloc(m*sizeof(t*));\
for(int i=i;i<n;i++)\
a[i]=(t*)malloc(n*sizeof(t));
#define matfree(m,a) for(int i=0;i<n;i++)\
free(a[i]);\
free(a);
int**a, m, n;
...
matalloc(m,n,a,int)
...
matfree(m,a)
TPA:
- Sa se scrie macrocomenzi pentru alocarea dinamica si eliberarea memoriei pentru a matrice in stilul al doilea.
- Sa se aloce dinamic memorie pentru o matrice triunghiulara de dimensiune n.
- Sa se scrie macrocomanda pentru alocarea dinamica a memoriei pentru a matrice 3D de dimensiuni mnp. Sa se scrie o macrocomanda pentru o astfel de matrice.
void matrsort(int m, int n, float** a) //fac modificare la adresa, dar nu modific adresa
{
float* s=(float*)calloc(m,sizeof(float));
for(int i=0;i<m;i++)
for(int j=0;j<m;j++)
s[i]+=a[i][j];
for(int i=0;i<n-1;i++)
for(int j=0;j<m;j++)
if(s[i]>s[j])
{
inter(s[i],s[j])
inter(a[i],a[j])
}
free(s);
}
Obs.: inter
este macrocomanda definita in cursuri anterioare.
La parasirea functiei matrsort
, a[0]
va retine adresa liniei care are suma cea mai mica, a[1]
retine adresa urmatoarei linii ca suma, etc.
void main()
{
int m,n;
float** a;
scanf("%d%d",&m,&n);
matalloc(m,n,a,float);
//citire matrice a
matrsort(m,n,a);
//afisare matrice a
matfree(m,a) //fara ; pentru ca este macrocomanda
}