如何在C++中在遇到EOF停止输入流后恢复输入流?

6

我想写一个程序,从终端接收两组整数输入,并计算出两个和。我的意图是通过EOF(按下Ctrl + D)来分离这两组输入。以下是我的代码:

#include <iostream>
using namespace std;

int main(){
    int i,sum=0;
    while((cin>>i).good())
        sum+=i;
    cout<<"Sum 1 is "<<sum<<endl;
    cin.clear();
    sum=0;
    while((cin>>i).good())
        sum+=i;
    cout<<"Sum 2 is "<<sum<<endl;
    return EXIT_SUCCESS;
}

第一个整数输入后,编译程序表现良好。但是当我按下Ctrl+D键后,第一个和被计算并输出了,然后程序没有再接受任何输入,直接将第二个和输出为0。所以基本上第二个while循环在一开始就失败了,尽管cin.iostate在之前被设置为good了。那么这是为什么呢?我该如何更改程序使第二个while循环能够正常运行呢?


@KerrekSB OP正在使用std::cin.clear()将流重置为良好状态,但他还需要使用std::cin.ignore()清除缓冲区,以便在EOF后继续使用该流,对吗? - Manu343726
不要测试 std::cin.good(),因为它会导致最后一行被忽略,例如当最后一行缺少行终止符时。只需使用 while(std::cin >> I)。然而,这种更改并不能解决你的问题。 - Dietmar Kühl
1
@Manu343726:Ctrl-D将关闭标准输入,没有恢复的方法。您需要防止Ctrl-D关闭流。 - Dietmar Kühl
1个回答

10
当你在规范模式下使用Ctrl-D时,会关闭系统级别的管道。无论你对std::cin做什么都不能将流恢复到良好的状态。如果你坚持使用Ctrl-D来表示序列的结束(这是一种不寻常的界面,最好避免),则需要使用tcgetattr()tcsetattr()清除标准输入流(文件描述符0)中的ICANON标志。你将需要处理任何控制字符。
最简单的方法是读取到第一个失效点,调用clear()函数来清除状态,并忽略有问题的字符或检查它们是否具有特定的值。

我曾尝试使用无效输入(例如输入字符而不是整数)来终止第一个循环,结果与按下Ctrl+D的效果相同。这是由于与Ctrl+D相同的原因吗? - God_of_Thunder
3
@God_of_Thunder: 不会。当您输入无效字符时,它会导致std::ios_base::failbit被设置,从而被clear()。但是,该字符将保留在那里,直到其被消耗。您需要摆脱该字符,例如使用std::cin.ignore()。如果有多个[非空格]字符,则可能需要ignore()所有这些字符。 - Dietmar Kühl
clear()仅重置iostate中的位,而不是恢复输入流?听起来并不太有帮助。 - God_of_Thunder
1
@雷神:clear() 不知道如何从失败的输入中恢复。实际上,您可能希望以其他方式使用遇到的字符,例如,确认遇到的字符是“end”以指示第一组数据的结尾。 - Dietmar Kühl

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