精選 13 道經典 C 語言面試題,涵蓋 static、記憶體佈局、堆棧溢出、switch 限制、浮點比較、字串轉整數、測試分類、軟體設計流程、指針運算、unsigned char 迴圈陷阱、宏副作用,附標準答案與深度解析。
static 有什麼用途?答案:三大語義——靜態區域變數(函數內保持值、儲存在全域區)、內部連結全域變數/函數(檔案級私有、避免符號衝突)、靜態儲存期(程式啟動前分配、全程駐留)。
答案:代碼區(.text)、**全域/靜態區**(.data/.bss)、**堆**(malloc)、**棧**(區域變數、參數)、**常量區**(字面常數)。圖示見原文。
答案:棧溢出:遞歸過深、大區域陣列/結構體。堆耗盡:記憶體洩漏(malloc 無 free)、分配過大塊。兩者本質不同。
switch 不能用的型別?答案:浮點型別(float/double)。switch 僅支援**整數型別**(int, char, enum 等)。
float 與零比較正確寫法?答案:if (x < 0.000001 && x > -0.000001)(或 fabs(x) < EPS)。float 精度約 6-7 位有效數字,直接 == 0 極不可靠。
答案:long atol(const char *nptr);(C 標準庫)。同族:atoi (int), atof (double), strtol/strtoul/strtod(更健壯,支援錯誤檢查、進制)。
答案:C 用 **宏** (#define);C++ 用 **inline 函數**(型別安全、可除錯、支援重載)。
答案:黑盒測試(功能/介面,不看代碼);白盒測試(邏輯覆蓋、路徑、單元測試,看代碼)。另有灰盒、回歸、壓力、模糊測試等。
答案:概要設計階段(高層設計)。流程:市場調研 → 需求分析 → **概要設計** → 詳細設計 → 編碼 → 測試 → 維護。
p1+5, p2+5
unsigned char *p1 = (unsigned char*)0x801000;
unsigned long *p2 = (unsigned long*)0x810000;
// 假設 long=4位元組 (32位系統) 或 8位元組 (64位系統 LP64)
解析:指針加減按**指向型別大小**縮放。
p1 型別 unsigned char* (1位元組) → p1+5 = 0x801000 + 5*1 = 0x801005。
p2 型別 unsigned long* (4或8位元組) → p2+5 = 0x810000 + 5*4 = 0x810014 (32位) 或 0x810028 (64位)。
關鍵:指針運算單位 = sizeof(指向型別)。
int a[60][250][1000];
for (k=0; k<1000; k++)
for (j=0; j<250; j++)
for (i=0; i<60; i++)
a[i][j][k] = 0;
問題:最內層 k 變化最快,但 C 陣列**行優先**儲存,a[i][j][k] 連續記憶體是 k 維。原迴圈**跳躍式訪問**,Cache Miss 極高。
優化:將 k 移至最內層(即原碼已正確!原題說「把迴圈語句內外換一下」可能指調整順序使 i 最內層)。正確順序:for(i) for(j) for(k) 或 for(k) for(j) for(i) 視訪問模式。
補充:該陣列約 60×250×1000×4 ≈ 600MB,**超過棧限制**,必須改為 static 或 malloc。
unsigned char 迴圈陷阱
#define MAX_CB 500
unsigned char ucCmdNum;
for (ucCmdNum = 0; ucCmdNum < MAX_CB; ucCmdNum++) { ... }
死循環:unsigned char 範圍 0~255,ucCmdNum++ 到 255 後歸零,**永遠 < 500**,無法結束。
修正:用 int 或 unsigned short/uint16_t。
SQUARE(a++)
#define SQUARE(a) ((a)*(a))
int a=5, b=SQUARE(a++); // 展開: ((a++)*(a++)) → a 增加 2 次,b=25, a=7
教訓:宏參數**勿含副作用**。改用 inline int square(int x) { return x*x; }。
這 13 題觸及 C 語言**核心機制(static、記憶體、指針運算)**、**標準庫正確用法**、**工程常識(測試、設計流程)**、**經典陷阱(浮點比較、宏副作用、型別溢位)**。面試前逐行推演、動手驗證,方能臨場從容。