3

以下代码打印相同的结果 - 两次 (!)(使用 Microsoft Visual C++ 2010 IDE)。我还打印了每个变量的最终值以查看发生了什么,实际上有两组值满足if语句条件。

我的问题是,因为指令是break;如果条件评估为 TRUE,任何人都可以解释一下我是如何/为什么在我没有要求的情况下得到这两个结果的(不是说这是一件坏事,只是想理解)?这是if构造的一部分还是与循环有关?如果条件不止一次评估为 TRUE,似乎某些东西知道返回多个解决方案,我只是不明白当指令没有明确说明这样做时它是如何做到这一点的(除非有内置的东西-我不知道)。

基本上,为什么循环没有在break;满足条件后立即结束,或者我是否以错误的方式思考这个问题?

同样,如果有人知道或者我在这里遗漏了一些基本的东西,请告诉我!我是 C++ 新手,所以只是想学习,提前谢谢你。

这是代码:

#include "stdafx.h"
#include <iostream>     

int main()
{
    for (int a = 1; a < 500; ++a)
    {
        for (int b = 1; b < 500; ++b)
        {
            for (int c = 1; c < 500; ++c)
            {
                if ((a + b + c) == 1000 && ((a*a + b*b) == (c*c)))
                {
                 cout << "The product abc = " << a*b*c << endl << "a = " << a << ", b = " << b << ", c = " << c << endl;
                 break;
                }
            }
        }
    }
    cout << endl << "Loop terminated";

    char d;
    cin >> d;
    return 0;
}

控制台输出如下:

产品 abc = 31875000

a = 200,b = 375,c = 425

产品 abc = 31875000

a = 375,b = 200,c = 425

循环终止

4

7 回答 7

5

break唯一的突破内部循环,所以外部循环继续执行。

一种可能性是将该代码移动到一个单独的函数中,并在您第一次找到匹配项时从该函数返回。然后(除非您再次调用该函数)该代码的执行将完全停止。

我也会c完全消除循环。唯一有意义的值c1000 - (a+b),因此您不妨直接计算它,而不是遍历 500 个不同的值来找到它。

于 2013-04-22T05:04:42.213 回答
0

正如许多人已经说过的那样,break只能突破最里面的循环。

某些语言提供了解决此问题的方法。Ada 肯定有一种方法来命名每个循环,它最接近的等价于 break, exit when <condition>;, 也可以写成exit <loopname> when <condition>;。IIRC C# 也可能对此有特殊的语法。

在 C++ 中,您的选择是...

  1. 使用goto而不是break. 将目标标签放在最外层循环之后。

  2. throw跳出循环的异常,所有嵌套循环都嵌套在try块内。

  3. 根本不要跳出循环。取而代之的是,有一个标志done或类似的东西来指示您何时完成。检查所有循环的条件。

  4. 正如Jerry Coffin所说,使用将循环移动到一个单独的函数并使用return(不知道我怎么错过了那个!)。

纯粹主义者可能会更喜欢 3,并在 2 上有一个选项。特别是,唯一不违反结构化编程的“单出口原则”的选项是 (3),但break无论如何也违反了该原则。就个人而言,我更喜欢 1 因为它产生的混乱更少(假设您使用它的功能很小,并且在goto视觉上很明显)它更具可读性。

goto通常避免使用,这是有充分理由的。很多人完全禁止它们,这是不合理的,但那些人可能会考虑breakcontinue成为“隐藏的 goto”并禁止它们(当然,除了breakswitch声明中)。无论如何,结果,你甚至可能不知道这goto是可能的。

goto 这里有语法的描述- 基本上goto <labelname>;labelname:.

于 2013-04-22T05:21:47.637 回答
0

所以 - 你听说这break;不是解决方案 - 但什么是解决方案?

如果您将每个循环的限制(当前为 500)设为变量,例如

int myLim = 500;

并将每个for循环条件替换为

