我正在尝试控制小型控制台应用程序的使用,并且不希望用户键入超过一个字符的任何内容。到目前为止我有什么
int main()
{
char choice;
string strChoice;
/*Set the title bar title to Binary Calculator*/
system("title Binary Calculator 2014");
do{
Menu();
getline(cin,strChoice);
choice = toupper(strChoice[0]); //convert value to uppercase for conformity
DetermineChoice(choice);
} while (mistakes < 3);
}
但是当我打字时
bbbbbbbb
屏幕像地狱一样出错(我相信这是由 do while 循环引起的(,所以我只需要刷新除第一个字符之外的所有字符。同样,当我第一次选择程序运行时B
,然后我返回并尝试再次选择B
它说我在输入缓冲区中除了回车符之外什么都没有。
以上是我的 int main。我将向您展示确定选择函数和错误处理函数。
void DetermineChoice(char value)
{
/*
Purpose: Determine what character was passed to value
Pre: a hopefully valid character
Post: Will go through cases below and then pass to another function
*/
string binary;
int decimal;
switch (value)
{
case 'B':
case 'C':
ConversionOperation(value);
case 'P':
cout << "Process File" << endl;
break;
case '+':
case '-':
case '/':
case '*':
case '%': ArithmeticActions(value);
case 'Q':
PrintSummary();
break;
default:
HandleChoiceError(value);
break;
}
}
选择错误:
void HandleChoiceError(char value)
{
/*
Purpose: Handles the errorenous character passed
Pre: an invalid character
Post: Will output the error, pausing the screen then reprint the menu
*/
system("cls");
mistakes++;
cout << setw(40) << "The option you selected (" << value << ") is not a valid choice." << endl;
cout << setw(25) << "You have made " << mistakes << " mistake" << (mistakes > 1 ? "s" : "") <<" becareful only three allowed!" << endl;
cout << setw(60) << "Please press enter and try again" << endl;
if (mistakes < 3)
{
system("pause");
}
}
需要注意的一些事项:
我只能使用系统(所以请不要告诉我这是糟糕的或资源消耗!
除了cin.clear()
之外,我不能使用fflush
或任何冲洗
除了iostream
、iomanip
、fstream
、string
和ctype.h
之外,我不能使用任何其他库
谢谢大家,我现在程序可以正常工作。
int main()
{
char choice;
string strChoice;
/*Set the title bar title to Binary Calculator*/
system("title Binary Calculator 2014");
do{
Menu();
if ( getline(cin, strChoice) )
{
choice = toupper(strChoice[0]);
DetermineChoice(choice);
cin.ignore(10000, 'n');
}
else
{
cout << "Something went wrong with the input, please restart the program and try again." << endl;
break;
}
} while (mistakes < 3);
return 0;
}
没有"冲洗"std::istream
这样的事情。冲洗是一个输出概念。由于控制台输入有多个缓冲区(std::istream
std::streambuf
内的输入缓冲区和操作系统的 consolde 缓冲区(,因此没有可靠的方法来实际删除所有输入字符。您可以通过禁用 concole 的缓冲区来删除所有字符(在 UNIX 上,您将使用 tcsetattr()
和 tcgetattr()
来清除 ICANON
标志(。
您的需求来说,应该足够好的方法是忽略当前行上的所有字符或删除输入缓冲区中的所有字符:
- 要删除当前的所有字符,请使用具有要忽略的最大字符数和停止字符的
std::istream::ignore()
,即换行符的'n'
。为了根据需要匹配尽可能多的字符,您需要传递魔术值std::numeric_limits<std::streamsize>::max()
(一个相当大的值,例如 10000,也可以满足实际需求(。 - 您可以使用
in.rdbuf()->in_avail()
找到立即可用的字符下限。此函数确定可以在不阻塞流的情况下读取多少个字符。实际上,这是std::istream
输入缓冲区中的字符数,即像in.ignore(in.rdbuf()->in_avail())
应该删除所有字符。
从角度来说,我会使用带有合适count
的in.ignore(count, 'n')
(我显然会使用std::numeric_limits<std::streamsize>::max()
但似乎你不能使用此功能,可能是因为我目前正在帮助您完成家庭作业(。当然,无论如何,std:getline()
已经阅读了整行,也就是说,没有什么可以忽略的。
请注意,您应始终验证输入操作是否成功:
if (std::getline(std::cin, line)) {
// process successful line
}
else {
// deal with the input having failed
}
请注意,即使行为空,该行的输入也是成功的!在访问第一个字符之前,您应该验证它是否存在,例如,使用 !line.empty()
。
顺便说一句,正如你clear()
提到的:这实际上并没有忽略任何字符。相反,它会清除流错误标志,即正在测试的内容以验证输入是否成功。在笔记上时:任何<cctype>
函数的参数必须是 unsigned char
加 EOF
的值范围内的非负int
。由于char
倾向于被签名,因此传递任意char
,例如,strChoice[0]
会导致未定义的行为(例如,当传递我的第二个名字的ISO-Latin-1或UTF-8表示时(。正常的解决方法是使用
std::toupper(static_cast<unsigned char>(strChoice[0]))
最容易修补:替换
cin.ignore(1);
跟
cin.ignore(numeric_limits<streamsize>::max(), 'n');
和
#include <limits>
在文件的顶部。这意味着:"忽略流中的所有字符,直到下一个换行符(n
("。这是因为
cin.ignore(n, c);
表示"忽略 Cin 中的n
字符,但在找到c
后停止",numeric_limits<streamsize>::max()
是 streamsize
类型中的最大值,也是表示无穷大istream::ignore
的特殊情况。
这将很好地适用于您的用例,因为用户输入通常是基于行的。这比丢弃输入缓冲区要好,因为输入缓冲区中的内容并不总是可预测的(有人可以通过管道将文件传送到您的程序,终端可能会奇怪地缓冲,用户可能是一个非常快速的打字员,等等(。批量丢弃输入缓冲区有时会产生奇怪的结果,但如果在命令后丢弃该行的其余部分,没有人会感到非常惊讶。