web-dev-qa-db-fra.com

Allouer un tableau 2d de mémoire dans la fonction C

Comment allouer de la mémoire dynamique pour un tableau 2D en fonction? J'ai essayé de cette façon:

int main()
{
  int m=4,n=3;
  int** arr;
  allocate_mem(&arr,n,m);
}


void allocate_mem(int*** arr,int n, int m)
{
  *arr=(int**)malloc(n*sizeof(int*));
  for(int i=0;i<n;i++)
    *arr[i]=(int*)malloc(m*sizeof(int));
} 

Mais ça ne marche pas.

14
serhii

Votre code est incorrect dans *arr[i]=(int*)malloc(m*sizeof(int)); parce que priorité de l'opérateur [] Est supérieur à l'opérateur de déférence *: Dans l'expression *arr[i], D'abord arr[i] Est évalué puis * Est appliqué. Ce dont vous avez besoin est l'inverse (déréférencer arr, puis appliquer []).

Utilisez des parenthèses comme ceci: (*arr)[i] Pour remplacer la priorité de l'opérateur. Maintenant, votre code devrait ressembler à ceci:

void allocate_mem(int*** arr, int n, int m)
{
  *arr = (int**)malloc(n*sizeof(int*));
  for(int i=0; i<n; i++)
    (*arr)[i] = (int*)malloc(m*sizeof(int));
} 

Pour mieux comprendre ce qui se passe dans le code ci-dessus, lisez cette réponse .

Il est important de toujours désallouer explicitement la mémoire allouée dynamiquement une fois que vous avez fini de l'utiliser. Pour libérer la mémoire allouée par la fonction ci-dessus, vous devez procéder comme suit:

void deallocate_mem(int*** arr, int n){
    for (int i = 0; i < n; i++)
        free((*arr)[i]);
    free(*arr); 
}

De plus, une meilleure façon de créer un tableau 2D est de allouer la mémoire contiguë avec un seul appel de fonction malloc() comme ci-dessous:

int* allocate_mem(int*** arr, int n, int m)
{
  *arr = (int**)malloc(n * sizeof(int*));
  int *arr_data = malloc( n * m * sizeof(int));
  for(int i=0; i<n; i++)
     (*arr)[i] = arr_data + i * m ;
  return arr_data; //free point
} 

Pour désallouer cette mémoire:

void deallocate_mem(int*** arr, int* arr_data){
    free(arr_data);
    free(*arr);
}

Notez que dans la deuxième technique, malloc n'est appelé que deux fois, et donc dans le code de désallocation free n'est appelé que deux fois au lieu de l'appeler en boucle. Cette technique devrait donc être meilleure.

25
Grijesh Chauhan

Si votre tableau n'a pas besoin d'être redimensionné (enfin, vous pouvez, mais il sera un peu plus compliqué), il existe un moyen plus facile/plus efficace de créer des tableaux 2D en C.

Jetez un œil à http://c-faq.com/aryptr/dynmuldimary.html .

La deuxième méthode (pour le tableau appelé array2) est assez simple, moins pénible (essayez d'ajouter les tests pour la valeur de retour de mallocs), et bien plus efficace.

Je viens de le comparer, pour un tableau 200x100, alloué et désalloué 100000 fois:

  • Méthode 1: 1,8 s
  • Méthode 2: 47 ms

Et les données du tableau seront plus contiguës, ce qui peut accélérer les choses (vous pouvez obtenir des techniques plus efficaces pour copier, réinitialiser ... un tableau alloué de cette façon).

3
Cyrille Faucheux

Plutôt allouer la mémoire dans de nombreux blocs différents, on peut l'allouer dans un bloc de mémoire consécutif. Procédez comme suit:

int** my2DAllocation(int rows,int columns)
{
   int i;
   int header= rows *sizeof(int *);
   int data=rows*cols*sizeof(int);
   int ** rowptr=(int **)malloc(header+data);
   if(rowptr==NULL)
   {
      return NULL:
   }
   int * buf=(int*)(rowptr+rows);
   for(i=0;i<rows;i++)
   {
      rowptr[i]=buf+i*cols;
   } 
   return rowptr;
}
2
Smit Patel

Considérez ceci: une seule allocation

int** allocate2D(int m, int n)
{
    int **a = (int **)malloc(m * sizeof(int *) + (m * n * sizeof(int)));

    int *mem = (int *)(a + m);

    for(int i = 0; i < m; i++)
    {
        a[i] = mem + (i * n);
    }

    return a;
}

Libérer:

free(a);
2
TheMan

C'est une façon inutilement compliquée d'allouer de l'espace à un tableau. Considère ceci:

int main(void) {
    size_t m = 4, n = 3;
    int (*2D_array)[m];
    2D_array = malloc(n * sizeof *2D_array);
    free(2D_array);
    return 0;
}
1
autistic

J'ai essayé le code suivant pour allouer de la mémoire à un tableau bidimensionnel.

    #include<stdio.h>
    #include<malloc.h>
    void main(void)
    {
    int **p;//double pointer holding a 2d array
    int i,j;
    for(i=0;i<3;i++)
    {
    p=(int**)(malloc(sizeof(int*)));//memory allocation for double pointer
    for(j=(3*i+1);j<(3*i+4);j++)
    {
    *p = (int*)(malloc(sizeof(int)));//memory allocation for pointer holding integer array
    **p = j;                  
    printf(" %d",**p);//print integers in a row 
    printf("\n");
    p++;
    }
    }
    }

La sortie du code ci-dessus est: -

1 2 3

4 5 6

7 8 9

Afin de comprendre le tableau bidimensionnel en termes de pointeurs, nous devons comprendre comment il sera alloué en mémoire, cela devrait être quelque chose comme ceci: -

                1    2    3
    1000 -->   100  104  108

                4    5    6
    1004 -->   200  204  208

                7    8    9
    1008 -->   300  304  308 

d'après ce qui précède, nous comprenons que, lorsque nous allouons de la mémoire au pointeur p qui est un double pointeur, il pointe vers un tableau d'entiers, donc dans cet exemple, nous voyons que le 0x1000 est le pointeur p.

Ce pointeur pointe vers un pointeur entier * p qui est un tableau d'entiers, lorsque la mémoire est allouée à l'intérieur de la boucle for, pendant la première itération, le pointeur est 0x100 qui pointe vers la valeur entière 1, lorsque nous affectons ** p = j. De même, il pointera sur 2 et 3 dans les prochaines itérations de la boucle.

Avant la prochaine itération de la boucle externe, le double pointeur est incrémenté, à l'intérieur de la prochaine itération, comme on le voit dans cet exemple, le pointeur est maintenant à 0x1004 et pointe vers un pointeur entier qui est un tableau d'entiers 4,5,6 et similaire pour les prochaines itérations de la boucle.

0
Nanobrains