要求使用cout/cin进行有效输入

Requiring valid input with cout/cin

本文关键字:cin 有效输入 cout      更新时间:2023-10-16

我有一个游戏,用户需要在一定范围内输入x和y坐标,一次输入一个。现在我的输入代码如下:

do {
    printf("n");
    cout << "X: ";
    cin >> x;
    cout << "Y: ";
    cin >> y;
} while (cin.fail());

我是c++的新手,但阅读文档让我相信这是一种可以接受的验证用户输入的方法。当输入有效时,它可以完美地工作,但当输入是不同类型(例如输入"a")时,它会无限循环使用"X:Y:"。我需要做什么不同的事情才能让它像第一次读取行一样等待用户输入?

您应该检查每一个输入操作:

std::cout << "X: ";
if (!(std::cin >> x)) { /* error */ }
std::cout << "Y: ";
if (!(std::cin >> y)) { /* error */ }

如何处理这个错误取决于你自己。你可以提前返回,打破循环,抛出异常。。。这完全取决于情况。

请注意,可以循环,直到获得可解析的内容,但如果用户关闭输入流,这是危险的。最好逐行阅读并解析:

std::cout << "Please enter an integer X: ";
int x;
bool success = false;
for (std::string line; std::getline(std::cin, line); )
{
    std::istringstream iss(line);
    if (iss >> x >> std::ws && iss.get() == EOF)  // #1
    {
        success = true;
        break;
    }
    std::cout << "Sorry, please try again: ";
}
if (!success)
{
    std::cerr << "Unexpected end of input stream!n";
    std::exit(1);
}

这样,如果用户在会话中间按下[Ctrl]-D,程序会立即关闭,并且不会尝试从关闭的输入流中读取更多的值。

标记为#1的行上的条件既测试整数的成功解析,也测试是否已到达行的末尾(吞噬中间空白)。

尝试解析每个变量的最大问题是,当用户犯了错误时,他们的整个输入都会受到怀疑。

考虑是否跳过无效输入并输入:"3e4 40"。我的意思是"34 40",但跳过e可能会变成"3 4",然后留下"40",或者可能留下"4 40"。

考虑使用getline读取整行,并像现在一样使用istringstream对其进行解析——任何错误都会变成错误,而不会使输入流处于奇怪的状态。