我需要阅读以下文本文件:

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来获取第二行。但我不知道怎么做。

最佳答案

除非显式初始化,否则函数内部定义的局部变量将具有不确定值。对于指针,这意味着它们指向一个看似随机的位置。使用任何未初始化的变量(初始化变量除外)都会导致undefined behavior
这里发生的情况是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

输入存储在内存中的缓冲区中,然后从该缓冲区中读取。使用上述输入,缓冲区将如下所示
+----+----+----+----+----+----+----+----+----+
|2 | 2 | \n | h | e | l | l | o | \n|
+----+----+----+----+----+----+----+----+----+
scanf调用读取输入缓冲区中的两个数字之后
+----+----+----+----+----+----+----+
|\n | h | e | l | l | o | \n|
+----+----+----+----+----+----+----+
因此,循环中对fgets的第一个调用将看到换行符。所以它读取了换行符,然后就完成了,将字符串scanf留在缓冲区中,以便第二次调用fgets
有几种方法可以解决这个问题。我个人更喜欢使用"hello\n"来读取行,如果您需要对行进行简单的解析,那么使用fgets(注意前面的fgets,也请see here for a good reference of all sscanf variants)来读取行。
另一种方法是简单地从输入中读取字符,一次读取一个字符,然后丢弃它们。阅读换行符时,停止循环并继续执行程序的其余部分。

关于c - 如何同时使用scanf和fgets读取文件,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39078372/

10-13 08:49