这是一个看似简单的问题,但我回答太久了:
我正在尝试使用fgets()从C程序中的用户读取输入。但是,我遇到一个问题,如果用户输入的字符多于设置为读取的fgets()的字符,则下一次从用户读取字符串的调用会自动读取stdin缓冲区中的其余字符,这不是我的行为想。
我尝试了多种方法清除stdin流,虽然我知道类似的东西
while(getchar()!='\n');
将起作用,这需要用户点击输入一个额外的时间,这不是我想要的时间。
代码的结构看起来像这样:
void read_string(char *s, int width){
fgets(s,width,stdin);
clear_stdin();
.
.
}
while (1){
read_string()
.
.
}
但是我无法获得需要正常工作的clear_stdin()函数。我到底该如何清除标准输入,而无需用户不必要两次按Enter键?
答案 0 :(得分:4)
您无法以可移植的方式清除stdin
(因为未指定来自<stdio.h>
的功能)。顺便说一句,stdin通常不仅可以是终端,还可以是redirection或pipe(甚至可能是某些socket)。细节当然很重要(例如您的操作系统和/或运行环境)。
您可以避免stdio并使用operating system特定的方式来处理标准输入(例如,在POSIX系统上以file descriptor级别工作)。
在Linux上(具体而言),您可能会了解有关the Tty demystified的更多信息,并根据这些知识编写低级代码。参见termios(3)。考虑使用readline(3)。
您可以use(至少在Linux上)getline(3)读取堆分配的行缓冲区。
答案 1 :(得分:4)
要实现所需的功能-如果提供的缓冲区被过度填充,则读取并忽略换行符,直到换行符为止-您需要有条件地读取换行符,只有在其中没有换行符时才这样做读取的输入缓冲区。
void read_string(char *s, int width)
{
if (fgets(s, width, stdin) != 0)
{
size_t length = strlen(s);
if (length > 0 && s[length-1] != '\n')
{
int c;
while ((c = getchar()) != '\n' && c != EOF)
;
}
/* Use the input data */
}
else
/* Handle EOF or error */
}
该技术的另一部分是确保使用足够大的缓冲区,以防止任何人溢出该缓冲区。将char buffer[4096];
视为开标价;您可以根据需要增加它。这样一来,任何人都不可能(能够)在一行上键入足够的数据来溢出您提供的缓冲区,从而避免了该问题。
另一种选择是使用POSIX getline()
。它将一行读入已分配的空间,分配更多的空间,直到数据适合(或内存不足)。与fgets()
相比,它还有至少另一个主要优点-它报告读取的行中的字符数,这意味着它不会与空字节('\0'
混淆,通常键入 Control -@ )。相比之下,您无法用fgets()
判断在第一个空字节之后是否输入了任何数据;您必须假设输入在第一个空字节处停止。
请注意,如果问题(while (getchar() != '\n');
中显示的简单循环在读取换行符之前遇到EOF,则该循环将变为无限循环。
答案 2 :(得分:2)
while ((getchar()) != '\n');
这并不总是可行的...(但是,好的一面是,它不如它可移植的情况)。但是,如果尚未重定向stdin,则除非手动EOF
,否则用户输入的终端字符通常会换行。提取期望内容后,假设您不期望\n
,则可以耗尽其中的内容,直到(包括)“ \ n”,然后重新进行迭代。正如其他人所建议的那样,大多数情况下,与手动条纹案例处理相比,存在更高级别的界面来更可靠地处理此细节。
More Details on Challenge and Solutions 此链接的标题中包含“ C \ C ++”的基本原理,它不作为实体存在。请放心,我们给出了单独的 C示例,这些示例与其他C ++示例是离散的。