C 語言標準庫提供了豐富的 I/O 函數族,但「靈活」往往伴隨著「危險」。本文系統梳理字符串輸入輸出的主流函數,對比其行為差異,並重點揭示 gets 的安全隱患與現代替代方案。
| 函數 | 原型 | 特點 | 適用場景 |
|---|---|---|---|
puts | int puts(const char *s) | 僅輸出字符串,自動換行,效率高 | 簡單文本輸出 |
printf | int printf(const char *fmt, ...) | 格式化輸出,支持 %s 等轉換符,不自動換行 | 混合類型、格式化報表 |
// puts 自動換行演示
puts("Hello"); // 輸出: Hello\n
puts("World"); // 輸出: World\n
// printf 需手動換行
printf("Hello\n");
printf("World\n");
n-1 字符,遇換行符停止並保留 \n,末尾自動加 \0。char buf[81];
if (fgets(buf, sizeof(buf), stdin)) {
// 移除末尾換行符(若存在)
size_t len = strlen(buf);
if (len > 0 && buf[len-1] == '\n') buf[len-1] = '\0';
printf("輸入: %s\n", buf);
}
scanf("%80s", buf):跳過空白字符,讀取單詞(遇空格/換行停止),不會讀取整行。scanf("%80[^\n]", buf):掃描集,讀取整行(除換行符外),但首次調用前需處理殘留換行符。// 錯誤 char *ptr; gets(ptr); // ptr 野指針,崩潰 // 正確 char buf[256]; fgets(buf, sizeof(buf), stdin);
int n;
scanf("%d", &n); // 輸入 123\n,緩衝區剩 \n
char line[100];
fgets(line, sizeof(line), stdin); // 直接讀到 \n,line 為空串
// 修正:清空輸入緩衝區
int c; while ((c = getchar()) != '\n' && c != EOF);
fgets + 手動去換行。scanf 族,但務必檢查返回值(匹配項數)。fread / fwrite。NULL/EOF,區分 EOF 與讀取錯誤(ferror)。-D_FORTIFY_SOURCE=2、靜態分析工具強制攔截。#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_LINE 256
int main(void) {
char input[MAX_LINE];
puts("請輸入一行文字 (Ctrl+D/EOF 結束):");
while (fgets(input, sizeof(input), stdin)) {
// 去除末尾換行
input[strcspn(input, "\n")] = '\0';
printf("您輸入: %s\n", input);
printf("長度: %zu\n", strlen(input));
puts("--- 請繼續輸入 ---");
}
puts("輸入結束。");
return 0;
}
掌握 C 語言 I/O 的精髓,在於「尊重緩衝區邊界」與「理解流的行為」。拒絕 gets,擁抱 fgets,是寫出健壯 C 代碼的第一步。