printf 與 scanf 是 C 語言最核心的 I/O 函數,定義於 <stdio.h>。本文系統整理兩者的格式控制、修飾符、返回值、常見陷阱與最佳實踐,並附贈標準庫 15 個頭檔能力分級表。
| 級別 | 頭檔 | 核心功能 |
|---|---|---|
| 合格 | <stdio.h> | 標準輸入輸出 |
<ctype.h> | 字符測試/轉換 | |
<stdlib.h> | 工具函數/記憶體/轉換 | |
<string.h> | 字符串操作 | |
| 熟練 | <assert.h> | 斷言 |
<limits.h> | 型別極限值 | |
<stddef.h> | 通用定義 | |
<time.h> | 時間/日期 | |
| 優秀 | <float.h> | 浮點特性 |
<math.h> | 數學函數 | |
<errno.h> | 錯誤碼 | |
<locale.h> | 本地化 | |
<setjmp.h> | 非局部跳轉 | |
<signal.h> | 信號處理 | |
<stdarg.h> | 可變參數 |
int printf(const char *format, ...);
返回值:輸出字符數,錯誤返回負值。
% 開頭,指定輸出格式| 符號 | 輸出 | 備註 |
|---|---|---|
| %d | 有符號十進制整數 | |
| %f | 浮點數(預設 6 位小數) | 不能輸出整型 |
| %c | 單字符 | |
| %s | 字符串 | 至 \0 |
| %o | 八進制 | |
| %x | 十六進制 | 小寫 |
| %p | 指標地址 | |
| %ld | long 整數 | 非 double |
| %u | 無符號整數 |
float f1 = 3.1415926f;
printf("%f\n", f1); // 3.141593 (預設6位,四捨五入)
printf("%.7f\n", f1); // 3.1415925 (強制7位)
float a = 1111.111111f, b = 2222.22222f;
printf("%f\n", a+b); // 3333.333252 (float 有效位數~7位,後續無效)
// 解決:使用 double
double d1 = 3.141592653589793;
printf("%.15f\n", d1); // 15 位有效數字
規則:float ~7 位有效數字,double ~15 位。printf 將 float 自動提升為 double,但精度已在賦值時丟失。
| 格式 | 效果 | 範例輸出 |
|---|---|---|
| %5d | 寬度 5,右對齊補空格 | " 10" |
| %-5d | 寬度 5,左對齊 | "10 " |
| %05d | 寬度 5,前導 0 | "00010" |
| %+d | 正數顯示 + | "+10" |
| % d | 正數前加空格 | " 10" |
printf("\\\n"); // 輸出: \
printf("%%\n"); // 輸出: %
printf("\"\n"); // 輸出: "
printf("\tTab\n"); // 輸出: Tab (製表符)
int scanf(const char *format, ...);
返回值:成功匹配賦值的項目數,EOF 表示輸入結束。
%d、%f 等自動跳過前導空格/換行/Tab%c **不跳過**空白:需用 " %c" (前加空格) 跳過| 錯誤輸入 | 現象 | 對策 |
|---|---|---|
12,45 (逗號分隔) | scanf("%d,%d", &a, &b) 需原樣輸入逗號 | 格式字串含逗號,或用空格分隔 |
12 a 45 (混合空格) | %d,%c,%d 讀取異常 | 嚴格按格式輸入 |
非數字輸入 abc | 匹配失敗,變數不變,字符留在緩衝區 | 檢查返回值,清理緩衝區 |
int a, b;
scanf("%d%*d%d", &a, &b); // 輸入: 1990 11 20
// %*d 跳過中間 11
// a=1990, b=20
scanf 按格式從緩衝區提取scanf 繼續從殘留處讀取// 清理殘留換行/無效字符 int c; while ((c = getchar()) != '\n' && c != EOF);
| 特性 | printf | scanf |
|---|---|---|
| 方向 | 輸出 | 輸入 |
| 引數 | 值/變數 | **地址** (&var) |
| 返回值 | 輸出字符數 | 賦值項目數 |
| %f 精度 | 預設 6 位 | 讀取 float/double |
| %c 空白 | 輸出空格 | **讀取空白**,需 " %c" |
| 緩衝區 | 行緩衝/全緩衝 | 系統輸入緩衝區 |
「掌握 I/O 細節,是從『能跑通』到『寫得穩』的關鍵一步。」

程式設計如人生,在無紅綠燈的十字路口,選擇太多反而無所適從。但請記得:寫下第一行正確的代碼,就是最好的開始。