非格式化 I/O 函數不處理格式字串,僅傳輸字元或字串。編譯後代碼體積小、執行速度快、介面簡單,是嵌入式、教學、簡易工具的首選。
puts / getsputs — 輸出字串並自動換行
int puts(const char *s);
// 等價於 printf("%s\n", s) 但更快、無格式解析開銷
// 僅能輸出字串,不可輸出數值或格式化
範例:
char s[20] = "Hello Turbo C";
char *p = "Thank you";
puts(s); // 輸出 s 內容 + 換行
puts(p); // 輸出字串常數 + 換行
puts("Direct"); // 直接輸出字面值
gets — 讀取整行字串(含空白)
char *gets(char *s);
// 從 stdin 讀取直到 '\n' (不包含 '\n') 或 EOF
// 返回 s,失敗返回 NULL
關鍵差異:scanf("%s", s) 遇空白停止;gets(s) 讀取整行(含空白),直到 Enter。
範例:
char name[30], ageStr[10];
printf("What's your name? ");
gets(name); // 可輸入 "John Smith"
printf("How old? ");
gets(ageStr); // 讀取 "25"
puts(name);
puts(ageStr);
gets 嚴重安全漏洞gets,現代編譯器編譯時警告fgets(s, sizeof(s), stdin) — 指定最大讀取長度,保留 \n 需自行移除getchar / putchar
int getchar(void); // 等價 fgetc(stdin)
int putchar(int c); // 等價 fputc(c, stdout)
返回 int 而非 char,以容納 EOF (-1)。
int ch, letters=0, digits=0, spaces=0, others=0;
while ((ch = getchar()) != EOF) {
if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') ++letters;
else if (ch >= '0' && ch <= '9') ++digits;
else if (ch == ' ' || ch == '\t' || ch == '\n') ++spaces;
else ++others;
}
printf("Letters:%d Digits:%d Spaces:%d Others:%d\n", letters, digits, spaces, others);
gets/puts vs scanf/printf 完整對比| 維度 | gets/puts | scanf/printf |
|---|---|---|
| 格式化 | 無 | 完整格式化支援 |
| 空白處理 | gets 讀取整行含空白 | %s 遇空白停止 |
| 換行處理 | puts 自動加 \n,gets 丟棄 \n | 手動控制 |
| 型別安全 | 僅字串 | 支援所有型別 |
| 緩衝區安全 | gets 不安全 | scanf 寬度限定較安全 |
| 效能 | 極快 (無解析) | 較慢 (格式解析) |
| 代碼體積 | 極小 | 較大 |
puts/getchar/putchargets,改用 fgets;scanf 輸入字串時必須加寬度 %19sputs/fputs,避免 printf 格式解析開銷getchar 單字元讀取無需 Enter (配合 getch 非回顯)非格式化 I/O 以極簡介面提供高效能字元/字串傳輸。理解 gets 讀取整行特性、puts 自動換行特性、getchar/putchar 字元級控制,並堅決棄用 gets 改用 fgets,是寫出安全、高效 C 程式的基本功。