Comment inclure un tableau dynamic DANS une structure en C?

J’ai regardé autour de moi mais je n’ai pas trouvé de solution à ce qui doit être une question bien posée. Voici le code que j’ai:

#include  struct my_struct { int n; char s[] }; int main() { struct my_struct ms; ms.s = malloc(sizeof(char*)*50); } 

et voici l’erreur que me donne gcc: erreur: utilisation non valide d’un membre de tableau flexible

Je peux le faire comstackr si je déclare la déclaration de s à l’intérieur de la structure pour être

 char* s 

et c’est probablement une implémentation supérieure (l’arithmétique de pointeur est plus rapide que les tableaux, oui?), mais j’ai pensé que c

 char s[] 

est le même que

 char* s 

La façon dont vous l’avez écrit maintenant s’appelait le “struct hack”, jusqu’à ce que C99 le bénisse en tant que “membre de tableau flexible”. La raison pour laquelle vous obtenez une erreur (probablement de toute façon) est qu’elle doit être suivie d’un point-virgule:

 #include  struct my_struct { int n; char s[]; }; 

Lorsque vous allouez de l’espace pour cela, vous voulez allouer la taille de la structure plus la quantité d’espace souhaitée pour le tableau:

 struct my_struct *s = malloc(sizeof(struct my_struct) + 50); 

Dans ce cas, le membre de tableau flexible est un tableau de caractères, et sizeof (caractère) == 1, vous n’avez donc pas besoin de le multiplier par sa taille, mais comme tout autre malloc dont vous auriez besoin s’il s’agissait d’un object. tableau d’un autre type:

 struct dyn_array { int size; int data[]; }; struct dyn_array* my_array = malloc(sizeof(struct dyn_array) + 100 * sizeof(int)); 

Éditer: Cela donne un résultat différent de changer le membre en pointeur. Dans ce cas, vous avez (normalement) besoin de deux allocations distinctes, une pour la structure elle-même et une pour les données “supplémentaires” à pointer vers le pointeur. En utilisant un membre de groupe flexible, vous pouvez allouer toutes les données dans un seul bloc.

Vous devez décider ce que vous essayez de faire en premier.


Si vous voulez avoir une structure avec un pointeur sur un tableau [indépendant] à l’intérieur, vous devez le déclarer comme

 struct my_struct { int n; char *s; }; 

Dans ce cas, vous pouvez créer l’object struct actuel comme bon vous semble (comme une variable automatique, par exemple)

 struct my_struct ms; 

puis allouer la mémoire pour le tableau indépendamment

 ms.s = malloc(50 * sizeof *ms.s); 

En fait, il n’y a pas de nécessité générale d’allouer dynamicment la mémoire de masortingce

 struct my_struct ms; char s[50]; ms.s = s; 

Tout dépend du type de vie dont vous avez besoin pour ces objects. Si votre structure est automatique, dans la plupart des cas, le tableau sera également automatique. Si l’object struct est propriétaire de la mémoire de tableau, il est tout simplement inutile de procéder autrement. Si la structure elle-même est dynamic, le tableau doit normalement être dynamic.

Notez que dans ce cas, vous avez deux blocs de mémoire indépendants: le struct et le tableau.


Une approche complètement différente consisterait à utiliser l’idiome “struct hack”. Dans ce cas, le tableau devient une partie intégrante de la structure. Les deux résident dans un seul bloc de mémoire. En C99, la structure serait déclarée comme

 struct my_struct { int n; char s[]; }; 

et pour créer un object, vous devez allouer le tout dynamicment

 struct my_struct *ms = malloc(sizeof *ms + 50 * sizeof *ms->s); 

Dans ce cas, la taille du bloc de mémoire est calculée pour tenir compte des membres de la structure et du tableau de fin de la taille d’exécution.

Notez que dans ce cas, vous n’avez aucune option pour créer des objects struct tels que des objects statiques ou automatiques. Les structures avec des membres de tableau flexibles à la fin ne peuvent être allouées dynamicment qu’en C.


