368

是否可以使用该break函数退出多个嵌套for循环?

如果是这样,你会怎么做呢?您还可以控制break出口的循环次数吗?

4

20 回答 20

307

不,不要用break. 这是剩下的最后一个据点供使用goto

于 2009-08-10T23:24:17.920 回答
281

AFAIK,C++ 不支持命名循环,就像 Java 和其他语言一样。您可以使用 goto,或创建您使用的标志值。在每个循环结束时检查标志值。如果它设置为 true,那么您可以中断该迭代。

于 2009-08-10T23:20:14.900 回答
113

只是为了使用 lambdas 添加一个明确的答案:

  for (int i = 0; i < n1; ++i) {
    [&] {
      for (int j = 0; j < n2; ++j) {
        for (int k = 0; k < n3; ++k) {
          return; // yay we're breaking out of 2 loops here
        }
      }
    }();
  }

当然,这种模式有一定的局限性,显然仅限于 C++11,但我认为它非常有用。

于 2015-10-16T15:56:07.163 回答
61

打破嵌套循环的另一种方法是将两个循环分解为一个单独的函数,并return在您想要退出时从该函数中退出。

当然,这带来了另一个论点,即您是否应该return在函数末尾以外的任何地方显式地访问该函数。

于 2009-08-10T23:39:30.400 回答
37

break将仅退出包含它的最内层循环。

您可以使用goto跳出任意数量的循环。

当然goto通常被认为是有害的。

使用中断功能[...]是否合适?

使用 break 和 goto 会使推理程序的正确性变得更加困难。有关此问题的讨论,请参见此处: Dijkstra 并不疯狂

于 2009-08-10T23:20:22.403 回答
30

这个怎么样?

for(unsigned int i=0; i < 50; i++)
{
    for(unsigned int j=0; j < 50; j++)
    {
        for(unsigned int k=0; k < 50; k++)
        {
            //Some statement
            if (condition)
            {
                j=50;
                k=50;
            }
        }
    }
}
于 2012-03-30T15:37:24.257 回答
22

一个代码示例使用goto和一个标签来打破嵌套循环:

for (;;)
  for (;;)
    goto theEnd;
theEnd:
于 2015-03-10T23:11:08.913 回答
22

尽管已经提出了这个答案,但我认为一个好的方法是执行以下操作:

for(unsigned int z = 0; z < z_max; z++)
{
    bool gotoMainLoop = false;
    for(unsigned int y = 0; y < y_max && !gotoMainLoop; y++)
    {
        for(unsigned int x = 0; x < x_max && !gotoMainLoop; x++)
        {
                          //do your stuff
                          if(condition)
                            gotoMainLoop = true;
        }
    }

}
于 2011-11-03T08:27:56.623 回答
12

打破几个嵌套循环的一种好方法是将代码重构为一个函数:

void foo()
{
    for(unsigned int i=0; i < 50; i++)
    {
        for(unsigned int j=0; j < 50; j++)
        {
            for(unsigned int k=0; k < 50; k++)
            {
                // If condition is true
                return;
            }
        }
    }
}
于 2013-06-12T04:00:44.830 回答
7

goto 对于打破嵌套循环非常有帮助

for (i = 0; i < 1000; i++) {
    for (j = 0; j < 1000; j++) {
        for (k = 0; k < 1000; k++) {
             for (l = 0; l < 1000; l++){
                ....
                if (condition)
                    goto break_me_here;
                ....
            }
        }
    }
}

break_me_here:
// Statements to be executed after code breaks at if condition
于 2016-09-27T14:57:46.120 回答
6

我知道这是一个老话题,但我觉得这真的需要说,而且没有其他地方可以说。对于这里的每个人,请使用goto。我刚用过。

