通常fscanf,當使用 , 掃描非整數時%d,將失敗,直到從輸入流中顯式洗掉非整數字符。嘗試掃描a123失敗,直到a從輸入流中洗掉。
嘗試掃描------123失敗(fscanf回傳0)但從-輸入流中洗掉。
這是正確的行為fscanf嗎?
該檔案包含----------123此代碼的結果:
#include <stdio.h>
int main(void) {
int number = 0;
int result = 0;
FILE *pf = NULL;
if (NULL != (pf = fopen("integer.txt", "r"))) {
while (1) {
if (1 == (result = fscanf(pf, "%d", &number))) {
printf("%d\n", number);
} else {
if (EOF == result) {
break;
}
printf("result is %d\n", result);
}
}
fclose(pf);
}
return 0;
}
是:
result is 0
result is 0
result is 0
result is 0
result is 0
result is 0
result is 0
result is 0
result is 0
-123
如果檔案包含a123結果是一個無限回圈。
在我看來,這似乎是不一致的行為。不?
uj5u.com熱心網友回復:
這里的重點不是不一致,而是家庭的許多限制之一*scanf()。
*scanf()該標準對如何決議輸入非常具體。字符從輸入中一一獲取,并根據格式字串進行檢查。如果它們匹配,則從輸入中獲取下一個字符。如果它們不匹配,則將字符“放回”,并且轉換失敗。
但是只有最后一個讀取的字符會被放回。
(這在 C11 腳注 285 中明確說明。它實際上與一個位元組的回推無關,它ungetc()保證——因為庫函式可能不會呼叫 ungetc()——為用戶保留那個回推位元組。 )
這允許庫將一個位元組的“放回”輸入塞進某處,而不必擁有某種足以應對各種可能性的緩沖區。
它還會在某些字符序列的中間*scanf()失敗,而不會實際回溯到它開始轉換嘗試的位置。
在您的情況下,"--123"請閱讀為"%d":
- 采取第一個
'-'。符號。一切順利,繼續。 - 服用第二個
'-'。匹配錯誤。 - 放回最后一個
'-'。'-'不能按上述放回第二個。 - 回傳
0(轉換失敗)。
這是您永遠不應在可能的格式錯誤的輸入上使用的(其中一個)原因*scanf():掃描可能會失敗,而您不知道它到底在哪里失敗。
這也是我上次檢查時在許多主流庫實作中沒有正確實作的標準的一個模糊角落。;-)
其他原因包括,但不限于,數值溢位根本沒有得到妥善處理。因此,通常的建議是使用 讀取完整的輸入行,然后使用等fgets()決議記憶體中的行,這可以并且將以明確定義的方式處理上述內容。strtol()strtod()
uj5u.com熱心網友回復:
這是 fscanf 的正確行為嗎?
是的,正如@stark 在評論中指出的那樣,-當您%d用作格式說明符時,它是結果的一部分。
如果你想掃描一個正整數(只有數字),你可以使用一個模式fscanf來丟棄所有非數字。
fscanf(pf, "%*[^0-9]%d", &number)
uj5u.com熱心網友回復:
指定此行為:將fscanf最多一個輸入字符推回輸入流,即使在ungetc()可以成功推回多個位元組的平臺上也是如此。
以下是 C2x 標準中的相關段落:
7.21.6.2
fscanf功能[...]
7 作為轉換規范的指令定義了一組匹配的輸入序列,如下面的每個說明符所述。轉換規范按以下步驟執行:
8 跳過輸入的空白??字符,除非規范包含[、c或n說明符。
9 從流中讀取輸入項,除非規范包含n說明符。輸入項被定義為最長的輸入字符序列,它不超過任何指定的欄位寬度,并且是匹配輸入序列的前綴。310)輸入項之后的第一個字符(如果有)保持未讀狀態。如果輸入項的長度為零,則指令執行失敗;這種情況是匹配失敗,除非檔案結尾、編碼錯誤或讀取錯誤阻止了來自流的輸入,在這種情況下,它是輸入失敗。
10 除了在%說明符的情況下,輸入項(或者,在%n指令的情況下,輸入字符的計數)被轉換為適合轉換說明符的型別。如果輸入項不是匹配序列,則指令執行失敗:此條件為匹配失敗。除非分配抑制由*, 轉換的結果放在格式引數后面的第一個引數所指向的物件中,該引數還沒有收到轉換結果。如果此物件沒有適當的型別,或者轉換的結果無法在物件中表示,則行為未定義。
310)
fscanf將最多一個輸入字符推回輸入流。strtod因此,一些對,等可接受的序列對strtol是不可接受的fscanf。
在您的示例中,首字母-是匹配輸入序列的前綴,而下一個字符 another-不匹配,因此它保留在輸入流中。輸入項-不是匹配序列,因此您會遇到轉換失敗并0回傳但第一個-已被消耗。
這是腳注暗示的另一個病態示例:輸入0xxfor 轉換%i會導致轉換失敗,因為輸入項0x??不是匹配的輸入序列,而strtol具有基本引數0or16將接受此輸入,回傳0并設定指向的結束指標xx。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/487777.html
標籤:C
上一篇:字串陣列的分段錯誤
