C 函式返回區域性變數指標的問題

2021-07-07 01:39:17 字數 3068 閱讀 2587

講這個問題之前要先簡單講一下c++的記憶體管理。

更詳細的內容可以參考這篇文章《c++記憶體管理》。

c++程式的記憶體被分為堆(heap),棧(stack),全域性/靜態儲存區,自由儲存區和常量儲存區。

1)堆(heap):new的都存放在這裡,屬於動態分配,如果在程式中呼叫delete釋放掉,那麼將一直存在,直到程式結束,由程式釋放掉。

2)棧(stack):由系統自動分配,形參和區域性變數均儲存在這裡,函式退出時該棧自動銷毀。

3)全域性/靜態儲存區:程式一開始執行即分配,生命週期持續到程式結束,存放全域性變數,靜態變數。

4)自由儲存區域:與堆的區別在於存放的是malloc的。

5)常量儲存區:顧名思義,存放常量的儲存區。

明白了c++的記憶體管理,接下來函式呼叫過程就比較好理解了。

注意:棧空間是從高位址向低位址增長的。所以壓棧即表示棧頂指標變小,而出棧則相反。

函式呼叫者維護了乙個棧空間(stack),擁有棧底指標ebp和棧頂指標esp。

呼叫函式時,棧變化過程簡單描述如下:

1)先將函式返回位址ret壓棧,即函式執行完畢後將從**繼續執行下去

2)將ebp壓棧

3)講esp賦值給ebp

4)將函式區域性變數壓棧

函式執行完畢後,棧變化過程如下:

1)函式區域性變數出棧

2)ebp出棧,恢復ebp的值

3)函式返回位址出棧

從以上的變化過程可以看到,函式呼叫者通過操作ebp和esp的值變化來維護棧的變化。即是,雖然函式執行完畢後棧「銷毀」了,但在重入之前,儲存在棧中的資料仍然存在!這個時候,通過指標來訪問該位置仍然可以獲得正確的值!

但是為什麼不推薦使用這種方式來獲得區域性變數的值呢?原因也是顯而易見的,棧隨時會被重入!重入之後,對應位置的值變成了不可**,訪問它會導致不可**的後果。

那在什麼情況下可以通過函式返回指標的方式來訪問函式區域性變數呢?參照c++的記憶體管理,答案很明顯,new的變數在函式結束之後仍然可以通過指標「安全」地訪問!但這其實帶來了新的問題:你要負責管理這個變數的生命週期或者任由它生存到程式結束(可能白白占用了記憶體!)

乙個簡單的例子如下:

[cpp]view plain

copy

#include 

using

namespace

std;  

intfunc1(

intparam)  

int* func2(

intparam)  

int*func3(

intparam)  

intmain()    

**:

全域性變數

作用域:全域性作用域(全域性變數只需在乙個原始檔中定義,就可以作用於所有的原始檔。) 

生命週期:程式執行期一直存在 

引用方法:其他檔案中要使用必須用extern 關鍵字宣告要引用的全域性變數。 

記憶體分布:全域性資料區 

注意:如果在兩個檔案中都定義了相同名字的全域性變數,連線出錯:變數重定義 

例子: 

+ expand sourceview plaincopy to clipboardprint?   

int g_ivalue = 1;  

extern int g_ivalue;  

int main()  

int g_ivalue = 1;

extern int g_ivalue;

int main()

全域性靜態變數

作用域:檔案作用域(只在被定義的檔案中可見。)

生命週期:程式執行期一直存在

記憶體分布:全域性資料區

定義方法:static關鍵字,const 關鍵字

注意:只要檔案不互相包含,在兩個不同的檔案中是可以定義完全相同的兩個靜態變數的,它們是兩個完全不同的變數

例子:+ expand sourceview plaincopy to clipboardprint?const int ivalue_1;  

static const int ivalue_2;  

static int ivalue_3;  

int main()  

const int ivalue_1;

static const int ivalue_2;

static int ivalue_3;

int main()

靜態區域性變數

作用域:區域性作用域(只在區域性作用域中可見)

生命週期:程式執行期一直存在

記憶體分布:全域性資料區

定義方法:區域性作用域用中用static定義

注意:只被初始化一次,多執行緒中需加鎖保護

例子:+ expand sourceview plaincopy to clipboardprint?void function()  

void function()

區域性變數

作用域:區域性作用域(只在區域性作用域中可見)

生命週期:程式執行出區域性作用域即被銷毀

記憶體分布:棧區

注意:auto指示符標示

還有一點要說明,掌握static關鍵字的使用很關鍵。以下是引用別人的一些經驗之談:

tips:

若全域性變數僅在單個c檔案中訪問,則可以將這個變數修改為靜態全域性變數,以降低模組間的耦合度;

若全域性變數僅由單個函式訪問,則可以將這個變數改為該函式的靜態區域性變數,以降低模組間的耦合度;

設計和使用訪問動態全域性變數、靜態全域性變數、靜態區域性變數的函式時,需要考慮重入問題,因為他們都放在靜態資料儲存區,全域性可見;

如果我們需要乙個可重入的函式,那麼,我們一定要避免函式中使用static變數(這樣的函式被稱為:帶「內部儲存器」功能的的函式)

函式中必須要使用static變數情況:比如當某函式的返回值為指標型別時,則必須是static的區域性變數的位址作為返回值,若為auto型別,則返回為錯指標。 

來csdn很久了,一直都想寫點東西,今天終於出手了。水平有限,只能跟大家分享一些基礎知識的總結,以共勉,共同提公升。

C 函式返回區域性變數

原因 返回值是拷貝值,區域性變數的作用域為函式內部,函式執行結束,棧上的區域性變數會銷毀,記憶體釋放。可返回的區域性變數 1.返回區域性變數本身 int sum int a,int b 2.常量 char returnvalue warning deprecatedconversion from s...

C 函式返回區域性變數

目錄2 可返回的區域性變數 示例 int get 或 char getmemory void 示例 int sum int a,int b 常量 char getmemory void 示例 const char getmemory void 或者int returnvalue return val...

函式返回區域性變數的問題

1.返回區域性變數的值 可以有兩種情況 返回區域性自動變數和區域性靜態變數,比如,int func 區域性變數temp儲存在棧中,函式返回時會自動複製乙份temp的copy給呼叫者,沒有問題。int func 區域性變數a儲存在靜態 全域性 儲存區中,從初始化後一直有效直到程式結束,僅分配一次記憶體...