1

ぶら下がっているポインターを持つプログラムを C で作成しました。

#include<stdio.h>

int *func(void)
{
    int num;
    num = 100;
    return &num;
}

int func1(void)
{
    int x,y,z;
    scanf("%d %d",&y,&z);
    x=y+z;
    return x;
}

int main(void)
{
    int *a = func();
    int b;
    b = func1();
    printf("%d\n",*a);
    return 0;
}

ポインターがぶら下がっているにもかかわらず、出力が 100になっています。

上記の関数に 1 つの変更を加えましたfunc1()y上記のプログラムのように標準入力との間で値を取得する代わりに、zコンパイル時に値を割り当てています。

func1()を次のように再定義しました。

int func1(void)
{
    int x,y,z;
    y=100;
    z=100;
    x=y+z;
    return x;
}

現在、出力は 200です。

誰かが上記の2つの出力の理由を説明してもらえますか?

4

7 に答える 7

16

未定義の動作とは、期待どおりに動作することを含め、何でも起こり得ることを意味します。この場合、スタック変数は上書きされませんでした。

void func3() {
  int a=0, b=1, c=2;
}

func3()func1に呼び出しを含めるとprintf、別の結果が得られます。

編集:一部のプラットフォームで実際に何が起こるか。

int *func(void)
{  
    int num;  
    num = 100;  
    return &num;  
}

簡単にするために、この関数を呼び出す前のスタック ポインターは 10 であり、スタックが上向きに成長すると仮定します。

関数を呼び出すと、戻りアドレスがスタック (位置 10) にプッシュされ、スタック ポインターが 14 にインクリメントされます (はい、非常に単純化されています)。次に、変数 num がスタックの位置 14 に作成され、スタック ポインターが 18 にインクリメントされます。

戻ると、アドレス 14 へのポインターが返されます。戻りアドレスはスタックからポップされ、スタック ポインターは 10 に戻ります。

void func2() {
    int y = 1;
}

ここでも、同じことが起こります。位置にプッシュされた戻りアドレス、位置 14 で作成された y、y に 1 を割り当て (アドレス 14 に書き込み)、戻り、ポインターを位置 10 にスタックします。

ここで、oldはポイントからアドレス 14 にint *戻り、そのアドレスに加えられた最後の変更は func2 のローカル変数の割り当てでした。funcしたがって、への呼び出しからの残りの値を指すダングリング ポインター (スタック内の位置 10 より上のものは有効ではありません) があります。func2

于 2011-03-13T11:20:32.160 に答える
4

これは、メモリが割り当てられる方法が原因です。

ダングリング ポインターを呼び出しfuncて返した後、num格納されていたスタックの部分にはまだ値があります100(後で表示されます)。観察された動作に基づいて、その結論に達することができます。

変更後、呼び出しが を指すメモリ位置を内部の加算の結果でfunc1上書きするように見えます(以前に使用されていたスタック領域が によって再利用されるようになりました)。そのため、200 が表示されます。afunc1funcfunc1

もちろん、これはすべて未定義の動作であるため、これは哲学的には良い質問かもしれませんが、答えても実際には何も得られません。

于 2011-03-13T11:24:33.520 に答える
2

未定義の動作です。あなたのコンピュータで今すぐ正しく動作するかもしれませんし、今から 20 分後にはクラッシュするかもしれません。1 時間後にクラッシュするかもしれませnumん。

于 2011-03-13T11:22:01.613 に答える
1

ダングリング ポインター (関連付けが解除された場所へのポインター) は、未定義の動作を引き起こします。つまり、何でも発生する可能性があります。

特に、メモリの場所は* で偶然再利用されfunc1ます。結果は、スタック レイアウト、コンパイラの最適化、アーキテクチャ、呼び出し規約、およびスタック セキュリティ メカニズムによって異なります。

于 2011-03-13T11:21:54.697 に答える
1

ダングリング ポインターを使用すると、プログラムの結果は未定義になります。スタックとレジスタの使用方法によって異なります。異なるコンパイラ、異なるコンパイラ バージョン、および異なる最適化設定を使用すると、異なる動作が得られます。

于 2011-03-13T11:22:04.150 に答える
1

ローカル変数へのポインターを返すと、未定義の動作が発生します。つまり、プログラムが行うことはすべて (まったく) 有効です。期待どおりの結果が得られた場合、それは運が悪いだけです。

于 2011-03-13T11:23:33.250 に答える
-1

基本的なCから関数を勉強してください。あなたのコンセプトには欠陥があります...mainはずです

int main(void)  
{  
    int *a = func();  
    int b;

    b = func1();  
    printf("%d\n%d",*a,func1());  
    return 0;  
}

これは出力されます100 200

于 2012-06-21T13:35:50.313 に答える