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 中的格式化佔位符 大致相同。
格式字串中很少有常量(即不是格式化佔位符 的字元),主要是因為程式通常不是為了讀取已知資料而設計的。例外情況是 1 個或多個空白 字元,它們會丟棄輸入中的所有空白字元。
以下是一些最常用的佔位符
%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: 掃描一個字串。掃描在空白 處結束。一個空字元 會儲存在字串的末尾,這意味著提供的緩衝區必須比指定的輸入長度至少長 1 個字元。%c: 掃描一個字元 (char)。不會新增空字元。(空格): 空格掃描空白 字元。%lf: 作為雙精度 浮點數掃描。%Lf: 作為長雙精度 浮點數掃描。
以上可以在數值修飾符和 l、L 修飾符(代表“長”)之間複合使用,這些修飾符位於百分號和字母之間。百分號和字母之間也可能存在數值(在 long 修飾符之前,如果有的話),指定要掃描的字元數。百分號之後的一個可選的星號 (*) 表示透過此格式說明符讀取的資料不應儲存在變數中。格式字串後面的引數不應包含此丟棄的變數。
printf 中的 ff 修飾符在 scanf 中不存在,導致輸入和輸出模式之間存在差異。ll 和 hh 修飾符在 C90 標準中不存在,但在 C99 標準中存在。[1]
格式字串的示例為
"%7d%s %c%lf"
以上格式字串將前七個字元掃描為十進位制整數,然後讀取剩餘字元作為字串,直到遇到空格、換行符或製表符,然後掃描其後的第一個非空白字元,以及其後的雙精度浮點數。
scanf 通常用於程式無法保證輸入格式正確的情況。因此,健壯的程式必須檢查 scanf 呼叫是否成功,並採取相應的措施。如果輸入格式不正確,錯誤資料仍然會保留在輸入流中,必須在讀取新輸入之前讀取並丟棄。避免這種情況的另一種讀取輸入的方法是使用 fgets,然後檢查讀取的字串。最後一步可以使用 sscanf 完成,例如。
與 printf 一樣,scanf 容易受到 格式字串攻擊 的影響。應非常小心地確保格式化字串包含字串和陣列大小的限制。在大多數情況下,來自使用者的輸入字串大小是任意的;它無法在 scanf 函式執行之前確定。這意味著使用沒有長度說明符的 %s 佔位符本質上是不安全的,並且可以利用緩衝區溢位。另一個潛在問題是允許動態格式化字串,例如儲存在配置檔案或其他使用者控制檔案中的格式化字串。在這種情況下,除非事先檢查格式化字串並強制執行限制,否則無法指定允許的字串大小的輸入長度。與此相關的是額外的或不匹配的格式佔位符,它們與實際的 vararg 列表不匹配。這些佔位符可能會部分從堆疊中提取,包含不希望的甚至不安全的指標,具體取決於 varargs 的特定實現。
/* 另一種僅在某些特殊編譯器上有效的用法是
scanf("請輸入一個值 %d",&n);
它會列印引號內的字串,並在指示的 % 號處停止接受輸入。*/
- : 輸入格式轉換 – Linux 庫函式 手冊
- C++ 對
std::scanf的參考
- ↑ C99 標準,第 7.19.6.2 節“fscanf 函式” 第 11 行。