像几乎所有东西一样,goto 不是 100% 非此即彼/异或“坏”或“好”。我会说至少有两种用途,如果你对它们使用 goto - 并且不要将它用于其他任何东西 - 你不仅应该 100% 没问题,而且你的程序将比没有它更具可读性,因为它使您的意图更加清晰(有一些方法可以避免它,但我发现它们都更加笨拙):

  1. 打破嵌套循环,以及
  2. 错误处理(即在函数结束时跳转到清理例程,以返回失败代码并释放内存。)。

不要只是教条地接受诸如“马马虎虎就是‘邪恶’”之类的规则,而是要理解为什么会声称这种情绪,并遵循“为什么”而不是情绪的文字。不知道这也给我带来了很多麻烦,以至于我会说教条地称事物为“邪恶”可能比事物本身更有害。在最坏的情况下,你只是得到了糟糕的代码——然后你知道你没有正确使用它,只要你听到要保持警惕,但如果你为了满足教条主义而苦恼自己,我会说那更糟。

为什么“goto”被称为“evil”是因为你不应该用它来代替普通的 ifs、fors 和 whiles。为什么会这样?试一试,一直尝试使用“goto”而不是普通的控制逻辑语句,然后尝试用控制逻辑再次编写相同的代码,并告诉我哪个看起来更好更容易理解,哪个看起来更乱. 你去吧。(奖励:现在尝试在 goto-only 代码中添加一个新功能。)这就是为什么它是“邪恶的”,在“邪恶”周围有合适的范围限定。用它来短路C的“ break”命令的缺点是不行的一个有问题的用法,只要你从代码中明确你的 goto 应该完成什么(例如使用“nestedBreak”之类的标签或其他东西)。跳出嵌套循环是非常自然的。

(或者更简单地说:使用 goto 跳出循环。我会说这甚至更可取。不要使用 goto 来创建循环。那是“邪恶的”。)

你怎么知道你是不是教条主义的?如果遵循“xyz is evil”规则导致您的代码难以理解,因为您正在扭曲自己试图绕过它(例如通过在每个循环上添加额外的条件,或一些标志变量,或其他类似的技巧) ,那么你很可能是教条主义的。

学习良好的思维习惯是无可替代的,比良好的编码习惯更重要。前者先于后者,一旦采用前者,后者往往会紧随其后。然而,问题是,我经常发现后者没有得到足够的解释。太多的人只是说“这很糟糕”和“这需要更多思考”,而没有说明要思考什么、要思考什么以及为什么。这是一个很大的耻辱。

(FWIW,在 C++ 中,仍然需要跳出嵌套循环,但不需要错误代码:在这种情况下,始终使用异常来处理错误代码,永远不要返回它们,除非它过于频繁以至于异常抛出和捕获将导致性能问题,例如在高需求服务器代码中的紧密循环中,也许[有些人可能会说“异常”应该“很少使用”,但这是深思熟虑的教条主义的另一部分:不,至少根据我在推翻该教条后的经验,我发现它们使事情变得更加清晰——只是不要滥用它们来做错误处理之外的其他事情,比如将它们用作控制流;实际上与“goto”相同。如果您将它们全部用于错误处理,这就是它们的用途。]。)

于 2020-07-24T00:49:52.943 回答
3

break语句终止它出现的最近的封闭do, for, switch, or语句的执行。while控制权传递给终止语句之后的语句。

来自msdn

于 2009-08-10T23:19:21.673 回答
3

我确实认为 agoto在这种情况下是有效的:

要模拟break/ continue,您需要:

休息

for ( ;  ;  ) {
    for ( ;  ;  ) {
        /*Code here*/
        if (condition) {
            goto theEnd;
        }
    }
}
theEnd:

继续

for ( ;  ; ) {
    for ( ;  ;  ) {
        /*Code here*/
        if (condition) {
            i++;
            goto multiCont;
        }
    }
    multiCont:
}
于 2015-11-27T09:58:51.280 回答
3

我不确定这是否值得,但您可以使用一些简单的宏来模拟 Java 的命名循环:

