通常在函數體內定義的局部變量,當程序運行到該語句時會給該局部變量分配棧內存。但隨着程序退出函數體,系統就會收回棧內存,局部變量也相應失效。
在局部變量前加上關鍵字"static",就被定義成為一個靜態局部變量。靜態局部變量保存在全局數據區,而不是保存在棧中,每次的值保持到下一次調用,直到下次賦新值。
靜態局部變量的用途有許多:可以使用它確定某函數是否被調用過。使用它保留多次調用的值。
如果是通過定義一個全局變量來實現,那變量已經不再屬於函數本身了,不再僅受函數的控制,給程序的維護帶來不便。
代碼示例:
#include <iostream> using namespace std; void func(); int main() { func(); func(); func(); } void func() { static int n=10; cout<<n<<endl; ++n; }
輸出:
10 11 12
程序中靜態局部變量n僅在第一次調用時被初始化,第二次進入該函數時,不再進行初始化,這時它的值是第一次調用后的結果值11。
靜態局部變區別:
- 靜態局部變量在靜態存儲區內分配存儲單元,在程序整個運行期間都不釋放。而普通局部變量屬於動態存儲類別,存儲在動態存儲區空間,函數調用結束后即釋放;
- 靜態局部變量只初始化一次,以后每次調用函數時保留上次函數調用結束時的值。而自動變量每調用一次函數重新執行一次賦值語句;
- 靜態局部變量一般在聲明處初始化,如果沒有顯式初始化,會被程序自動初始化為0(對數值型變量)或空字符(對字符型變量)。而對自動變量來說,如果不賦初值,則它的值是一個不確定的值。這是由於每次函數調用結束后存儲單元已釋放,下次調用時又重新另分配存儲單元,而所分配的單元中的值是不確定的。
- 靜態局部變量始終駐留在全局數據區,直到程序運行結束。但其作用域仍為局部作用域,當定義它的函數或語句塊結束時,其作用域隨之結束。雖然靜態局部變量在函數調用結束后仍然存在,但其他函數是不能引用它的。
關於局部靜態變量初始化時機:
這里引用我覺得另一個博主寫的很好的答案。
首先,靜態局部變量和全局變量一樣,數據都存放在全局區域,所以在主程序之前,編譯器已經為其分配好了內存,但在C和C++中靜態局部變量的初始化節點又有點不太一樣。
在C中,初始化發生在代碼執行之前,編譯階段分配好內存之后,就會進行初始化,所以我們看到在C語言中無法使用變量對靜態局部變量進行初始化,在程序運行結束,變量所處的全局內存會被全部回收。
而在C++中,初始化時在執行相關代碼時才會進行初始化,主要是由於C++引入對象后,要進行初始化必須執行相應構造函數和析構函數,在構造函數或析構函數中經常會需要進行某些程序中需要進行的特定操作,並非簡單地分配內存。所以C++標准定為全局或靜態對象是有首次用到時才會進行構造,並通過atexit()來管理。在程序結束,按照構造順序反方向進行逐個析構。所以在C++中是可以使用變量對靜態局部變量進行初始化的。
后面再來談談另一個問題,假如我們在一個循環中,定義了一個靜態局部變量並進行初始化,循環過程中,編譯器怎么知道當前的靜態局部變量已經初始化過了呢?
這個問題C和C++的處理方式也是不一樣的。C中編譯器會直接跳過這一個語句,因為在編譯的時候已經對靜態局部變量進行過分配空間並初始化,所以代碼執行過程中根本不需要再次執行。而在C++中,編譯器會在編譯器分配內存后,在全局區域(當前靜態局部變量的地址)附近同樣分配一塊空間,進行記錄變量是否已經進行過初始化。之所以說附近是根據編譯器不同,處理方式不同導致的。
C++11