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

深入理解 C 語言 I/O:流、緩衝區、標準庫函數與緩衝區清空

     編輯:關於C

C 語言 I/O 核心機制

流的概念

  • 流是對信息的抽象:輸入流 = 數據源,輸出流 = 數據目的地
  • C 不區分設備類型,統一視為字節流
  • 兩類流:文本流(行導向,以 '\n' 結束)與 二進制流(原始字節序列)
  • UNIX 下不區分兩者

三大標準流

流文件描述符POSIX 宏默認設備緩衝模式
stdin0STDIN_FILENO鍵盤行緩衝
stdout1STDOUT_FILENO終端行緩衝
stderr2STDERR_FILENO終端無緩衝

程序啟動自動打開,正常退出自動關閉並刷新緩衝區。

緩衝區類型與控制

控制函數:

void setbuf(FILE *fp, char *buf);           // buf=NULL 關閉緩衝
int setvbuf(FILE *fp, char *buf, int mode, size_t size);
// mode: _IOFBF(全) _IOLBF(行) _IONBF(無)

核心 I/O 函數族

字符 I/O

int getc(FILE* fp); int fgetc(FILE* fp); int getchar(void);  // 讀
int putc(int c, FILE* fp); int fputc(int c, FILE* fp); int putchar(int c);  // 寫
// getc/putc 可為宏,fgetc/fputc 為函數
// 返回 EOF(-1) 表示錯誤或文件結束,需配合 ferror/feof 區分

行 I/O

char *fgets(char *str, int n, FILE *fp);  // 讀取 n-1 字符或遇 '\n'
int fputs(const char *str, FILE *fp);     // 寫入字符串,不含 '\0'
// 建議棄用 gets()(緩衝區溢出風險)

格式化 I/O

int printf(const char *fmt, ...);
int fprintf(FILE *fp, const char *fmt, ...);
int snprintf(char *buf, size_t n, const char *fmt, ...);  // 安全版本

int scanf(const char *fmt, ...);
int fscanf(FILE *fp, const char *fmt, ...);
int sscanf(const char *buf, const char *fmt, ...);

scanf 抑制賦值用 *,掃描集用 [](如 %[^\n] 讀整行)。

輸入緩衝區清空方案對比

類型觸發條件典型場景
全緩衝緩衝區滿磁盤文件
行緩衝遇到 '\n' 或緩衝區滿終端交互
無緩衝每次調用即執行 I/Ostderr、錯誤日誌
方法代碼可移植性評價
fflush(NULL)fflush(NULL)差僅刷新輸出流,輸入流行為未定義
關閉緩衝setbuf(stdin, NULL)好將 stdin 設為無緩衝,影響性能
循環讀取while((c=getchar())!='\n' && c!=EOF);最好標準 C,完全可移植,推薦
scanf 掃描集scanf("%*[^\n]%*c");中留下 '\n' 需額外處理

printf 實現原理

變參函數,通過 stdarg.h 宏 va_start/va_arg/va_end 遍歷參數列表。簡易模擬:

void simon_printf(char *fmt, ...) {
    va_list ap; va_start(ap, fmt);
    for (char *p=fmt; *p; p++) {
        if (*p != '%') { putchar(*p); continue; }
        switch(*++p) {
            case 'd': printf("%d", va_arg(ap,int)); break;
            case 'f': printf("%f", va_arg(ap,double)); break;
            case 's': for(char*s=va_arg(ap,char*);*s;s++) putchar(*s); break;
        }
    }
    va_end(ap);
}

最佳實踐建議

  • 優先使用 fgets/fputs 處理行輸入輸出
  • 格式化輸出用 snprintf 防止緩衝區溢出
  • 清空輸入緩衝區用循環 getchar() 方案
  • 檢查返回值區分 EOF 與錯誤:ferror(fp) / feof(fp)
  • 關鍵數據寫入後調用 fflush(fp) 確保落盤
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved