我正在使用提示创建命令行应用程序。只要输入适合缓冲区,它就可以正常工作,但是当输入较大时,我会得到一些奇怪的行为。下面是一个简化的最小示例,它具有相同的错误。
int main()
{
for (;;) {
const int size = 8;
char str[size];
printf("> ");
fgets(str, size, stdin);
toupper_str(str);
printf("Result: %s\n", str);
}
}
如果输入小于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");
}
当检测到这个时,如何阻止它在下一次迭代中读取剩余的太长时间的输入?
我在这里看到过类似的问题,但没有人提出同样的问题。
答案 0 :(得分:4)
如何阻止它在下一次迭代中读取剩余的太长时间的输入?
代码需要1)检测输入是否“太长”2)消耗额外的输入。
fgets()
不会溢出缓冲区。如果它确实填充了缓冲区,则缓冲区中的最后一个char
为'\0'
。所以在阅读之前将其设置为非'\0'
。然后代码知道整个缓冲区是否已填满。然后检查前面的char
是否为'\n'
。如果它不是行尾,则char
stdin
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
的内容未定义。
注意:代码可以使用str[sizeof str - 1] == '\0'
而不是strlen(str) == sizeof str - 1
。如果fgets()
读取空字符'\0'
,这会被愚弄。
转角案件:
1.典型的str
最多为98 char
,然后是'\n'
和'\0'
。可以最后 str
是99 char
然后是'\0'
吗?
2.如果#1没问题,那么典型的str
可能有99 char
然后是'\0'
吗?
答案 1 :(得分:1)
当输入太长时,您需要在继续下一次循环迭代之前读取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");
}
如果您使用的是OSX或Linux等POSIX系统,则getline
函数已从流中读取任意长度的换行符终止字符串。您还可以在线找到此功能的许多免费/开源版本。