題目要求:讀入一行長度 ≤ 80 的英文句子,單詞間單空格分隔,行尾無多餘空格,輸出單詞順序逆序的句子。本文提供雙數組存儲法與流式 scanf 法兩種實現,並深度分析後者依賴 EOF 行為的編譯器差異問題。
#include#include #define MAX_LEN 80 #define MAX_WORDS 40 // 最多約 40 個單字母單詞 int main() { char words[MAX_WORDS][MAX_LEN + 1]; // 存儲每個單詞 char line[MAX_LEN + 1]; int count = 0; // 讀取整行(含空格) if (fgets(line, sizeof(line), stdin) == NULL) return 0; line[strcspn(line, "\n")] = '\0'; // 移除換行符 // 解析單詞:手動掃描或 sscanf char *token = strtok(line, " "); while (token != NULL && count < MAX_WORDS) { strcpy(words[count++], token); token = strtok(NULL, " "); } // 逆序輸出 for (int i = count - 1; i >= 0; i--) { printf("%s", words[i]); if (i > 0) printf(" "); } printf("\n"); return 0; }
優點:邏輯清晰,不依賴特定輸入結束標記,可處理任意空白分隔(strtok 自動處理多空格),移植性最強。
scanf("%s")` + EOF` 判斷(代碼極簡但有陷阱)#include#define MAX 80 int main() { char s[MAX/2][MAX+1]; // 假設最多 40 個單詞 int cnt = 0; // 關鍵:scanf("%s") 跳過空白,讀取單詞;遇 EOF 返回 EOF while (scanf("%s", s[cnt++]) != EOF); cnt -= 2; // 循環結束時 cnt 多增 1,且最後一次讀失敗不算,實際有效 cnt-1,輸出索引從 cnt-2 開始 while (cnt > 0) { printf("%s ", s[cnt--]); } printf("%s\n", s[0]); // 最後一個單詞不加空格 return 0; }
EOF` 觸發條件差異EOF,scanf 返回 EOF,循環正常結束。EOF,程序會卡在 scanf 等待輸入,需手動輸入 Ctrl+Z + Enter 才能結束,體驗極差。EOF,行為正常。若前序有 scanf("%d", &n) 讀取整數,緩衝區殘留 \n,後續 scanf("%s") 會跳過它(%s 自動跳過空白),通常無影響。但若混用 getchar()/gets() 需手動清理。
代碼固定 s[40][81],若輸入單詞超過 40 個(極短單詞),發生緩衝區溢出。安全做法:動態分配或檢查 cnt < MAX_WORDS。
#include#include void reverse(char *s, int l, int r) { // 反轉 s[l..r] while (l < r) { char t = s[l]; s[l++] = s[r]; s[r--] = t; } } int main() { char line[81]; fgets(line, sizeof(line), stdin); line[strcspn(line, "\n")] = '\0'; int len = strlen(line); // 1. 整體反轉 reverse(line, 0, len - 1); // 2. 各單詞單獨反轉 int start = 0; for (int i = 0; i <= len; i++) { if (line[i] == ' ' || line[i] == '\0') { reverse(line, start, i - 1); start = i + 1; } } puts(line); return 0; }
原理:"Hello World" → "dlroW olleH" → "World Hello"。單次掃描,原地修改,空間最優,無編譯器依賴,推薦作為標準解法。
| 方案 | 空間 | 時間 | 可移植性 | 代碼複雜度 | 推薦場景 |
|---|---|---|---|---|---|
| 雙數組存儲 | O(N) | O(N) | ★★★★★ | 低 | 教學、通用工具、輸入格式複雜 |
| scanf+EOF | O(N) | O(N) | ★★☆☆☆ (依賴文件EOF) | 極低 | OJ 刷題、快速驗證、輸入保證單行文件結束 |
| 原地反轉 | O(1) | O(N) | ★★★★★ | 中 | 嵌入式、大數據流、面試標準答案 |
核心收穫:
scanf("%s") + EOF是 OJ 刷題的「速成技巧」,但不可用於交互式程序或跨平台產品代碼。工程實踐中,請使用fgets讀整行 +strtok/手動解析,或原地反轉算法。理解EOF在文件流 vs 終端流的行為差異,是 C 語言 IO 系統編程的必修課。