Skip to content

Latest commit

 

History

History
158 lines (146 loc) · 6.85 KB

FP_22_C_2021-12-09.md

File metadata and controls

158 lines (146 loc) · 6.85 KB

ALOCAREA MEMORIEI DINAMIC PENTRU MATRICE

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.

Imagine: Alocare dinamica matrice

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;

Imagine: Alocare dinamica matrice metoda II

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

Comparatia intre cele doua metode:

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

Avantajele celei de-a doua metode:

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:

  1. Sa se scrie macrocomenzi pentru alocarea dinamica si eliberarea memoriei pentru a matrice in stilul al doilea.
  2. Sa se aloce dinamic memorie pentru o matrice triunghiulara de dimensiune n.
  3. 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
}