讀取標準輸入直到 EOF,統計數字(0-9)、空白字元(空格、Tab、換行)與其他字元的出現次數,展示 switch 多標籤落入與陣列索引映射技巧。
#include <stdio.h>
void countChars(void);
int main(void) {
countChars();
return 0;
}
void countChars(void) {
int c, i;
int nWhite = 0, nOther = 0;
int nDigit[10] = {0}; // 初始化為 0
while ((c = getchar()) != EOF) {
switch (c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
// 字元 '0'~'9' 連續編碼,c - '0' 即為對應索引
nDigit[c - '0']++;
break;
case ' ': case '\t': case '\n':
nWhite++;
break;
default:
nOther++;
break;
}
}
printf("digits =");
for (i = 0; i < 10; i++)
printf(" %d", nDigit[i]);
printf(", white space = %d, other = %d\n", nWhite, nOther);
}
case '0': case '1': ... case '9':
nDigit[c - '0']++;
break;
十個 case 連寫,無 break,執行同一區塊。這是 switch 的標準用法,等同 if (c >= '0' && c <= '9') 但編譯器常優化為跳躍表,效率極高。
c - '0'ASCII 中 '0'~'9' 碼位連續,'0'=48, '1'=49...,故 c - '0' 直接得到 0~9,作為陣列索引,避免 if-else 鏈,也是簡易雜湊/計數排序的雛形(犧牲空間換時間)。
case ' ': case '\t': case '\n':
nWhite++;
同理合併三種常見空白字元。
default 捕獲其餘字元任何不屬於上述類別的字元(標點、字母、控制碼等)皆計入 nOther。
$ ./a.out
Hello World 123
^D
digits = 0 1 1 1 0 0 0 0 0 0, white space = 2, other = 10
(輸入結束:Linux/Mac 按 Ctrl+D,Windows 按 Ctrl+Z)
nDigit[10] 擴充為 int freq[256],freq[(unsigned char)c]++ 即可統計所有 ASCII 字元頻率。if (!seen[c]) { seen[c]=1; output(c); },O(n) 時間去重,無需排序。switch 配合狀態變數,可實作簡易詞法分析器(如識別數字、識別字、運算子)。break:導致非預期落入下一 case。char 有號問題:c - '0' 若 char 為 signed 且輸入非 ASCII 可能產生負索引,建議用 int c 接收 getchar() 回傳值,並轉 unsigned char 索引。getchar() 回傳 int,必須用 int c 接收,否則 EOF(通常為 -1)會被截斷導致無限迴圈。此程式雖小,卻展示了 switch 多標籤、字元算術索引、計數陣列三大經典技法,是 C 語言字元處理與統計類問題的範本寫法。