Déclaration étrange de tableau de taille variable

En lisant cette implémentation, je suis tombé sur ce fragment de code:

typedef struct nodeStructure{ keyType key; valueType value; node forward[1]; /* variable sized array of forward pointers */ }; 

Pour moi, il semble que forward[1] désigne un tableau à un élément. Et le commentaire appelle cela un tableau de taille variable .

Est-ce que je comprends mal quelque chose ou est-ce juste une erreur dans la source que je lis?

Ceci est une astuce courante pour les anciens compilateurs C (avant C99): les compilateurs vous permettaient de déréférencer les éléments au-delà de la fin de la longueur déclarée de forward , qui est le dernier élément de la struct ; vous pouvez alors malloc suffisamment de mémoire pour les éléments de node supplémentaires, comme ceci:

 nodeStructure *ptr = malloc(sizeof(nodeStructure)+4*sizeof(node)); for (int i = 0 ; i != 5 ; i++) { // The fifth element is part of the struct ptr->forward[i] = ... } free(ptr); 

L’astuce vous permet d’intégrer des tableaux de taille variable dans une structure sans allocation dynamic séparée. Une autre solution consisterait à déclarer le node *forward , mais vous devrez ensuite malloc et le free séparément de la nodeStructure , en doublant inutilement le nombre de malloc et en augmentant potentiellement la fragmentation de la mémoire:

Voici à quoi ressemblerait ce fragment sans le hack:

 typedef struct nodeStructure{ keyType key; valueType value; node *forward; }; nodeStructure *ptr = malloc(sizeof(nodeStructure)); ptr->forward = malloc(5*sizeof(node)); for (int i = 0 ; i != 5 ; i++) { ptr->forward[i] = ... } free(ptr->forward); free(ptr); 

EDIT (en réponse aux commentaires d’Adam Rosenfield): C99 vous permet de définir des tableaux sans taille, comme ceci: node forward[]; Ceci est appelé membre de groupe flexible , il est défini dans la section 6.7.2.1.16 de la norme C99.

C’est ce qu’on appelle la struct hack . Il s’agit de l’ ancienne forme du membre de groupe flexible introduit dans C99.

Cela a été utilisé dans le passé pour imiter un tableau de variables dans le dernier membre d’une structure, mais ce n’est pas une construction ssortingctement conforme en C.

C’est un paradigme de programme en C que vous verrez parfois. Lors de l’allocation de la structure, vous allez allouer sizeof (struct nodeStructure + numNodes * sizeof (noeud)).

Cela vous permet d’avoir plusieurs nœuds de transfert pour la structure, même si elle n’est déclarée que pour en avoir un. C’est un peu un bidouillage laid, mais ça marche.

Généralement, lorsque vous faites cela, il y aura également un fichier appelé “compte” ou quelque chose, de sorte que vous sachiez combien d’entrées supplémentaires sont après le nœud.

L’implémentation de la structure de données est très probablement écrite par rapport à la norme C90, qui ne comportait pas de membres de tableau flexibles (ajouté en C99). À cette époque, il était courant d’utiliser un tableau de taille 1 ou même 0 (*) à la fin d’une structure pour permettre l’access à un nombre d’éléments variable de manière dynamic.

Le commentaire ne doit pas être interprété comme signifiant des tableaux de longueur variable de style C99; de plus, en C99, la définition idiomatique et conforme à la norme pour membre forward serait node forward[]; . Un type tel que struct nodeStructure avec un tel membre est alors appelé type incomplet . Vous pouvez définir un pointeur sur celui-ci, mais vous ne pouvez pas définir une variable de ce type ni prendre sa taille. Toutes les opérations autorisées par node forward[0] ou par node forward[1] acceptables, bien que ces opérations ne concordent pas avec l’intention du programmeur.

(*) Les baies de taille 0 sont interdites par la norme mais GCC les a acceptées comme une extension pour cette utilisation.