第一部分:核心觀念問答(精選)
- static 三大作用
- 1) 函數內靜態區域變數:保持值不隨呼叫銷毀。2) 檔案域靜態全域變數/函數:限制連結可見度於本編譯單元。3) 類別靜態成員(C++):屬於類別而非物件。
- 指標 vs 參考
- 參考必須初始化、不可重新綁定、無空參考;指標可為 NULL、可改變指向、支援運算。
- #include <h> vs #include "h"
- 前者搜尋系統標準路徑;後者先搜尋當前目錄,再搜尋系統路徑。
- 堆疊 vs 堆積
- 堆疊:編譯器自動管理,連續記憶體,大小固定(通常 1~8MB),速度快。堆積:程式設計師手動 malloc/free,非連續,受限於虛擬記憶體,易產生碎片。
- const 與 volatile
- const:唯讀,編譯器可優化;volatile:告知編譯器該變數可能被外部(硬體、中斷、執行緒)改變,每次存取必須重讀記憶體。兩者可共存(如唯讀硬體暫存器)。
- 位元操作技巧
- 設定 bit3:
x |= (1u<<3);清除 bit3:x &= ~(1u<<3);翻轉:x ^= (1u<<3)。
- 結構體對齊
- 成員依宣告順序排列,每個成員偏移量為其型別大小的倍數;結構體總大小為最大成員對齊需求的倍數。可用
#pragma pack(n) 改變對齊。
第二部分:程式碼找錯與輸出分析(精選)
1. 無號與有號混合比較
unsigned int a = 6; int b = -20;
(a+b > 6) ? puts(">6") : puts("<=6"); // 輸出 ">6"
// -20 轉無號變大數,結果為真
2. 字串字面常量不可修改
char *p = "hello";
p[0] = 'H'; // 未定義行為(段錯誤)
// 正確:char p[] = "hello"; 或 const char *p = "hello";
3. sizeof 陣列退化為指標
void f(char str[]) { printf("%zu", sizeof(str)); } // 印 4 或 8(指標大小)
char s[] = "abcde";
printf("%zu", sizeof(s)); // 印 6(含 \0)
4. 宏副作用陷阱
#define SQUARE(x) ((x)*(x))
int i = 5;
printf("%d", SQUARE(++i)); // 展開為 (++i)*(++i) → 36 或 42(未定義)
// 改用 inline 函數
第三部分:經典編程題(附解法大綱)
- 檔案倒序輸出:動態陣列讀入,反向寫出;或遞迴讀行、回溯時寫出。
- 整數拆解組合:雙指標
i=1, j=n-1 向中間收斂,O(n)。
- 遞迴反轉字串:
void rev(char *s){ if(*s) rev(s+1), putchar(*s); }
- 第 k 大元素:快選演算法 平均 O(n);或堆排序 O(n log k)。
- 歸併排序(鏈表):分半、遞迴排序、合併,O(n log n)、穩定。
- 判斷遞增陣列:
bool inc(int a[],int n){ return n<=1 || (a[n-1]>=a[n-2] && inc(a,n-1)); }
- 單向鏈表建立/反轉/刪除:三指標法反轉
prev, cur, next。
- 時間換空間 / 空間換時間:位圖法、查找表、快取。
- 最長連續數字子串:單掃描記錄起始/長度。
- 整數轉字串:取餘法產生反序字元,再反轉。
- 組合數生成:回溯法或迭代棧模擬。
- 指標反轉字串:雙端指標交換。
- 分數序列求和:迴圈累加
1.0/(2*i)。
- 約瑟夫環:循環鏈表或陣列模擬,O(n m) 或 O(n log n) 數學解。
- strcpy 實作:
char* strcpy(char* d,const char* s){ char* r=d; while((*d++=*s++)); return r; } 回傳目的地址支援鏈式呼叫。
第四部分:位域補充
- 位域不跨越儲存單元(通常 4/8 位元組),超過自動換到下一單元。
- 無名位域可用於對齊填充:
unsigned :0; 強制換行。
- 位域長度不可超過底層型別寬度。
掌握上述核心觀念與經典題型,配合實際編碼練習,足以應付絕大多數 C 語言面試。