我需要阅读以下文本文件:
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/