一個健壯的控制台菜單需要:清晰的選項展示、輸入驗證與清理、功能分發、可複用的工具函數。本文提供一個完整、可直接編譯運行的範例,涵蓋字符選項、整數輸入、緩衝區清理等實戰細節。
#include
#include
#include
// 前向聲明
char get_choice(void);
char get_first(void);
int get_int(void);
void count(void);
int main(void) {
int choice;
while ((choice = get_choice()) != 'q') {
switch (choice) {
case 'a': printf("Buy low, sell high\n"); break;
case 'b': putchar('\a'); break; // 蜂鳴
case 'c': count(); break;
default: printf("Invalid option\n");
}
}
puts("Bye.");
return 0;
}
// 顯示菜單並獲取有效選項
char get_choice(void) {
char ch;
puts("Enter the letter of your choice:");
puts("a. advice b. bell");
puts("c. count d. quit");
ch = get_first();
while ((ch < 'a' || ch > 'c') && ch != 'q') {
puts("Please respond with a, b, c, or q");
ch = get_first();
}
return ch;
}
// 讀取首個非空白字符,丟棄行尾剩餘
char get_first(void) {
int ch = getchar();
while (isspace(ch)) ch = getchar(); // 跳過換行/空格
while (getchar() != '\n') continue; // 清空本行其餘
return (char)ch;
}
// 讀取並驗證整數
int get_int(void) {
int input;
char ch;
while (scanf("%d", &input) != 1) {
while ((ch = getchar()) != '\n') putchar(ch); // 回顯非法輸入
puts(" is not an integer.\nPlease enter an integer value, such as 25, -178, or 3:");
}
return input;
}
// 功能 c:計數演示
void count(void) {
int n, i;
puts("Count how far? Enter an integer:");
n = get_int();
for (i = 1; i <= n; ++i) printf("%d\n", i);
while (getchar() != '\n') continue; // 清理殘留換行
}
| 函數 | 職責 | 健壯性細節 |
|---|---|---|
get_first | 獲取首個可見字符 | isspace 跳過空白;循環清空至 \n,防殘留汙染下次輸入 |
get_int | 讀取合法整數 | scanf 返回值檢查;非法輸入回顯並提示重輸;消耗整行 |
get_choice | 菜單交互 | 白名單驗證 a/b/c/q;錯誤友好提示 |
count | 業務邏輯 | 調用 get_int 復用驗證邏輯 |
// 模式 1:清空至換行 (最常用)
while (getchar() != '\n') continue;
// 模式 2:清空至 EOF 或換行 (更安全)
int c; while ((c = getchar()) != '\n' && c != EOF) {}
// 模式 3:scanf 後單字符殘留
scanf("%d", &n); getchar(); // 僅吃掉一個 \n,若用戶輸入 "123 abc" 會殘留 " abc"
建議:統一使用「讀取目標數據 → 循環清空至換行」模式。
get_choice 返回枚舉,主循環遞歸調用子菜單函數。\033[2J)、移動光標、顏色高亮。SIGINT(Ctrl+C) 優雅退出而非強制中斷。控制台菜單看似簡單,輸入驗證、緩衝區清理、錯誤提示 才是決定用戶體驗與程序穩健度的關鍵。將這些通用邏輯封裝為 get_first/get_int/get_choice 等工具函數,業務代碼即可專注於核心邏輯,實現關注點分離與代碼復用。