[英]Read from stdin with fgets, bug if input is greater than size
我正在创建带有提示的命令行应用程序。 只要输入适合缓冲区,它就可以正常工作,但是当输入较大时,我会得到一些奇怪的行为。 以下是具有相同错误的简化的最小示例。
int main()
{
for (;;) {
const int size = 8;
char str[size];
printf("> ");
fgets(str, size, stdin);
toupper_str(str);
printf("Result: %s\n", str);
}
}
如果输入的size
小于size
,则效果很好。
> asdf
Result: ASDF
>
当输入较大时,将处理范围内的输入部分,并在下一个循环迭代中,立即从fgets
返回其余给定输入。 这导致输入的那部分也被处理和一些奇怪的输出。
> asdfghjk
Result: ASDFGHJ
> Result: K
>
通过将最后一个字符与换行符进行比较,可以看到输入是否大于或等于大小。 只要适合, fgets
保留换行符。
fgets(str, size, stdin);
if (str[strlen(str) - 1] != '\n') {
fprintf(stderr, "Input too long\n");
}
当检测到此错误时,如何停止它在下次迭代中读取其余太长的输入?
我在这里看到过类似的问题,但没有人问过同样的问题。
如何阻止它在下一次迭代中读取其余太长的输入?
代码需要1)检测输入是否“太长” 2)消耗额外的输入。
fgets()
不会溢出缓冲区。 如果确实填满了缓冲区,则缓冲区中的最后一个char
为'\\0'
。 因此,在读取之前将其设置为非'\\0'
。 然后代码知道整个缓冲区是否已满。 然后检查前面的char
是否为'\\n'
。 如果不是行尾, 则 stdin
可能存在其他char
char str[100]; // Insure buffer is at least size 2
for (;;) {
str[sizeof str - 1] = `x`;
if (fgets(str, size, stdin) == NULL) {
// No more to read or IO error
break;
}
int extra_data_found = 0;
if (str[sizeof str - 1] == '\0' && str[sizeof str - 2] != '\n') {
// Cope with potential extra data in `stdin`: read and toss
int ch;
while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
extra_data_found = 1;
}
}
// Use `str` as needed, noting if additional unsaved data found
foo(str, extra_data_found);
}
注意:发生文件错误时, fgets()
返回NULL
并且str
的内容未定义。
注意:代码可以使用strlen(str) == sizeof str - 1
代替str[sizeof str - 1] == '\\0'
。 如果fgets()
读取空字符'\\0'
这将被愚弄。
角落案例:
1.典型的str
最多为98个char
,然后为'\\n'
和'\\0'
。 可以, 最后一个 str
是99 char
然后是'\\0'
吗?
2.如果#1正常,那么典型的str
可以有99个char
,然后是'\\0'
吗?
当输入太长时,您需要在stdin上读取其余字符,然后再继续循环的下一次迭代。
if (fgets(str, size, stdin) == NULL) {
if (feof(stdin)) {
return 0;
else {
perror("Could not read from stdin");
exit(1);
}
}
else if (strchr(str, '\n') == NULL) {
int c;
while((c = getc(stdin)) != '\n' && c != EOF);
fprintf(stderr, "Input too long\n");
}
如果您使用的是OS X或Linux之类的POSIX系统,则已经有getline
函数可以从流中读取任意长度的换行符终止的字符串。 您也可以在线找到该功能的许多免费/开源版本。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.