16

假设我需要在最内层循环内发生某些事件时一次跳出三个或四个嵌套的 for 循环。这样做的好方法是什么?

我所做的是使用这样的标志

int i, j, k;
int flag1 = 0;
int flag2 = 0;

for (i = 0; i < 100; i++) {
    for (j = 0; j < 100; j++) {
        for (k = 0; k < 100; k++) {
            if (k == 50) {
                flag1 = 1;
                flag2 = 1;
                break;
            }
        }
        if (flag1 == 1)break;
    }
    if (flag2 == 1)break;
}

我认为这不是特别整洁。

你将如何完成同样的事情?(不使用跳跃)

4

14 回答 14

86

使用转到。它干净简单。

于 2009-10-19T04:24:08.073 回答
49

将所有循环放在一个函数中,然后返回而不是中断。

于 2009-10-19T04:26:20.703 回答
18

如果您使用的是 Java,则可以将标签与每个 for 块相关联,然后在 continue 语句后引用该标签。例如:

outerfor:
for (int i=0; i<5; i++) {
    innerfor:
    for (int j=0; j<5; j++) {
        if (i == 1 && j == 2) {
             continue outerfor;
        }
    }
}
于 2009-10-19T04:22:50.883 回答
14

你将如何完成同样的事情?(不使用跳跃)

为什么?没有什么是普遍邪恶的,每一个放置的工具都有它的用途(除了gets())。使用goto这里使您的代码看起来更干净,并且是我们仅有的选择之一(假设 C)。看:

int i, j, k;

for (i = 0; i < 100; i++) {
    for (j = 0; j < 100; j++) {
        for (k = 0; k < 100; k++) {
            if (k == 50) {
                goto END;
            }
        }
    }
}
END:

比所有这些标志变量更清晰,它甚至更清楚地显示了您的代码在做什么

于 2009-10-19T04:30:17.997 回答
5

稍微好一点。

int i, j, k;
int flag1 = 0;
int flag2 = 0;

for (i = 0; i < 100 && !flag2; i++) {
    for (j = 0; j < 100 && !flag1; j++) {
        for (k = 0; k < 100; k++) {
            if (k == 50) {
                flag1 = 1;
                flag2 = 1;
                break;
            }
        }
    }
}

但是如果你真的需要这些循环,那么为了可读性,在每个循环中明确声明它必须满足哪些条件才能继续是有意义的。

于 2009-10-19T04:23:36.793 回答
5

goto. 这是适合工具的极少数地方之一,goto通常是提出的论点,为什么goto不完全是邪恶的。

不过,有时我会这样做:

void foo() {
    bar_t *b = make_bar();
    foo_helper(bar);
    free_bar(b);
}

void foo_helper(bar_t *b) {
    int i,j;
    for (i=0; i < imax; i++) {
        for (j=0; j < jmax; j++) {
            if (uhoh(i, j) {
                return;
            }
        }
    }
}

这个想法是我得到一个保证免费的酒吧,加上我通过返回得到一个干净的两级突破。

于 2009-10-19T06:10:43.257 回答
4

如果您绝对不想使用 goto,请将所有循环条件设置为 false:

int i, j, k;

for (i = 0; i < 100; i++) {
    for (j = 0; j < 100; j++) {
        for (k = 0; k < 100; k++) {
            if (k == 50) {
                i = j = k = INT_MAX;
                break;
            }
        }
    }
}

注意:智能优化编译器会将 if 的内容跳转到最外层循环的末尾

于 2011-08-18T10:01:58.660 回答
3

有时你可以使用这样的技巧:

for (i = 0; i < 100 && !flag2; i++) {
for (j = 0; j < 100 && !flag1; j++) {
    for (k = 0; k < 100; k++) {
        if (k == 50) {
            k = 100;
            i = 100;
            j = 100;
        }
    }
}

}

或在循环中声明添加标志:

bool end = false;
for(int i =0; i < 1000 && !end; i++) {
   //do thing
   end = true;
}

我认为它只花费一条线但很干净。

贾斯汀

于 2009-10-19T04:56:02.063 回答
2

如果任何循环的过早完成总是意味着您也必须打破封闭循环,那么您不需要任何额外的标志。整个事情可能看起来如下

int i, j, k;
for (i = 0; i < 100; i++) {
    for (j = 0; j < 100; j++) {
        for (k = 0; k < 100; k++) {
            if (k == 50)
                break;
        }
        if (k < 100) break;
    }
    if (j < 100) break;
}

根据我的经验,这是大多数情况下需要的。

于 2009-10-19T06:43:57.340 回答
2

一点点愚蠢的自我记录:

int i, j, k;
int done = 0;

for (i = 0; i < 100 && ! done; i++) {
    for (j = 0; j < 100 && ! done; j++) {
        for (k = 0; k < 100 && ! done; k++) {
            if (k == 50) we_are(done);
        }
    }
}

//...

void we_are(int *done) {
    *done = 1;
}

但实际上,您不应该有三个嵌套的 for 循环。您应该考虑重构为不同的函数并改进程序的逻辑,而不是这样做。

虽然我同意有时goto确实是最好的解决方案,但我认为任何问题goto的解决方案都是糟糕代码的结果。

于 2009-10-19T18:20:01.257 回答
0

除以 0 是我知道的最可靠的方法,它可以让你摆脱任意数量的循环。这是有效的,因为 DIV 汇编指令不喜欢这种愚蠢。

所以,你可以试试这个:

int i, j, k;
int flag1 = 0;
int flag2 = 0;

for (i = 0; i < 100; i++) {
    for (j = 0; j < 100; j++) {
        for (k = 0; k < 100; k++) {
            if (k == 50) {
                flag1 = 1;
                flag2 = 1;
                int z = 1 / 0;  // we're outta here!!!
            }
        }
        if (flag1 == 1)break;
    }
    if (flag2 == 1)break;
}

从这些事件中发生的事情中恢复过来,trap作为一个练习留给读者(这很简单)。

于 2009-10-19T06:20:35.997 回答
0

我会做类似的事情:

  int i, j, k;

  for (i = 0; i < 100; i++) {
      for (j = 0; j < 100; j++) {
          for (k = 0; k < 100; k++) {
              if (k == 50) {
                  return;
              }
          }
      }
  }
于 2009-10-19T18:50:31.353 回答
0

如果您使用的是 GCC 和这个库,则break可以接受要退出的嵌套循环数:

int i, j, k;

for (i = 0; i < 100; i++) {
    for (j = 0; j < 100; j++) {
        for (k = 0; k < 100; k++) {
            if (k == 50) {
                break(3);
            }
        }
    }
}
于 2017-12-22T21:55:28.653 回答
-1

一种方法是状态机。但我仍然会使用 goto。这要简单得多。:)

state = 0;
while( state >= 0){
    switch(state){
        case 0: i = 0; state = 1; // for i = 0
        case 1:
            i++; 
            if (i < 100)   // if for i < 100 not finished
                state = 2; // do the inner j loop
            else
                state = -1; // finish loop
        case 2: j = 0; state = 3; // for j = 0
        case 3: 
            j++;
            if (j < 100)  // if j < 100 not finished
                state = 4 // do the inner k loop
            else
                state = 1; // go backt to loop i
            break;
        case 4: k = 0; state = 5;
        case 5:
            k++;
            if (k == 50){
                state = -1;
                break;
            }
            if (k < 100) // if k loop not finished
                state = 5; // do this loop
            else
                state = 3; // go back to upper loop
            break;
        default : state = -1;
    }
}
于 2009-10-19T06:00:12.467 回答