2012-04-10 51 views
3

我想確認從scanf()函數返回的值是否爲浮點數。我怎樣才能做到這一點?如果給scanf()函數提供了錯誤的數據類型,我的代碼不會運行。同樣如何確認返回的值是否是字符串?我們如何測試scanf()函數的返回值?

+0

我看過的所有'scanf'版本都返回一個'int'。 – leppie 2012-04-10 06:44:23

+1

@Saurabh在你之前的Qn中,我想你想知道_scanther scanf是否成功掃描了float_,而不是_它的返回值是否是float_,正如你的問題所述? – 2012-04-10 06:51:15

+3

也許關於'* scanf()'系列函數的最重要的事情是,如果掃描一個數值超出相應類型範圍的數字,則行爲是不確定的。例如,如果'scanf(「%d」)'試圖讀取'999999999999999999999',任何事情都可能發生;沒有辦法處理錯誤。除了使用'* scanf()'以外的東西,除了'strto *()'函數外,沒有什麼好的解決方法。 – 2012-04-10 07:07:35

回答

12

scanf()等人返回成功轉換次數。

如果您有:

scanf("%f", &f); 

你應該測試:

if (scanf("%f", &f) == 1) 
    ...all OK... 
else 
    ...EOF or conversion failure... 

如果你有幾個轉換,檢查,他們都完成了。如果您使用%n「轉化次數」,則不計算在內。

儘管scanf()確實會在EOF上返回EOF,但您不應該爲此測試—,您應該始終檢查是否已獲得您期望的轉換次數。例如,考慮bug的代碼:此後

while (scanf("%f %d %s", &f, &i, s) != EOF) // Here be BUGS! 
    ...loop body... 

如果鍵入3.14 x23 yes,那麼你將有一個無限循環,因爲scanf()將在第一次迭代返回1(它成功地轉換3.14),0(不EOF) 。

你可能會確定有:

while ((rc = scanf("%f %d %s", &f, &i, s)) != EOF) 
{ 
    if (rc != 3) 
     ...oops data problems... 
    else 
     ...all OK... 
} 

從以前的問題來看,你應該考慮使用fgets()(或可能POSIX getline())讀取數據的線,然後用sscanf()甚至像strtol()strtod()這樣的函數來讀取行中的特定值。如果您使用sscanf(),則上述有關檢查成功轉換次數的註釋仍適用。

我在生產代碼中不使用scanf();這太難控制了。我認爲它幾乎適用於開始程序—,除了它導致很多混淆。總體而言,最好的建議是「保持清除scanf()fscanf()」。請注意,這並不意味着您必須保持清除sscanf(),但即使sscanf()也需要謹慎。

+0

真棒的答案!但是我有一個疑問:會不會是一個人; scanf(「%c」,&a);'永遠返回零? – 2017-03-23 12:03:55

+0

如圖所示,'%c''應該永遠不會返回0,因爲要麼有要讀取的字符,所以結果將是1,或者沒有什麼可以讀取所以結果將是EOF,你仍然需要檢查這兩個選項中哪一個適用,並且使用if(scanf(「%c」,&a)== 1){...得到一個char ...}「仍然是正確的,是主要答案中推薦的內容。 – 2017-03-23 18:08:53

5

scanf返回值表示的項目數成功地讀取並分配給你的變量,或EOF:

這些函數成功返回輸入項目的數量 匹配 和分配,可以是少比提供的要早,或者甚至爲零,在早期匹配失敗的事件中。

如果在第一次成功轉換或發生匹配故障時 之前達到輸入的結尾,則會返回值EOF。如果發生讀取錯誤,EOF爲 也會返回,在這種情況下,流的錯誤指示器 (請參閱ferror(3))已設置,並且設置了錯誤號指示 錯誤。

如果scanf返回int比格式字符串(或至少需要一個參數的說明符傳遞)輸入符量越少值,那麼你可以假設出了問題。

但是,如果您想對浮點數執行更徹底的驗證,那麼您應該考慮使用strtod()。即。對於輸入"1.23abc",scanf會將1.23存儲到您的變量中,並告訴您一切順利,但使用strtod您可以檢查最後轉換的字符是否實際上是要分析的字符串的結尾。