首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言 scanf 函數完全指南:格式字串、輸入陷阱與最佳實務

     編輯:關於C語言

函數原型與回傳值

int scanf(const char *format, ...);
  • 從 stdin 讀取格式化輸入。
  • 成功返回成功賦值的項目數;輸入失敗或 EOF 返回 EOF(-1)。
  • 注意:返回值不等於讀取字元數,也不等於格式字串中 % 的個數(被 * 抑制賦值的不計入)。

格式字串三大組成

  1. 格式說明符:以 % 開頭,指定資料型別與轉換方式。
  2. 空白字元:空格、Tab、換行等。作用:跳過輸入流中任意數量的空白字元(含零個)。
  3. 非空白非格式字元:如逗號、等號、字母。作用:精確匹配並消耗輸入流中對應字元,不匹配則掃描停止。

常用格式說明符總表

符號讀取類型對應引數型別備註
%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] 讀整行
%%字面 % 字元無

長度修飾符

修飾符意義適用類型
hhsigned char/unsigned char%hhd, %hhu
hshort/unsigned short%hd, %hu
l (ell)long/unsigned long/double%ld, %lf
lllong long/unsigned long long%lld, %llu
Llong double%Lf

寬度與抑制賦值

  • %10d:最多讀 10 字元作為整數。
  • %*d:讀取整數但不賦值,不計入返回值。用於跳過不需要的欄位。

經典陷阱與解決方案

陷阱 1:忘記取址符 &

int a; scanf("%d", a); // 錯誤!未定義行為
scanf("%d", &a);       // 正確

陣列名本身即位址:char s[10]; scanf("%s", s); 正確。

陷阱 2:%s 遇空白停止

char s[100];
scanf("%s", s); // 輸入 "hello world" → 只讀 "hello"

解法:

  • scanf("%99[^\n]", s); 讀整行(除換行外所有字元)。
  • fgets(s, sizeof(s), stdin); 更安全,保留換行符。

陷阱 3:%c 讀取殘留換行符

int a; char c;
scanf("%d", &a); // 輸入 "123\n"
scanf("%c", &c); // c = '\n' 而非下一個字元

解法:

  • scanf(" %c", &c); 前置空白跳過空白字元。
  • scanf("%*c%c", &c); 抑制讀取一字元。

陷阱 4:格式字串中的字面字元必須精確匹配

scanf("%d,%d", &a, &b); // 必須輸入 "3,4","3, 4" 會失敗(空白不匹配)

建議:格式字串避免字面字元,改用空白字元自動跳過:scanf("%d %d", &a, &b);

陷阱 5:緩衝區溢位

char s[10];
scanf("%s", s); // 輸入超過 9 字元 → 溢位
scanf("%9s", s); // 限制寬度,安全

scanf 返回值的正確判斷

int a, b;
if (scanf("%d %d", &a, &b) == 2) { /* 成功讀取兩個整數 */ }
else if (feof(stdin)) { /* EOF */ }
else { /* 格式錯誤,輸入流停留在錯誤位置 */ }

錯誤時輸入流不前進,需手動清理(如 while (getchar() != '\n');)否則陷入無限迴圈。

現代替代方案

  • fgets + sscanf/strtol/strtod:先讀整行,再解析,錯誤處理更彈性。
  • C++ iostream:型別安全、可擴充、異常處理。
  • 掃描集合 %[...]:%[^\n] 讀行、%[0-9] 讀數字串。

總結

scanf 功能強大但陷阱眾多。關鍵原則:永遠檢查返回值、限制寬度、善用掃描集合、理解空白字元語意、小心緩衝區殘留字元。教學與簡單工具可用;健壯的生產代碼建議改用行讀取 + 解析模式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved