web-dev-qa-db-fra.com

Utilisation de malloc pour l'allocation de tableaux multidimensionnels avec différentes longueurs de ligne

J'ai le code C suivant:

int *a;
size_t size = 2000*sizeof(int);
a = (int *) malloc(size);

qui fonctionne bien. Mais si j'ai les éléments suivants:

char **b = malloc(2000*sizeof *b);

où chaque élément de b a une longueur différente.

Comment est-il possible de faire la même chose pour b que je l’ai fait pour a; c'est-à-dire que le code suivant serait correct?

char *c;
size_t size = 2000*sizeof(char *);
c = (char *) malloc(size);
65
asel

Tout d’abord, vous devez allouer un tableau de pointeurs comme char **c = malloc( N * sizeof( char* )), puis allouer à chaque ligne un appel distinct à malloc, probablement dans la boucle:


/* N is the number of rows  */
/* note: c is char** */
if (( c = malloc( N*sizeof( char* ))) == NULL )
{ /* error */ }

for ( i = 0; i < N; i++ )
{
  /* x_i here is the size of given row, no need to
   * multiply by sizeof( char ), it's always 1
   */
  if (( c[i] = malloc( x_i )) == NULL )
  { /* error */ }

  /* probably init the row here */
}

/* access matrix elements: c[i] give you a pointer
 * to the row array, c[i][j] indexes an element
 */
c[i][j] = 'a';

Si vous connaissez le nombre total d’éléments (par exemple, N*M), vous pouvez le faire en une seule allocation.

75
Nikolai Fetissov

La forme typique pour l’allocation dynamique d’un tableau NxM de type T est

T **a = malloc(sizeof *a * N);
if (a)
{
  for (i = 0; i < N; i++)
  {
    a[i] = malloc(sizeof *a[i] * M);
  }
}

Si chaque élément du tableau a une longueur différente, remplacez M par la longueur appropriée pour cet élément; par exemple

T **a = malloc(sizeof *a * N);
if (a)
{
  for (i = 0; i < N; i++)
  {
    a[i] = malloc(sizeof *a[i] * length_for_this_element);
  }
}
48
John Bode

L'allocation de mémoire équivalente pour char a[10][20] serait la suivante.

char **a;

a=(char **) malloc(10*sizeof(char *));

for(i=0;i<10;i++)
    a[i]=(char *) malloc(20*sizeof(char));

J'espère que cela semble simple à comprendre.

27
Ramesh

L'autre approche consisterait à allouer un bloc de mémoire contigu comprenant un bloc d'en-tête pour les pointeurs vers des lignes ainsi qu'un bloc de corps pour stocker les données réelles dans des lignes. Ensuite, il suffit de marquer la mémoire en attribuant des adresses de mémoire dans le corps aux pointeurs de l’en-tête, ligne par ligne. Cela ressemblerait à ceci:

int** 2dAlloc(int rows, int* columns) {    
    int header = rows * sizeof(int*);

    int body = 0;
    for(int i=0; i<rows; body+=columnSizes[i++]) {  
    }
    body*=sizeof(int);

    int** rowptr = (int**)malloc(header + body);

    int* buf  = (int*)(rowptr + rows);
    rowptr[0] = buf;
    int k;
    for(k = 1; k < rows; ++k) {
        rowptr[k] = rowptr[k-1] + columns[k-1];
    }
    return rowptr;
}

int main() {
    // specifying column amount on per-row basis
    int columns[] = {1,2,3};
    int rows = sizeof(columns)/sizeof(int);
    int** matrix = 2dAlloc(rows, &columns);

    // using allocated array
    for(int i = 0; i<rows; ++i) {
        for(int j = 0; j<columns[i]; ++j) {
            cout<<matrix[i][j]<<", ";
        }   
            cout<<endl;
    }

    // now it is time to get rid of allocated 
    // memory in only one call to "free"
    free matrix;
}

L'avantage de cette approche est la libération élégante de mémoire et la possibilité d'utiliser une notation semblable à un tableau pour accéder aux éléments du tableau 2D résultant.

10
Dmitry Aleks

Si chaque élément de b a des longueurs différentes, vous devez faire quelque chose comme:

int totalLength = 0;
for_every_element_in_b {
    totalLength += length_of_this_b_in_bytes;
}
return (char **)malloc(totalLength);
3
plinth

Je pense qu’une approche en 2 étapes est préférable, car les tableaux c-2-D sont simples et se présentent sous forme de tableaux. La première étape consiste à allouer un seul tableau, puis à le parcourir en allouant des tableaux pour chaque colonne au fur et à mesure. Cet article donne de bons détails.

2
zdav

Allocation de mémoire dynamique de matrice 2D

int **a,i;

// for any number of rows & columns this will work
a = (int **)malloc(rows*sizeof(int *));
for(i=0;i<rows;i++)
    *(a+i) = (int *)malloc(cols*sizeof(int));
1
Sridhar T

malloc n'alloue pas sur des limites spécifiques, il faut donc supposer qu'il attribue des octets.

Le pointeur renvoyé ne peut alors pas être utilisé s'il est converti en un autre type, car l'accès à ce point produira probablement une violation de l'accès à la mémoire par la CPU et l'application sera immédiatement fermée.

0
Vendicar Decarian