2011-11-18 59 views
1

請參閱下面的代碼示例。 函數中的函數fun_ret_loc_ptr()返回一個警告:「函數返回局部變量的地址」。另一方面,函數fun_ret_loc_var()中的語句return a不這樣做。爲什麼gcc在返回指向局部變量的指針時拋出警告,而不是在返回局部變量時拋出警告?

#include <stdio.h> 
int* fun_ret_loc_ptr() 
{ 
    int i = 10; 
    return (&i); 
} 

int fun_ret_loc_var() 
{ 
    int a = 20; 
    return a; 
} 

int main() 
{ 
    printf("val frm local ptr = %d\n", *fun_ret_loc_ptr()); 
    printf("val frm local var = %d\n", fun_ret_loc_var()); 
} 

我明白的是,在第一功能返回的地址(return (&i);)審閱到,這是對應於起作用fun_ret_loc_ptr()堆棧幀的一部分的存儲器位置。一旦這個函數返回,棧幀(激活記錄)就會被銷燬。同樣的東西應該適用於函數fun_ret_loc_var()中的變量'a'(return a;)。即使它被返回,當它在main中被使用時,對應於'a'的內存也會死掉。

從「return」語句的功能角度來看,爲什麼會出現這種差異?

回答

5

通過值返回變量複製它,因此從函數返回後使用它是安全的。

返回一個引用(或指針)到一個局部變量是不安全的(因爲引用/指針從函數返回後不再有效)。

現在,如果程序好像做你所期望的,那純屬巧合。這就是所謂的Undefined Behaviour。事實上,結果可能是任何事情(從你的汽車吹起來到在未來三週內仔細做午飯吧,這只是undefined

2

你在帖子結尾很好地解釋了這個問題。你唯一的「錯誤」是說在函數調用結束時變量a「死亡」。確實它死了,但返回一個副本,而不是函數堆棧中的一個。因此,訪問該函數的返回值沒有問題。

+0

如果函數返回值,主函數如何知道返回值返回哪個位置? – Abhijeet

+1

@Abhijeet:在返回期間,函數將其返回值推送到堆棧。然後調用者函數從堆棧中檢索(例如:彈出)它。 – jweyrich

+2

@jweyrich複製返回值的位置取決於正在使用的調用約定。它可能會被傳回寄存器或跨越多個寄存器。 – James

1

您可以通過按值或引用傳遞參數來進行類比。

在這裏,您通過引用或按值返回值。如果您按值返回值,則該值在調用者中可用。如果您通過引用返回值,則該值的引用將返回給調用者。要訪問該值,調用者必須解除引用,但該引用不再指向任何有效值。

0

函數不返回變量;他們返回。價值是否來自局部變量是無關緊要的;即使沒有,它也來自一個「本地表達」(我的術語),它的生存期比本地變量的壽命更短。將指針返回到本地(假設它是自動而非靜態的)變量的問題是指針的無效,並且在函數返回後對其的任何使用都會導致未定義的行爲。

相關問題