Ce que vous dites dans votre message est absolument correct. Je dirais que chaque développeur C arrive exactement à la même découverte et à exactement la même conclusion quand (s'il) atteint un certain niveau de maîtrise du langage C.
Lorsque les spécificités de votre domaine d'application appellent un tableau de taille fixe spécifique (la taille du tableau est une constante au moment de la compilation), la seule façon appropriée de transmettre un tel tableau à une fonction consiste à utiliser un paramètre pointeur vers tableau
void foo(char (*p)[10]);
(en langage C ++, cela se fait également avec des références
void foo(char (&p)[10]);
).
Cela activera la vérification du type au niveau de la langue, ce qui garantira que le tableau de taille exactement correcte est fourni comme argument. En fait, dans de nombreux cas, les gens utilisent cette technique implicitement, sans même s'en rendre compte, en cachant le type de tableau derrière un nom typedef
typedef int Vector3d[3];
void transform(Vector3d *vector);
/* equivalent to `void transform(int (*vector)[3])` */
...
Vector3d vec;
...
transform(&vec);
Notez en outre que le code ci-dessus est invariant, le Vector3d
type étant un tableau ou un struct
. Vous pouvez basculer la définition de Vector3d
à tout moment d'un tableau à a struct
et inversement, et vous n'aurez pas à modifier la déclaration de la fonction. Dans les deux cas, les fonctions recevront un objet agrégé "par référence" (il y a des exceptions à cela, mais dans le contexte de cette discussion, c'est vrai).
Cependant, vous ne verrez pas cette méthode de passage de tableau utilisée explicitement trop souvent, simplement parce que trop de gens sont déroutés par une syntaxe plutôt alambiquée et ne sont tout simplement pas assez à l'aise avec ces fonctionnalités du langage C pour les utiliser correctement. Pour cette raison, dans la vie réelle moyenne, passer un tableau comme pointeur vers son premier élément est une approche plus populaire. Cela semble juste "plus simple".
Mais en réalité, utiliser le pointeur vers le premier élément pour le passage d'un tableau est une technique très niche, une astuce, qui sert un objectif très spécifique: son seul et unique objectif est de faciliter le passage de tableaux de taille différente (c'est-à-dire de taille d' exécution) . Si vous avez vraiment besoin de pouvoir traiter des tableaux de taille d'exécution, alors la bonne façon de passer un tel tableau est par un pointeur vers son premier élément avec la taille concrète fournie par un paramètre supplémentaire
void foo(char p[], unsigned plen);
En fait, dans de nombreux cas, il est très utile de pouvoir traiter des tableaux de taille d'exécution, ce qui contribue également à la popularité de la méthode. De nombreux développeurs C ne rencontrent tout simplement jamais (ou ne reconnaissent jamais) la nécessité de traiter un tableau de taille fixe, restant ainsi inconscients de la technique de taille fixe appropriée.
Néanmoins, si la taille du tableau est fixe, le passer en tant que pointeur vers un élément
void foo(char p[])
est une erreur technique majeure, malheureusement assez répandue de nos jours. Une technique pointeur vers tableau est une bien meilleure approche dans de tels cas.
Une autre raison qui pourrait entraver l'adoption de la technique de passage de tableaux de taille fixe est la prédominance de l'approche naïve du typage des tableaux alloués dynamiquement. Par exemple, si le programme appelle des tableaux fixes de type char[10]
(comme dans votre exemple), un développeur moyen utilisera malloc
des tableaux tels que
char *p = malloc(10 * sizeof *p);
Ce tableau ne peut pas être passé à une fonction déclarée comme
void foo(char (*p)[10]);
ce qui déroute le développeur moyen et lui fait abandonner la déclaration de paramètre de taille fixe sans y réfléchir davantage. En réalité cependant, la racine du problème réside dans l' malloc
approche naïve . Le malloc
format indiqué ci-dessus doit être réservé aux tableaux de taille d'exécution. Si le type de tableau a une taille au moment de la compilation, une meilleure façon de malloc
procéder serait la suivante
char (*p)[10] = malloc(sizeof *p);
Ceci, bien sûr, peut être facilement transmis à la déclaration ci-dessus foo
foo(p);
et le compilateur effectuera la vérification de type appropriée. Mais encore une fois, cela est trop déroutant pour un développeur C non préparé, c'est pourquoi vous ne le verrez pas trop souvent dans le code quotidien moyen "typique".
10
peut être remplacé par n'importe quelle variable dans la portée