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

C語言格式輸入函數scanf()完整指南

     編輯:關於C語言

scanf() 是 C 語言標準庫中最核心的格式化輸入函數,雖然用法看似簡單,但其格式字串細節、地址傳遞機制、輸入緩衝區特性、錯誤處理機制等深層機制,是無數初學者甚至資深開發者頻繁踩坑的重災區。本文將從原理、語法、陷阱、最佳實踐四個維度,徹底講透 scanf()。

核心原理:地址傳遞與內存模型

scanf() 的本質是「向變量所在內存地址寫入數據」。這與賦值語句 a = 5(直接操作變量名)有本質區別:

操作語法本質左值要求
賦值語句a = 5;編譯器知道 a 的地址,直接寫入變量名
scanf 輸入scanf("%d", &a);程式員必須顯式提供地址 &a地址表達式

& 是取地址運算符,&a 是一個表達式,其值為變量 a 在內存中的起始地址。

函數原型與基本語法

int scanf(const char *format, ...);
// 返回值:成功讀取的項目數;EOF 表示輸入失敗/結束

一般形式:

scanf("格式控制字串", 地址表列);
  • 格式控制字串:只能包含格式符(如 %d),不能包含提示文字(這點與 printf 不同)
  • 地址表列:每個變量前必須加 &(字符數組/指針除外)

格式字串完整語法

%[*][寬度][長度]類型

1. 類型格式符對照表

2. 修飾符詳細說明

格式符對應類型說明
%dint *十進制整數
%ldlong *長整數
%lldlong long *長長整數 (C99)
%f/%lffloat */double *浮點數(scanf 必須區分 %f/%lf)
%cchar *單個字符(含空白字符)
%schar *字符串(遇空白結束)
%o/%xunsigned *八/十六進制整數
%uunsigned *無符號十進制

經典範例與陷阱深度解析

範例 1:基本整數輸入

  1. int main(){
  2. int a,b,c;
  3. printf("input a,b,c\n");
  4. scanf("%d%d%d",&a,&b,&c);
  5. printf("a=%d,b=%d,c=%d",a,b,c);
  6. }

關鍵點:

  • 格式串 "%d%d%d" 無分隔符 → 輸入時需用空格、Tab、換行分隔
  • 輸入 7 8 9 或 7\n8\n9 均可
  • 缺少 & 會導致未定義行為(崩潰或寫錯內存)

範例 2:跳過輸入項 (* 修飾符)

scanf("%d %*d %d", &a, &b);
// 輸入: 1 2 3
// 結果: a=1, 2 被跳過, b=3

範例 3:寬度限制

scanf("%5d", &a);
// 輸入: 12345678
// 結果: a=12345, "678" 留在緩衝區

scanf("%4d%4d", &a, &b);
// 輸入: 12345678
// 結果: a=1234, b=5678

範例 4:字符輸入的空白字符陷阱 ⚠️

  1. scanf("%c%c%c", &a, &b, &c);
  • 輸入 d e f(含空格)→ a='d', b=' ', c='e' 空格被讀入!
  • 輸入 def(無空格)→ a='d', b='e', c='f' ✓
  • 解決:scanf(" %c %c %c", ...) 格式串加空格跳過空白字符

範例 5:非格式字符作分隔符

scanf("%d,%d,%d", &a, &b, &c);
// 必須輸入: 5,6,7  (逗號必須匹配)

scanf("a=%d,b=%d,c=%d", &a, &b, &c);
// 必須輸入: a=5,b=6,c=7

範例 6:類型不匹配的災難

  1. int a;
  2. scanf("%d", &a);
  3. printf("%ld", a); // 錯誤!%ld 期望 long,實傳 int

後果:讀取錯誤位數、輸出亂碼、棧平衡破壞。格式符必須與變量類型嚴格匹配。

scanf() 核心機制:輸入緩衝區與掃描規則

掃描終止條件

對數值類型(%d, %f 等),遇以下任一情況結束當前項掃描:

  1. 空白字符(空格、Tab、換行)
  2. 非法字符(如 %d 遇到 'A')
  3. 達到寬度限制

字符類型(%c, %[...])不跳過空白字符,除非格式串顯式包含空白。

緩衝區殘留問題經典案例

int x; char c;
scanf("%d", &x);  // 輸入 "123\n",'\n' 留在緩衝區
scanf("%c", &c);  // 直接讀到 '\n',c = '\n'!

解決方案:

  • scanf(" %c", &c); 格式串前加空格跳過空白
  • getchar(); 讀走殘留換行符
  • 改用 fgets() + sscanf() 整行讀取解析(推薦)

返回值檢查:健壯程式的生命線

int count = scanf("%d %d", &a, &b);
if (count != 2) {
    // 處理輸入錯誤:非數字、EOF、格式不匹配
    // 清理緩衝區:while(getchar() != '\n');
}

返回值含義:

  • >=0:成功匹配並賦值的項目數
  • EOF(通常 -1):輸入流結束或讀取錯誤,無任何賦值發生

現代替代方案:fgets() + sscanf()

為避免緩衝區殘留、格式錯誤難處理等問題,生產代碼推薦:

  1. char line[256];
  2. if (fgets(line, sizeof(line), stdin)) {
  3. if (sscanf(line, "%d %d", &a, &b) == 2) {
  4. // 成功
  5. }
  6. }

優勢:整行讀取、緩衝區隔離、錯誤恢復容易、支援行編輯。

總結:scanf() 避坑速查表

修飾符位置作用範例
*% 後抑制賦值:讀取但不存儲,跳過該輸入%*d 跳過一個整數
寬度* 後最大讀取字符數%5d 最多讀 5 位數字
h類型前short 整數%hd
l類型前long 整數 / double 浮點數%ld, %lf
ll類型前long long (C99)%lld
L類型前long double%Lf
陷阱症狀解決
漏寫 &崩潰/亂碼所有非數組/指針變量必加 &
%f/%lf 混用浮點數讀錯float 用 %f,double 用 %lf
%c 讀到空白字符錯位格式串加空格 " %c" 或用 fgets
緩衝區殘留換行下次 %c 讀空加空格/讀走/改用 fgets+sscanf
不檢查返回值錯誤輸入導致變量未初始化必檢查返回值 == 預期項目數
輸入格式不匹配掃描卡住/停止格式串匹配預期輸入格式

結語

scanf() 是 C 語言輸入的基石,其地址傳遞語義、格式掃描機制、緩衝區特性構成了完整的輸入模型。掌握其精髓,不僅能避開無數坑,更能深入理解 C 語言「內存、地址、指針」的核心哲學。生產環境建議採用 fgets() + sscanf() 組合,將輸入解析與緩衝管理分離,構建更健壯的輸入系統。

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