C++中while循环中的cout打印两次

3
我从Bjarne Stroustrup的C++编程:原理与实践中改编了这段代码,以尝试检查所给的输入是否有效:
#include <iostream>
using namespace std;

int main()
{
    cout << "Please enter your first name and age: ";
    string first_name = "???";
    int age = -1;
    cin >> first_name >> age;

    while (!cin) {
        cin.clear();
        cout << "Sorry, can you enter that again? ";
        cin >> first_name >> age;
    }

    cout << "Hello, "<<first_name<<"! (age "<<age<<")\n";
    return 0;
}  

这个代码的运行结果符合预期,只是单词“Sorry, can you enter that again? ”被打印了两次,一次在第二个输入之前,一次在之后。请问有人知道为什么会出现这种情况吗?谢谢。

我在Visual Studio 2010中测试过了,按照预期运行正常。你使用哪个编译器进行编译? - EddieBytes
在 Ubuntu x64 上测试过 gcc 4.6.3,确实打印了两次,非常奇怪 :S - SingerOfTheFall
2个回答

3

仅仅清除失败标记是不够的, 您还需要清除输入缓冲区中剩余的任何字符. 此外, 代码看起来比必要的更加复杂. 下面的代码可以解决这个问题:

std::string name;
int age;

std::cout << "Please enter your name & age: ";

while (not (std::cin >> name >> age)) {
    std::cout << "Sorry, can you enter that again? ";
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

std::cout << "Hello " << name << " (" << age << ")\n";

哦,对了,不要忘记刷新输出流,我认为这不会自动为您完成。

话虽如此,标准输入/输出流是“流式”的,因此它们并不适合交互式输入。您应该使用适当的库,例如readlinencurses

为了说明这一点的重要性,请想象用户输入“foo42”并按返回键。您希望程序现在说“抱歉,请再输入一次”,但它没有。相反,它顺从地等待用户输入第二个标记。从可用性的角度来看,这绝对不是您所期望的。


1
默认情况下,std::cinstd::cout 相关联,因此对 std::cin 的任何输出都会自动刷新 std::cout - James Kanze
@James 哦,好的,知道了。你是在说“默认”……我怎么改呢?/编辑 找到了,ios :: tie - Konrad Rudolph

1

这取决于您输入了什么!

  • 输入"Tim 29":可以,输出"Hello Tim(29)"。

  • 输入"Tim Tom 29":可以,有一个重复,输出"Hello Tom(29)"。

  • 输入"Tim Tom Tina 29":可以,有两个重复,输出"Hello Tina(29)"。

我假设您正在尝试第三种情况。第一个失败的是Tom,因为他不是数字。重置错误状态没问题,但它并没有消除Tom。我们仍然需要再次失败才能消耗掉他(在那时,Tina已经不是数字)。只有这样,我们才准备好处理Tina


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接