1

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

2番目の問題は何printfですか?

#include<stdio.h>
int* fun() {
   int a =10;
   return &a;
}
int main() {
   int *a;
   a = fun();
   printf("%d",*a);
   printf("%d",*a);
   return 0;
}

ローカル変数のアドレスを返し、それをに渡しましたprintf。1回目は「10」として正しく印刷されますが、2回目はジャンク値が表示されます。

最初aにのアドレスを指すダングリングポインタだった場合10、なぜ2回目ではないのですか?

誰かがこれを説明できますか?

printf初めて呼び出す前に他の関数を呼び出そうとしましたが、それでも同じ出力が得られます。

BeniBelaの答えの後、私はこれを試してみました。

#include<stdio.h>
int* fun()
{
int a =10;
return &a;
}
void fun2(int d)
{
int a,b,c;
}

int main()
{
int *a,b;
a = fun();
fun2(5);
printf("%d",*a);
printf("%d",*a);
return 0;
}

まだ同じ出力..:(

4

4 に答える 4

9

に問題はありません。printfコードの動作は未定義です。
関数にローカルな変数のアドレスを返すと、変数の有効期間{は関数のscope( 、 )に制限されます}。関数のスコープが終了すると、変数は存在しなくなります。標準では、もう存在する変数。

したがって、ポインタは存在しないものを参照します(それは可能性があります)。簡単に言えば、それは未定義の動作であり、コンパイラに翻弄されます。動作を示し、その説明を提供しない場合があります。

于 2012-09-06T12:14:56.357 に答える
3

実際に起こることは次のとおりです。

すべてのローカル変数はスタックに格納されます。

  1. funを呼び出す前は、スタックには次のようなmainの*変数のみが含まれています。|int *a = undefined||

  2. funが呼び出されると、funへのパラメーター(つまりnone)、mainへのアドレス、およびfunのローカル変数がスタックに追加されます:(|int *a = undefined| return to main | int a = 10 || フレームポインターもありますが、それは問題ではありません)

  3. 楽しみが戻った後、スタックは|int *a = 2nd next stack var|| return to main | int a = 10 |です。最後の2つのスタック変数は無効ですが、まだ存在しています。

  4. 最初のprintfがprintfのパラメータと呼ばれると(* a then "%d"の逆順)、printfのリターンアドレスとローカル変数が* aの後に再び追加され、古い値が上書きさ れ
    ます 。ついに|int *a = 2nd next stack var| int a = 10 || int a = 10 |
    |int *a = 2nd next stack var| int a = 10 | "%d" |
    |int *a = 2nd next stack var| int a = 10 | "%d" | return to main ||
    |int *a = 2nd next stack var| int a = 10 | "%d" | return to main | local vars of printf ||

  5. 2番目のprintfが呼び出されたとき、* aはまだ2番目のビンを指していますが、そのビンには「%d」が含まれています。これは奇妙な数字として表示されます。

[編集:]

fun2はスタックの10をオーバーライドしません。これは、gccがスタックに空のビンを予約し、呼び出された関数の引数が置かれるためです。ですから|int *a = 2nd next stack var| return to main | int a = 10 |、私が上で書いたようなものではなく、もっと似てい|int *a = 4th next stack var | empty | empty | return to main | int a = 10 |ます。
fun2が呼び出されると、それは|int *a = 4th next stack var | empty | 5 | return to main | int a = 10 |になり、10はまだオーバーライドされません。

関数内はint *a,b,c値が割り当てられていないため、重要ではありません。

gdbを使用すると、実際のスタックを確認できます(後方に大きくなります)。

楽しむ前に:

0xffffd454:    0x080496f0    0xffffd488    0x080484eb    0x00000001
                 noise     (framepointer)  address      noise/empty bin     
                                           in main

楽しんだ後、fun2とその引数の前:

0xffffd454:    0x0000000a    0xffffd488    0x08048441    0x00000001
                 a         (framepointer)   address     noise/empty bin     
                                            in main

fun2の後:

0xffffd454:    0x0000000a    0xffffd488    0x08048451    0x00000005

                 a         (framepointer)   address       argument     
                                            in main       for fun2
于 2012-09-06T12:32:50.257 に答える
1

コンパイルするときは警告に注意してください。

yourfile.c: In function ‘fun’:
yourfile.c:6:14: warning: function returns address of local variable [enabled by default]

これはスコープの問題です。変数「a」は「fun」関数内にローカルスコープを持っています。つまり、メイン(スコープ外)からそのローカル変数のアドレスにアクセスしようとすると、そのアドレスは無効になります。これを修正したい場合は、変数をグローバルにすることができます(ただし、名前を変更してください)。そうすると、コードが期待どおりに機能することがわかります。

int b;

int* fun() 
{  
  b = 10;
  return &b; 
} 

int main() 
{ 
  int *a; 
  a = fun(); 
  printf("%d",*a); 
  printf("%d",*a);
  getc(stdin);
  return 0; 
}

出力:

> 1010
于 2012-09-06T12:20:19.797 に答える
0

関数内で作成されたオブジェクトのアドレスを返すため、関数の終了後に有効でなくなる可能性があります。代わりにポインタを作成してください!

于 2012-09-06T12:15:30.557 に答える