而当 CIN 的输入是'dot'时循环到无穷大

while loop to infinity when the input of a cin is a 'dot'

本文关键字:循环 无穷大 dot CIN 而当 输入      更新时间:2023-10-16

我在使用cin方法获取变量时遇到了麻烦。当输入的是数字时没有问题,但是当输入的是像点[.]这样的特殊字符时,while循环循环到无限远。我做错了什么?

cout << "What is your race" <<endl<<"1.Humann2.trolln3.zombie"<<endl;
    cin >> *race;
    while(*race<1||*race>3)
    {
    system("cls");
    cout << "Wrong choice"<<endl<< "What is your race" <<endl<<"1.Humann2.trolln3.zombie"<<endl;
    cin >> *race;
    }

我搜索了答案,我应该刷新缓冲区,但我不知道如何做到这一点。我对c++还是个新手。谢谢

race设置为字符,然后您将能够:

while (*race < '1' || *race > '3')

这可能就是你想要达到的目标。

解释:

当您将cin >>转换为int时,它将给定的ASCII字符串转换为整数值。.不具有整数意义,因此它不被读取到racefailbit被设置-进一步>>s是无操作的,直到您清除它们。但是,如果您将cin >>转换为char并将其与其他char进行比较(实际上是它们的ASCII码),您将能够轻松检查它。

这个例子完全再现了你的问题:

#include <iostream>
int main()
{
    int i = 5;
    while (i < 1 || i > 3)
    {
        std::cin >> i;
    }
}

的情况如下:当operator>>读取整数失败时(例如,当您键入点并按enter键时),您键入的将保留在流中,包括换行符。所以在while循环的下一次迭代中,下一个输入已经在那里了,因为它不是一个有效的整数,所以循环永远不会中断。您需要确保,当operator>>失败时,清空流并清除已设置的所有错误标志。

#include <iostream>
#include <limits>
int main()
{
    int i = 5;
    while (i < 1 || i > 3)
    {
        if (!(std::cin >> i))
        {
            // clear streams internal error flags
            std::cin.clear();
            // ignore what's left in the stream, up to first newline character
            // or the entire content, whichever comes first
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), 'n');
        }
    }
}

您的代码有几个问题。第一种是你不知道验证您的输入是否成功;的正确条件while应为:

while ( !cin || (*race < 1 || *race > 3) )

如前所述,如果输入失败(这就是当您输入'.'(假设race的类型为int*),然后输入*race包含前一个值,无论前一个值是什么。

第二个是,如果你从cin得到一个错误,你不清除它。一旦流处于错误状态,它就会一直保持这种状态,直到您明确地清除它。如果cin失败,则需要执行:

cin.clear();

在循环的某个地方

第三个是,如果cin失败,则不提取其中的字符使其失败,以便清除错误状态后,您需要提取它。考虑到你组织对话的方式,你可能想要忽略行尾之前的所有内容:

cin.ignore( INT_MAX, 'n' );

即使cin在循环中没有失败,您也可能想要这样做(如果由于*race < 1 || *race > 3条件而输入),或在成功的案例。或者,你可能想要转向读行,并确保该行只包含字符后面的空白

我将采用最后一个解决方案,因为它处理得很好很多以上的问题。所以我的代码看起来像这样:

//  return -1 on error in input,
//  throw exception on (unexpected) end of file
int
getRace( std::istream& source )
{
    std::string line;
    if ( !std::getline( source, line ) ) {
        throw std::ios_base::failure( "Unexpected end of file" );
    }
    std::istringstream tmp( line );
    int results;
    return tmp >> results >> std::ws && tmp.get() == EOF
        ? results
        : -1;
}
//  ...
int race = -1;
while ( race < 0 ) {
    std::cout << "What is your racen"
                 "1. Humann"
                 "2. Trolln"
                 "3.  Zombien" << std::flush;
    race = getRace( std::cout );
    if ( race < 0 ) {
        std::cout << "Wrong choice" << std::endl;
    }
}

注意,通过一行输入,可以避免任何问题重置格式错误,跳过错误输入或重新同步

除了接受的解决方案之外,另一种解决方案是清除cin的failbit并忽略最后的输入,如下所示:

cout << "What is your race" <<endl<<"1.Humann2.trolln3.zombie"<<endl;
cin >> *race;
while(*race<1||*race>3)
{
    // Clears the state of cin to be in good state
    cin.clear();
    // Ignores the last input read so that it's not read back again
    cin.ignore();
    system("cls");
    cout << "Wrong choice"<<endl<< "What is your race" <<endl<<"1.Humann2.trolln3.zombie"<<endl;
    cin >> *race;
}