2016-10-07 6 views
-2

これは私が話したいスナップショットです。このコードでは、main関数はローカルに宣言された変数 'a'のアドレスを返す 'foo'を呼び出します。私は、ローカルで宣言された変数が範囲外になったときにメモリの割り当てを解除するという印象を受けました。変数 'a'は、fooへの呼び出しが終了した後に割り当て解除され、 'a'に関連するものは残されてはいけません。しかし、この場合、その基本的な前提を壊しているようです。下には何が起こっていますか?ローカル変数とプログラムの戻りアドレスがまだ残っています

int* foo() { 
    int a = 5; 
    return &a; 
} 

int main() { 
    int* p = foo(); 
    // Prints 5 
    std::cout << "Coming from foo = " << *p << std::endl; 
    *p = 8; 
    // Prints 8 
    std::cout << "Setting explicitly = " << *p << std::endl; 
} 
+1

これは未定義の動作です。そのようなプログラムの予測可能な動作を考慮しないでください。 –

+0

@RSahu。私はそれが未定義の動作であることを理解しています。これを別のマシンで(何度も)コンパイルしようとすると、私の疑惑が増えます。 –

+0

スタックフレーム全体が必ずしも上書きされる必要はありませんが、コンパイラやスタックスペースの量、OSなどによって異なる場合があります。 – George

答えて

4

コードでは、未定義の動作が発生します。適切に名前が付けられているように、それは定義されていません。つまり、期待される結果を得るか、そうでないかもしれません。あなたがすべきことは、明確に定義されていないので、そのような結果に依存しないことです。あなたは期待した結果を得て運が良かったかもしれませんが、私を信じて、それは罠です!

+0

私は未定義の動作であることを理解します。しかし、私はなぜ同じ価値を得たのかという疑問がありました。私は以下の答えがそれを書いたと思う。 –

+2

@HemantBhargava「未定義の振る舞い」は同じ値を表示する可能性があることを意味していないようです –

+0

@ M.M、このコードを別のマシンでコンパイルすると、その値は '5'になります。それが私の疑惑が増えた理由です。 –

0

どのような値が印刷されるかは、マシン/コンパイラによって異なります。スタックの割り当て解除は、以前に何が消去されたのかを意味するものではありません。エリアが無効になったことを意味します。つまり、それらのアドレスにアクセスしようとするとその動作が保証されません。あなたのケースでは、ローカル変数aを格納するために使用される場所が上書きされていないことが起こります。

+0

これは私が聞きたかったものです。ありがとう! –

+0

コメントと答えは未定義の動作が定義されておらず、何が起きる可能性があるのか​​という点について、すでにポイントホームを追求しようとしています。これを再度強調したいと思いますが、上記のコードを実行すると、理由を理解したい場合は、スタックポインタと呼ばれるものを調べる必要があります。基本的に、アプリケーションのスタック( 'int a = 8 'のような変数を割り当てる)は、一方の側から成長して収縮する連続的なメモリブロックです。その大きさを追跡するために、[... ctd] – CompuChip

+0

[ctd]と呼ばれる特別なポインタが保持され、スタックの "top"を指しています。これは基本的に割り当てられたものと未割り当てのものですメモリ。'int x;'を書いてスタックメモリを割り当てると、基本的にスタックポインタの1つの位置が未割り当て領域に移されます( 'x'に値を割り当てないと、' x'は何でもそこ)。 'a'があなたのコードで範囲外になったときのように、メモリを解放する最も速い方法は、SPを元に戻すことです。 (Beginning)プログラマーは、メモリがゼロなどになることもしばしば期待していますが、それは誰にも使わなくてはならないという高価な[..ctd] – CompuChip

関連する問題