C 語言看似簡單,實則細節決定成敗。本文彙整 29 個核心知識點,涵蓋輸入輸出、字串、函式、記憶體、指標、陣列、結構體、位運算、檔案操作等,幫你建立正確的心智模型,避開常見陷阱。
int x = 5;
printf("%d %d %d", x, ++x, ++x);
// VC6.0 / GCC (舊版) 輸出: 7 7 6
// GCC (新版) / Clang 輸出: 7 7 7 (未定義行為,勿依賴)
// ✅ 正解:不要在同一表達式中多次修改同一變數
標準規定:函式參數求值順序未定義,跨編譯器、跨版本、跨最佳化等級皆可能不同。
%md:寬度 m,不足左補空格,超寬按實際輸出%-md:左對齊,不足右補空格'0' + mint m = 5; char c = '0' + m; // c == '5'
c - 'a' + 'A' (僅適用 ASCII)char c = 'h'; char upper = c - 'a' + 'A'; // 'H'
switch (x) {
case 1: puts("one");
case 2: puts("two"); // x==1 時也會印出 "two"
default: puts("other");
}
char str[5] = "china"; // ❌ 需 6 位元組: 'c','h','i','n','a','\0' char str[6] = "china"; // ✅
| 函式 | 空白處理 | 緩衝區溢出風險 | 備註 |
|---|---|---|---|
scanf("%s", str) | 遇空白/換行停止 | 高 (無長度限制) | 不安全 |
gets(str) | 讀整行含空白 | 極高 (已移除 C11) | 禁用 |
fgets(str, n, stdin) | 讀 n-1 字元或遇 \n | 無 (指定長度) | ✅ 推薦 |
strcpy(dest, src) // 複製含 \0,dest 需足夠空間 strncpy(dest, src, n) // 複製 n 字元,不足補 \0,超長不加 \0 ⚠️ strcat(dest, src) // 追加,dest 需足夠空間 strncat(dest, src, n) // 追加 n 字元 strcmp(s1, s2) // 比較,相等 0,s1>s2 正數,s1三、函式與參數傳遞
9. 單向值傳遞:形參改變不影響實參
void swap(int a, int b) { int t=a; a=b; b=t; } // ❌ 無效 void swap(int *a, int *b) { int t=*a; *a=*b; *b=t; } // ✅ 傳址10. 陣列作為參數:退化為指標
void func(int arr[]) { } // 等價於 int *arr void func(int arr[10]) { } // 長度資訊丟失,仍為 int *arr void func(int (*arr)[5]) { } // 二維陣列:保留第二維,退化為指向陣列的指標四、變數儲存類別與生命週期
儲存類別 關鍵字 儲存區 生命週期 作用域 預設初值 自動 (區域) (無)/auto 堆疊 函式呼叫期間 區塊 不定值 (垃圾值) 靜態區域 static 靜態區 程式全程 區塊 0 靜態全域 static (檔案層級) 靜態區 程式全程 檔案 (內部連結) 0 外部全域 extern (預設) 靜態區 程式全程 全程式 (外部連結) 0 暫存器 register CPU 暫存器/堆疊 同 auto 區塊 不定值 11. static 區域變數:只初始化一次,跨呼叫保持值
void f() { static int a = 0; // 編譯期初始化 0,只執行一次 printf("%d ", ++a); } f(); f(); f(); // 輸出: 1 2 3五、指標與陣列進階
12. 運算子優先級與結合性
[]、()、.、->最高,左結合*、&、++、--(前綴/後綴) 次高,右結合*p++≡*(p++)(取值後指標遞增)*++p≡*(++p)(指標遞增後取值)13. 二維陣列記憶體佈局:行優先
int a[2][3] = {{1,2,3},{4,5,6}}; // 記憶體: 1 2 3 4 5 6 // a → 第 0 行首址 // a+1 → 第 1 行首址 (跨過 3 個 int) // *a / a[0] → a[0][0] 址 // *(a+1) / a[1] → a[1][0] 址14. 陣列指標 vs 指標陣列
int (*p)[4]; // 陣列指標:指向含 4 個 int 的陣列 (行指標) int *p[4]; // 指標陣列:含 4 個 int* 的陣列15. 字串輸入必須先配置空間
char *cp; scanf("%s", cp); // ❌ 野指標,崩潰 char buf[20]; scanf("%s", buf); // ✅ char *cp = malloc(20); scanf("%s", cp); // ✅六、結構體、共用體、列舉
16. 結構體初始化:僅定義時可用大括號
struct Student { int id; char *name; }; struct Student s1 = {1, "Tom"}; // ✅ 定義時初始化 struct Student s2; s2 = {2, "Jerry"}; // ❌ 定義後不可用大括號 // 定義後需逐欄位賦值: s2.id=2; s2.name="Jerry";17. 共用體:同一記憶體,同一時間只有一個成員有效
- 大小 = 最大成員大小 (對齊後)
- 不可作為函式參數/回傳值 (C89),C99 允許
- 常用於型別雙關、位欄位、省記憶體
18. 列舉:預設從 0 遞增
enum Color { RED, GREEN, BLUE }; // RED=0, GREEN=1, BLUE=2 enum Color c = RED; int i = RED; // i == 0七、typedef 型別別名
typedef int INTEGER; typedef struct { int num; char name[10]; float score; } Student; Student s1, s2, *ps;typedef 不創建新型別,僅為現有型別起別名。
八、位運算與移位
19. 位運算規則:補碼參與運算,符號位參與
&(AND)、|(OR)、^(XOR)、~(NOT)- XOR 性質:
a^a=0、a^0=a、a^~a=-1(全 1)- 無暫存器交換:
a^=b; b^=a; a^=b;20. 移位運算:實作定義 (Implementation-defined)
類型 左移 右移 邏輯移位 低位補 0 高位補 0 算術移位 低位補 0 高位補符號位 (保持正負) 循環移位 移出的位移入另一端 同上 C 標準未規定有號數右移行為,**x86/MSVC/GCC 通常採算術移位**,但不可攜帶假設。無號數右移保證邏輯移位 (補 0)。
⚠️ 移位不改變原變數:
a >> 2產生新值,a不變;需a = a >> 2才改變。九、檔案操作 (FILE*)
21. FILE 結構體:標準庫不透明型別
typedef struct _iobuf { char *_ptr; int _cnt; char *_base; int _flag; int _file; ... } FILE;22. 開檔模式
模式 說明 建檔 截斷 讀寫位置 r 唯讀 否 否 開頭 w 唯寫 是 是 開頭 a 附加 是 否 末尾 r+ 讀寫 否 否 開頭 w+ 讀寫 是 是 開頭 a+ 讀寫附加 是 否 末尾 二進位模式加
b:rb,wb,ab... (Windows 區分換行轉換,Linux/Unix 無差異)23. 緩衝區與資料完整性
- 預設全緩衝 (通常 4KB/8KB),行緩衝 (終端機),無緩衝 (stderr)
- 異常終止會丟失緩衝區資料,必須
fclose()或fflush()強制寫入fclose(fp)回傳 0 表成功,EOF 表失敗24. 檔案讀寫函式族
// 字元 int fgetc(FILE*); int fputc(int, FILE*); // 字串 (含 \n, 以 \0 結尾) char* fgets(char*, int, FILE*); int fputs(const char*, FILE*); // 格式化 int fscanf(FILE*, const char*, ...); int fprintf(FILE*, const char*, ...); // 區塊 (二進位) size_t fread(void* ptr, size_t size, size_t nmemb, FILE*); size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE*);25. 隨機存取
rewind(fp); // 回到開頭 fseek(fp, offset, SEEK_SET/CUR/END); // 移動位置 long ftell(fp); // 取得目前位置 (相對開頭) int feof(FILE*); // 檢查 EOF 標記 (讀取失敗後才置位)十、動態記憶體管理
26. malloc/free 基礎
void *malloc(size_t size); // 成功回傳對齊位址,失敗回傳 NULL void free(void *ptr); // ptr 必須是 malloc/calloc/realloc 回傳值 // 必須配對,釋放後指標不可再用 (懸空指標),建議 free 後設 NULL27. 常見錯誤
- 未檢查
NULL直接解參考- 釋放非堆疊記憶體、重複釋放、釋放後使用
realloc(ptr, 0)行為實作定義 (可能等同 free),C17 標準化為類似 free十一、預處理指令
28. #include 路徑搜尋差異
#include <header.h>:僅搜尋系統標準路徑 (/usr/include, 專案 include 目錄)#include "header.h":先搜尋當前檔案目錄,找不到再搜尋系統路徑29. 條件編譯常用模式
#ifdef DEBUG #define LOG(...) printf(__VA_ARGS__) #else #define LOG(...) #endif #ifndef HEADER_H #define HEADER_H // 內容 #endif總結
C 語言的精髓在於「理解機器模型」:記憶體佈局、指標運算、呼叫慣例、預處理機制。掌握這 29 點核心知識,並養成 檢查回傳值、初始化變數、配對 malloc/free、邊界檢查、避免未定義行為 的習慣,即能寫出健壯、高效、可移植的 C 程式碼。