深度理解函式返回區域性變數問題

2022-09-19 20:51:14 字數 1674 閱讀 5639

在被呼叫函式裡把儲存區的位址作為返回值使用的時候就可以讓呼叫函式使用被呼叫函式的儲存區。這個時候被呼叫函式需要提供乙個指標型別的儲存區記錄作為返回值的位址。

且不可以把非靜態區域性變數儲存區的位址作為返回值來使用。這裡主要是由函式裡區域性變數所存在的儲存區的型別所決定的。

c程式的儲存空間布局可以分為:

1、正文段:通常存放cpu執行的機器指令部分。

2、初始化資料段:通常也叫資料段,用來存放程式中已初始化的全域性變數的一塊記憶體區域。資料段屬於靜態記憶體分配。

3、未初始化資料段(bss):通常是指用來存放程式中未初始化的或者初始值為0的全域性變數的一塊記憶體區域。bss段屬於靜態記憶體分配。

4、棧:存放函式的引數,返回值,區域性變數等。

5、堆:由程式設計師自行分配釋放並管理。

所以,儲存在靜態區域的物件的生存週期是主函式的生存週期,而儲存在棧區域的物件生存週期為指標函式開始執行到指標函式結束,當指 針函式結束時儲存在棧區域的物件生存週期也就結束,其位址也變成無效位址。棧空間由編譯器自動分配和釋放,函式結束時其棧空間釋放記憶體。堆區域一般由程式設計師來控制其生存週期。因此,指標函式返回的指標能夠指向靜態區域的變數而不能指向自動區域性變數。

當函式使用指標作為返回值時,它可以指向靜態區域的位址,可以指向堆記憶體的位址,也可以指向函式呼叫者的棧空間,但是它不可以指向乙個函式內部棧記憶體的位址。

因此,能不能返回區域性指標變數,不在於這個指標變數的型別和性質(不在於該指標是不是區域性指標變數),而在於該指標指向的物件的型別和性質。如果該指標指向函式內部的棧空間,則程式非法,如果指向靜態區域的位址,則合法。

下面咱們來看程式,使用的編譯器及linux版本為(gcc version 4.8.2 (ubuntu 4.8.2-19ubuntu1))

區域性變數演示:

1

int *doit(void)7

8int main(void

)

編譯之後執行,結果如下:

你可以驚奇的發現,函式已經返回了,區域性變數**,為什麼*ptr的值還是7呢?

原來編譯器在函式執行結束後,的確會對區域性變數進行銷毀,但是需要一定的時間。例如以下**

int *doit(void)  

int main(void

)

我在第一條列印出sleep 1秒之後再列印輸出,可見*ptr的值已經發生改變:

int *doit(void)  

int main(void

)

這樣執行結果就是:

符合預期要求。

當區域性變數為陣列的時候,也是不可以的:

int *doit(void)

int main(void

)

結果為:

但是如果字串是這種形式:

int * doit(void

)int main(void

)

結果為:

若用malloc在堆區申請記憶體,則:

int * doit(void

)int main(void

)

則:

可見要深刻理解這句話:能不能返回區域性指標變數,不在於這個指標變數的型別和性質(不在於該指標是不是區域性指標變數),而在於該指標指向的物件的型別和性質。

函式返回區域性變數

一般的來說,函式是可以返回區域性變數的。區域性變數的作用域只在函式內部,在函式返回後,區域性變數的記憶體已經釋放了。因此,如果函式返回的是區域性變數的值,不涉及位址,程式不會出錯。但是如果返回的是區域性變數的位址 指標 的話,程式執行後會出錯。因為函式只是把指標複製後返回了,但是指標指向的內容已經被...

函式返回區域性變數

函式返回區域性變數 一般的來說,函式是可以返回區域性變數的。區域性變數的作用域 只在函式內部,在函式返回後,區域性變數的記憶體已經釋放了。因此,如果函式返回的是區域性變數的值,不涉及位址,程式不會出錯。但是如果返回的是區域性變數的位址 指標 的話,程式執行後會出錯。因為 函式只是把指標複製後返回了,...

函式返回區域性變數

一般的來說,函式是可以返回區域性變數的。區域性變數的作用域只在函式內部,在函式返回後,區域性變數的記憶體已經釋放了。因此,如果函式返回的是區域性變數的值,不涉及位址,程式不會出錯。但是如果返回的是區域性變數的位址 指標 的話,程式執行後會出錯。因為函式只是把指標複製後返回了,但是指標指向的內容已經被...