刷新输入缓冲区中的所有其他字符

时间:2014-12-15 23:28:02

标签: c++ buffer main

我正在尝试控制小型控制台应用程序的使用,并且不希望用户键入任何多个字符。到目前为止我有什么

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,它说除了输入缓冲区中的回车之外什么也没有。

以上是我的主要内容。我将向您展示确定选择函数和错误处理函数。

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");
   }
}

有些事情需要注意::

我只能使用系统(所以请不要告诉我它的糟糕或资源匮乏!)

我无法使用fflush或除cin.clear()之外的任何冲洗

除了iostreamiomanipfstreamstringctype.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;
 }

2 个答案:

答案 0 :(得分:2)

最容易打补丁:替换

cin.ignore(1);

cin.ignore(numeric_limits<streamsize>::max(), '\n');

#include <limits>

位于文件顶部。这意味着:&#34;忽略流中的所有字符,直到下一个换行符(\n)&#34;。这是因为

cin.ignore(n, c);

表示&#34;忽略来自cin的n个字符,但在找到c后停止,&#34;并且numeric_limits<streamsize>::max()streamsize类型中的最大值,istream::ignore是{{1}}的特殊情况,它表示无穷大。

这对您的用例很有效,因为用户输入通常是基于行的。它比丢弃输入缓冲区更好,因为输入缓冲区中的内容并不总是可预测的(某人可能会将文件传输到您的程序,终端可能会奇怪地缓冲,用户可能是一个非常快速的打字员,除其他外)。丢弃输入缓冲区有时会产生奇怪的结果,但是如果你在命令之后丢弃其余部分,没有人会非常惊讶。

答案 1 :(得分:2)

没有&#34;冲洗&#34; std::istream。 Flushing是一种输出概念。由于有多个缓冲区用于从控制台输入(std::istream&#39; s std::streambuf内的输入缓冲区和操作系统consolde缓冲区),因此没有可靠的方法来实际摆脱所有输入字符。您可以通过禁用concole的缓冲区来删除所有字符(在UNIX上,您使用tcsetattr()tcgetattr()清除ICANON标志。

对你来说应该足够好的方法是忽略当前行上的所有字符或删除输入缓冲区中的所有字符:

  1. 要删除当前所有字符,请使用std::istream::ignore(),其中包含要忽略的最大字符数以及要停止的字符,即换行符为'\n'。为了匹配所需数量的字符,你可以传递神奇的值std::numeric_limits<std::streamsize>::max()(一个相当大的值,比如10000,也可以满足实际需要)。
  2. 您可以使用in.rdbuf()->in_avail()找到可立即使用的下限字符。此函数确定在没有流阻塞的情况下可以读取多少个字符。实际上,这是std::istream输入缓冲区中的字符数,即in.ignore(in.rdbuf()->in_avail())之类的内容应删除所有字符。
  3. Pesronally,我会使用in.ignore(count, '\n')并使用合适的count(我明显使用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()

    BTW,正如您所提到的clear():实际上并没有忽略任何字符。相反,它清除流错误标志,即正在测试以验证输入是否成功的标志。在记录时:任何<cctype>函数的参数必须是intunsigned char值范围内的非负EOF。由于char往往被签名,传递任意char,例如strChoice[0]可能会导致未定义的恶作剧(例如,当传递我的第二个的ISO-Latin-1或UTF-8表示时)名称)。正常的解决方法是使用

    std::toupper(static_cast<unsigned char>(strChoice[0]))