71 votes

Comment puis-je obtenir la taille d'un tableau à partir d'un pointeur en C?

J'ai alloué un "tableau" de mystruct de la taille de l' n comme ceci:

if (NULL == (p = calloc(sizeof(struct mystruct) * n,1))) {
 /* handle error */
}

Plus tard, je n'ai accès qu'à l' p, et n'ont plus d' n. Est-il un moyen pour déterminer la longueur du tableau donné juste le pointeur p?

Je me dis qu'il doit être possible, puisque free(p) . Je connais malloc() garde une trace de la quantité de mémoire qu'elle a alloué, et c'est pourquoi il connaît la longueur; il est peut-être un moyen d'interroger cette information? Quelque chose comme...

int length = askMallocLibraryHowMuchMemoryWasAlloced(p) / sizeof(mystruct)

Je sais que je devrais retravailler le code pour que je sache n, mais je préfère ne pas si c'est possible. Des idées?

56voto

Barry Wark Points 73462

Non, il n'y a aucun moyen d'obtenir cette information sans dépendre fortement sur les détails de mise en œuvre de l' malloc. En particulier, malloc peut allouer plus d'octets que vous demandez (par exemple, pour plus d'efficacité dans une architecture de mémoire). Il serait beaucoup mieux de revoir votre code afin que vous garder une trace de l' n explicitement. L'alternative est au moins autant la refonte et bien plus dangereux de l'approche (étant donné qu'il est non-standard, les abus de la sémantique des pointeurs, et aura un entretien cauchemar pour ceux qui viennent après vous): stocker la longueurn à la malloc avais l'adresse, le suivi du tableau. L'Allocation serait alors:

void *p = calloc(sizeof(struct mystruct) * n + sizeof(unsigned long int),1));
*((unsigned long int*)p) = n;

n est actuellement stocké en *((unsigned long int*)p) et le début de votre tableau est maintenant

void *arr = p+sizeof(unsigned long int);

Edit: Juste pour jouer l'avocat du diable... je sais que ces "solutions" toutes nécessitent des remaniements, mais nous allons jouer dehors. Bien sûr, la solution présentée ci-dessus est juste un hacky mise en œuvre d'une (bien emballé) struct. Vous pouvez ainsi définir:

typedef struct { 
  unsigned int n;
  void *arr;
} arrInfo;

et de faire passer arrInfos plutôt que brut de pointeurs.

Maintenant, nous faisons la cuisine. Mais aussi longtemps que vous êtes la refonte, pourquoi s'arrêter là? Ce que vous voulez vraiment est un type abstrait de données (ADT). Tout texte d'introduction à l'un des algorithmes et structures de données de la classe. Un ADT définit l'interface publique d'un type de données, mais cache la mise en œuvre de ce type de données. Ainsi, publiquement un ADT pour un tableau pourrait ressembler

typedef void* arrayInfo;
(arrayInfo)newArrayInfo(unsignd int n, unsigned int itemSize);
(void)deleteArrayInfo(arrayInfo);
(unsigned int)arrayLength(arrayInfo);
(void*)arrayPtr(arrayInfo);
...

En d'autres termes, l'ADT est une forme de données et le comportement de l'encapsulation... en d'autres mots, il est à peu près aussi proche que vous pouvez obtenir à la Programmation Orientée Objet à l'aide de droites C. Sauf si vous êtes coincé sur une plate-forme qui n'est pas un compilateur C++, vous pourriez aussi bien aller ensemble de porcs et d'utiliser la STL std::vector.

Là, nous avons pris une simple question à propos de C et a terminé au C++. Que dieu nous aide tous.

16voto

Steven A. Lowe Points 40596

garder une trace de la taille de la matrice de vous-même; gratuit utilise la fonction malloc de la chaîne pour libérer le bloc qui a été allouée, qui n'a pas nécessairement de la même taille que le tableau que vous avez demandé

9voto

paercebal Points 38526

Juste pour confirmer les réponses précédentes: Il n'y a aucun moyen de savoir, juste par l'étude d'un pointeur, la quantité de mémoire allouée par malloc qui a rendu ce pointeur.

Que si cela a fonctionné?

Un exemple de pourquoi ce n'est pas possible. Imaginons le code avec un hypothétique fonction appelée get_size(void *) qui retourne la mémoire allouée par un pointeur:

typedef struct MyStructTag
{ /* etc. */ } MyStruct ;

void doSomething(MyStruct * p)
{
   /* well... extract the memory allocated? */
   size_t i = get_size(p) ;
   initializeMyStructArray(p, i) ;
}

void doSomethingElse()
{
   MyStruct * s = malloc(sizeof(MyStruct) * 10) ; /* Allocate 10 items */
   doSomething(s) ;
}

Pourquoi, même si elle a travaillé, il ne serait pas de toute façon?

Mais le problème de cette approche est que, dans C, vous pouvez jouer avec le pointeur de l'arithmétique. Réécrivons doSomethingElse():

void doSomethingElse()
{
   MyStruct * s = malloc(sizeof(MyStruct) * 10) ; /* Allocate 10 items */
   MyStruct * s2 = s + 5 ; /* s2 points to the 5th item */
   doSomething(s2) ; /* Oops */
}

Comment get_size est censé fonctionner, que vous avez envoyé la fonction un pointeur valide, mais pas celui retourné par malloc. Et même si get_size est passé par toutes les difficultés à trouver la taille (c'est à dire dans un moyen inefficace), il serait de retour, dans ce cas, une valeur qui pourraient être mal dans votre contexte.

Conclusion

Il y a toujours des moyens pour éviter ce problème, et en C, vous pouvez toujours écrire votre propre allocateur, mais encore une fois, c'est peut-être trop de problèmes lorsque tous vous avez besoin est de se rappeler combien de mémoire a été allouée.

8voto

dmityugov Points 2786

Certains compilateurs fournir msize() ou des fonctions similaires (_msize (), etc), qui vous permettent de faire exactement cela

4voto

Claudiu Points 58398

Puis-je recommander un terrible moyen de le faire?

Allouer tous vos tableaux comme suit:

void *blockOfMem = malloc(sizeof(mystruct)*n + sizeof(int));

((int *)blockofMem)[0] = n;
mystruct *structs = (mystruct *)(((int *)blockOfMem) + 1);

Ensuite, vous pouvez toujours jeter vos tableaux afin d' int * et l'accès à l'-1er élément.

Assurez-vous d' free le pointeur, et pas le pointeur sur le tableau lui-même!

Aussi, cela risque d'engendrer de terribles bugs qui vous permettra de vous arracher les cheveux. Peut-être que vous pouvez envelopper les alloc funcs dans les appels d'API ou de quelque chose.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X