0
#include<stdio.h>

int *fun();
int main()    
{
   int *ptr;
   ptr=fun();
   printf("%d",*ptr);
   printf("%d",*ptr);
}
int * fun()
{
   int k=4;//If auto then cannot print it two times.....stack will be changed
   return(&k);
}

O/P: 4
    -2

初めて printf() を呼び出すと、正しい値が出力されます。

fun( ) の呼び出しの直後に任意の関数 (printf( ) を含む) を呼び出す。今度は printf( ) がガベージ値を出力します。これはなぜですか?最初の print ステートメント自体でガベージ値を取得しないのはなぜですか????

4

3 に答える 3

1

なぜそれはあなたを驚かせるのですか?動作は未定義ですが、観察したことを観察することに異常はありません。

すべての変数はメモリ内のどこかに存在します。変数が正式に破棄されると (関数が終了するときのローカル変数のように)、それが占有していたメモリはまだ存在し、ほとんどの場合、最後に書き込まれた値を保持しています。そのメモリは現在正式に解放されていますが、他のコードがそのメモリを他の目的で再利用して上書きするまで、最後の値を保持し続けます。

これは、実験で観察したことです。変数kはもう存在しませんが、ポインターptrはまだ以前の場所を指しています。kそして、その以前の場所はたまたま の最後の値、つまりを保持してい4ます。

最初のprintf「成功」は、印刷用にその値のコピーを受け取ります。そして、それprintfは実際には古いメモリ位置を再利用し、 の以前の値を上書きするものですk。それ以降の逆参照の試みはすべて、それがもはや存在しないptrことを示します。これが、2番目に別のものを出力する理由です。4printf

于 2012-07-27T21:08:57.957 に答える
1

これは信頼できる動作ではありません。コンパイラのバージョンが異なる場合やコンパイラ スイッチが異なる場合でも、システムによって異なる可能性があります。

それを考えると、何が起こっている可能性がありますか: fun は、k を格納した場所へのポインターを返します。スタックのその部分は、それを割り当てた関数が終了したため、信頼できなくなりました。とはいえ、まだ誰も書き直していないので、4 はまだ書かれた場所のままです。次に、main は printf を呼び出す準備をします。そのために、最初の引数 *ptr を取得します。これを行うには、k の (以前の) アドレスである ptr ポイントの場所からロードするため、ロードはそこにある 4 を取得します。この 4 は、レジスタまたはスタックの場所に格納され、printf に渡されます。次に、フォーマット文字列「%d」のアドレスが保存され、printf に渡されます。次に、printf が呼び出されます。この時点で、printf は大量のスタックを使用し、k があった場所に新しいデータを書き込みます。ただし、引数として渡された 4 は、printf への引数があるべき安全な場所にあり、したがって、printfはそれを印刷します。その後、printf が返されます。次に、メイン ルーチンは再度 printf を呼び出す準備をします。今回は、ptr が指している場所からロードすると、4 がなくなりました。これは、printf の最初の呼び出し時に書き込まれた値です。したがって、その値が printf に渡され、出力されます。

この動作を使用するコードを記述しないでください。信頼性が低く、適切なコードではありません。

于 2012-07-27T20:08:56.927 に答える
0

変数kは にローカルfun()です。つまり、関数が戻るときに破棄されます。これは非常に悪いコーディング手法であり、常に問題が発生します。

printfそして、最初が正しい値を返す理由:

まず第一に、値を返す場合と返さない場合があります。kスタックメモリのどこかに書かれていると思われます。関数が初めて printf を返すとき、メモリのその部分がしばらく存在する可能性があるため、正しい値が得られる可能性があります。しかし、これは保証されません。

于 2012-07-27T20:13:01.277 に答える