| 類型 | 觸發條件 | 典型場景 |
| 全緩衝 | 緩衝區滿 | 磁盤文件 |
| 行緩衝 | 遇到 '\n' 或緩衝區滿 | 終端交互 |
| 無緩衝 | 每次調用即執行 I/O | stderr、錯誤日誌 |
控制函數:
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] 讀整行)。
輸入緩衝區清空方案對比
| 方法 | 代碼 | 可移植性 | 評價 |
| 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) 確保落盤
- 上一篇文章: C 語言結構體完整指南:定義、初始化、指針、嵌套與內存對齊
- 下一篇文章: C 語言每日小練:蛇形矩陣填充算法實現
Copyright ©
程式碼之家 All Rights Reserved