1. 程式人生 > 實用技巧 >C語言複習篇之儲存類、連結和記憶體管理

C語言複習篇之儲存類、連結和記憶體管理

儲存類、連結和記憶體管理

對儲存類、記憶體管理這方面的學習,能夠讓我們更加的理解程式的一個執行過程,理解程式在執行中的具體機制和它的實現方法。雖然對於寫程式碼本身並沒有太大的幫助,但是它能夠使得我們更好的理解程式,更容易去判斷程式是否能按我們的意願來實現,或者說讓我們糾錯更容易的知道是哪裡出了問題。

當然,複習的第一步依然是概念:

1.儲存型別

C語言中的儲存型別有下面幾個關鍵字:auto、static、register、extern。

auto:自動儲存類,由系統自動分配棧儲存空間,使用者不用操心。這種型別的變數是區域性於某個程式範圍內的,只能在某個程式範圍內使用,一般在函式體內,定義變數的預設方式就是屬於auto類變數。

static:靜態儲存類,既可以在函式體外也可以在函式體內定義,它在記憶體中是以固定地址存放的,在整個程式的執行過程中它都不會消失,並且static型別的變數只被初始化一次,且變數的值具有繼承性。舉個例子:

  1. voidfunc(void)
  2. {
  3. inti=0;
  4. i+=1;
  5. printf("%d\n",i);
  6. }
  7. intmain(void)
  8. {
  9. func();
  10. func();
  11. func();
  12. return0;
  13. }

執行結果:1,1,1

但是如果定義是這樣的:static int i = 0;結果就不一樣了,變成了1,2,3 。我們可以看到加了static關鍵字之後,每次呼叫函式func不會重複賦值而是延續上次運算的結果。

register:暫存器儲存型別,這種型別是比較牛的,因為不是你寫了register關鍵字它就會變成暫存器型別的變數,這是要看“心情”的,若是“心情”不好就會直接降級成為auto型變數。我們知道暫存器內執行速度是很快的,所以資源就比較寶貴,你定義了這樣一個變數之後,編譯器會自動判斷是否需要滿足你。因此對於暫存器變數的定義一般是使用頻率比較高的變數。

extern:外部儲存型別,用於外部變數的宣告,它的作用範圍是從定義開始到程式執行結束,它對於變數的型別和值是沒有改變的許可權的,因為extern關鍵字是用於宣告而不是定義。

宣告 定義
可以多次宣告 只能定義一次
不分配記憶體,不可初始化 分配記憶體空間,可以初始化
定義是特殊的宣告

2.作用域

程式碼塊作用域:在程式碼塊中({.....}之內的變數)定義的變數的作用的範圍。如:區域性變數,static區域性變數。

函式原型作用域:函式宣告(int fun(int x),小括號內的範圍)使用變數作用的範圍。

檔案作用域:在所有函式之外定義的變數的作用的範圍,又分為本檔案作用域(全域性變數static,函式static)和多檔案作用域(全域性變數和函式)。

3.連結

連結型別其實是和作用域對應起來的。

空連結:具有程式碼塊作用域和函式作用域的變數是空連結。

內部連結:具有檔案作用域的變數,它可以在一個檔案的任何地方使用。

外部連結:具有檔案作用域的變數,它可以在一個多檔案程式的任何地方使用。

4.儲存期

靜態儲存期,從變數定義開始到整個程式執行結束。

自動儲存期:棧裡定義的變數(由系統分配維護),程式進入這些變數的程式碼塊時,將為這些變數分配記憶體,退出時釋放記憶體。

動態儲存期:堆裡定義的變數,使用者自己定義,malloc( )開始到free ( )或者退出程式碼塊結束。

下面的總結和一個例子:

  1. inta;//全域性變數,靜態儲存期,外部連結,多檔案作用域
  2. staticintb;//全域性變數,靜態儲存期,內部連結,本檔案作用域
  3. voidfun(void)
  4. {
  5. intx;//區域性變數,自動儲存期,空連結,程式碼塊作用域
  6. staticinty;//區域性變數,靜態儲存期,空連結,程式碼塊作用域
  7. }
  8. intmain(void)
  9. {
  10. ....
  11. ....
  12. return0
  13. }

程式碼分析比較:

  1. A: B:
  2. int main(void) int main(void)
  3. { {
  4. char *p = "abcdefg"; char p[]="abcdefg";
  5. *p = ‘x’; *p = ‘x’;
  6. printf("%s\n",p); printf("%s\n",p);
  7. return 0; return 0;
  8. } }
  9. //A 錯誤,B正確。

以上程式碼為什麼會有這樣的結果呢?這就是一個儲存位置的問題了,程式碼A中字串“abcdefg”儲存於常量區只讀資料段,因此是不能改變它的,試圖改變它的結果只有一個段錯誤;而程式碼B就不同了,陣列元素是在棧中分配記憶體的,可以進行改變等操作。

網上下載的兩個圖表:

轉載於:https://blog.51cto.com/doublewen/765202