在 C 中刷新标准输入缓冲区
Flushing standard input buffer in C
此代码是我正在处理的一个较大项目的简化版,它在一个简单示例中总结了问题。我从用户那里获取输入,他们的名字,然后从任何不适合 C 字符串的输入中清除缓冲区。问题是在输入名称后,用户必须按两次 enter 才能让程序响应,而且因为我使用 getchar() 来刷新缓冲区,所以我创建的循环逻辑中存在明显的误解。如何防止用户输入两次 Enter,换句话说我错过了什么?谢谢!
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#define BUFFSIZE 10
int main(void)
{
unsigned char name[BUFFSIZE];
printf("ENTER YOUR NAME: ");
fgets(name, BUFFSIZE, stdin);
name[strcspn(name, "\n")] = '[=10=]';
//flush the input buffer
int flush;
while (flush = getchar() != '\n' && flush != EOF);
printf("Your name is: %s!\n ", name);
printf("Press enter to continue...");
getchar();
return 0;
}
我只是阅读你的代码的疯狂猜测是错误在这里:
while (flush = getchar() != '\n' && flush != EOF);
您想 getchar()
直到输出缓冲区为 '\n' 或 EOF,对吗?然后试试这个:
while (flush = getchar() != '\n' || flush != EOF);
首先,如果没有余数,则不要消耗该行的余数,否则将跳过额外的一行。其次,赋值的优先级低于大多数操作,这意味着 flush =
在
之后计算
getchar() != '\n' && flush != EOF
.
比较赋值时的结果时应添加显式括号:
flush = getchar() != '\n'
到 (flush = getchar()) != '\n'
或者,可以将赋值移动到条件之外,见下文。
以下编辑使用 strlen
获取最后一个字符,并将赋值移动到循环中。
#include <stdio.h>
#include <string.h>
#define BUFFSIZE 10
int main(int argc, char *argv[])
{
char name[BUFFSIZE];
size_t len;
int c;
printf("ENTER YOUR NAME: ");
fgets(name, BUFFSIZE, stdin);
len = strlen(name);
if (name[len - 1] == '\n')
name[len - 1] = '[=10=]';
else
do
c = getchar();
while (c != '\n' && c != EOF);
printf("Your name is: %s!\n ", name);
printf("Press enter to continue...");
getchar();
return 0;
}
您的程序中的问题是您没有区分这两种情况:a) 用户的输入适合缓冲区,而 b) 输入不适合。这些情况的区别在于缓冲区中存在换行符。当您覆盖该字符时,该信息将被破坏:
fgets(name, BUFFSIZE, stdin);
name[strcspn(name, "\n")] = '[=10=]';
我们这里需要的是:
size_t nlcspn = strcspn(name, "\n");
bool incomplete = name[nlcspn] == 0;
name[nlcspn] = 0;
现在我们有一个 incomplete
标志要测试。只有当这个标志通知输入不包含换行符时,我们才能继续完成 fgets
的 "get line" 操作,用一个小循环扫描直到收到换行符。 (在那种情况下,一些错误恢复可能也是一个好主意,比如通知用户输入太长,并创造机会纠正它)。
另一件需要注意的事情是 fgets
returns 一个应该检查的值。如果它 returns 是一个空指针,则意味着流在任何输入被消耗之前就结束了。问题是在这种情况下,fgets
不会将任何内容放入数组中。该数组保留其先前的值,该值可能是先前读取的输入,或者由于未初始化的内容而不确定的值("garbage")。
此代码是我正在处理的一个较大项目的简化版,它在一个简单示例中总结了问题。我从用户那里获取输入,他们的名字,然后从任何不适合 C 字符串的输入中清除缓冲区。问题是在输入名称后,用户必须按两次 enter 才能让程序响应,而且因为我使用 getchar() 来刷新缓冲区,所以我创建的循环逻辑中存在明显的误解。如何防止用户输入两次 Enter,换句话说我错过了什么?谢谢!
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#define BUFFSIZE 10
int main(void)
{
unsigned char name[BUFFSIZE];
printf("ENTER YOUR NAME: ");
fgets(name, BUFFSIZE, stdin);
name[strcspn(name, "\n")] = '[=10=]';
//flush the input buffer
int flush;
while (flush = getchar() != '\n' && flush != EOF);
printf("Your name is: %s!\n ", name);
printf("Press enter to continue...");
getchar();
return 0;
}
我只是阅读你的代码的疯狂猜测是错误在这里:
while (flush = getchar() != '\n' && flush != EOF);
您想 getchar()
直到输出缓冲区为 '\n' 或 EOF,对吗?然后试试这个:
while (flush = getchar() != '\n' || flush != EOF);
首先,如果没有余数,则不要消耗该行的余数,否则将跳过额外的一行。其次,赋值的优先级低于大多数操作,这意味着 flush =
在
之后计算
getchar() != '\n' && flush != EOF
.
比较赋值时的结果时应添加显式括号:
flush = getchar() != '\n'
到 (flush = getchar()) != '\n'
或者,可以将赋值移动到条件之外,见下文。
以下编辑使用 strlen
获取最后一个字符,并将赋值移动到循环中。
#include <stdio.h>
#include <string.h>
#define BUFFSIZE 10
int main(int argc, char *argv[])
{
char name[BUFFSIZE];
size_t len;
int c;
printf("ENTER YOUR NAME: ");
fgets(name, BUFFSIZE, stdin);
len = strlen(name);
if (name[len - 1] == '\n')
name[len - 1] = '[=10=]';
else
do
c = getchar();
while (c != '\n' && c != EOF);
printf("Your name is: %s!\n ", name);
printf("Press enter to continue...");
getchar();
return 0;
}
您的程序中的问题是您没有区分这两种情况:a) 用户的输入适合缓冲区,而 b) 输入不适合。这些情况的区别在于缓冲区中存在换行符。当您覆盖该字符时,该信息将被破坏:
fgets(name, BUFFSIZE, stdin);
name[strcspn(name, "\n")] = '[=10=]';
我们这里需要的是:
size_t nlcspn = strcspn(name, "\n");
bool incomplete = name[nlcspn] == 0;
name[nlcspn] = 0;
现在我们有一个 incomplete
标志要测试。只有当这个标志通知输入不包含换行符时,我们才能继续完成 fgets
的 "get line" 操作,用一个小循环扫描直到收到换行符。 (在那种情况下,一些错误恢复可能也是一个好主意,比如通知用户输入太长,并创造机会纠正它)。
另一件需要注意的事情是 fgets
returns 一个应该检查的值。如果它 returns 是一个空指针,则意味着流在任何输入被消耗之前就结束了。问题是在这种情况下,fgets
不会将任何内容放入数组中。该数组保留其先前的值,该值可能是先前读取的输入,或者由于未初始化的内容而不确定的值("garbage")。