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

C語言 gets/scanf 混用導致輸入跳過:緩衝區殘留換行符完整解決方案

     編輯:C 語言問答

現象


gets(st[i].name);          // 第 1 圈:讀到空行 (上一個 scanf 留下的 \n)
scanf("%d,%d,%d,%d", ...); // 後續正常

根本原因

  • scanf("%d", &x) 讀完整數,**停在換行符前**,換行符留在 stdin 緩衝區。
  • gets(str) **讀取並丟棄換行符**,遇到換行符即返回空字串。
  • 結果:第一次 gets 讀到空行,姓名輸入被跳過。

三種解決方案

改寫後的完整程式碼


#include 
#include 

struct student {
    char name[20];
    int no, score1, score2, score3;
} st[2];

int main() {
    int i, ave[2];
    char line[100];
    printf("請輸入姓名、學號、三科成績 (逗號分隔):\n");
    for (i = 0; i < 2; i++) {
        // 讀姓名 (整行)
        printf("姓名: ");
        fgets(st[i].name, sizeof(st[i].name), stdin);
        st[i].name[strcspn(st[i].name, "\n")] = '\0'; // 去換行

        // 讀數字行
        printf("學號,成績1,成績2,成績3: ");
        fgets(line, sizeof(line), stdin);
        sscanf(line, "%d,%d,%d,%d", &st[i].no, &st[i].score1, &st[i].score2, &st[i].score3);

        ave[i] = (st[i].score1 + st[i].score2 + st[i].score3) / 3;
    }
    for (i = 0; i < 2; i++)
        printf("%s: 平均=%d\n", st[i].name, ave[i]);
    return 0;
}

鐵律

永遠不要混用 scanf 和 gets/fgets。 選定一種輸入風格:
① 全用 fgets + sscanf/strtol (最安全、教學推薦)。
② 全用 scanf 族,處理換行靠 %*c 或空格跳過 (需極熟悉掃描集)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方案程式碼優缺點
1. 統一用 fgets + sscanf (推薦)
char line[100];
fgets(line, sizeof(line), stdin);
sscanf(line, "%d,%d,%d,%d", &a, &b, &c, &d);
徹底避免緩衝區殘留,行導向解析最直觀
2. scanf 後吃掉換行
scanf("%d", &x);
getchar(); // 或 scanf("%*c"); 吃掉一個字元 (含 \n)
簡單但脆弱:若輸入有空格、多字元會遺漏
3. scanf 格式字串加空格
scanf(" %s", name); // %s 前加空格:跳過所有空白 (含 \n)
僅適用 %s、%c 等跳過空白的轉換規格,**不適用 gets**