Votre hypothèse selon laquelle les produits d’aiguille au pointeur sont plus rapides que les tableaux est absolument incorrecte. Par définition, les tableaux fonctionnent par arithmétique de pointeur, ils sont donc fondamentalement les mêmes. De plus, un tableau authentique (non décomposé en pointeur) est généralement un peu plus rapide qu’un object pointeur. La valeur du pointeur doit être lue dans la mémoire, tandis que l’emplacement du tableau en mémoire est “connu” (ou “calculé”) à partir de l’object tableau lui-même.

L’utilisation d’un tableau de taille non spécifiée n’est autorisée qu’à la fin d’une structure et ne fonctionne que dans certains compilateurs. C’est une extension de compilateur non standard. (Bien que je pense me souvenir que C ++ 0x permettra cela.)

Le tableau ne sera cependant pas une allocation distincte de la structure. Vous devez donc allouer tout my_struct , pas seulement la partie tableau.

Ce que je fais est simplement de donner au tableau une taille petite mais non nulle. Habituellement, 4 pour les tableaux de caractères et 2 pour les tableaux de wchar_t afin de préserver l’alignement sur 32 bits.

Ensuite, vous pouvez prendre en compte la taille déclarée du tableau lors de l’allocation. Je ne fais souvent pas l’hypothèse que le slop est plus petit que la granularité dans laquelle le gestionnaire de tas travaille dans tous les cas.

De plus, je pense que vous ne devriez pas utiliser sizeof (char *) dans votre allocation.

C’est ce que je ferais.

 struct my_struct { int nAllocated; char s[4]; // waste 32 bits to guarantee alignment and room for a null-terminator }; int main() { struct my_struct * pms; int cb = sizeof(*pms) + sizeof(pms->s[0])*50; pms = (struct my_struct*) malloc(cb); pms->nAllocated = (cb - sizoef(*pms) + sizeof(pms->s)) / sizeof(pms->s[0]); } 

Les tableaux vont se résoudre en pointeurs, et ici vous devez définir s tant que char *s . La structure est fondamentalement un conteneur et doit (IIRC) avoir une taille fixe, il est donc impossible d’avoir un tableau de taille dynamic à l’intérieur. De toute façon, étant donné que vous vous malloc la mémoire, cela ne devrait faire aucune différence dans ce que vous cherchez.

En gros, vous dites que s indiquera un emplacement de mémoire. Notez que vous pouvez toujours y accéder plus tard en utilisant une notation telle que s[0] .

l’arithmétique de pointeur est plus rapide que les tableaux, oui?

Pas du tout – ils sont en fait les mêmes. les tableaux se traduisent en arithmétique de pointeur au moment de la compilation.

 char test[100]; test[40] = 12; // translates to: (test now indicates the starting address of the array) *(test+40) = 12; 

Je suppose que le compilateur ne sait pas combien d’espace il devra allouer pour s [], si vous choisissez de déclarer une variable automatique avec elle.

Je suis d’accord avec ce que dit Ben, déclare ta structure

 struct my_struct { int n; char s[1]; }; 

De plus, pour clarifier son commentaire sur le stockage, déclarer char *s ne mettra pas la structure sur la stack (puisqu’elle est allouée dynamicment) et allouera s dans le tas, ce qui sera interprété par la première sizeof(char *) octets de votre tableau en tant que pointeur, de sorte que vous ne serez pas opérer sur les données que vous pensez être, et sera probablement fatal.

Il est essentiel de se rappeler que, bien que les opérations sur les pointeurs et les tableaux puissent être mises en œuvre de la même manière, elles ne sont pas la même chose.

Il y a beaucoup de réponses concernant le tableau flexible C99.

Je voulais commenter la réponse d’Alexander Gessler concernant les pointeurs identiques aux tableaux.

Ils ne sont pas; Les tableaux sont une expression, les pointeurs sont une variable.

Ils ont des différences subtiles, en particulier lors de la traversée de grandes quantités de données. Parfois, vous devez extraire chaque msec (je travaille sur des systèmes graphiques embarqués).

le code généré sera identique (tableau et ptr). Mis à part le fait que le tableau que vous ne comstackrez pas est

et BTW – faites-le c ++ et utilisez vector