本文精選15道經典C語言筆試題,涵蓋標準庫返回值、宏展開機制、指針算術、運算符優先級、位運算提升、短路求值、sizeof特性等核心考點,附帶詳細解析與避坑指南。
int main() {
int i = 43;
int n = printf("%d\n", i); // 輸出 "43\n"
printf("%d\n", n); // 輸出什麼?
return 0;
}
答案:3(字符'4'、'3'、'\n'共3個)
規律:printf返回成功輸出字符數,錯誤返回負數;scanf返回成功賦值項目數,失敗返回EOF。
原因:需區分有效字符0xFF(255)與EOF(-1)。若返回char,有符號時兩者均為-1,無符號時無法表示-1。
#define TOTAL_ELEMENTS (sizeof(array)/sizeof(array[0]))
int array[] = {23,34,12,17,204,99,16};
int main() {
int d;
for(d = -1; d <= (TOTAL_ELEMENTS-2); d++)
printf("%d\n", array[d+1]);
return 0;
}
現象:無輸出
原因:sizeof返回size_t(無符號),比較時d被提升為無符號數,-1變為巨大正數,循環條件不成立。
修正:for(d = -1; d <= (int)TOTAL_ELEMENTS-2; d++)
#define f(a,b) a##b
#define g(a) #a
#define h(a) g(a)
printf("%s\n", h(f(1,2))); // 輸出?
printf("%s\n", g(f(1,2))); // 輸出?
答案:12 和 f(1,2)
解析:
g(f(1,2)):#直接字符串化參數,不展開內層宏 → "f(1,2)"h(f(1,2)):h先展開參數 f(1,2)→12,再傳給g字符串化 → "12"int a[5]; // 假設地址 0xbfe2e100,32位系統
printf("%x\n", a); // ?
printf("%x\n", a+1); // ?
printf("%x\n", &a); // ?
printf("%x\n", &a+1); // ?
答案:
a:bfe2e100(數組首元素地址)a+1:bfe2e104(+1个int,即+4字節)&a:bfe2e100(數組地址值相同,但類型是int(*)[5])&a+1:bfe2e114(+1個數組,即+5*4=20字節=0x14)int a = 2;
if(a & 1 == 0) // 實際解析為 a & (1==0) 即 a & 0
printf("a & 1 == 0");
else
printf("a & 1 != 0"); // 輸出此行
優先級:==/!= > & > ^ > | > && > ||
int i = 6;
if( ((++i < 7) && (i++/6)) || (++i <= 9) );
printf("%d\n", i); // 輸出 8
過程:++i→7,7<7為假,&&短路跳過i++/6,||繼續評估++i<=9(i變8),最終i=8。
int i = 1;
sizeof(i++);
printf("%d\n", i); // 輸出 1(i未增)
原因:sizeof編譯期求值,僅根據類型計算大小,不生成計算代碼。
t = a<<2 + a; // 實際為 a << (2+a),非 (a<<2)+a
// 修正:t = (a<<2) + a;
優先級:+ > <<
unsigned char c = 0xfc;
unsigned int i = ~c;
printf("%x\n", i); // 輸出 0xffffff03,非 0x03
原因:c先提升為int(0x000000fc),再取反得0xffffff03。若c為char(有符號),提升為0xfffffffc,取反得0x03。
#define MAX 255
unsigned char A[MAX], i;
for(i = 0; i <= MAX; i++) // i最大255,i++後變0,無限循環
A[i] = i;
max = ((a+b) + abs(a-b)) / 2;
min = ((a+b) - abs(a-b)) / 2;
#define MAX(a,b) ((((a)-(b)) & (1<<31)) ? (b) : (a)) // 32位系統
利用符號位判斷a-b正負。
#define OFFSET(struct, member) ((unsigned int)&((struct*)0)->member)
利用空指針解引用計算偏移(編譯期常量,不產生實際訪問)。
int pow2_ceil(unsigned int x) {
x--;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
x++;
return x;
}
位填充技巧:將最高位1後的所有位置1,再+1得到下一個2的冪。
// 設置bit5為1: x |= (1<<5);
// 清除bit5為0: x &= ~(1<<5);
// 測試bit5是否1: (x & (1<<5)) != 0
// 判斷偶數: (num & 1) == 0
作用:告訴編譯器「此變量可能意外改變」,禁止優化器缓存寄存器值,強制每次從內存讀取。
典型場景:
經典失效案例:線程A在循環中檢查寄存器中緩存的flag,線程B修改內存中flag,A永遠看不到變化 → 死循環。加volatile強制每次讀內存解決。