让我们一步一步来看:
"... 用scanf("%[^\n]");读取一行。"
scanf("%[^\n]", buf)
并不是读取一整行。它几乎可以这样做 - 有时候。 "%[^\n]"
指示scanf()
读取任何数量的非'\n'
字符,直到遇到一个(然后将'\n'
放回stdin
)或EOF发生。
这种方法存在一些问题:
- 如果第一个字符是
'\n'
,scanf()
会将其放回stdin
,而不对buf
进行任何更改!buf
保持原样 - 可能是未初始化的。 scanf()
然后返回0。
- 如果至少读取了一个非
'\n'
,它将保存到buf
中,并继续读取更多字符,直到出现'\n'
。接着在buf
末尾添加一个'\0'
,将'\n'
放回stdin
,并且scanf()
返回1。这种无限制的方式很容易导致buf
的溢出。如果没有保存任何字符并且发生EOF
或输入错误,则scanf()
返回EOF
。
- 始终检查
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();
buf[strcspn(buf, "\n")] = 0;
strcpy(lines[i], buf);
我建议缓冲区的大小应该是预期输入的两倍。对于健壮的代码,它会检测是否需要读取更多行。在我看来,这种过长的行更常见于黑客而不是合法使用。
"%[^\n]"
φîΙδΗΚ" %[^\n]"
ψIJ - BLUEPIXYscanf("%[^\n]", lines[i]);
从不消耗\n
。请使用fgets()
。 - chux - Reinstate Monicascanf("\n%d", &variable)
和scanf("%d", &variable)
以及scanf(" %5d", &variable)
几乎是相同的。前导空格并没有为代码带来太多好处。(注意:确保你的5
是%
) - chux - Reinstate Monicafflush(stdin)
是未定义的。 - Iharob Al Asimifflush(stdin)
中所述。一些平台定义了fflush(stdin)
的行为,但C标准和POSIX没有定义。 - Jonathan Leffler