簡體   English   中英

使用fscanf()與fgets()和sscanf()

[英]Using fscanf() vs. fgets() and sscanf()

在《實用C編程》一書中,我發現fgets()sscanf()的組合用於讀取輸入。 但是,在我看來,僅使用fscanf()函數可以更輕松地實現相同的目標:

從書中(想法,而不是示例):

int main()
{
    int age, weight;
    printf("Enter age and weight: ");

    char line[20];
    fgets(line, sizeof(line), stdin);
    sscanf(line, "%d %d", &age, &weight);

    printf("\nYou entered: %d %d\n", age, weight);
    return 0;
}

我認為應該如何:

int main()
{
    int age, weight;
    printf("Enter age and weight: ");
    fscanf(stdin, "%d %d", &age, &weight);

    printf("\nYou entered: %d %d\n", age, weight);
    return 0;
}

還是我缺少一些隱藏的怪癖?

兩種方法之間存在一些行為差異。 如果使用fgets() + sscanf() ,則必須在同一行上輸入兩個值,而如果stdin (或等效的scanf() )上的fscanf()找不到第二個值,則會從不同的行讀取它們在您輸入的第一行。

但是,最重要的差異可能與處理錯誤情況以及行輸入和場輸入的混合有關。

如果您在使用fgets()讀取一行后讀取了無法用sscanf()解析的行,則程序可以簡單地放棄該行並繼續前進。 但是, fscanf()無法轉換字段時,會將所有輸入保留在流中。 因此,如果您無法讀取所需的輸入,則必須去讀取所有要忽略的數據。

如果要在代碼中混合面向字段的調用(ala scanf() )和面向行的調用(例如fgets() ),則會出現另一個細微的陷阱。 例如,當scanf()轉換一個int ,它將在輸入流上留下一個\\n (假設有一個,例如,按回車鍵),這將導致對fgets()的后續調用僅返回輸入中的那個字符。 對於新程序員來說,這確實是一個普遍的問題。

因此,雖然可以使用fscanf()這樣正確,但通過使用fgets() + sscanf()可以避免一些麻煩。

僅使用fscanf()的問題主要是在錯誤管理中。

假設您在兩個程序中都輸入了“ 51年,85 Kg ”。

第一個程序在sscanf()失敗,並且您仍然可以通過該line向用戶報告錯誤,嘗試對某事物進行不同的解析選擇;

第二個程序在幾年后失敗, age可用, weight不可用。

請務必始終檢查*scanf()的返回值以進行錯誤檢查。

    fgets(line, sizeof(line), stdin);
    if (sscanf(line, "%d%d", &age, &weight) != 2) /* error with input */;

編輯

對於第一個程序,在錯誤之后,輸入緩沖區被清除; 在第二個程序中,輸入緩沖區以YEAR開頭。

在第一種情況下,恢復很容易; 在第二種情況下,恢復必須經過某種清除輸入緩沖區的過程。

在以下情況下, fscanf()fgets() / sscanf()之間沒有區別:

  1. 輸入數據格式正確。

發生兩種類型的錯誤:I / O和格式。 fscanf()在一個函數中同時處理這兩種錯誤類型,但提供的恢復選項很少。 分開的fgets()sscanf()允許將I / O問題與格式問題進行邏輯分離,從而實現更好的恢復。

  1. 只有1個解析路徑。

將I / O與掃描sscanf()可以使用多個sscanf()選項。 如果給定的緩沖區掃描無法實現所需的結果,則可以使用其他具有不同格式的sscanf()

  1. 沒有嵌入的'\\0'

很少發生'\\0' ,但是如果發生一次,則sscanf()不會看到它,因為掃描隨着發生而停止,而fscanf()繼續。

在所有情況下,請檢查所有三個功能的結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM