c 程式設計/stdio.h/scanf
| 此頁面可能需要 驗證事實 並引用可靠的出版物。 您可以透過新增對可靠出版物的引用或 更正被引用為事實的陳述 來提供幫助。 |
scanf 是一個 函式,它從給定的字串流源中讀取指定格式的資料,起源於 C 程式語言,並且存在於許多其他程式語言中。
scanf 函式原型是
int scanf(const char *format, ...);
該函式返回成功匹配的專案總數,這可能少於請求的專案數。如果輸入流耗盡或在任何專案匹配之前從該流中讀取失敗,則返回 EOF。
就可追溯性而言,“scanf” 代表“掃描格式”,因為它掃描輸入以查詢有效令牌並根據指定的格式解析它們。
scanf 函式存在於 C 中,它從 標準輸入(通常是 命令列介面 或類似的 文字使用者介面)讀取數字和其他 資料型別 的輸入。
以下展示了 C 中的程式碼,該程式碼從標準輸入中讀取可變數量的無格式十進位制 整數,並在單獨的行上打印出每個整數
#include <stdio.h>
int
main(void)
{
int n;
while (scanf("%d", & n))
printf("%d\n", n);
return 0;
}
在由上面的程式處理後,一組雜亂的整數,例如
456 123 789 456 12
456 1
2378
將整齊地顯示為
456 123 789 456 12 456 1 2378
列印一個單詞
#include <stdio.h>
int
main(void)
{
char word[20];
if(scanf("%19s", word) == 1)
puts(word);
return 0;
}
無論程式設計師希望程式讀取什麼資料型別,引數(如上面的 &n)都必須是 指標,指向記憶體。否則,該函式將無法正常執行,因為它將嘗試覆蓋錯誤的記憶體區域,而不是指向您試圖獲取輸入的變數的記憶體位置。
由於 scanf 被指定為僅從標準輸入讀取,因此許多具有 介面 的程式語言,例如 PHP,有派生函式,如 sscanf 和 fscanf,但沒有 scanf 本身。
根據輸入的實際來源,程式設計師可以使用 scanf 的不同派生函式。兩個常見的例子是 sscanf 和 fscanf。
fscanf 派生函式從指定的 檔案流 讀取輸入。原型如下
int fscanf (FILE *file, const char *format, ...);
(PHP)
mixed fscanf (resource file, const string format [, mixed args...])
fscanf 派生函式的工作方式與原始的 scanf 函式類似 - 一旦讀取了輸入的一部分,就不會再次讀取,直到該檔案被關閉並重新開啟。
sscanf 派生函式從作為第一個引數傳遞的字元字串中讀取輸入。與 fscanf 的一個重要區別是,每次呼叫該函式時,都會從字串的開頭讀取。沒有在成功讀取操作後遞增的“指標”。原型如下
int sscanf (const char *str, const char *format, ...);
(PHP)
mixed sscanf (const string str, const string format [, mixed args...])
int vscanf (const char *format, va_list args);
int vsscanf (const char *source, const char *format, va_list args);
int vfscanf (FILE *file, const char *format, va_list args);
這些函式與沒有 v 字首的相同函式類似,除了它們從 va_list 獲取引數。(參見 stdarg.h。)這些變體可用於可變引數函式。
scanf 中的格式 佔位符 與其逆函式 printf 中的格式佔位符大致相同。
格式字串中很少有常量(即不是格式 佔位符 的字元),主要是因為程式通常不是為了讀取已知資料而設計的。例外是 空白 字元,它會丟棄輸入中的所有空白字元。
以下是最常用的佔位符
%d: 將整數掃描為帶符號的 十進位制 數。%i: 將整數掃描為帶符號的數字。類似於%d,但在以0x開頭時將其解釋為 十六進位制,以0開頭時解釋為 八進位制。例如,字串031使用%d將被讀取為 31,使用%i將被讀取為 25。%hi中的標誌h表示轉換為short,hh表示轉換為char。%u: 掃描十進位制unsigned int(請注意,在 C99 標準中,輸入值的減號是可選的,因此如果讀取負數,則不會出現錯誤,結果將是 二進位制補碼。參見strtoul().Template:Failed verification) 相應地,%hu掃描unsigned short,%hhu掃描unsigned char。%f: 將浮點數掃描為普通 (定點) 表示法。%g,%G: 將浮點數掃描為普通或指數表示法。%g使用小寫字母,%G使用大寫字母。%x,%X: 將整數掃描為無符號的 十六進位制 數。%o: 將整數掃描為 八進位制 數。%s: 掃描一個字元字串。掃描在遇到空白字元時結束。一個空字元儲存在字串的末尾,這意味著提供的緩衝區必須比指定的輸入長度至少長一個字元。%c: 掃描一個字元(char)。不新增任何空字元。(space): 空格掃描空白字元。%lf: 掃描為雙精度浮點數。%Lf: 掃描為長雙精度浮點數。
以上可以在數字修飾符和表示“long”的l、L修飾符之間進行組合使用。在百分號和字母之間,還可以有數值(在任何“long”修飾符之前),指定要掃描的字元數。百分號後面的可選星號 (*) 表示透過此格式說明符讀取的資料不儲存在變數中。格式字串後面的引數不應包含此丟棄的變數。
ff修飾符在printf中不存在,導致輸入和輸出模式之間存在差異。ll和hh修飾符在C90標準中不存在,但在C99標準中存在。[1]
格式字串的示例為
"%7d%s %c%lf"
上面的格式字串將前七個字元掃描為十進位制整數,然後讀取剩餘的字元作為字串,直到遇到空格、換行符或製表符,然後掃描後面的第一個非空白字元,最後掃描雙精度浮點數。
錯誤處理
[edit | edit source]scanf通常用於程式無法保證輸入是否為預期格式的情況。因此,健壯的程式必須檢查scanf呼叫是否成功,並採取適當的措施。如果輸入格式不正確,錯誤資料將仍然保留在輸入流中,必須先讀取並丟棄,才能讀取新的輸入。另一種避免這種情況的輸入讀取方法是使用fgets,然後檢查讀取的字串。最後一步可以用sscanf完成,例如。
安全
[edit | edit source]與printf類似,scanf容易受到格式字串攻擊。應格外小心,確保格式字串包含字串和陣列大小的限制。在大多數情況下,使用者輸入的字串大小是任意的;它在執行scanf函式之前無法確定。這意味著不帶長度說明符的%s佔位符本質上是不安全的,可以被利用來進行緩衝區溢位。另一個潛在問題是允許動態格式字串,例如儲存在配置檔案或其他使用者控制檔案中的格式字串。在這種情況下,除非事先檢查格式字串並強制執行限制,否則無法指定允許的字串大小的輸入長度。與之相關的是額外的或不匹配的格式佔位符,它們與實際的可變引數列表不匹配。這些佔位符可能部分從堆疊中提取,包含不希望的甚至不安全的指標,具體取決於可變引數的特定實現。
/*另一種只在某些特殊編譯器上有效的用法是
scanf("請輸入一個值 %d",&n);
它會列印引號中的字串,並在指示的%符號處停止接受輸入。*/
另請參見
[edit | edit source]外部連結
[edit | edit source]- : 輸入格式轉換 – Linux 庫函式 手冊
- C++ 對
std::scanf的引用
- ↑ C99 標準,§7.19.6.2 “fscanf 函式” 第 11 行。