簡體   English   中英

如何同時使用scanf和fgets讀取文件

[英]how to use both scanf and fgets to read a file

我需要閱讀以下文本文件:

2 2
Kauri tree
Waterfall
0 0 W S
0 1 E N

我想使用scanf來獲取第一行,並使用fgets來獲取第二行和第三行,然后再將scanf用作其余的行。

我寫了這樣的代碼:

#include <stdio.h>

#define NUM_OF_CHAR 2

int main()
{
    int node, edge;
    scanf("%d %d", &node, &edge);

    FILE* fp;
    fp = stdin;

    char* str[NUM_OF_CHAR];  //should be char str[NUM_OF_CHAR];

    for (int i = 0; i < node; i++) {
        fgets(str[i], 2, fp);     //should be fgets(str, 2, fp);
    }
    printf("%s", str[0]);         //printf("%s", str);
}

我輸入的輸入是:

2 2
hello

我遇到了Segmentation fault

我在這里看到了一個類似的問題,一個人提到我可以一次調用fgets來獲取第一行,但是忽略它,然后再次使用fgets來獲取第二行。 但是我不知道該怎么做。

除非明確初始化,否則函數內部定義的局部變量將具有不確定的值。 對於指針,這意味着它們正在指向看似隨機的位置。 使用任何未初始化的變量(除非對其進行初始化)都會導致未定義的行為

此處發生的情況是fgets將使用(未初始化且看似隨機的)指針並將其寫入其指向的內存中。 在大多數情況下,此內存不屬於您或您的程序,甚至可能會覆蓋一些其他重要數據。 這可能會導致崩潰或其他怪異的行為或結果。

最簡單的解決方案是使str成為字符數組,例如

#define NUM_OF_STRINGS 2
#define STRING_LENGTH 64
...
char str[NUM_OF_STRINGS][STRING_LENGTH];
...
fgets(str[i], sizeof str[i], stdin);

您需要確保上面的STRING_LENGTH足以容納每個字符串, 包括換行符和字符串終止符。 在上面顯示的是64的情況下,這意味着您最多可以有62個字符的行。


現在,對於另一個問題,我指出了,第一個對fgets調用讀取了一個空行。

如果您有輸入

2 2
hello

輸入存儲在內存中的緩沖區中,然后scanffgets從該緩沖區讀取。 通過上面的輸入,緩沖區看起來像這樣

+----+----+----+----+----+----+----+----+----+
|  2 |  2 | \n |  h |  e |  l |  l |  o | \n |
+----+----+----+----+----+----+----+----+----+

scanf調用讀取兩個數字之后,輸入緩沖區看起來像

+----+----+----+----+----+----+----+
| \n |  h |  e |  l |  l |  o | \n |
+----+----+----+----+----+----+----+

因此,循環中對fgets第一個調用將是換行符。 因此它將讀取該換行符,然后完成該操作,將字符串"hello\\n"留在緩沖區中,以供第二次調用fgets

有幾種方法可以解決此問題。 我個人更喜歡使用通用的fgets讀取行,如果您需要對行進行簡單的解析,請使用sscanf (注意sscanfs ,也請參見此處,以獲得所有scanf變體的良好參考 )。 。

另一種方法是簡單地從輸入中讀取字符,一次輸入一個字符,然后丟棄它們。 閱讀換行符時,請停止循環並繼續執行該程序的其余部分。

考慮以下示例,其中的注釋解釋了一些要點:

#include <stdio.h>

#define NUM_OF_CHAR 2
#define LEN_OF_STR 20

int main()
{
    int node, edge;
    FILE* fp;
    fp = stdin;
    char strbuf[LEN_OF_STR];
    // stream is available after that
    // reading numbers
    fscanf(fp, "%d %d", &node, &edge);
    // reading strings
    for (int i = 0; i < node; i++) {
        // reading line from input stream
        fgets(strbuf, LEN_OF_STR, fp);
    }
    // cleaning input buffer
    while (getchar() != '\n');
    // reading lines with data
    char str[NUM_OF_CHAR];
    int a, b;
    for (int i = 0; i < node; i++) {
        // reading two numbers and two characters
        fscanf(fp, "%d %d %c %c", &a, &b, &str[0], &str[1]);
        // do something with dada, e.g. output
        printf("%d %d %c %c\n", a, b, str[0], str[1]);
    }
    return 0;
}

使用scanffscanf讀取數據時,可以檢查結果,例如:

    if (4 == fscanf(fp, "%d %d %c %c", &a, &b, &str[0], &str[1]))
    {
        // actions for correct data
    }
    else
    {
        // actions for wrong input
    }

此處的格式行有4個說明符-“%d%d%c%c”,因此我們將其檢查為“比較返回值與4”

我已經解決了我的問題。 我不應該使用char*指針並將其指向數組。 傳遞給fgets函數的第一個參數應該是char*所以我應該只使用數組。

另外,由於scanf已經掃描了第一行,如果我接下來使用fgets ,它將自動獲取下一行。

#include <stdio.h>

#define NUM_OF_CHAR 100

int main()
{
    int node, edge;
    scanf("%d %d", &node, &edge);

    FILE* fp;
    fp = stdin;

    char str[NUM_OF_CHAR] = {'\0'};

    for (int i = 0; i < node; i++) {
        fgets(str, NUM_OF_CHAR, fp);
    }
    printf("%s", str);
}

暫無
暫無

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

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