web-dev-qa-db-fra.com

Allouer correctement des tableaux multidimensionnels

Le but de cette question est de fournir une référence sur la façon d'allouer correctement des tableaux multidimensionnels de manière dynamique en C. C'est un sujet souvent mal compris et mal expliqué, même dans certains livres de programmation en C. Par conséquent, même les programmeurs C expérimentés ont du mal à faire les choses.  


Mon professeur de programmation/livre/tutoriel m'a appris que la méthode correcte pour allouer de manière dynamique un tableau multidimensionnel consiste à utiliser un pointeur à un autre. 

Cependant, plusieurs utilisateurs de référence élevée sur SO me disent maintenant que cette pratique est mauvaise et mauvaise. Ils disent que les pointeurs sur pointeurs ne sont pas des tableaux, que je ne les alloue pas et que mon code est inutilement lent. 

Voici comment on m'a appris à allouer des tableaux multidimensionnels:

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

int** arr_alloc (size_t x, size_t y)
{
  int** pp = malloc(sizeof(*pp) * x);
  assert(pp != NULL);
  for(size_t i=0; i<x; i++)
  {
    pp[i] = malloc(sizeof(**pp) * y);
    assert(pp[i] != NULL);
  }

  return pp;
}

int** arr_fill (int** pp, size_t x, size_t y)
{
  for(size_t i=0; i<x; i++)
  {
    for(size_t j=0; j<y; j++)
    {
      pp[i][j] = (int)j + 1;
    }
  }

  return pp;
}

void arr_print (int** pp, size_t x, size_t y)
{
  for(size_t i=0; i<x; i++)
  {
    for(size_t j=0; j<y; j++)
    {
      printf("%d ", pp[i][j]);
    }
    printf("\n");
  }
}

void arr_free (int** pp, size_t x, size_t y)
{
  (void) y;

  for(size_t i=0; i<x; i++)
  {
    free(pp[i]);
    pp[i] = NULL;
  }
  free(pp);
  pp = NULL;
}


int main (void)
{
  size_t x = 2;
  size_t y = 3;
  int** pp;

  pp = arr_alloc(x, y);
  pp = arr_fill(pp, x, y);
  arr_print(pp, x, y);
  arr_free(pp, x, y);

  return 0;
}

Sortie

1 2 3
1 2 3

Ce code fonctionne très bien! Comment pourrait-il se tromper?

45
Lundin

C ne dispose pas de tableaux multidimensionnels. Mais vous pourriez avoir des tableaux de tableaux (ou d’autres agrégats) et des tableaux de pointeurs.

Une approche possible consiste à raisonner avec un type de données abstrait (peut-être en utilisant membres du tableau flexible , qui est une astuce d'implémentation, et vous pourriez utiliser d'autres approches) comme dans cette réponse .

Nous ne pouvons suggérer aucun type de données abstrait, car cela dépend du texte de vos devoirs, que nous n'avons pas. Vous devez concevoir votre type de données abstrait (sur un morceau de papier), et plus tard pour le mettre en œuvre.

Une fois que vous avez répertorié (sur un papier ou sur un tableau) toutes les opérations nécessaires sur votre ADT, leur mise en œuvre est simple.

Ce code fonctionne très bien! Comment pourrait-il se tromper?

Cette phrase est incohérente (fausse w.r.t. quelles spécifications?) ...

Je recommande de compiler avec tous les avertissements et les informations de débogage (par exemple, avecgcc -Wall -Wextra -g avec GCC ), afin d'améliorer votre code jusqu'à ce que vous n'ayez plus d'avertissements, d'utiliser le débogueur gdb (pour comprendre). ce qui se passe dans votre programme) et d’autres outils comme valgrind .

0