Renvoie un pointeur qui pointe vers une variable locale

Je ne sais pas pourquoi ça marche. Puisque x est une variable locale, j’ai pensé que j’aurais une erreur en essayant de la renvoyer. Cependant, le premier printf fonctionne bien, mais ensuite, il affiche simplement 0. Quelqu’un peut-il expliquer ce qui se passe ici?

#include  int* func1() { int x = 123123; int *y = &x; return y; } int main() { int* c = func1(); printf("%d\n", *c); // output: 123123 printf("%d\n", *c); // output: 0 return 0; } 

Ce qui suit se produit:

  1. Dans func1 , vous avez créé la variable x locale et l’avez initialisée avec une valeur, c’est-à-dire que x est maintenant dans la stack.
  2. Vous obtenez l’adresse de x et le retournez à main .
  3. En retournant, func1 et ses variables x (et, sans rapport avec la question, y ) sont free d, ou sortent de la stack, c’est-à-dire que leurs emplacements mémoire ne sont plus réservés pour conserver leurs valeurs. Ensuite, toute autre partie du programme est autorisée à utiliser l’espace mémoire alloué à x dans func1 , car func1 n’est plus actif.
  4. Votre premier appel à printf toujours l’ancienne valeur de l’emplacement mémoire où x trouvait (mais cela n’est pas garanti) et
  5. le second appel à printf indique clairement que quelque chose d’autre (avec la valeur 0, telle que la valeur de retour de la première printf décrite par R. Joiny ) utilise (ou utilisait) la même adresse que x dans func1 .

Cet article du Boot Camp de programmation en C décrit assez bien votre situation:

Une clé pour comprendre la stack est la notion que, lorsqu’une fonction est fermée, toutes ses variables sont extraites de la stack (et sont donc perdues à jamais). Ainsi, les variables de stack sont de nature locale. Ceci est lié à un concept que nous avons vu précédemment connu sous le nom de variable variable, ou variables locales vs globales. Un bug courant dans la programmation en C tente d’accéder à une variable créée sur la stack dans une fonction, à partir d’un emplacement de votre programme situé en dehors de cette fonction (c’est-à-dire après que cette fonction a été fermée).

printf est fondamentalement une fonction. Comme ton func1 .

Les fonctions utilisent de la RAM, votre espace de travail pour les variables locales. Si vous quittez la fonction, elle sera considérée comme quelque chose comme “effacer pour utiliser” (non supprimé!).

Comme la première printf() vient directement après la fonction func1() , la variable locale C est toujours présente, car elle n’a pas encore été écrasée. Donc ça marche. Mais si vous regardez cette page MAN, vous pouvez voir que printf a pour valeur de retour int. Donc, cela doit être écrit quelque part, alors que ferait votre PC? Bien sûr, écrivez-le à la première adresse libre de la RAM, affectée à votre programme. Et là vous avez votre zéro.

Il est important de noter qu’aucun autre programme ne peut accéder à votre RAM. Windows la réserve automatiquement pour chaque processus. Il doit donc correspondre à la valeur printf() par printf() (ou à une autre variable locale utilisée par printf lors de son exécution).

Puisque x est une variable locale, j’ai pensé que j’aurais une erreur en essayant de la renvoyer.

Une réponse plus générale à ce problème est la suivante: Un code incorrect dans le code C ne génère pas nécessairement une erreur de compilation ou d’exécution.

Si vous êtes très chanceux, vous obtiendrez une erreur ou un avertissement du compilateur.

Si vous avez de la chance, vous obtiendrez un blocage de l’exécution lorsque le code erroné sera exécuté (cela se produit souvent avec des erreurs de pointeur nul). C’est facile à localiser avec un débogueur.

Mais si vous n’êtes pas chanceux, un code erroné peut provoquer des plantages ultérieurs (dans un code apparemment non apparenté) ou corrompre en silence certaines structures de données code apparemment inoffensif ailleurs, ou utilisez un compilateur différent, ou une version différente du même compilateur, ou simplement des options de compilation différentes).


Techniquement, votre code a un comportement indéfini sur cette ligne:

 int* c = func1(); 

Vous utilisez la valeur de retour de func1 (en l’écrivant en c ). Mais cette valeur est l’adresse d’une variable locale dans func1 , qui n’existe plus au moment du retour de func . Cela signifie que la valeur de retour est un pointeur non valide et que le simple fait d’ utiliser un tel pointeur entraîne un comportement indéfini (vous n’avez même pas à la déréférencer).

 printf("%d\n", *c); // output: 123123 

Eh bien, cette ligne utilise le mauvais pointeur (en le lisant de c ) et le déréférence. Le programme semble toujours fonctionner correctement.

 printf("%d\n", *c); // output: 0 

Un ajout apparemment inoffensif, mais cette ligne ne produit pas le résultat attendu. Maintenant, cela ressemble à une corruption de données silencieuse.

Notez que rien de tout cela n’est garanti. Un compilateur différent ou le même compilateur utilisant des parameters d’optimisation différents peut générer un code se comportant différemment. En ce qui concerne la norme, un compilateur doit produire un code correspondant au comportement observable du code C. Mais le code C dont le comportement est indéfini peut provoquer quoi que ce soit; il n’y a aucune garantie ou ressortingction sur ce que le compilateur peut en faire.