我想知道当验证结束条件(不同于正确的迭代次数)时是否可以在C ++中结束for循环。例如:

for (int i = 0; i < maxi; ++i)
    for (int j = 0; j < maxj; ++j)
        // But if i == 4 < maxi AND j == 3 < maxj, 
        // then jump out of the two nested loops.

我知道这可以在Perl中使用下一个LABEL或最后一个LABEL调用和标记块,是否可以在C ++中执行,或者我应该使用while循环?

谢谢。

有帮助吗?

解决方案

您可以使用return关键字:将嵌套循环移动到子例程中,调用子例程以运行嵌套循环,并从子例程中“返回”以退出[all]循环。

其他提示

尽管<!>“goto被认为是有害的<!>”;争论,这似乎是<=>的理想场所。这基本上就是你在Perl中所做的。说真的......考虑其他选择:

额外状态变量


for (int i=0; i<maxi; ++i) {
    bool leaveLoop = false;
    for (int j=0; j<maxj; ++j) {
        if (i == 4 && j == 3) {
            leaveLoop = true;
            break; // leave the inner loop
        }
    }
    if (leaveLoop) {
        break; // leave the outside loop
    }
}

以异常方式离开


try {
    for (int i=0; i<maxi; ++i) {
        for (int j=0; j<maxj; ++j) {
            if (i == 4 && j == 3) {
                throw leave_loop();
            }
        }
    }
} catch (leave_loop const&) {
}

复杂逻辑


int j = 0;
for (int i=0; i<maxi && !(i==4 && j==3); ++i) {
    for (j=0; j<maxj && !(i==4 && j==3); ++j) {
        // inner loop
    }
}

<强> <=>


for (int i=0; i<maxi; ++i) {
    for (int j=0; j<maxj; ++j) {
        if (i==4 && j==3) {
            goto leave_loop;
        }
    }
}
leave_loop:

最后一个不太清楚吗?我不相信它。它更脆弱了吗?恕我直言,与<=>版本相比,其他版本容易出错且易碎。很抱歉在这里站在肥皂盒上,但这件事困扰了我一段时间;)

唯一需要承认的是<=>和异常非常相似。它们都为泄漏资源提供了机会,并且不小心对待它们。

让我强调(但礼貌地;-)尽可能地说:用类似c语言的for结构与计算无关。

确定是否继续的测试表达式可以是与循环目的相关的任何内容;更新表达式不必是<!>“;将一个添加到计数器<!>”;

for (int i = 0, j = 0; i < maxi && j < maxj && i != 4 && j != 3;) {
    if (j < maxj) {
        ++j;
    } else {
        j = 0;
        ++i;
    }
}

将是一种(相当随意的)重写方式。

关键在于,如果建立一些条件是一个交互点,通常可以用一种更明确地表明继续/终止条件的方式编写一个循环(使用while或<=>)。 / p>

(如果你可以发布实际发生的事情的描述,它可能会写出一些看起来不像上面那样任意的东西。)

你不能用一个中断指令跳出两个循环,但你可以使用goto从内部循环跳到外面。

如果goto是本地化的,意味着逻辑少于其他我认为它是完全可以接受的代码。有额外的标志变量,或者从内循环中提取迭代器变量,这样你就可以在外循环中对它进行比较,这样就不会更容易理解代码恕我直言。

从上面的所有建议中我都会避免使用try / catch机制,因为异常应该保留用于特殊情况,而不是正常的控制流。

如果您可以适当地创建第二个条件,则可以使用两个中断。为此目的使用布尔值也很好,你甚至可以将它连接到每个for循环的条件。例如:

bool exit_loops = false;
for (int a = 0; a < A && !exit_loops; ++a)
{
    for (int b = 0; b < B && !exit_loops; ++b)
    {
        if (some_condition) exit_loops = true;
    }
}

虽然如果你使用两个以上的循环,将它们包装在一个函数中可能更合适,只需使用return退出函数(以及所有的循环)。然后你可以用一种方法重构代码,除了其中一个循环之外,可以通过调用一个函数来执行内部循环代码等等。

最后不要害怕在这种情况下使用goto,通常goto是糟糕的非结构化编程,但在某些情况下(像这样)它们非常有用。

bool done = false;

for (int i = 0; i < maxi && !done; ++i)
    for (int j = 0; j < maxj && !done; ++j)
        if (i == 4 && i < maxi && j == 3 && j < maxj )
             done = true;
        else {
        }

或者你可以转到。或不: - )

你不能在C / C ++中这样跳出来:

for (...)
{
  for (...)
  {
    // from here...
  }
}
// ...to here

不使用goto。你需要一个像:

这样的结构
for (...)
{
  bool
    exit = false;

  for (...)
  {
    if (do_exit)
    {
      exit = true; // or set outer loop counter to end value
      break;
    }
  }
  if (exit)
  {
    break;
  }
}

或者,使用throw和catch - 但这并不好,因为throw应该用于异常而不是流量控制。

