【问题标题】:Please assist: "if" statement in C++请协助:C++中的“if”语句
【发布时间】:2013-04-14 22:04:11
【问题描述】:

以下代码打印相同的结果 - 两次 (!)(使用 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

循环终止

【问题讨论】:

  • break 只跳出最里面的 for 循环。
  • 谢谢,是的,我很笨...
  • 虽然我的官方回答很垃圾,很快就被删除了,看看这个answer我提交了一个类似的问题。这是完全不同的,但总体结果是在类似情况下消除了重复。还要注意使用布尔值来控制循环。
  • break 是错误的解决方案。 ab 在您求解的方程中完全可以互换。除非您将 b 从上方或下方限制为 a,否则您将获得重复的解决方案。尝试将第二个循环设置为 for (int b = a; b &lt; 500; ++b) 并且 ab 互换的重复项将消失。

标签: c++ if-statement conditional-statements


【解决方案1】:

您的break 只跳出循环,所以外循环继续执行。

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

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

【讨论】:

  • 一种更骇人听闻的方式是一个布尔 isdone 标志,您可以检查所有循环条件。
  • 啊……非常感谢大家!!!我感到如释重负(像个白痴一样),我完全忘记了这一点。我也刚刚意识到if 语句中缺少第三个条件,我应该包含 a
  • @montecarlo76 - 如果你有a&lt;b&lt;c,你可以通过根据外部循环位置指定bc 的内部循环范围来加快速度 - 例如for (int b = a+1; ...。您不需要明确地测试a&lt;b&lt;c,您可以通过仔细指定循环来确保始终如此。
  • 我喜欢分离功能的想法。在 C++11 中,有一个新模式,就像你只使用 lambda:非常干净,不需要单独的声明/定义,也允许变量捕获,有什么不喜欢的? ;) 有点过时了,但是这种 lambda 模式对于需要复杂初始化的 const 变量也非常好。
【解决方案2】:

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;

}

【讨论】:

  • 如果在 for 循环结束时检查了标志,那么它可以被优化,并且将执行两个循环,然后这个......只是对优化感到好奇,否则好的逻辑工作正常......跨度>
【解决方案3】:

您使用的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:

"This is the last remaining stronghold for the use of goto"

【讨论】:

  • 我想我想为 any goto -1 作为建议 (imo),但我要 +1 因为我认为这是我第一次'见过有人这样做。
【解决方案4】:

所以 - 你听说 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)
            {

然后你说myLim = -1而不是break - 你会跳出所有的循环。

注意 - 当 if 条件满足时,一些编译器会不赞成你设置 a=500b=500,因为你正在修改循环变量;但如果你改变条件,没人会介意。这比添加标志要干净一些,但仍然有点 hack。

【讨论】:

    【解决方案5】:

    在您的代码中,您只应用了一次中断。所以最里面的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;
        }
    

    【讨论】:

      【解决方案6】:

      正如许多人已经说过的那样,break 只会跳出最里面的循环。

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

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

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

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

      3. 根本不要跳出循环。相反,有一个标志,done 或类似的,以指示您何时完成。检查所有循环的条件。

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

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

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

      goto here 的语法描述——基本上是goto &lt;labelname&gt;;labelname:

      【讨论】:

        【解决方案7】:

        如果您尝试检查稍大的数字范围,您的代码将会非常缓慢。您实际上尝试了从 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。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-11-04
          相关资源
          最近更新 更多