2016-06-23 1 views
1
#include <iostream> 
using namespace std; 
int main() 
{ 
    int a=50; 
    int b=50; 
    int *ptr = &b; 
    ptr++; 
    *ptr = 40; 
    cout<<"a= "<<a<<" b= "<<b<<endl; 
    cout<<"address a "<<&a<<" address b= "<<&b<<endl; 
    return 0; 
} 

Les impressions de code ci-dessus:comportement non défini observé en C++/allocation de mémoire

a= 50 b= 50 
address a 0x7ffdd7b1b710 address b= 0x7ffdd7b1b714 

Alors que lorsque je retire la ligne suivante du code ci-dessus

cout<<"address a "<<&a<<" address b= "<<&b<<endl; 

je reçois sortie comme

a= 40 b= 50 

Ma compréhension était que le pile se développe vers le bas, de sorte que la deuxième réponse semble être la bonne. Je ne suis pas capable de comprendre pourquoi la déclaration d'impression gâcherait la mise en page de la mémoire.

EDIT:

J'ai oublié de mentionner, je suis en utilisant la machine x86 64 bits, avec OS qu'Ubuntu 14.04 et la version gcc 4.8.4

+7

Il est juste * un comportement non défini *. – juanchopanza

+0

Ce n'est pas le cas dans VS2005. Je lance le code ci-dessus avec et sans l'adresse 'cout <<" une ligne "<< ..' et le résultat est a = 50, b = 50 dans les deux cas. – Makif

Répondre

4

Tout d'abord, il est tout comportement non défini. La norme C++ dit que vous pouvez incrémenter des pointeurs seulement tant que vous êtes dans les limites de tableau (plus un élément après), avec quelques exceptions supplémentaires pour les classes de mise en page standard, mais c'est à peu près tout. Donc, en général, fouiner avec des pointeurs est un territoire inexploré. Venant à votre code actuel: puisque vous ne demandez jamais son adresse, le compilateur a probablement laissé a dans un registre, ou même l'a propagé comme une constante dans tout le code. Pour cette raison, a ne touche jamais la pile, et vous ne pouvez pas le corrompre en utilisant le pointeur. Notez de toute façon que le compilateur n'est pas limité aux variables push/pop de la pile dans l'ordre de leur déclaration - ils sont réordonnés dans l'ordre qu'ils semblent appropriés, et ils peuvent même se déplacer dans le cadre de la pile (ou être remplacé) dans toute la fonction - et un changement apparemment minime dans la fonction peut amener le compilateur à modifier complètement la disposition de la pile. Donc, même en comparant les adresses comme vous l'avez fait ne dit rien sur la direction de la croissance de la pile.

+0

De plus, même dans la version '& a', il est possible que le compilateur insère' 50' dans la première ligne 'cout'. – melpomene

+0

@melpomene: oui, peut-être qu'il compile avec des paramètres d'optimisation pas très agressifs. –

+0

Je n'utilise aucun indicateur d'optimisation et je suis d'accord que ce n'est pas la façon de trouver la direction de croissance de la pile. Ce que vous dites est logique, mais n'est-ce pas censé être comme si b était empilé sous une mise en mémoire? Au moins, est-ce que c'est ce qu'on nous a enseigné? J'essayais d'exploiter la façon dont la mémoire est disposée dans un programme/pile et pas exactement délimitée par les limites comme dans les tableaux et les classes. Je ne peux pas l'exploiter de cette façon? – animentary

2

UB - Vous avez pris un pointeur vers b, vous déplacez ce pointeur ptr++ ce qui signifie que vous pointez sur un inconnu, mémoire non affecté et que vous essayez d'écrire sur cette région de mémoire, ce qui provoquera un comportement non défini.

Le VS 2008, le débogage étape par étape jetteront ce message pour vous qui est très explicite :: enter image description here

+0

J'utilise gdb et il n'y a pas d'erreur, je suis allé aussi pas à pas là-bas, mais rien de ce genre n'est apparu. – animentary

+0

Avez-vous essayé d'utiliser Valgrind? Je pense que cela aiderait, pas sûr cependant.Le message lancé n'est pas important ici. L'important est que vous essayez d'accéder à la mémoire qui ne vous est pas assignée. – Abhineet