static作用:靜態變量的生存週期和作用域

首先要理解生存週期與作用域的區別:
生存週期: 變量從定義到銷燬的時間範圍。存放在全局數據區的變量的生存週期存在於整個程序運行期間,而存放在棧中的數據則隨着函數等的作用域結束導致出棧而銷燬,除了靜態變量之外的局部變量都存放於棧中。
作用域: 變量的可見代碼域(塊作用域,函數作用域,類作用域,程序全局作用域)。

static變量是指靜態的變量,不管是在全局還是局部聲明的static變量都存放於程序的全局變量區域,所以它的生命週期是從程序開始到程序結束。但是static變量的作用域並不等同於它的生存週期,它的作用域決定於它被定義的位置。可以認爲static變量的作用域<=生存週期。

舉一個局部聲明的例子。在函數test中聲明靜態變量i:
void test()
{
int m=3;
static int i=5;
}
局部變量m存放在棧中,當test函數結束,m將被銷燬;靜態變量i不存放在棧中,而是存放於程序的全局變量區域,因此隨着函數test的結束,它並不隨着出棧操作而被銷燬,它的生存週期存在於程序的整個運行期;然而m和i的作用域都僅存在於test函數中它們的定義之後,即test調用結束之後,m和i就不再可用,但是i仍存在於內存之中。

再舉一個全局聲明的例子。在文件A 中定義靜態變量j:
int n=3; //默認爲extern
static int j=5; //聲明爲static
全局變量和靜態變量j都存放於程序的全局數據區域,它們的生存週期都是程序的整個運行期,但是n的作用域爲全局作用域,可以通過extern在其他文件中使用,而j只能在文件A中使用,例如在文件B中:
extern int n; //ok
extern int j; //error: j在文件B中不可見
int a=n;//ok:但這裏有個初始化先後的問題,具體參見參考一
int b=j;//error
也就是說,在聲明全局的static變量時,static沒有改變它的生存週期,也即存儲位置(因爲全局變量本來就存儲在全局數據域),而是將變量的作用域限制在當前文件中。

中興通訊2012校招筆試題的一道問答題:
1. static全局變量與普通的全局變量有什麼區別 ?
 全局變量(外部變量)的說明之前再冠以static 就構成了靜態的全局變量。
  全局變量本身就是靜態存儲方式, 靜態全局變量當然也是靜態存儲方式。 這兩者在存儲方式上並無不同。
  這兩者的區別在於非靜態全局變量的作用域是整個源程序, 當一個源程序由多個源文件組成時,非靜態的全局變量在各個源文件中都是有效的。 而靜態全局變量則限制了其作用域, 即只在定義該變量的源文件內有效, 在同一源程序的其它源文件中不能使用它。由於靜態全局變量的作用域侷限於一個源文件內,只能爲該源文件內的函數公用,因此可以避免在其它源文件中引起錯誤。
static全局變量只初使化一次,防止在其他文件單元中被引用;  
2. static局部變量和普通局部變量有什麼區別 ?
  把局部變量改變爲靜態變量後是改變了它的存儲方式即改變了它的生存期。把全局變量改變爲靜態變量後是改變了它的作用域,限制了它的使用範圍。
  static局部變量只被初始化一次,下一次依據上一次結果值;  
3. static函數與普通函數有什麼區別?
   static函數與普通函數作用域不同,僅在本文件。只在當前源文件中使用的函數應該說明爲內部函數(static修飾的函數),內部函數應該在當前源文件中說明和定義。對於可在當前源文件以外使用的函數,應該在一個頭文件中說明,要使用這些函數的源文件要包含這個頭文件.
static函數在內存中只有一份,普通函數在每個被調用中維持一份拷貝

P.S.
C程序一直由下列部分組成:
1)正文段(代碼段)——CPU執行的機器指令部分;一個程序只有一個副本;只讀,防止程序由於意外事故而修改自身指令;
2)初始化數據段(數據段)——在程序中所有賦了初值的全局變量,存放在這裏。
3)非初始化數據段(bss段)——在程序中沒有初始化的全局變量;內核將此段初始化爲0。(這就是爲什麼全局內置類型變量會初始化,而局部變量就爲未初始化的未知值)
4)棧——增長方向:自頂向下增長;自動變量以及每次函數調用時所需要保存的信息(返回地址;環境信息)。
5)堆——動態存儲分。
程序在內存中申請了代碼段,全局數據段(初始化和未初始化),棧和堆:程序代碼放於代碼段,全局變量和靜態變量存放在全局數據段中,一直存在直到程序結束,而局部變量都放於臨時的棧中,隨着作用域的結束隨着出棧操作而銷燬。malloc和new出來的內存不屬於上面提到的程序申請的內存中,而是在系統中申請到的內存,所以如果在程序中沒有明確free和delete的話,程序結束後該內存仍不會被釋放,造成內存泄漏。例如:
int test()
{
int * p=new int(3);
}
則test函數結束後,p指針本身被銷燬,因爲它是存在於函數棧中的局部變量,而p指向的int整型內容仍存在於內容堆中,沒有被釋放,造成內存泄漏。
詳細內存使用和參考http://blog.csdn.net/cc198877/article/details/8849694

參考
http://www.cnblogs.com/jerry19880126/archive/2013/03/09/2951186.html
http://www.cnblogs.com/jerry19880126/archive/2012/12/22/2829394.html
http://www.cnblogs.com/stoneJin/archive/2011/09/21/2183313.html
http://bbs.csdn.net/topics/350238100

發佈了44 篇原創文章 · 獲贊 87 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章