以上是我們對內存區域的一個簡單的劃分,其中包括:代碼段、全局(靜態)變量區、棧以及堆,接下來讓我們看看一些常見的內容分別位於哪個區域內,並對其生命週期、作用域、默認值、鏈接屬性進行總結。
一、全局變量:定義在函數外部的變量
生命週期:從程序運行開始創建,程序結束銷燬(太佔內存)
作用域:從定義該變量開始,一直到文件的結束
默認值:0
內存區域:全局(靜態)變量區
鏈接屬性:外部
全局變量可以在其他的源文件中使用,例如:
首先在test_01 中定義一個全局變量a,並將其賦值爲50
然後在另一個源文件test_02中,我們可利用extern 來使用全局變量 a。
注:extern 是計算機語言中的一個關鍵字,可置於變量或者函數前,以表示變量或者函數的定義在別的文件中。提示編譯器遇到此變量或函數時,在其它模塊中尋找其定義,另外,extern也可用來進行鏈接指定。
可以順利運行
二、靜態全局變量:
生命週期:從程序運行開始創建,程序結束銷燬
作用域:從定義該變量開始,一直到文件的結束
默認值:0,
內存區域:全局(靜態)變量區
鏈接屬性:內部
當我們在全局變量前加關鍵字 static 時,就變成了靜態全局變量,靜態全局變量具有以下特點:
(a)不必擔心其它源文件使用相同變量名,彼此相互獨立。
(b)在某源文件中定義的靜態全局變量不能被其他源文件使用或修改。
(c) 只能在本文件中使用!不允許在其他文件裏調用;
例如:
還是繼續運行 test_02 ,運行失敗是可預見的
三、局部變量:定義在函數內部的變量,包括形參。
生命週期:進入函數時創建,函數退出時銷燬
作用域:只在函數內部有效
默認值:隨機值
內存區域:棧
鏈接屬性:無
例:
此程序運行的結果如下:
這是因爲,局部變量在它的生命週期結束時,它的內存也隨之消失,再次使用時再次申請空間,並且每次重新定義和初始化。
四、靜態局部變量:
生命週期:第一次進入函數時創建,程序結束時銷燬
作用域:只在函數內部有效
默認值:0
內存區域:全局(靜態)變量區
鏈接屬性:——
例:
我們把 a 定義成一個靜態局部變量,雖然只加了一個關鍵字 static ,但結果會有很大差異
產生這種結果的原因是:靜態局部變量所在的函數在多調用多次時,只有第一次才經歷變量定義和初始化,以後多次在調用時不再定義和初始化,而是維持之前上一次調用時執行後這個變量的值。本次接着來使用。靜態局部變量的這種特性,和全局變量非常類似。它們的相同點是都創造和初始化一次,以後調用時值保持上次的不變。不同點在於作用域不同。
五、動態內存:(下篇博客會具體介紹)
生命週期:調用動態內存創建函數時創建,free時銷燬
作用域:在未free該動態內存前,只要獲得該動態內存的首地址就可以使用
默認值:——
內存區域:堆
鏈接屬性:——
六、函數:
有時候我們需要從別的源文件中引用其中的函數,我們有以下兩種做法。當然前提是該函數不是 static 函數
第一種方法,我們直接用extern關鍵字來引用這個函數,如:
test_01 中定義了一個 add 函數,接下來在test_02中引用它:
可以正常運行。其結果爲:
另一種方法就是自己創建一個頭文件(add .h),在其中對所需函數進行聲明。如下:
然後我們就可以在需要使用這個函數的源文件中引用這個頭文件:
這個也是可以順利運行的,其結果和第一種方法的運行結果一樣。
這裏插個題外話,#include後面可以是 < > 或者 “ ”,這兩個是有一點區別的。
< > 是隻從系統的標準路徑查找頭文件
“ ” 是首先在自己的工程裏查找文件,找不到後,再去系統裏找
再說回函數,和靜態全局變量一樣,static函數也是不能被外部引用的,也就是說以上的兩種方法都會運行不了。如:
最後對函數總結一下,如果我們將來會在不同的源文件中使用很多相同的函數,大可以創建一個頭文件,然後在其中對所需函數進行聲明,這樣每個源文件只需要引用這個頭文件就可以了,而不需要去重複定義一個函數。