輸入 T 組字串(僅小寫字母),每組輸出出現次數最多的字母;若有多個同為最大,輸出字典序最小者。
#include
#include
int maxchar(char x[1010]) {
int i,j,temp,max;
int a[26]={0};
for (i = 0,temp =0;i
| 類別 | 問題 | 影響 |
|---|---|---|
| 緩衝區安全 | scanf("%s",s) 無長度限制 | 溢位風險 |
| 效能 | 迴圈中重複呼叫 strlen(x) | O(n²) → 應為 O(n) |
| 魔術數字 | 97, 26, 1010 硬編碼 | 可讀性差、難維護 |
| 函數簽名 | char x[1010] 陣列大小被忽略,誤導 | 應用 char * |
| 輸入驗證 | 未檢查 T 範圍、字串合法性 | 非預期輸入導致 UB |
| 結構 | 統計與尋找最大混在一個函數 | 單一職責原則違背 |
| 變數命名 | temp, max, j 語義不清 | 可讀性低 |
// letter_freq.c
#include
#include
#define MAX_LEN 1009
#define STR_FMT "%1009s" // 防溢位
// 統計字母頻率
void count_freq(int freq[26], const char *s) {
for (; *s; ++s) {
if (islower(*s)) freq[*s - 'a']++;
}
}
// 找最大頻率字母(同頻取字典序最小)
char most_frequent(const int freq[26]) {
int best = 0;
for (int i = 1; i < 26; ++i)
if (freq[i] > freq[best]) best = i;
return 'a' + best;
}
int main(void) {
int T;
if (scanf("%d", &T) != 1) return 1;
if (!(0 < T && T < 25)) return 1; // 輸入驗證
while (T--) {
char s[MAX_LEN + 1];
if (scanf(STR_FMT, s) != 1) break;
int freq[26] = {0};
count_freq(freq, s);
putchar(most_frequent(freq));
putchar('\n');
}
return 0;
}
MAX_LEN, STR_FMT 集中維護,修改一處生效。scanf("%1009s", s) 限制讀取長度。for (; *s; ++s) 同時檢查結束與處理字符,無 strlen 開銷。count_freq 只統計,most_frequent 只找最大,可獨立測試、複用。freq, best, most_frequent 即文檔。T 範圍、scanf 返回值。islower 替代手寫範圍檢查,區域設定安全。若題目移除長度限制,改用動態記憶體:
char *read_line(void) {
size_t cap = 128, len = 0;
char *buf = malloc(cap);
int ch;
while ((ch = getchar()) != EOF && ch != '\n') {
if (len + 1 >= cap) {
cap *= 2;
buf = realloc(buf, cap);
}
buf[len++] = ch;
}
buf[len] = '\0';
return buf; // 呼叫者負責 free
}
「能跑」只是起點。工程級代碼要求:安全(防溢位)、高效(避免重複計算)、可讀(語義命名、單一職責)、可維護(常數集中、錯誤處理)、可測試(函數解耦)。養成這些習慣,從 ACM 刷題到生產環境開發皆受用無窮。