首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C Primer Plus 第 12 章:儲存類別、連結與記憶體管理

     編輯:關於C語言

第 12 章 儲存類別、連結與記憶體管理

12.1 儲存類別概觀

儲存類別決定變數的作用域、連結屬性與儲存期(生命週期)。不同組合形成不同的儲存類別。

12.1.1 作用域

  • 區塊作用域:在區塊 {...} 內定義,從定義處至區塊結束可見。函數參數也屬此類(隸屬函數本體區塊)。C99 允許在區塊任意位置宣告。
  • 函數原型作用域:原型宣告中參數名僅在原型內可見,編譯器僅關心型別。
  • 檔案作用域:所有函數外部定義,從定義處至檔案結尾可見。
  • 函數作用域:僅適用於 goto 標籤。

12.1.2 連結屬性

  • 外部連結:多檔案程式中可在任何檔案使用(預設檔案作用域變數)。
  • 內部連結:僅在定義該變數的檔案內可見(static 修飾檔案作用域變數)。
  • 無連結:區塊/原型作用域變數,僅屬於定義處區塊私有。

12.1.3 儲存期

  • 靜態儲存期:程式執行期間持續存在。所有檔案作用域變數(無論內部/外部連結)皆屬此類。
  • 自動儲存期:區塊作用域變數預設為自動,進入區塊建立,離開區塊銷毀。
  • 動態儲存期:malloc()/free() 管理的堆疊記憶體。

12.1.4 自動變數

區塊內預設為 auto(可省略)。迴圈/判斷敘述隱含區塊亦適用。

12.1.5 暫存器變數

register 僅為請求,編譯器可能忽略。受限於暫存器大小與數量,無法取址(&)。

12.1.6 區塊作用域靜態變數

static 修飾區塊內變數:靜態儲存期、區塊作用域、無連結。程式載入時已就位,保留值跨越函數呼叫。

12.1.7 外部連結靜態變數(外部變數)

函數外部定義即為外部變數。其他檔案用 extern 宣告引用。定義宣告配置記憶體並可初始化(僅一次);參考宣告用 extern 告知編譯器別處有定義。未初始化的外部變數自動歸零。

12.1.8 內部連結靜態變數

檔案作用域加 static:僅限本檔案函數使用,隱藏於連結器。

12.2 儲存類別說明符

關鍵字用途
auto區塊作用域自動變數(預設)
register區塊作用域,請求暫存器,不可取址
static區塊內:靜態儲存期;檔案層級:內部連結
extern宣告外部定義的變數/函數
typedef型別別名,語法歸屬此類但與儲存無關

單一宣告中只能出現一個儲存類別說明符。

12.3 函數的儲存類別

函數預設外部連結(可跨檔案呼叫),加 static 限制為內部連結(僅本檔案可見)。

12.4 動態記憶體配置:malloc() 與 free()

double *ptd = (double*)malloc(30 * sizeof(double));
if (ptd) { /* 使用 */ free(ptd); }

malloc 依位元組配置,成功返回起始位址,失敗返回 NULL。每次 malloc 應對應一次 free,釋放非 malloc 記憶體導致未定義行為。原型在 <stdlib.h>。標準庫提供 EXIT_SUCCESS/EXIT_FAILURE 作為 exit() 參數。

12.4.1 free() 的重要性

自動變數記憶體自動管理;靜態變數固定;唯動態配置記憶體若不 free 會持續增長,造成記憶體洩漏。

12.4.2 calloc()

long *newmem = (long*)calloc(100, sizeof(long));

calloc(n, size) 配置 n*size 位元組並全數歸零。同樣用 free() 釋放。

12.4.3 動態配置 vs 變長陣列 (VLA)

  • VLA:自動儲存類別,離開定義區塊自動釋放,侷限於函數內部。
  • malloc:動態儲存期,可跨函數傳遞指標,靈活但需手動管理。

自動變數使用堆疊(LIFO);動態配置使用堆積。

12.5 ANSI C 型別限定詞

C99 規定限定詞冪等:const const int n = 6; 等同 const int n = 6;。

12.5.1 volatile

告訴編譯器:該變數可能被程式外部代理(硬體暫存器、中斷服務程式、多執行緒共享記憶體)修改,禁止優化掉存取。可同時為 const volatile(程式唯讀,硬體可寫)。

12.5.2 restrict (C99)

僅用於指標,指明該指標是存取某資料物件的唯一且初始途徑,幫助編譯器優化(如避免別名分析)。

int *restrict restar = (int*)malloc(10 * sizeof(int)); // 唯一存取路徑
int *par = ar; // 非唯一,不可加 restrict

void *memcpy(void *restrict s1, void *restrict s2, size_t n);
// s1、s2 不重疊,編譯器可積極優化
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved