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

C語言標準庫字符與字符串輸入函數全解析:fgetc、getc、getchar、gets、fgets 深度對比與避坑指南

     編輯:關於C

五大輸入函數速查表

函數原型源返回值關鍵特性
fgetcint fgetc(FILE *stream)指定流字符值(int) / EOF基礎單字符讀取
getcint getc(FILE *stream)指定流字符值(int) / EOF通常為宏實現,性能略優
getcharint getchar(void)stdin字符值(int) / EOF等價 getc(stdin)
getschar *gets(char *s)stdins / NULL極度危險,C11 已移除
fgetschar *fgets(char *s, int n, FILE *stream)指定流s / NULL安全替代品,可控長度

字符輸入三劍客:緩衝區與換行符陷阱

所有字符輸入函數均為行緩衝:用戶輸入內容存入內核緩衝區,按 Enter 後程序才能讀取。關鍵行為:

  • 讀取字符後,流位置前移 1
  • 換行符 \n 也會被讀取並返回
int main() {
    char ch; int cnt = 0;
    puts("輸入字符 (EOF 結束):");
    while (EOF != (ch = fgetc(stdin))) {
        printf("讀到: '%c' (0x%02X)\n", ch, ch);
        if (++cnt > 5) break;
    }
    printf("共讀 %d 個字符\n", cnt);
}

輸入 aEnterbEntercEnter 實際讀取序列:'a' '\n' 'b' '\n' 'c' '\n' —— 3 個可見字符 + 3 個換行符 = 6 次循環。

字符串輸入:gets 之死與 fgets 之生

gets:緩衝區溢出的元兇

  • 不檢查目標緩衝區大小
  • 遇到 \n 或 EOF 停止,丟棄 \n,末尾加 \0
  • GCC 編譯直接報警:warning: the 'gets' function is dangerous
  • C11 標準已刪除,現代代碼禁用

fgets:安全、可控、標準首選

char buf[100];
if (fgets(buf, sizeof(buf), stdin)) {
    // 成功讀取
    // buf 包含內容 + 可能的 '\n' + 結尾 '\0'
}

行為細節:

  1. 最多讀取 n-1 個字符,留 1 位給 \0
  2. 遇到 \n 會包含在緩衝區中(與 gets 關鍵差異)
  3. 遇到 EOF 或錯誤返回 NULL
  4. 若輸入行超過 n-1,剩餘字符留在流中,下次調用繼續讀取

實戰對比演示

#define BUFSIZ 1024
int main() {
    char buf[BUFSIZ];
    char *p;

    puts("=== gets (僅演示,勿生產使用) ===");
    if (gets(buf)) {
        puts("gets 讀取結果:");
        puts(buf);  // 自動換行
        for (p=buf; *p; p++) putchar(*p);  // 手動輸出,無額外換行
        putchar('\n');
    }

    puts("=== fgets ===");
    if (fgets(buf, BUFSIZ, stdin)) {
        puts("fgets 讀取結果:");
        puts(buf);  // 自動換行,注意:buf 已含 \n,會雙換行
        for (p=buf; *p; p++) putchar(*p);  // 手動輸出,含原始 \n
    }
}

輸入 a bEnter 兩次:

=== gets ===
a b
a b
=== fgets ===
a b

a b
a b

fgets 保留 \n 導致 puts 雙換行,手動遍歷輸出可見原始 \n。

去除 fgets 尾部換行符的標準模式

char *line = fgets(buf, sizeof(buf), stdin);
if (line) {
    size_t len = strlen(line);
    if (len > 0 && line[len-1] == '\n')
        line[len-1] = '\0';  // 移除換行符
    // 處理 line...
}

工程選型決策樹

  1. 需讀取單字符、處理二進制流 → fgetc/getc
  2. 交互式命令行讀取整行文本 → fgets + 去換行
  3. 高性能掃描格式化輸入 → scanf 族(但錯誤恢復困難)
  4. 解析已讀取的行緩衝區 → sscanf/strtok/手動解析
  5. 永遠不使用 gets

常見錯誤與修正

錯誤代碼問題修正
char c; c = getchar();返回值截斷,無法區分 EOFint c; c = getchar();
fgets(buf, 100, stdin); printf("%s", buf);雙換行移除 \n 或用 fputs(buf, stdout)
while (fgets(buf, n, fp)) { ... }最後一行無 \n 也正常處理正確,但需注意行未滿緩衝區時無 \n
gets(buf);緩衝區溢出漏洞替換為 fgets(buf, sizeof(buf), stdin)

掌握輸入函數的緩衝機制、換行符語義、長度邊界,是編寫健壯 C 程序的基礎功。選對工具,敬畏緩衝區,方能行穩致遠。

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