#define LOOP_NAME(name) \
    if ([[maybe_unused]] constexpr bool _namedloop_InvalidBreakOrContinue = false) \
    { \
        [[maybe_unused]] CAT(_namedloop_break_,name): break; \
        [[maybe_unused]] CAT(_namedloop_continue_,name): continue; \
    } \
    else

#define BREAK(name) goto CAT(_namedloop_break_,name)
#define CONTINUE(name) goto CAT(_namedloop_continue_,name)

#define CAT(x,y) CAT_(x,y)
#define CAT_(x,y) x##y

示例用法:

#include <iostream>

int main()
{
    // Prints:
    // 0 0
    // 0 1
    // 0 2
    // 1 0
    // 1 1

    for (int i = 0; i < 3; i++) LOOP_NAME(foo)
    {
        for (int j = 0; j < 3; j++)
        {
            std::cout << i << ' ' << j << '\n';
            if (i == 1 && j == 1)
                BREAK(foo);
        }
    }
}

另一个例子:

#include <iostream>

int main()
{
    // Prints: 
    // 0
    // 1
    // 0
    // 1
    // 0
    // 1

    int count = 3;
    do LOOP_NAME(foo)
    {
        for (int j = 0; j < 3; j++)
        {
            std::cout << ' ' << j << '\n';
            if (j == 1)
                CONTINUE(foo);
        }
    }
    while(count-- > 1);
}
于 2020-04-26T22:30:21.897 回答
1

只需一个变量即可打破任意数量的循环,bool请参见下文:

bool check = true;

for (unsigned int i = 0; i < 50; i++)
{
    for (unsigned int j = 0; j < 50; j++)
    {
        for (unsigned int k = 0; k < 50; k++)
        {
            //Some statement
            if (condition)
            {
                check = false;
                break;
            }
        }
        if (!check)
        {
            break;
        }
    }
    if (!check)
    {
        break;
    }
}

在这段代码中,我们break;所有的循环。

于 2019-07-17T11:46:12.010 回答
0

其他语言如 PHP 接受 break 参数(即 break 2;)来指定要中断的嵌套循环级别的数量,但 C++ 不接受。您必须通过使用在循环之前设置为 false 的布尔值来解决这个问题,如果要中断,则在循环中设置为 true,在嵌套循环之后加上条件中断,检查布尔值是否设置为 true如果是,则打破。

于 2009-08-10T23:23:07.937 回答
0

我知道这是旧帖子。但我会建议一个合乎逻辑且更简单的答案。

for(unsigned int i=0; i < 50; i++)
    {
        for(unsigned int j=0; j < conditionj; j++)
        {
            for(unsigned int k=0; k< conditionk ; k++)
            {
                // If condition is true

                j= conditionj;
               break;
            }
        }
    }
于 2016-05-30T07:57:26.307 回答
-1
  while (i<n) {
    bool shouldBreakOuter = false;
    for (int j=i + 1; j<n; ++j) {
      if (someCondition) {
          shouldBreakOuter = true;
      }
    }

    if (shouldBreakOuter == true)
      break;

  }
于 2017-10-21T15:37:10.083 回答
-2

您可以使用 try...catch。

try {
    for(int i=0; i<10; ++i) {
        for(int j=0; j<10; ++j) {
            if(i*j == 42)
                throw 0; // this is something like "break 2"
        }
    }
}
catch(int e) {} // just do nothing
// just continue with other code

如果你必须一次跳出几个循环,无论如何它通常是一个例外。

于 2013-04-02T14:49:33.660 回答
-5

跳出 for 循环对我来说有点奇怪,因为 for 循环的语义通常表明它将执行指定的次数。但是,在所有情况下都不错。如果您正在搜索集合中的某些内容并希望在找到它后打破它,那么它很有用。然而,在 C++ 中不可能跳出嵌套循环。它在其他语言中是通过使用带标签的中断来实现的。您可以使用标签和 goto,但这可能会让您在晚上胃灼热..?似乎是最好的选择。

于 2009-08-10T23:20:01.657 回答