3 回答

TA貢獻1775條經驗 獲得超11個贊
根據C語言標準(n1256):
7.19.6.2 fscanf函數
...
4 fscanf函數依次執(zhí)行格式的每個指令。如果指令失敗,如下所述,函數將返回。失敗描述為輸入失?。ㄓ捎诎l(fā)生編碼錯誤或輸入字符不可用)或匹配失?。ㄓ捎诓贿m當的輸入)。
...
7作為轉換規(guī)范的指令定義了一組匹配的輸入序列,如下文針對每個說明符所述。轉換說明將按照以下步驟執(zhí)行:
8除非輸入規(guī)范中包含[,c或n說明符,否則將跳過輸入的空白字符(由isspace函數指定)。250)
9從流中讀取一個輸入項,除非規(guī)范包括n個說明符。輸入項定義為最長的輸入字符序列,該序列不超過任何指定的字段寬度,并且是匹配輸入序列的前綴,或者是匹配輸入序列的前綴。251)輸入項之后的第一個字符(如果有)保持未讀狀態(tài)。如果輸入項的長度為零,則該指令的執(zhí)行失敗;否則,該指令的執(zhí)行失敗。除非文件末尾,編碼錯誤或讀取錯誤阻止了來自流的輸入,否則此條件是匹配失敗,在這種情況下,這是輸入失敗。
10除非是%說明符,否則輸入項(或者,如果是%n指令,即輸入字符數)轉換為適合轉換說明符的類型。如果輸入項不是匹配序列,則指令的執(zhí)行失?。捍藯l件是匹配失敗。除非用*表示禁止分配,否則轉換結果將放置在尚未收到轉換結果的format參數后面的第一個參數指向的對象中。如果該對象沒有適當的類型,或者無法在對象中表示轉換結果,則該行為是不確定的。
在第10段中添加了重點。%d轉換說明符希望輸入文本的格式設置為十進制整數。如果不是,則轉換失敗,并且導致轉換失敗的字符保留在輸入流中。scanf()使用%d轉換說明符進一步調用將會阻塞相同的字符。
scanf()返回成功分配的數量;您需要檢查此結果以查看轉換是否成功,如下所示:
int x = 0;
while (x != 4)
{
int result = scanf("%d", &x);
if (result != 1)
{
printf("Last call to scanf() failed; exiting\n");
break;
}
}
不幸的是,您仍然將錯誤的輸入卡在輸入流中。有許多策略可以解決這個問題。您可以使用刪除令人反感的字符,getchar然后重試:
while (x != 4)
{
int tmp;
if (scanf("%d", &tmp) == 0)
getchar();
else
x = tmp;
}
或者,您可以嘗試讀取下一個換行符,假設所有剩余的輸入都為b0rked:
while (x != 4)
{
int tmp;
if (scanf("%d", &tmp) == 0)
while (getchar() != '\n')
;
else
x = tmp;
}
或者,您可以嘗試將輸入讀取為文本,然后使用strtol()(我的首選技術)將其轉換為整數:
char input[SOME_SIZE];
int x = 0;
...
while (x != 4)
{
if (fgets(input, sizeof input, stdin))
{
char *check;
int tmp = (int) strtol(input, &check, 10);
if (!isspace(*check) && *check != 0)
{
printf("%s is not a valid integer: try again\n", input);
}
else
{
x = tmp;
}
}
else
{
printf("Read error on standard input\n");
break;
}
}
這需要做更多的工作,但可以讓您在將錯誤的輸入分配給之前捕獲錯誤的輸入x。

TA貢獻1860條經驗 獲得超8個贊
您無需檢查scanf
實際是否成功,因此會陷入錯誤。對于每個循環(huán),scanf
都會嘗試讀取并失敗。
scanf
返回成功讀取項的數量,因此將循環(huán)修改為如下形式 while (x!=4) { if (scanf("%d",&x) != 1) break; }

TA貢獻1804條經驗 獲得超2個贊
當scanf在輸入流中的特定位置停止掃描時,它將永遠不會推進該流,因此下一個scanf將再次嘗試相同的錯誤...并再次嘗試...
輸入:42 23 foo ...
scanf:^
x 42
scanf:^
x 23
scanf:^
x無法使用
scanf:^
x無法使用
scanf:^
x無法使用
scanf:^
x無法使用
scanf:^
x無法使用
- 3 回答
- 0 關注
- 907 瀏覽
添加回答
舉報