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

C語言輸入緩衝區殘留換行符導致gets讀取異常的解決方案

     編輯:C 語言問答

問題現象

在解決 ACM 題目「統計字符串中數字個數」時,代碼邏輯看似正確,但運行結果錯誤。核心代碼片段如下:

int n;
char c[100];
scanf("%d", &n);
while(n--) {
    gets(c); // 此處直接調用 gets
    // ... 統計邏輯
}

輸入測試數據:

2
abc123
def456

預期輸出:3 和 3,實際首行輸出為 0。

根因分析:scanf 留下的「隱形殺手」

scanf("%d", &n) 讀取整數 2 後,**緩衝區中殘留換行符 \n**。隨後 gets(c) 讀取該換行符並認為輸入結束,導致第一組字符串實際為空串,統計結果自然為 0。第二次循環才真正讀取到 abc123。

三種修復方案對比

方案代碼示例優點缺點/注意
方案一:消耗換行符 (推薦新手)
scanf("%d", &n);
getchar(); // 吞掉緩衝區中殘留的 \n
while(n--) { gets(c); ... }
簡單直觀,無需修改後續邏輯 若輸入格式不規範 (如輸入 2 abc) 可能吞掉有效字符
方案二:scanf 格式字符串匹配空白符
scanf("%d\n", &n); // 或 scanf("%d%*c", &n);
while(n--) { gets(c); ... }
緊湊,標準庫行為 \n 只匹配單個換行;%*c 吞掉任意單字符,若無殘留會阻塞等待輸入
方案三:全面棄用 gets,改用 fgets (最佳實踐)
fgets(c, sizeof(c), stdin);
// 移除 fgets 保留的尾隨 \n
c[strcspn(c, "\n")] = '\0';
安全、可控制長度、無緩衝區溢出風險,C11 標準已移除 gets 需手動處理尾部換行符,稍顯繁瑣

進階:健壯的輸入處理模板

針對競賽/工程場景,建議封裝通用讀行函數:

// 安全讀取一行,自動去除尾部 \n,返回實際長度
int read_line(char *buf, int maxlen) {
    if (!fgets(buf, maxlen, stdin)) return -1; // EOF 或錯誤
    int len = strlen(buf);
    if (len > 0 && buf[len-1] == '\n') buf[--len] = '\0';
    // 若行過長導致未讀完 \n,清空殘留緩衝區
    if (len == maxlen - 1 && buf[maxlen-2] != '\n') {
        int ch;
        while ((ch = getchar()) != '\n' && ch != EOF);
    }
    return len;
}

// 主程式調用
int n; char line[1024];
scanf("%d", &n); getchar(); // 簡單場景足夠
while(n--) {
    read_line(line, sizeof(line));
    // 統計數字...
}

總結

C 語言標準輸入流 stdin 為**全緩衝/行緩衝**,scanf 系列不消耗分隔符 (空白、換行),gets/fgets 以換行符為邊界。**混用兩類函數必須顯式處理殘留換行符**。現代 C 開發強制棄用 gets,統一使用 fgets + 手動去換行,是杜絕此類低級錯誤的根本之道。

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