1

重複の可能性:
ローカル変数のメモリにそのスコープ外でアクセスできますか?

最近、次のコードに出くわしました。

#include <stdio.h>

int* abc () {
   int a[3] = {1,10,100};
   return a;
}
int* xyz () {
   int b[1] = {222};
   return b;
}
int main() {
   int *a, *b;
   a = abc();
   b = xyz();
   printf("%d\n", *a);
   return 0;
}

出力は222です。'a'内で宣言された配列を指していxyz()ます。

私の質問は:

  1. が内部で宣言されている配列を指しているのはなぜですかxyz()

  2. 関数内で宣言された配列は、関数xyz()の実行後にスコープ外になる必要があります。なぜそれが起こらないのですか?

4

6 に答える 6

8

2: 発生しており、プログラム全体で未定義の動作が発生しています。これは正しいプログラムではありません。ifs と buts について熟考するのはほとんど意味がありません。

于 2012-09-17T16:28:35.593 に答える
3

222が表示されるのは、ローカル配列に使用されていたメモリがabc別のもの (関数のスタック) に使用されているためですxyz。そして、そのメモリへのアドレスを渡しています。さらにいくつかの関数呼び出しを行い、*a他の値が含まれている可能性があります。

関数の実行後にスコープ外に出る必要があります。なぜそれが起こらないのですか?

変数範囲外になりました。関数の外でそのアドレスを使用するのは、正しくないコードです。関数から返されたローカル データへのポインターを使用することは、未定義の動作です。

于 2012-09-17T16:27:15.213 に答える
2

変数abは自動変数です。それらのアドレスを他の関数で使用することは、未定義の動作です。何でも起こりえます: 出力を期待することはできません (例えば、最適化コンパイラーが不正なコードを削除する可能性があります)。

于 2012-09-17T16:27:46.733 に答える
1

ポインターを返すには、動的に割り当てられた変数または静的変数またはグローバル変数へのポインターである必要があります。

スタック変数へのポインターを返すと、新しいメソッドを呼び出すときに再利用されるスタックへのポインターが作成されます。

あなたの場合、スタック変数を別の配列に再利用し、最初のメソッドを呼び出したときに保存された古い値を上書きすることが起こりました。

printfprintf の最初の呼び出しでスタックの内容が変更されたため、もう一度呼び出してみると、異なる出力が表示されます。

于 2012-09-17T16:34:22.570 に答える
0

なぜそれが起こらないのですか?

正式に、それは起こります。未定義の動作は、クラッシュしたり誤動作したりする義務はありません。「何かが起こる可能性がある」ということは、エラーなしで実行できるように見えることも意味します。私はちょうど同様の質問に答えました。

于 2012-09-17T16:29:00.803 に答える
0

関数abcと関数はそれぞれ、ローカルに作成された配列xyzにアドレスを返しています。後続の呼び出しは、以前に使用された (そしてあなたに返された) メモリをマッシュアップしています。

これらは自動ローカル変数と呼ばれます。

これらの配列を静的として宣言するか、別の方法でメモリを割り当てる必要があります。

于 2012-09-17T16:29:51.443 に答える