2010-07-17 2 views
5

Quelle est la différence entre ceci:C++: définition de tableau local par rapport à un appel malloc

somefunction() { 
    ... 
    char *output; 
    output = (char *) malloc((len * 2) + 1); 
    ... 
} 

et ceci:

somefunction() { 
    ... 
    char output[(len * 2) + 1]; 
    ... 
} 

Quand est un plus approprié que l'autre?

merci à tous pour vos réponses. voici un résumé:

  1. ex. 1 est l'allocation de tas
  2. ex. 2 est l'allocation pile
  3. il y a une limitation de la taille de la pile, l'utiliser pour les petites allocations
  4. vous devez allocation de tas libre, ou il fuira
  5. l'allocation de la pile n'est pas accessible une fois la fonction sort
  6. l'allocation du tas est accessible jusqu'à ce que vous libérer (ou l'application se termine)
  7. VLA ne faites pas partie de la norme C++

corrections bienvenues.

ici est une explication de la différence entre tas vs pile:
What and where are the stack and heap?

+0

Vous devriez consulter votre livre C++. Si vous n'avez pas de livre C++, je vous recommande d'obtenir l'un des textes pour débutants listés dans [Le Guide et la Liste Complète du Livre C++] (http://stackoverflow.com/questions/388242/the-definitive-c-book -guide-and-list). –

+4

En outre, la question dépend entièrement de la définition de 'len'; si ce n'est pas une constante, alors le second exemple de code est C++ mal formé. –

+0

len est un entier et affecté au résultat de strlen dans la fonction. – Gush

Répondre

5

Utilisez les locals lorsque vous ne disposez que d'une petite quantité de données et que vous n'allez pas utiliser les données en dehors de la portée de la fonction dans laquelle vous les avez déclarées. Si vous voulez transmettre les données, utilisez malloc.

Les variables locales sont conservées sur la pile, qui est beaucoup plus limitée en taille que la pile, où vont les tableaux alloués avec malloc. Je vais habituellement pour tout ce qui> 16 octets est mis sur le tas, mais vous avez un peu plus de flexibilité que cela. N'allouez simplement pas les locaux dans la plage de taille kb/mb - ils appartiennent au tas.

+2

+1 pour mentionner les limitations de taille de la pile, mais je pense que 16 octets est un peu faible. La taille de la pile par défaut n'est-elle pas sur la plupart des plates-formes dans les mégaoctets (donc les variables multi-Ko devraient être bien dans la plupart des cas)? –

+0

Oui, mais lorsque vous allouez sur la pile, vous devez également prendre en compte la durée de vie des données ainsi que leur taille. Je voulais dire 16 octets pour les valeurs dont la durée de vie peut ne pas être connue. Vous pouvez allouer plusieurs kb sur la pile, puis bifurquer dans une autre fonction, qui alloue également beaucoup de kb, et ainsi de suite - elle peut rapidement se remplir. (Discuté plus dans la réponse de StackedCrooked.) –

+3

Puisque la question concerne le C++, je suis fermement opposé à la recommandation d'utiliser malloc. En C, utilisez malloc. En C++, utilisez new. –

6

La première alloue de la mémoire sur le tas. Vous devez vous rappeler de libérer la mémoire, ou elle va fuir. Ceci est approprié si la mémoire doit être utilisée en dehors de la fonction, ou si vous devez allouer une quantité importante de mémoire.

La seconde alloue de la mémoire sur la pile. Il sera récupéré automatiquement lorsque la fonction reviendra. C'est le plus pratique si vous n'avez pas besoin de retourner la mémoire à votre interlocuteur.

+1

D'autre part, vous ne voulez pas mettre trop sur la pile, car il n'est pas aussi gros que le tas. Donc, 'int data [10]' est très bien, mais je ne compterais pas sur 'int data [10000]' fonctionnant du tout. – zvone

5

Le premier exemple alloue un bloc de stockage à partir du tas. Le second alloue le stockage de la pile. La différence devient visible lorsque vous renvoyez la sortie de somefunction(). Le stockage alloué dynamiquement est toujours disponible pour votre utilisation, mais le stockage basé sur la pile dans le second exemple est, euh, nulle part. Vous pouvez toujours écrire dans ce stockage et le lire pendant un certain temps, jusqu'à la prochaine fois que vous appelez une fonction, moment auquel le stockage sera écrasé aléatoirement avec des adresses de retour, des arguments, etc.

Il y a beaucoup d'autres choses bizarres qui se passent avec le code dans cette question aussi. Tout d'abord, il s'agit d'un programme C++, vous voudriez utiliser un nouveau lieu de malloc() si vous voulez dire

output = new char[len+1]; 

Et ce qui est le len * 2 + 1 de toute façon?Peut-être que c'est quelque chose de spécial dans votre code, mais je suppose que vous voulez allouer des caractères Unicode ou des caractères multi-octets. Si c'est unicode, la terminaison NULL prend deux octets comme chaque caractère, et char est le mauvais type, étant 8 bits octets dans la plupart des compilateurs. Si c'est multibyte, alors hé, tous les paris sont désactivés.

+1

+1 pour nouveau vs malloc – bstpierre

+0

Je ne sais pas si ce que je fais est correct - mais il provient des docs pour PQescapeStringConn - "'to' doit pointer vers un tampon qui peut contenir au moins un octet de plus deux fois la valeur de longueur " d'ici: http://www.postgresql.org/docs/7.3/static/libpq-exec.html – Gush

3

Première la terminologie:

  • Le premier échantillon est appelé allocation tas.
  • Le deuxième échantillon est appelé allocation de pile.

La règle générale est la suivante: répartir sur la pile, à moins que:

  1. La taille requise du tableau est inconnu au moment de la compilation.
  2. La taille requise dépasse 10% de la taille totale de la pile. La taille de la pile par défaut sous Windows et Linux est généralement de 1 ou 2 Mo. Votre tableau local ne doit donc pas dépasser 100 000 octets.
+1

Je pense que ces règles générales sont un peu faibles. Par exemple, je pourrais allouer 10% de ma pile dans main(), puis appeler une autre fonction (qui à son tour appellera de plus en plus, chacun remplissant la pile). Je ne vais pas être en mesure de libérer cet espace jusqu'à ce que toutes mes fonctions plus profondes soient terminées (essentiellement la fin du programme dans ce cas). Mon programme a automatiquement 10% d'espace de pile en moins. Je pense que cette règle de 10% devrait être limitée aux fonctions ** pure ** seulement. –

+1

@Mark H: Vous avez raison de dire que la règle des 10% ne devrait pas être allouée en main, et certainement pas en code réentrant. Cependant, je ne vois pas comment les fonctions pures seraient plus sûres contre le débordement de pile que les fonctions non-pures. – StackedCrooked

+1

Une fonction pure n'appellera pas d'autres fonctions (sauf si elles sont elles-mêmes pures) - mais elles effectueront généralement un algorithme et retourneront immédiatement. Toutes les variables locales que vous y allouerez seront de courte durée, ce qui devrait être le cas pour la pile. Les variables qui ont des durées de vie plus longues (comme l'exemple précédent) devraient aller sur le tas. –

1

Vous avez étiqueté votre question avec C++ et C, mais la deuxième solution n'est pas autorisée en C++. Les tableaux de longueur variable ne sont autorisés qu'en C (99).

Si vous deviez supposer que 'len' est une constante, les deux fonctionneront. Malloc() (et C++ 'new') allouent la mémoire sur le tas, ce qui signifie que vous devez free() (ou si vous avez alloué 'new', 'delete') le buffer, ou la mémoire ne jamais être récupéré (fuite). Ce dernier alloue le tableau sur la pile et disparaîtra quand il sortira de la portée. Cela signifie que vous ne pouvez pas renvoyer les pointeurs vers le tampon hors de la portée dans laquelle il est alloué.

Le premier est utile lorsque vous voulez passer le bloc de mémoire (mais en C++, il est mieux géré avec une classe RAII, pas manuellement), alors que ce dernier est le meilleur pour les petites matrices de taille fixe qui doivent seulement exister dans une portée.

Enfin, vous pouvez marquer le tableau autrement pile alloué avec « statique » pour enlever la pile et dans une section de données globales:

static char output[(len * 2) + 1]; 

Cela vous permet de renvoyer des pointeurs vers la mémoire tampon en dehors de Dans sa portée, cependant, tous les appels à une telle fonction se référeront à la même donnée globale, ne l'utilisez donc pas si vous avez besoin d'un bloc de mémoire unique à chaque fois. Enfin, n'utilisez pas malloc en C++ sauf si vous avez une très bonne raison (par exemple, realloc). Utilisez plutôt 'new' et le 'delete' qui l'accompagne.

+0

de http: //gcc.gnu.org/onlinedocs/gcc/Variable-Length.html Les tableaux automatiques à longueur variable sont autorisés dans la norme ISO C99 et, en tant qu'extension, GCC les accepte en mode C90 et en C++. Je suppose que c'est pour cela qu'il se compile et fonctionne pour moi en utilisant gcc. Je pourrais croire que ce n'est pas le C++ par la norme ou la bonne définition du langage auquel vous pourriez faire référence. Dois-je supprimer le tag C++? – Gush

+0

Je me demandais simplement ce que vous utilisiez, mais pour que je suppose C++, je pensais que je vous avais prévenu que les VLA ne font pas partie du C++ standard. –

+0

ok. je ne le savais pas et c'est pertinent – Gush

Questions connexes