3

これは、変数のスコープに関する非常に基本的な質問です。私は次のコードを持っています:

int main()
{
    int *p;
    p=func();
    printf("%d",*p);
    return 0;
}

int *func()
{
   int i;
   i=5;
   return &i;
}

私の質問

  • iのスコープは終了しましfunc()たが、のアドレスを返すのでiアクセスできますprintmain()
  • そうでない場合、なぜですか?コンパイラはそのアドレス空間にガベージ値を入れますか(これは行われていないと思います)。
  • それは実際にはどういう意味the scope of a variable is endedですか?iまた、スコープが終了すると、割り当てられたメモリは解放されますか?
4

5 に答える 5

4

変数のスコープは、変数にアクセスできる領域です。
変数の存続期間は、変数が存在することが保証されるまでの時間です。

あなたの場合、の寿命i関数の範囲内であり、それを超えていません。これはi、機能を超えて存在することが保証されていないことを意味します。関数を超えてローカル変数にアクセスする必要はなく、未定義動作です。

のスコープiは終了しましfunc()たが、のアドレスを返送しているので、アクセスしiて印刷できますか?5main()

あなたはそうかもしれませんが、それは未定義の振る舞いです。だからそれをしないでください。

そうでない場合、なぜですか?コンパイラはそのアドレス空間にガベージ値を入れますか(これは行われていないと思います)

関数がアドレスの場所を返すと、コンパイラは選択したものをその場所に置くことができ、不確定な値を保持します。

変数のスコープが終了するということは、実際にはどういう意味ですか?iまた、スコープが終了すると、割り当てられたメモリは解放されますか?

i{は自動/ローカル変数であり、}宣言されているスコープが終了すると、すべての自動変数が解放されます。したがって、名前は自動です。

于 2012-11-06T08:57:39.567 に答える
2

変数がスコープ外になった後に変数にアクセスすることは、未定義の動作です。これは、何が確実に起こるかを言うことができないことを意味します。投稿されたコードで5は、印刷されたり、他の値が印刷されたり、他の動作が発生したりする可能性があります(アクセス違反など)。

于 2012-11-06T08:57:51.690 に答える
2

あなたの例の振る舞いは未定義です。あなたprintfはおそらく5を出力しますが、それは良いデザインではなく運にかかっているでしょう。

この場合、変数のスコープが終了すると、さらに関数呼び出しがスタックアドレスを再利用して、変数が指す&i値を変更する場合があります。p

于 2012-11-06T08:58:01.987 に答える
2

いいえ、スコープ外の変数にアクセスすると、未定義の動作が発生します。v変数が使用されていたストレージが再利用されているため、クラッシュや予期しない動作につながる可能性のある他の何かを上書きする可能性があります。

于 2012-11-06T08:58:22.420 に答える
2

関数はおそらく5を出力しますが、これは絶対に行わないでください。あなたのプログラムはあなたのリターンのポインタが指す場所をもはや所有していないので(言い換えれば、あなたのプログラムはもはや所有していないi)、それは未定義の振る舞いです。

基本的に、関数が呼び出されるたびに、新しいスタックフレームに対応するためにスタックポインタが押し下げられます。関数呼び出しが終了すると、スタックポインタがバックアップされます。これは、別の関数が呼び出された場合、前の関数呼び出しと同じスタックスペースと重複することを意味します。

これをもう少しわかりやすく説明するために、次のことを考慮してください。

int main()
{
    int *p;
    p=func();
    printf("%d\n",*p);
    func2();
    printf("%d\n",*p);
    return 0;
}

int *func()
{
   int i;
   i=5;
   return &i;
}

void func2()
{
    int i = 1;
}

出力が51になる可能性はかなりあります。これは、2番目の呼び出しが同じスタックスペースを再利用するためです。

(上記のコードスニペットはひどいことに注意してください-そのようなことは絶対にしないでください-未定義の動作であり、実装に大きく依存します。)


質問に直接答えるには:

iのスコープはfunc()で終了しますが、iのアドレスを返すので、main()でアクセスしてprint5を実行できますか?

いいえ、できますが、すべきではありません。これがCの美しさです。コンパイラ/OSなどによっては、5を出力する場合もあれば、ランダムなガレージを出力する場合もあります。

そうでない場合、なぜですか?コンパイラはそのアドレス空間にガベージ値を入れますか(これは行われていないと思います)。

ローカル変数に使用されたスペースは再利用されます。答えの前半は、うまくいけば、これがどのように機能するかを示しています。(まあ、それが通常どのように機能するか。)

変数のスコープが終了するということは、実際にはどういう意味ですか?また、スコープが終了すると、iに割り当てられたメモリは解放されますか?

スタックベースのメモリ割り当ては、舞台裏で行われていることです。

于 2012-11-06T08:58:32.337 に答える