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

C 語言 scanf/fscanf 進階格式說明符:%[] 掃描集合與 %n 字元計數完全指南

     編輯:關於C

前言:超越 %s 的輸入掌控力

scanf 族函式的 %[] (掃描集合) 與 %n (字元計數) 是 C89/C99 標準規定、但教科書鮮少提及的進階功能。它們能解決 %s 無法處理的「含空白輸入」、「特定分隔符」、「精確位置追蹤」等問題。

一、%[] 掃描集合 — 定製你的輸入規則

語法

%[*][width][size] [scanset]
// 範例: %[abc]  %[^abc]  %10[^\n]  %*[^;]
  • *:指派抑制 (不儲存結果,只跳過)
  • width:最大讀取字元數 (不含結束 \0)
  • [scanset]:掃描字符集定義

兩種模式

模式語法掃描字符集 (接受的字元)分隔符 (停止讀取的字元)
正向%[abc]a, b, c除 a,b,c 外的所有字元
反向%[^abc]除 a,b,c 外的所有可輸入字元a, b, c

經典用法範例

char buf[100];

// 1. 讀取整行 (含空白),遇換行停止
scanf("%[^\n]", buf);          // 相當於 fgets 但不保留 \n
scanf("%*[^\n]"); scanf("%*c"); // 清除緩衝區剩餘換行符

// 2. 讀取 CSV 欄位:遇逗號停止
scanf("%[^,]", field);  // 讀取到 ',' 為止
scanf("%*c");           // 跳過 ','

// 3. 只接受數字與小數點
scanf("%[0-9.]", num_str);

// 4. 跳過 HTML 標籤內容
fscanf(fp, "%*[^>]>");  // 讀取並丟棄直到 '>'

// 5. 限制長度防緩衝區溢出
scanf("%99[^\n]", buf);  // 最多讀 99 字元

掃描集合特殊字元處理

  • ]:若要包含 ],放在第一個位置 (緊接 [ 或 [^):%[]abc]、%[^]abc]
  • -:表示範圍 (如 a-z);若要包含字面 -,放在第一個、最後一個、或緊接 ^ 後:%-abc]、%[abc-]、%[^-abc]
  • ^:僅在緊接 [ 時表示反向;其他位置視為字面字元

二、%n 字元計數 — 追蹤已讀取/輸出字元數

特性

  • 對應參數:int * (指向整數的指標)
  • 不消耗輸入,只記錄「目前為止已成功讀取/輸出的字元數」
  • 不影響函式回傳值 (scanf 回傳成功指派的項目數,printf 回傳輸出總字元數)
  • 可用於 scanf、printf、fscanf、fprintf 等

scanf 範例

int i, j, k;
scanf("%d %d%n", &i, &j, &k);
// 輸入: "434 6434"
// i=434, j=6434, k=8 (含空白共 8 字元: '4','3','4',' ','6','4','3','4')
// scanf 回傳 2 (成功指派 2 個 %d)

char ch;
int pos;
scanf("%c%n", &ch, &pos);
// 輸入: "sbcdefg"
// ch='s', pos=1 (只讀 1 字元), 非 7!

printf 範例

int i = 343, j = 123, k;
printf("i=%d, j=%d%n", i, j, &k);
// 輸出: "i=343, j=123" (12 字元)
// k = 12
// printf 回傳 12 (不含 %n 計數)

三、實戰組合:解析固定格式文字

// 解析: "key=value;" 格式
char key[50], val[100];
int n;
while (fscanf(fp, "%49[^=]=%99[^;];%n", key, val, &n) == 2) {
    printf("Key: %s, Value: %s (讀取 %d 字元)\n", key, val, n);
    // 繼續下一組
}

四、常見陷阱與注意事項

陷阱說明對策
%[] 不跳過前導空白%s/%d 會自動跳過空白,%[] 不會格式字串前加空白: " %[^\n]"
緩衝區溢出未指定 width 時,輸入過長會溢出永遠加 width: %99[^\n]
%n 不計入回傳值scanf 回傳不包含 %n 的指派數預期回傳值 = 格式說明符數 - %n 數
%[] 遇 EOF 行為若未讀到任何符合字元即遇 EOF,指派失敗檢查回傳值 == 項目數
掃描集合中的 - 歧義部分編譯器將中間 - 視為範圍,部分視為字面明確放在首尾或跳脫: %-az] 或 %[a-z-]

五、%[] vs %s vs fgets 對比

功能%s%[^\n]fgets
讀取空白❌ 停止✅ 讀取✅ 讀取
保留換行符❌❌✅
指定最大長度%99s%99[^\n]fgets(buf, 100, fp)
自訂分隔符❌ 固定空白✅ 任意字元集❌ 固定 \n/EOF
安全性需加 width需加 width✅ 內建長度限制
推薦場景單詞讀取整行/自訂分隔通用整行讀取 (最安全)

總結

  • %[]:輸入解析的瑞士刀,支援自訂接受字元集、分隔符、長度限制,解決 %s 無法讀空白、fgets 無法自訂分隔符的痛點。
  • %n:無副作用的位置追蹤器,適用於解析器實作、格式驗證、進度顯示。
  • 兩者結合,可構建健壯的文字協定解析器 (CSV、INI、簡易 JSON、Log 格式等)。
  • **永遠指定 width**,檢查回傳值,搭配 fgets/sscanf 組合使用更安全。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved