如何在C语言中读取输入

3

我正在尝试使用scanf("%[^\n]")读取一行;在它之前,我使用"%d"读取一个整数,有人告诉我scanf在读取后不会清除'\n',所以我必须调用fflush()避免这种情况发生。但即使这样做,我仍然遇到同样的问题,以下是我的代码:

scanf("%d", &n);
fflush(stdin);

lines = (char**)malloc(sizeof(char*)*n);

for(i = 0; i < n; i++){
    lines[i] = (char*)malloc(sizeof(char)*1001);
}

for(i = 0;i < n;i++){
    scanf("%[^\n]", linhes[i]);
}

我读取了一个整数,然后scanf不等待,开始读取输入——无论整数值是5还是10,scanf都会将所有字符串读取为空。已经尝试使用fgets,结果几乎相同,只是它会读取一些字符串并跳过其他字符串。


5
εΑÜ "%[^\n]" φîΙδΗΚ " %[^\n]"ψIJ - BLUEPIXY
2
scanf("%[^\n]", lines[i]);从不消耗\n。请使用fgets() - chux - Reinstate Monica
1
@ VermillionAzure scanf("\n%d", &variable)scanf("%d", &variable) 以及 scanf(" %5d", &variable) 几乎是相同的。前导空格并没有为代码带来太多好处。(注意:确保你的5%) - chux - Reinstate Monica
1
而且,根据标准,fflush(stdin)是未定义的。 - Iharob Al Asimi
2
请注意使用fflush(stdin)中所述。一些平台定义了fflush(stdin)的行为,但C标准和POSIX没有定义。 - Jonathan Leffler
显示剩余4条评论
2个回答

2
让我们一步一步来看:

"... 用scanf("%[^\n]");读取一行。"

scanf("%[^\n]", buf)并不是读取一整行。它几乎可以这样做 - 有时候。 "%[^\n]"指示scanf()读取任何数量的非'\n'字符,直到遇到一个(然后将'\n'放回stdin)或EOF发生。

这种方法存在一些问题:

  1. 如果第一个字符是'\n'scanf()会将其放回stdin,而不对buf进行任何更改!buf保持原样 - 可能是未初始化的。 scanf()然后返回0。
  2. 如果至少读取了一个非'\n',它将保存到buf中,并继续读取更多字符,直到出现'\n'。接着在buf末尾添加一个'\0',将'\n'放回stdin,并且scanf()返回1。这种无限制的方式很容易导致buf溢出。如果没有保存任何字符并且发生EOF或输入错误,则scanf()返回EOF
  3. 始终检查scanf()/fgets()等函数的返回值。如果您的代码没有对其进行检查,则buf的状态是未知的。

无论如何,'\n'通常仍然留在stdin中,因此并未完全读取。这个'\n'通常会影响下一个输入函数。

... scanf在读取后不会擦除'\n'

另一个常见的误解。 scanf()根据提供的格式读取'\n'或不读取。有些格式会消耗'\n',而其他格式则不会。

... 调用fflush()以避免这种情况

fflush(stdin)在一些编译器中是有定义的,但不符合C标准。通常问题是代码想要消除stdin中任何剩余的数据。当行末尚未出现时,常见的替代方法是读取并丢弃直到发现'\n'为止:

int ch;  // Use int
while ((ch = fgetc(stdin)) != '\n' && ch != EOF);

我仍然有同样的问题

在我看来,最好的解决方案是读入用户输入的一行,然后进行扫描。

char buf[sizeof lines[i]];
if (fgets(buf, sizeof buf, stdin) == NULL) return NoMoreInput();

// If desired, remove a _potential_ trailing \n
buf[strcspn(buf, "\n")] = 0;

strcpy(lines[i], buf);

我建议缓冲区的大小应该是预期输入的两倍。对于健壮的代码,它会检测是否需要读取更多行。在我看来,这种过长的行更常见于黑客而不是合法使用。


当你的程序期望一行输入,但有一个限制,当达到这个限制时,我认为剩余的部分可以被丢弃,最好的方法是创建自己的函数(使用fgetc)来处理它,并避免浪费时间学习那些函数。在我的情况下,这是一个马拉松训练程序,所以我不想创建这些函数,但我还是创建了一个测试,效果很好。 - user2542813

0

BLUEPIXY在评论中回答了我的问题:

尝试将"%[^\n]"改为" %[^\n]"


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接