2013-10-14 37 views
4

在這裏,在函數返回值是我的代碼:使用指針在C

#include <stdio.h> 
//returning a pointer 
int *fun() 
{ 
    int i = 10; 
    //printf ("%u\n",i); 
    //printf ("%u\n",&i); 
    return &i; 
} 
int main() 
{ 
    int *p; 
    p = fun(); 
    printf ("p = %u\n", p); 
    printf ("i = %u \n",*p); 
    return 0; 
} 

如果我在函數fun刪除評論,那麼第二個printf在主顯示10作爲輸出。否則會顯示垃圾值。任何想法?

+13

而你想知道的是什麼? 'i'位於堆棧上,所以當函數返回'&i'時,'i'的內存位置變爲無效。我想你想說:'int * i = malloc(sizeof(int)); * i = 10;返回i;' – clcto

+2

同樣在你的printf格式字符串中,你傳遞了%u,這意味着無符號,但給它一個int,這是有符號的 - 將導致未定義的行爲。 –

+0

我明白爲什麼* p顯示垃圾值,我不明白的是爲什麼在函數fun中取消printf的註釋,導致第二個printf在main中打印正確的輸出10 ..! – whizvids

回答

3

沒有註釋行i從未使用過。所以根據你的優化器,i可能永遠不會被分配。當你在函數中添加printf,現在使用的變量,這樣編譯器爲i堆棧幀(這恰好沒有在你的第二組用printfs的發生點被開墾)上分配內存。當然,您不能依賴何時回收內存 - 但發生的下一個函數調用很可能會覆蓋fun()堆棧幀。

如果你設置你的編譯器禁用代碼優化你可能有不同的結果。或者你可以嘗試變量設置爲volatile它告訴它不知道該變量的所有用途,所以它分配,即使優化器說,它是沒有必要的(這將不從後被釋放停止你的變量的內存編譯器你離開函數,它只會強制分配在第一位)。

作爲一個側面說明這個問題可以拿出在你有一個指針,設置時觸發硬件操作的硬件寄存器嵌入式系統(例如,你可能有控制機器人手臂運動硬件寄存器)。如果你沒有聲明指向該寄存器volatile的指針,那麼編譯器可能會認爲它從未被使用過,從而優化你的分配。

0

fun返回,i超出範圍,以便您現在返回的地址指向其他內容。嘗試malloc()一些內存並返回。而且不要忘記調用free()當你用它做:)

而且還main第二printf顯示10是一個純粹的運氣,因爲你還沒有使用的空間/地址別的東西。

0

由於@clcto提到的第一個評論的變量i是本地的工作,並得到它去分配函數返回時。

現在爲什麼取消註釋函數fun()中的兩個print語句使p的值爲10?
這可能是由於很多原因,可能取決於C和您的系統的內部行爲。但我的猜測是,這是因爲印刷工作的發生。
它維護我知道的緩衝區。它會填充它,然後在完全填充時將其打印到控制檯。因此,前兩個打印調用fun()會將我推送到尚未完全填充的緩衝區。所以當你從fun()返回時,可能i沒有被取消分配,因爲緩衝區正在使用它(或者可能是其他任何我不確定的原因,但是由於緩衝區i被保留。)

爲了支持我的猜測我試圖重新打印之前刷新緩衝區,現在它不打印10.您可以看到輸出here和修改後的代碼如下:

#include <stdio.h> 
//returning a pointer 
int *fun() 
{ 
    int i = 10; 
    printf ("%u\n",i); 
    printf ("%u\n",&i); 
    return &i; 
} 
int main() 
{ 
    int *p; 
    p = fun(); 
    fflush(stdout); 
    printf ("p = %u\n", p); 
    printf ("i = %u \n",*p); 
    return 0; 
} 

我覺得我的猜想是錯誤的,正如@KayakDave指出的那樣。它完全適合這種情況。請參考his answer以獲得正確的解釋。

+1

flush()調用創建一個新的堆棧框架將覆蓋fun()所使用的框架。這可能就是我停止打印的原因。 – KayakDave

+0

是啊,謝謝!指出。 –