基本上在每个printf之前的windows的代码块中我有“fflush(stdin);”哪个有效。当我将我的代码复制到Linux时,它不起作用,也没有“fflush(stdin);”的替代方案。我发现了。无论我采用哪种方式,输入似乎都没有在缓冲区中清除,或者我的代码中的某些内容不正确。
#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <ctype.h>
int main()
{
char pbuffer[10], qbuffer[10], kbuffer[10];
int p=0, q=0, k=0;
int r, i, Q, count, sum;
char a[3];
a[0]='y';
while(a[0]=='y' || a[0]=='Y')
{
printf("Enter a p value: \n");
fgets(pbuffer, sizeof(pbuffer), stdin);
p = strtol(pbuffer, (char **)NULL, 10);
printf("Enter a q value: \n");
fgets(qbuffer, sizeof(qbuffer), stdin);
q = strtol(qbuffer, (char **)NULL, 10);
printf("Enter a k value: \n");
fgets(kbuffer, sizeof(kbuffer), stdin);
k = strtol(kbuffer, (char **)NULL, 10);
while(p<q+1)
{
Q=p;
sum=0;
count=0;
while(Q>0)
{
count++;
r = Q%10;
sum = sum + pow(r,k);
Q = Q/10;
}
if ( p == sum && i>1 && count==k )
{
printf("%d\n",p);
}
p++;
a[0]='z';
}
while((a[0]!='y') && (a[0]='Y') && (a[0]!='n') && (a[0]!='N'))
{
printf("Would you like to run again? (y/n) ");
fgets(a, sizeof(a), stdin);
}
}
return 0;
}
答案 0 :(得分:2)
调用fflush(stdin)
不是标准的,因此行为未定义(有关详细信息,请参阅this answer)。
不是在fflush
上调用stdin
,而是调用scanf
,传递一个格式字符串,指示函数读取所有内容,包括换行符'\n'
字符,像这样:
scanf("%*[^\n]%1*[\n]");
星号告诉scanf
忽略结果。
另一个问题是调用scanf
将字符读入变量a
,格式说明符为" %s"
:当用户输入非空字符串时,null终止符会创建缓冲区溢出,导致未定义的行为(char a
是一个字符的缓冲区;字符串"y"
有两个字符 - {'y', '\0'}
,第二个字符写在缓冲区的末尾。您应该将a
更改为包含多个字符的缓冲区,并将该限制传递给scanf
:
char a[2];
do {
printf("Would you like to run again? (y/n) \n")
scanf("%1s", a);
} while(a[0] !='y' && a[0] !='Y' && a[0]!='n' && a[0]!='N' );
}
答案 1 :(得分:0)
不需要刷新输入缓冲区。
OP使用fgets()
而不是scanf()
进入正确的轨道进行输入,OP应继续使用以下方法:
char a;
while(a !='y' && a !='Y' && a!='n' && a!='N' ) {
printf("Would you like to run again? (y/n) \n");
if (fgets(kbuffer, sizeof(kbuffer), stdin) == NULL)
Handle_EOForIOerror();
int cnt = sscanf(kbuffer, " %c", &a); // Use %c, not %s
if (cnt == 0)
continue; // Only white-space entered
}
最好不要使用scanf()
,因为它试图一次性处理用户IO和解析,并且做得不好。
某些现有OP的问题源于fgets()
之后的scanf(" %s", &a);
(UB应该是scanf(" %c", &a);
。将scanf()
与fgets()
混合通常会出现问题scanf(" %c", &a);
在输入缓冲区中留下 Enter 或'\n'
,迫使代码在下一个fgets()
之前想要输入缓冲区。除此之外fgets()
1}}获取陈旧的'\n'
而不是新的信息行。
仅使用fgets()
用户IO,需要否定刷新。
示例fgets()
包装
char *prompt_fgets(const char *prompt, char dest, long size) {
fputs(prompt, stdout);
char *retval = fgets(dest, size, stdin);
if (retval != NULL) {
size_t len = strlen(dest);
if (len > 1 && dest[len-1] == '\n') { // Consume trailing \n
dest[--len] = '\0';
}
else if (len + 1 == dest) { // Consume extra char
int ch;
do {
ch == fgetc(stdin);
} while (ch != '\n' && ch != EOF);
}
return retval;
}
答案 2 :(得分:0)
我认为你要做的事情比看起来更难。
我对你要做的事情的解释是禁用提前输入类型,这样如果用户在程序处理其他内容时输入某些字符,则它们不会出现在提示符处。这实际上很难做到,因为它是一个操作系统级功能。
在打印提示之前,您可以在设备上执行非阻塞读取,直到您在errno中获得EWOULDBLOCK。或者tcsetattr function family可能有所帮助。看起来有一种方法可以在那里消耗文件描述符的输入,但它可能与fgets / fscanf的交互很糟糕
更好的想法是不要担心它。 Unix用户习惯于预先输入类型,你想要的是他们想要的意外行为。