为什么在C++中输入“|”会导致代码进入无限循环?

3

我正在阅读《使用C++编程:原理与实践》(第二版)
我发现了这个问题:

  • 编写一个程序,其中包含一个while循环,每次循环都会读取两个整数,然后打印它们。当输入终止符“|”时退出程序。

以下是我的尝试:

#include <iostream>
using namespace std;
int main () {
int x, y;
while (x != '|' || y != '|'){
    cin >> x;
    cin >> y;
    cout << x << endl;
    cout << y << endl;
}

return 0;
}

输入 '|' 时,会出现类似于无限循环和意外输出的情况。

  • 发生了什么?
  • 我做错了什么?

3
你的代码中写着“当 x 不等于 '|' 或者 y 不等于 '|' 时......”,这意味着只有当两个变量都是 '|' 时,循环才会停止。 - eesiraed
2
另外,xy是整数,不是字符。它们不能是'|'。在输入之前使用cin.peek()检查'|'。 - eesiraed
6
你的代码存在未定义行为:你试图使用 xy,但没有将它们初始化为任何值。 - Tas
@FeiXiang,题目要求读取两个整数,使用 while 循环。不是字符串,先生。 - Darin Benas
4
请使用&&替代||,并考虑使用do...while循环。 - Remy Lebeau
显示剩余5条评论
3个回答

5
首先,在while循环中比较' | '之前,您尚未将x或y设置为任何值。这意味着它们可能具有任意值,而您的循环甚至可能不会开始。
至于为什么会看到无限循环,因为变量的类型为int,cin>>something将尝试将输入的字符转换为整数并放入变量中。
如果这些字符的初始序列不形成有效的整数(例如,它是'|'字符),则cin>>将失败,变量将保持不变,输入流将保持不变。
因此,当您再次获取下一个整数时,|仍然在输入流中,完全相同的事情会一遍又一遍地发生-请注意拉丁短语与您的问题标题之间的相似之处:-)
要解决这个问题,您可以尝试通过逐个字符查看来查看流中是否有|。如果是,请退出。如果没有,请尝试使用正常的if(stream>>variable)方法获取两个整数。
这可以使用cin.peek()检查下一个字符,以及cin.get()删除字符来完成。您还必须考虑到peek和get都不会跳过空格,就像operator>>可能会做的那样。
类似以下内容应该是一个好的开始:
#include <iostream>
#include <cctype>

int main() {
    int x, y;

    while (true) {
        // Skip all white space to (hopefully) get to number or '|'.

        while (std::isspace(std::cin.peek())) std::cin.get();

        // If it's '|', just exit, your input is done.

        if (std::cin.peek() == '|') break;

        // Otherwise, try to get two integers, fail and stop if no good.

        if (! (std::cin >> x >> y)) {
            std::cout << "Invalid input, not two integers\n";
            break;
        }

        // Print the integers and carry on.

        std::cout << "You entered " << x << " and " << y << "\n";
    }

    return 0;
}

使用各种测试数据,证明它涵盖了我能想到的所有情况:

pax$ ./myprog </dev/null
Invalid input, not two integers

pax$ echo hello | ./myprog
Invalid input, not two integers

pax$ echo 1 | ./myprog
Invalid input, not two integers

pax$ echo 1 2 | ./myprog
You entered 1 and 2
Invalid input, not two integers

pax$ printf '1 2|' | ./myprog
You entered 1 and 2

pax$ printf '1 2\n3 4\n5     6 7   8   \n|' | ./myprog
You entered 1 and 2
You entered 3 and 4
You entered 5 and 6
You entered 7 and 8

pax$ printf '1 10     11   12   13    14    |   ' | ./myprog
You entered 1 and 10
You entered 11 and 12
You entered 13 and 14

对不起,我不知道什么是测试数据。我是个初学者,先生。 - Darin Benas
@DarinBenas,测试数据就是用来测试你的程序的数据 :-) 最后一节展示了各种测试案例(输入由echoprintf语句提供给程序)。你 可以 运行程序并自己输入这些值,但通常自动化测试更加有用。 - paxdiablo

3

正如评论区和paxdiablo的答案指出的那样,您的两个变量未初始化,您正在尝试将其输入到int中,然后将其与char进行比较。

我们可以使用cin.peek()来查看下一个字符并检查它是否为'|',而不是尝试将输入的int与char进行比较。

#include <iostream>
int main()
{
    int x, y;
    while(std::cin.peek() != '|') //cin.peek() will return the next character to be read
    {
        std::cin >> x >> y;
        std::cout << x << ' ' << y << '\n';
        std::cin.ignore(); //ignore whitespace/linebreak character left by extraction (>> operator)
    }
}

应该检查 cin 的状态。对于非整数输入,这是一个无限循环。顺便说一下,我不是那个给你点踩的人.... - llllllllll
仅为完整起见,您可能希望查看空格处理。问题在于peek不会跳过空格行,而cin >> someInt会跳过,因此输入<space>|将导致问题。您的答案(包括一个字符的ignore)似乎假定没有多余的空格。此外,不检查cin >>的结果以确保它已工作(与在C中检查scanf的返回值相同)通常不是一个好主意。 - paxdiablo
@paxdiablo 我通常假设我的示例程序中输入格式正确,否则你会得到一些不太相关的代码,这会让人们感到困惑。例如,OP可能不理解为什么 if(!(cin >> x)) 检查输入是否失败。对于其他程序,这可能是检查输入是否在范围内的代码。这只是我的个人意见。 - eesiraed

-1

因为你将 x 和 y 定义为整数,但你输入的是字符。 尝试使用以下代码

#include <iostream>
using namespace std;
int main ()
{
    char x=NULL, y=NULL;
    while (x != '|' || y != '|')
    {
        cin >> x;
        cin >> y;
        cout << x << endl;
        cout << y << endl;
    }

    return 0;
}

但它也有限制。您只能将输入作为单个数字处理。如果您想输入大量数字,请尝试这个。

#include <iostream>
using namespace std;
int main ()
{
    string  x="", y="";
    while (x != "|" || y != "|")
    {
        cin >> x;
        cin >> y;
        cout << x << endl;
        cout << y << endl;
    }

    return 0;
}

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