一种干净的方法是使内循环成为一个函数:

bool F ()
{
  if inner loop terminates, return false else return true
}

void G ()
{
  for (...)
  {
    if (!F ())
    {
      break;
    }
  }
}
for (int i = 0; i < maxi; ++i)
{
    int j = 0;
    for (j = 0; j < maxj; ++j)
    {
         if (i == 4 && j == 3) // i < maxi and j < maxj otherwise we would not be here
             break; // exit inner loop
    }
    if (i == 4 && j == 3) // i < maxi and j < maxj otherwise we would not be here
        break; // exit outer loop
}

您可以使用转到语句 ,但这通常被认为是一种不好的做法。

你的另一个选择是做这样的事情

int i;
int j = 0;
for (i = 0; i < maxi && !(i==4 && j==3); ++i)
    for (j = 0; j < maxj && !(i==4 && j==3); ++j)

阅读代码不应该像阅读一本侦探书(总是需要弄清楚)......

一个例子:

爪哇:

iterate_rows:
for (int i = 0; i < maxi; ++i)
{       
    for (int j = 0; j < maxj; ++j)
    {
        if (i == 4 < maxi && j == 3 < maxj) 
            break iterate_rows;
        else
            continue iterate_rows;
    }   
}

你不需要弄清楚iterate_rows的中断,你只需要阅读它。

C ++:

//iterate_rows:
for (int i = 0; i < maxi; ++i)
{
    for (int j = 0; j < maxj; ++j)
    {
        if (i == 4 < maxi && j == 3 < maxj) 
            goto break_iterate_rows;
        else
            goto continue_iterate_rows;
    }

continue_iterate_rows:;
}
break_iterate_rows:;

转到break_iterate_rows 只是 break iterate_rows 可见版本

如果您仅限于使用此类代码的goto和标签,则无法确定其意图。限制在这种代码上使用goto和标签将使您只需阅读代码,而不是分析或计算代码。你不会被指责为邪恶的程序员。

如果你真的限制你在这种代码中使用了这些代码,那么你就可以养成一种习惯,即不需要弄清楚你的代码中有什么用。额外的好处是您不必引入布尔值并跟踪它们(这会导致您检测代码,使其有点难以理解,这会破坏避免使用的目的)

P.S。

将这些标签与注释配对(在循环之前),当您通过goto语句读取这些行时,您已经知道那些gotos的意图

我有一些建议:

  1. throw ....将两个循环放在<!>“try {} <!>”中;然后<!> quot; catch <!> quot; <!>“throw <!>”;条件。

  2. 将两个循环放在一个方法中并返回条件。

  3. Goto不是邪恶的,人们也会使用它......你可以使用<!>“goto <!>”;它可以是最清晰的代码,尤其是在处理错误时。我20年没用过了。

我总是试图远离goto陈述(由于某种原因,它总是被学校和我的工作所看不起)。我会使用Daemin建议的东西。

您可以使用以下内容的标签:

Outer:
for(...)
{
    Inner:
    for(...)
    {
    if(condition)
        {
        goto End;
        }
    }
}
End:

在Java中你可以通过标签来打破我的想法吗?

编辑 - 将goto更改为End而不是Outer,但我不认为否定代表是合理的。这个答案给出了最简单的方法。

完全重新考虑for结构的另一个原因是它的作用域阻止了在循环终止后访问受控变量。在循环中变异的变量的值可能由于各种原因(例如,在搜索中区分成功与失败)而有用,否则在范围退出之后需要额外的变量来保存该信息。这是一个小例子,用于搜索名为a的方形数组以获取target值(假设SIZE非零,否则不需要搜索!):

int i = 0;
int j = 0;
while (i < SIZE && a[i][j] != target) { // still in array but not at target
    if (SIZE <= ++j) {                  // fallen off the end of a row
        j = 0;
        ++i;
    }
}

后续代码可以使用i < SIZE来确定是否找到了所需的值。

上述的另一个优点是灵活性。假设我们现在被告知<=>行中的值是升序的,因此如果遇到大于<=>的值,则行的其余部分无关紧要。很容易确切地知道要做出什么样的改变,以及在哪里做出改变。因为新信息允许我们放弃当前行,所以只有内部决策受到影响,成为:

    if (target < a[i][j] || SIZE <= ++j) { // can't be in row or fallen off end
    ...

我看到更多新的语言(特别是功能导向的语言)放弃了旧的<!>“count <!>”;循环结构;这可能是件好事,因为它鼓励我们考虑循环的含义,而不是简单地计算。

我见过的最好的方式涉及到macros和gotos,但它实际上相当很好(链接到帖子开始时谈论Perl,但最后一段左右引入了宏)。

它允许您编写如下代码:

named (LOOPS) for (i=1; i<10; i++) {
    for (j=1; j<10; j++) {
        for (j=1; j<10; j++) {
            /* Process data[i][j][k] here */
            if (data[i][j][k] < threshold) break(LOOPS);
        }
    }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top