簡體   English   中英

解釋 output

[英]Explain the output

#include<stdio.h>

int * fun(int a1,int b)
{
    int a[2];
    a[0]=a1;
    a[1]=b;
    return a;
}
int main()
{
    int *r=fun(3,5);
    printf("%d\n",*r);
    printf("%d\n",*r);
}

Output 運行代碼后:

3
-1073855580

我知道 a[2] 是 fun() 本地的,但為什么值會改變同一個指針?

變量 a 確實很有趣。 當您從該 function 返回時,堆棧被彈出。 memory 本身保持不變(目前)。 當您第一次取消引用 r 時,memory 就是您所期望的。 由於取消引用是在調用 printf之前發生的,因此不會發生任何不好的事情。 當 printf 執行時,它會修改堆棧並且值被擦除。 第二次通過時,您會看到第一次通過 printf 時發生的任何值。

“正常”調用約定的事件順序(我知道,我知道 - 沒有這樣的事情):

  • 解引用r (第一次通過,應該是這個)
  • 將值壓入堆棧(注意這是復制值)(可能會清除 a)
  • 將其他參數推入堆棧(順序通常是從右到左,IIRC)(可能會清除 a)
  • 在堆棧上為返回值分配空間(可能會清除 a)
  • 致電 printf
  • 將本地 printf 變量推入堆棧(可能會清除 a)
  • 做你的事情
  • 從 function 返回

如果你改變int a[2]; static int a[2]; 這將緩解問題。

因為r指向堆棧上可能被 function 調用覆蓋的位置。

在這種情況下,這是對printf本身的第一次調用,它正在更改該位置。

詳細地說,從fun的返回具有保留該特定位置的原因僅僅是因為尚未覆蓋它。

然后評估*r (作為 3)並傳遞給printf以進行打印。 printf的實際調用會更改該位置的內容(因為它使用 memory 作為自己的堆棧幀),但該值已經在此時提取,因此它是安全的。

在隨后的調用中, *r具有不同的值,由第一次調用更改。 這就是為什么在這種情況下有所不同。

當然,這只是可能的解釋。 實際上,任何事情都可能發生,因為您在那里編寫的代碼是未定義的行為。 一旦你這樣做了,所有的賭注都沒有了。

當您使用以下命令編譯代碼時:

$ gcc -Wall yourProgram.c 

它會產生一個警告,上面寫着。

In function ‘fun’:
warning: function returns address of local variable

在第一個r語句中取消引用printf時,可以保留 memory。 但是,第二個printf語句覆蓋了堆棧,因此我們得到了不希望的結果。

正如您所提到的, a[2]fun()本地的; 這意味着它是在fun()中的代碼開始執行之前在堆棧上創建的。 fun退出時,堆棧被彈出,這意味着它被展開,因此堆棧指針指向它在fun開始執行之前的位置。

編譯器現在可以自由地將任何它想要的東西粘貼到那些未展開的位置。 因此,由於各種原因,可能會跳過a的第一個位置。 也許它現在代表一個未初始化的變量。 也許是另一個變量的 memory alignment。 簡單的答案是,通過從 function 返回指向局部變量的指針,然后取消引用該指針,您正在調用未定義的行為並且任何事情都可能發生,包括惡魔飛出你的鼻子

因為 printf 正在使用堆棧位置,並在打印第一個值后更改它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM