我需要阅读以下文本文件:
2 2
Kauri tree
Waterfall
0 0 W S
0 1 E N
我想使用scanf
获取第一行,然后使用fgets
作为第二行和第三行,然后再使用scanf
作为其余行。< / p>
我写了这样的代码:
#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
获取第二行。但我不知道该怎么做。
答案 0 :(得分:2)
除非明确初始化,否则在函数内定义的局部变量将具有不确定值。对于指针,这意味着他们指向一个看似随机的位置。使用任何未初始化的变量,除了初始化它之外,都会导致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
输入存储在内存中的缓冲区中,然后scanf
和fgets
从此缓冲区中读取。通过上面的输入,缓冲区将看起来像这样
+----+----+----+----+----+----+----+----+----+ | 2 | 2 | \n | h | e | l | l | o | \n | +----+----+----+----+----+----+----+----+----+
在scanf
调用之后读取输入缓冲区的两个数字
+----+----+----+----+----+----+----+ | \n | h | e | l | l | o | \n | +----+----+----+----+----+----+----+
那么循环中第一次调用fgets
会看到换行符。所以它读取了换行符然后就完成了,将字符串"hello\n"
留在缓冲区中,以便第二次调用fgets
。
有几种方法可以解决这个问题。我个人更喜欢的是使用fgets
普遍读取行,如果您需要对行进行简单解析,请使用sscanf
(注意前导s
,也请{{1} 3}})这样做。
另一种方法是简单地从输入中读取字符,一次读取一个字符,然后丢弃它们。当您阅读换行符时,请停止循环并继续执行该程序的其余部分。
答案 1 :(得分:1)
考虑以下示例,其中注释解释了一些重要的观点:
#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;
}
当您使用scanf
或fscanf
阅读数据时,您可以检查结果,例如:
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”
答案 2 :(得分:1)
我已经解决了我的问题。我不应该使用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);
}