源自 Steven Kobes 的 C 測試題,專為招聘 C 開發者或自我檢測設計。涵蓋 setjmp/longjmp、結構體記憶體佈局、遞歸、指標算術、運算符優先級、sizeof 語義、函數指標、可變參數、位運算技巧等核心難點。
static jmp_buf buf;
int main() {
volatile int b = 3;
if (setjmp(buf) != 0) {
printf("%d\n", b); // 輸出 5
exit(0);
}
b = 5;
longjmp(buf, 1);
}
答案:B (5)。關鍵點:
volatile 防止編譯器優化掉 b 的修改setjmp 返回 0,執行 b=5 後 longjmp 跳回setjmp 返回 longjmp 的值 1,打印當前 b=5struct node { char a; char b; short c; int d; };
struct node s = {3, 5, 6, 99};
struct node *pt = &s;
printf("%X\n", *(int*)pt); // 輸出 60503
解析:32 位系統下 char=1B, short=2B, int=4B,結構體自然對齊無填充。pt 強轉為 int* 解引用,讀取前 4 字節:0x03, 0x05, 0x06, 0x00(小端序)組成 0x00060503 = 十六進制 60503。
int foo(int x, int n) {
int val = 1;
if (n > 0) {
if (n % 2 == 1) val *= x;
val *= foo(x * x, n / 2);
}
return val;
}
計算 x^n,採用「平方乘」法,遞歸深度 log₂n。紙上推演即可得解。
int a[5] = {1,2,3,4,5};
int *ptr = (int*)(&a + 1);
printf("%d %d\n", *(a+1), *(ptr-1)); // 輸出 2 5
關鍵:&a 類型為 int(*)[5],&a+1 跨越整個陣列(5*sizeof(int)),指向 a[5](越界位置)。強轉為 int* 後步長變為 sizeof(int),ptr-1 指向 a[4] 值 5。
void foo(int b[][3]) { ++b; b[1][1] = 9; }
int a[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
foo(a);
printf("%d\n", a[2][1]); // 輸出 9
++b 步長為 3*sizeof(int),指向第二行 {4,5,6}。b[1] 即第三行 {7,8,9},b[1][1] 對應 a[2][1] 被改為 9。
c = a, b; // c = a (賦值優先級 > 逗號) d = (a, b); // d = b (逗號表達式值為最後一項)
第 7 題同第 5 題原理。第 8 題:f1 返回棧上局部變數地址(未定義行為),f2 解引用未初始化指標(崩潰),f3 malloc 動態分配(正確)。
int i = 3, j; j = sizeof(++i + ++i); // i 仍為 3, j = sizeof(int) = 4
sizeof 運算元表達式不求值,僅在編譯期推導類型大小。
void (*p[2])(int*, int) 是函數指標陣列。f1 交換 *p 與 q,但 q 為值傳遞,外部 b 不變。輸出 5 3 5 3。
e(3) 遞歸調用,前置 --n 先減後用。輸出序列:0 1 0 1 2 1 0。
typedef int (*test)(float*, float*);
test 是「指向函數的指標類型」,該函數接受兩個 float* 返回 int。對照 bsearch、qsort、signal 練習。
(buf+1)[5] = *(buf+1+5) = buf[6] = 9。5[buf+1] 同理。利用 a[b] ≡ *(a+b) ≡ b[a] 特性。
i &= i - 1; // 消除最低位 1,循環次數 = 二進制中 1 的個數 // 7(111) → 6(110) → 4(100) → 0,計數 3
Hacker's Delight 經典技巧,計算 5(101) 和 7(111) 的 1 個數之和 = 2+3=5。
int counter(int i) {
static int count = 0; // 僅初始化一次,生命週期贯穿程序
count += i;
return count;
}
// main 中累加 0+1+2+3+4+5 = 15
| 領域 | 涉及題目 |
|---|---|
| 非局部跳轉/異常處理 | 1 |
| 記憶體佈局/對齊/指標轉換 | 2, 4, 5, 7 |
| 遞歸/演算法 | 3, 11 |
| 運算符優先級/逗號/ sizeof | 6, 9 |
| 函數指標/回調 | 10 |
| 未定義行為/棧/堆 | 8 |
| 複雜聲明/類型系統 | 12 |
| 陣列下標本質 | 13, 14 |
| 可變參數/位運算 | 15 |
| 存儲類別/生命週期 | 16 |