for (int a = 1; a < myLim; ++a)
    {
        for (int b = 1; b < myLim; ++b)
        {
            for (int c = 1; c < myLim; ++c)
            {

然后,而不是break你说myLim = -1- 你会打破所有的循环。

a=500注意 - 一些编译器会在你设置和满足条件b=500时皱眉if,因为你正在修改循环变量;但如果你改变条件,没人会介意。它比添加标志更清洁,但仍然有点黑客。

于 2013-04-22T05:07:38.737 回答
0

break语句只中断最里面的循环,您可能需要使用标志在中断的情况下退出其他循环

#include "stdafx.h"
#include <iostream>     

int main()
{
bool flag = false;
for (int a = 1; a < 500; ++a)
{
    for (int b = 1; b < 500; ++b)
    {

        for (int c = 1; c < 500; ++c)
        {
            if ((a + b + c) == 1000 && ((a*a + b*b) == (c*c)))
            {
             cout << "The product abc = " << a*b*c << endl << "a = " << a << ", b = " << b << ", c = " << c << endl;            
             flag = true;
             break;
            }
        }

        if(flag)
        { break; }
    }

    if(flag)
    { break; }
}
cout << endl << "Loop terminated";

char d;
cin >> d;
return 0;

}

于 2013-04-22T05:05:27.113 回答
0

您使用的break只是打破了大多数内部for循环而不是所有循环。

使用标志及其and条件for

bool found = false;
for (int a = 1; a < 500 && !found; ++a)
{
    for (int b = 1; b < 500 && !found; ++b)
    {
        for (int c = 1; c < 500 && !found; ++c)
        {
            if ((a + b + c) == 1000 && ((a*a + b*b) == (c*c)))
            {
             cout << "The product abc = " << ....
             found = true;
            }
        }
    }
}

甚至你可以goto 礼貌地使用!

for (int a = 1; a < 500; ++a)
{
    for (int b = 1; b < 500; ++b)
    {
        for (int c = 1; c < 500; ++c)
        {
            if ((a + b + c) == 1000 && ((a*a + b*b) == (c*c)))
            {
             cout << "The product abc = " << ...
             goto break_all;
            }
        }
    }
}
break_all:

“这是使用 goto 的最后一个据点”

于 2013-04-22T05:05:48.470 回答
0

在您的代码中,您只应用了一次中断。所以最里面的 for 循环将被打破,其他外部循环将继续。

所以你已经定义了标志变量来打破所有循环。

#include "stdafx.h"
#include <iostream>  
    int main()
    {
        bool flag = 0; //Set the flag
        for (int a = 1; a < 500 && !flag; ++a) //Check flag condition
        {
            for (int b = 1; b < 500  && !flag; ++b) //Check flag condition
            {
                for (int c = 1; c < 500 && !flag; ++c) //Check flag condition
                {
                    if ((a + b + c) == 1000 && ((a*a + b*b) == (c*c)))
                    {
                     cout << "The product abc = " << a*b*c << endl << "a = " << a << ", b = " << b << ", c = " << c << endl;
                     flag= 1; //Set the flag true
                     break;
                    }
                }
            }
        }
        cout << endl << "Loop terminated";

        char d;
        cin >> d;
        return 0;
    }
于 2013-04-22T05:14:41.957 回答
0

如果您尝试检查稍大的数字范围,您的代码将非常缓慢。您实际上尝试了从 1 到 500 的所有 c 值,并检查是否 a + b + c = 1000。很明显,如果 c = 1000 - a - b,总和仅为 1000。所以你可以写

int c = 1000 - a - b;
if ((c >= 1 && c < 500) && (a*a + b*b == c*c)) ...

这将运行大约 500 倍的速度...

现在您不喜欢同时打印 a = 200, b = 375 和 a = 375, b = 200。您可能会考虑一个 break 语句,但这会引入一个错误:在很多情况下,有多个解决方案不是像这里这样简单连接的。

您想要的是避免打印 a > b 的解决方案,因为如果 (a, b, c) 是一个解决方案,那么 (b, a, c) 也是一个解决方案。一个简单的方法是写

for (int b = a; b < 500; ++b) ...

当 a = 375 时,只检查值 375 到 499 的 b,从而避免打印 a = 375, b = 200。

于 2014-02-24T01:10:19.687 回答