Question

int main()
{
   char myString = NULL;
   realloc(&myString, 5);
   strncpy((char *)&myString, "test", 5);
}

semble fonctionner correctement mais je suis encore un peu confus au sujet de pile contre tas. Est-ce permis? Si cela est autorisé, myString doit-il être libéré manuellement ou le sera-t-il lorsque le contenu disparaîtra de sa portée?

Edit: Merci pour les réponses, donc je suppose que c'est également illégal

//I want the code to change myString to "tests"
char myString[5] = "test";
realloc(&myString, strlen(myString)+2);
myString[4] = 's';
myString[5] = '\0';
Était-ce utile?

La solution

Non, c'est complètement faux. realloc ne doit être utilisé que pour réaffecter la mémoire allouée par Malloc. Ce que vous faites ne fonctionne que par accident et finira par crasher

char *myString = malloc(x);
myString = realloc(myString,y);
free(myString)

Cependant, il vaut mieux utiliser new et delete, et encore mieux utiliser std :: string.

Autres conseils

Certains problèmes liés au code que vous avez publié:

  • Oui, vous devez libérer tout ce que vous allouez avec malloc et realloc, ainsi que les autres fonctions d’allocation de mémoire de style C associées.
  • Je pense que vous vouliez avoir char * myString, pas char. Passer l'adresse de quelque chose sur la pile (votre personnage) est complètement faux.
  • Vous devez initialiser votre pointeur de caractère myString sur NULL avant de l’utiliser dans realloc.
  • Vous devriez passer 4 dans strncpy et non 5, si vous aviez une chaîne plus longue, vous écraseriez la mémoire.
  • Vous devriez libérer le tampon que vous avez créé dans votre exemple
  • Vous devriez vérifier la valeur de retour de votre appel realloc. realloc ()
  

[Concernant la valeur de retour de realloc:] En cas de réussite avec une taille   différent de 0, realloc () renvoie un   pointeur vers le (éventuellement déplacé)   espace alloué. Si la taille est 0, soit   un pointeur nul ou un pointeur unique   qui peut être passé avec succès à   free () est renvoyé. S'il n'y a pas   assez de mémoire disponible, realloc ()   retourne un pointeur null et définit errno   vers [ENOMEM].

  • re-alloc fonctionnera comme malloc lorsque vous transmettez NULL:
  

Si ptr est un pointeur nul, realloc ()   se comporte comme malloc () pour le   taille spécifiée.

Une façon plus C ++ de le faire:

Cependant, vous avez étiqueté cela en C ++, et il est préférable d'utiliser le nouvel opérateur de C ++. Bien que le nouvel opérateur ne permette pas les réallocations, il fonctionnera pour les allocations et pour la réutilisation des mémoires tampons existantes (emplacement nouveau).

char *myString = new char[5];
strncpy(myString, "test", 4); 
//...
delete[] myString;

ou même:

#include <string>

//...

std::string str = "test";

source des 2 meilleures citations

Cela ne devrait pas marcher. Vous réaffectez quelque chose qui n'a pas été mallocé. Et non, il ne sera pas libéré quand il sortira du champ d'application - lorsque vous utilisez malloc ou realloc, c'est vous qui décidez.

Mise à jour: votre modification ne change rien - vous essayez toujours de réaffecter quelque chose qui n'a pas été mallocé au départ. De plus, vous ne pouvez pas ignorer la valeur de retour de realloc - si realloc doit déplacer la mémoire ailleurs, vous le trouverez dans le retour. En d'autres termes:

char* ptr = malloc(4);
ptr = realloc(ptr, 5);

Après realloc, ptr peut pointer vers un emplacement totalement différent en mémoire et continuer à utiliser la valeur originale de ptr peut vous laisser utiliser une mémoire libérée et moins grande que vous ne le pensez.

C’EST DANGEREUX! Cela corrompra votre pile. Si vous deviez réaffecter quelque chose sur la pile d'une fonction qui est ensuite retournée à main (), vous écraseriez le cadre de la pile et renverriez ailleurs que main (). C’EST UN TROU DE SÉCURITÉ POTENTIEL.

Essayez d’exécuter ce qui suit. S'il se bloque sur realloc, vous avez de la chance. Vous pouvez faire de gros dégâts avec quelque chose comme memcpy (& myString).

int dostuff();

int main()
{
        dostuff();
        return 0;
}

int dostuff()
{
        char myString = NULL;
        realloc(&myString, 5);
        strncpy((char *)&myString, "test", 5);
        return 0;
}

C’est ce que vous ne devriez jamais faire. Essayer de libérer () ou de realloc () une variable de pile peut entraîner un comportement indéfini, notamment une pile corrompue (entraînant un flux de contrôle imprévisible), des structures de service de segmentation corrompues, une mémoire utilisateur corrompue. Vous avez de la chance si le programme se bloque avec un antivirus. Cela peut fonctionner dans certains cas, mais vous ne devriez jamais essayer de le faire.

