首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C 語言新手代碼審查實戰:統計字母頻率 - 從「能跑」到「工程級」

     編輯:關於C

原始題目

輸入 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;
}

關鍵改進點解析

  1. 常數定義:MAX_LEN, STR_FMT 集中維護,修改一處生效。
  2. 防溢位掃描:scanf("%1009s", s) 限制讀取長度。
  3. 單次遍歷:for (; *s; ++s) 同時檢查結束與處理字符,無 strlen 開銷。
  4. 職責分離:count_freq 只統計,most_frequent 只找最大,可獨立測試、複用。
  5. 語義命名:freq, best, most_frequent 即文檔。
  6. 輸入驗證:檢查 T 範圍、scanf 返回值。
  7. 標準庫善用: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 刷題到生產環境開發皆受用無窮。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved