【问题标题】:Flush out all other characters in input buffer清除输入缓冲区中的所有其他字符
【发布时间】:2014-12-15 23:28:01
【问题描述】:

我正在尝试控制小型控制台应用程序的使用,并且不希望用户键入超过一个字符的任何内容。到目前为止我所拥有的

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

一些需要注意的事情::

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

我不能使用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;
 }

【问题讨论】:

  • std::getline,然后要么检测多个字符并发出一个错误,要么只处理第一个字符并忽略其余字符。
  • getline 不是也有问题吗?
  • 您指的是什么问题?它吸收了直到'\n' 的所有内容,丢弃了'\n' 并向您展示了这条线。如果该行长于单个字符,则您知道您输入了虚假输入。如果它有一个字符并且它不符合您的标准,再次,虚假输入。如果它有一个字符并且满足您的一个匹配项,那么您就可以开始了。也许你在想一些我没有(不太可能)的事情。
  • 好的,是的,我记得问题是getline 然后使用cin &gt;&gt; choicecin.get 在系统暂停后我需要刷新缓冲区,我相信这就是冲突所在,但我在在第一部分用你的决议更新我的问题
  • 我不知道你在说什么。我说的是std::string line; std::getline(cin, line);` 并使用line 来制作我上面描述的内容。 cin &gt;&gt; choicecin.get() 在我所描述的内容中无处。您的代码更新似乎反映了这一点,那么问题是什么?执行此操作后,输入缓冲区不应需要刷新。

标签: c++ buffer main


【解决方案1】:

没有“刷新”std::istream 这样的东西。冲洗是一个输出概念。由于来自控制台的输入有多个缓冲区(std::istreamstd::streambuf 内的输入缓冲区和操作系统 consolde 缓冲区),因此没有可靠的方法来实际删除所有输入字符。您可以通过禁用 concole 的缓冲区来删除所有字符(在 UNIX 上,您可以使用 tcsetattr()tcgetattr() 来清除 ICANON 标志)。

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

  1. 要删除当前的所有字符,您可以使用std::istream::ignore(),其中包含要忽略的最大字符数和停止位置的字符,即'\n' 用于换行。要根据需要匹配尽可能多的字符,您需要传递魔法值 std::numeric_limits&lt;std::streamsize&gt;::max()(一个相当大的值,比如 10000,也可以满足实际需要)。
  2. 您可以使用in.rdbuf()-&gt;in_avail() 找出立即可用的字符的下限。此函数确定在没有流阻塞的情况下可以读取多少个字符。实际上,这是std::istream 的输入缓冲区中的字符数,即类似in.ignore(in.rdbuf()-&gt;in_avail()) 应该删除所有字符。

个人而言,我会使用in.ignore(count, '\n') 和合适的count(我显然会使用std::numeric_limits&lt;std::streamsize&gt;::max(),但您似乎无法使用此功能,可能是因为我目前正在帮助您完成家庭作业)。当然,std:getline() 无论如何都已经读取了整行,也就是说,没有什么可以忽略的。

请注意,您应该始终验证输入操作是否实际成功:

if (std::getline(std::cin, line)) {
    // process successful line
}
else {
    // deal with the input having failed
}

请注意,即使该行为空,输入行也是成功的!在访问第一个字符之前,您应该验证它是否存在,例如,使用 !line.empty()

顺便说一句,正如您提到的clear():实际上并没有忽略任何字符。相反,它会清除流错误标志,即正在测试什么以验证输入是否成功。注意:任何&lt;cctype&gt; 函数的参数必须是unsigned char 加上EOF 的值范围内的非负int。由于char 倾向于被签名,传递任意char,例如strChoice[0] 可能会导致未定义的行为(例如,当传递我的第二个名字的ISO-Latin-1 或UTF-8 表示时)。正常的解决方法是使用

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

【讨论】:

  • 感谢您的这篇文章,它为我打开了很多。是的,这是一项家庭作业,但我从不要求任何人为我写任何东西:)当我看到它时,我讨厌它。当有人提到use this 或其他什么时,我通常可以找出其余的代码。我只是不知道在谷歌中输入什么。谢谢迪特玛 +1
  • @EasyBB:该死!我曾希望在没有投票的情况下接受答案并获得另一个帽子! :-) 当然,由于我进一步改进了答案(指出其他问题),我想,只有很小的机会......
  • 接受您的回答,因为 WhozCraig 尚未发布答案,但你们俩都对我帮助很大。伙计,我忘了帽子!!!
  • @EasyBB Deitmar 写了 solid 的答案,我没有任何问题可以加分(只是因为 Dietmar 已经把帽子丢给了别人的加分 =P)
  • @EasyBB:不用担心 - 这只是一件愚蠢的事情;)我已经收集了比看起来合理的更多的帽子。
【解决方案2】:

最容易修补:替换

cin.ignore(1);

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

#include <limits>

在文件的顶部。这意味着:“忽略流中的所有字符,直到下一个换行符 (\n)”。这是因为

cin.ignore(n, c);

表示“忽略 cin 中的 n 字符,但在找到 c 后停止”,numeric_limits&lt;streamsize&gt;::max()streamsize 类型中的最大值,是 istream::ignore 的特例,它表示无穷大。

这很适合您的用例,因为用户输入通常是基于行的。这比丢弃输入缓冲区要好,因为输入缓冲区中的内容并不总是可预测的(有人可以通过管道将文件传输到您的程序,终端可能会奇怪地缓冲,用户可能是一个非常快速的打字员,等等)。批量丢弃输入缓冲区有时会产生奇怪的结果,但如果您在命令后丢弃该行的其余部分,没人会感到非常惊讶。

【讨论】:

  • 我应该声明不能添加除 string、iomanip、iostream、fstream 和 ctype 之外的任何其他库。
  • 然后写streamsize(size_t(-1) / 2)而不是numeric_limits&lt;streamsize&gt;::max()。它看起来不那么漂亮,但它的意思是一样的。 size_t(-1)size_t 中的最大值(因为size_t 是无符号的),而streamsizesize_t 的签名对应物,所以它的最大值将是它的一半。
  • 仍然不能使用这些,它们可能是 STL 的一部分,但我的教授不接受我们没有学过的功能。相信我,我会因为使用三元而被扣分。我只会获得不需要大学来编码 lmao 的学位。尽管它们的局限性让我跳出框框思考,这是肯定的。对不起队友
  • 然后使用 100000 并完成它。它将涵盖您的所有用例。
  • 哈哈!是的,我会试试这个,但 80 不起作用,因为这是控制台应用程序的大小?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
相关资源
最近更新 更多