Règle générale: renvoyez uniquement la mémoire au gestionnaire de mémoire sur lequel elle a été allouée Dans ce cas, n'essayez pas de renvoyer la variable de pile dans le tas d'exécution.

Votre programme est conforme à la syntaxe C ++, mais il produira un comportement indéfini car vous transmettez l'adresse d'un objet de pile à l'allocateur de tas. Cela signifie généralement que votre programme se bloquera lorsqu’il sera exécuté.

La pile et le tas sont deux zones de mémoire distinctes allouées au processus exécutant votre programme. La pile s'agrandit à mesure que vous entrez une fonction contenant ses arguments et ses variables locales, et elle se réduit automatiquement lorsque vous revenez de la fonction. Le segment de mémoire, en revanche, est une région d’adresse distincte dans laquelle la mémoire peut être obtenue à la demande et doit être libérée de manière explicite quand elle n’est plus nécessaire.

Si l'adresse d'une variable locale est transmise à realloc (), celle-ci peut tenter de libérer sa mémoire et de l'allouer ailleurs. Comme l'adresse ne provient pas du tas et que realloc () fonctionne sur le tas, cela échouera. Realloc () détectera probablement que l'adresse ne provient pas du tas et abandonne le programme.

À part cela, l'exemple de programme contient quelques erreurs logiques.


char myString = NULL;

Vous déclarez qu'une variable doit contenir un caractère, pas une chaîne. Une chaîne de style C a le type char * , c’est-à-dire un pointeur sur char.

De plus, le caractère est attribué à NULL , l'adresse zéro qui est conventionnellement attribuée aux pointeurs non valides. Cela se compile car le préprocesseur remplace NULL par le littéral 0 . En réalité, vous stockez un octet zéro dans le caractère, qui est également, par convention, le terminateur d'une chaîne de style C.


realloc(&myString, 5);

Comme mentionné ci-dessus, ceci est illégal car vous transmettez l'adresse d'un objet de pile à l'allocateur de segment de mémoire. Ce problème reste dans votre deuxième exemple de code.

De plus, vous supprimez la valeur de retour. realloc () renvoie l'adresse à laquelle la nouvelle mémoire a été allouée. Ce n'est peut-être pas la même adresse qu'avant. Il peut même s'agir de NULL, qui est la méthode utilisée par realloc () pour vous indiquer que la mémoire est insuffisante.


strncpy((char *)&myString, "test", 5);

Ceci est correct, mais la distribution est redondante.

Voici une version plus correcte de votre programme:


#include <stdlib.h>
#include <string.h>

int main()
{
   /* allocate space for, say, one character + terminator */
   char* myString = (char*) malloc(2);

   /* some code using myString omitted */

   /* get more space */
   myString = (char*) realloc(myString, 5);

   /* write to the string */
   strncpy(myString, "test", 5);

   /* free the memory */
   free(myString);

   return 0;
}

En C ++, il est préférable d’éviter complètement realloc (). Par exemple, vous pouvez utiliser quelque chose comme ce qui suit:


#include <string>

int main()
{
   std::string myString;

   /* some code using myString */

   myString = "test";

   return 0;
}

Vous n'avez pas besoin de libérer myString car il se trouve sur la pile (qui est libérée lors de la sortie de la portée).

realloc est illégal, l'adresse doit être NULL ou une adresse renvoyée par un appel précédent à realloc , malloc. ou calloc .

Chaque variable que vous déclarez est sur la pile, même un pointeur:

int * x;

La variable x est sur la pile! Il est de type pointeur et contient une adresse.

x = (int *) malloc (sizeof (int));

attribue l'adresse renvoyée par malloc à la variable x! Le contenu de x est une adresse mémoire!

Le problème avec ce que vous faites est que vous gaspillez quelque chose qui n’est pas une variable. Vous avez défini myString comme un caractère et essayez donc de changer son adresse. C'est mauvais.

La fonction realloc () n'est pas censée changer quoi que ce soit qui y est passé. Il prend un pointeur sur la mémoire du tas (ou le pointeur null, si rien n’est déjà alloué) et renvoie un pointeur sur la mémoire du tas.

Par conséquent, vous fournissez un pointeur null ou un pointeur sur quelque chose alloué par malloc () ou realloc () ou calloc () et stockez le pointeur renvoyé.

Quelque chose comme

char * myString = NULL;
myString = realloc(myString, 5);

fonctionnera, mais vous voudrez libérer () myString.

En C ++, cependant, utilisez std :: string.

En réponse à votre deuxième exemple de code:

Oui, c'est également illégal. myString n'est pas alloué avec malloc (ou calloc), il ne peut donc pas être réaffecté avec realloc, ni libéré avec free.

De plus, realloc ne prend pas un pointeur vers un pointeur comme premier argument. Il faut un pointeur sur la mémoire allouée et retourne un autre pointeur (éventuellement différent). Écrivez l'appel comme ceci à la place:

myString = realloc(myString, strlen(myString)+2);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top