int scanf(const char *format, ...);
stdin 讀取格式化輸入。EOF(-1)。% 的個數(被 * 抑制賦值的不計入)。% 開頭,指定資料型別與轉換方式。| 符號 | 讀取類型 | 對應引數型別 | 備註 |
|---|---|---|---|
%d, %i | 有號十進制整數 | int * | %i 另支援 0x/0 開頭的十六/八進制 |
%u | 無號十進制整數 | unsigned int * | |
%o, %x, %X | 八/十六進制整數 | unsigned int * | |
%f, %e, %g | 浮點數 | float * | |
%lf, %le, %lg | 雙精度浮點數 | double * | scanf 必須用 %lf,printf 用 %f 即可 |
%c | 單一字元(含空白) | char * | 不跳過空白,需配合 %*c 或前置空白 |
%s | 字串(以空白結束) | char * | 自動加 '\0',需預留足夠緩衝區 |
%p | 指標位址 | void ** | 實作定義格式 |
%n | 已讀字元數 | int * | 不消耗輸入 |
%[...] | 掃描集合 | char * | 如 %[^\\n] 讀整行 |
%% | 字面 % 字元 | 無 |
| 修飾符 | 意義 | 適用類型 |
|---|---|---|
hh | signed char/unsigned char | %hhd, %hhu |
h | short/unsigned short | %hd, %hu |
l (ell) | long/unsigned long/double | %ld, %lf |
ll | long long/unsigned long long | %lld, %llu |
L | long double | %Lf |
%10d:最多讀 10 字元作為整數。%*d:讀取整數但不賦值,不計入返回值。用於跳過不需要的欄位。int a; scanf("%d", a); // 錯誤!未定義行為
scanf("%d", &a); // 正確
陣列名本身即位址:char s[10]; scanf("%s", s); 正確。
char s[100];
scanf("%s", s); // 輸入 "hello world" → 只讀 "hello"
解法:
scanf("%99[^\n]", s); 讀整行(除換行外所有字元)。fgets(s, sizeof(s), stdin); 更安全,保留換行符。int a; char c;
scanf("%d", &a); // 輸入 "123\n"
scanf("%c", &c); // c = '\n' 而非下一個字元
解法:
scanf(" %c", &c); 前置空白跳過空白字元。scanf("%*c%c", &c); 抑制讀取一字元。scanf("%d,%d", &a, &b); // 必須輸入 "3,4","3, 4" 會失敗(空白不匹配)
建議:格式字串避免字面字元,改用空白字元自動跳過:scanf("%d %d", &a, &b);
char s[10];
scanf("%s", s); // 輸入超過 9 字元 → 溢位
scanf("%9s", s); // 限制寬度,安全
int a, b;
if (scanf("%d %d", &a, &b) == 2) { /* 成功讀取兩個整數 */ }
else if (feof(stdin)) { /* EOF */ }
else { /* 格式錯誤,輸入流停留在錯誤位置 */ }
錯誤時輸入流不前進,需手動清理(如 while (getchar() != '\n');)否則陷入無限迴圈。
%[^\n] 讀行、%[0-9] 讀數字串。scanf 功能強大但陷阱眾多。關鍵原則:永遠檢查返回值、限制寬度、善用掃描集合、理解空白字元語意、小心緩衝區殘留字元。教學與簡單工具可用;健壯的生產代碼建議改用行讀取 + 解析模式。