什么是一次摆脱许多for循环的巧妙方法?

Moe*_*oeb 16 c for-loop break

假设我需要在最内层循环内的某个事件发生时立即中断三个或四个嵌套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;
}
Run Code Online (Sandbox Code Playgroud)

我认为这不是特别整洁.

你会如何完成同样的事情?(没有使用跳跃)

Tes*_*est 85

使用转到.它干净而简单.

  • 很多人认为,一堆旗帜在某种程度上比goto更好,只是因为他们曾经听过一些言论 (36认同)
  • @hanifr - 简单,清洁,清晰和可读性有什么不健康?通常,'goto`是_none_中的那些东西,但偶尔它会成为你问题的理想解决方案.几乎所有其他语言都有内容关键字的特殊用法,例如`continue`或`next`,以隐藏一种更好,更可控的面板背后的基本上这种`goto`,这与`if`和` while`和`for`语句.这里`goto`在任何方面都不错_ (12认同)
  • 是的,`goto`它是.我常常会惊讶于有些人愿意去避免编写那些"被诅咒"的关键词,即使它显然是最好的 - 就像最明显,最易读,最易维护的 - 解决手头的问题. (10认同)
  • +1这是我给java提供c ++或c#点的唯一地方.Java有一个`break <label>`语句,它打破了用某个标签命名的循环.C和C#都没有类似的东西,所以唯一干净的方法是使用`goto`.而@ asaph,不时为自己思考,它不会受到伤害! (5认同)
  • @Asaph - 曾经听说过狂热吗?迪克斯特拉说"有害",而不是"撒旦的产卵".你完全错过了他的观点. (4认同)
  • @Asaph,他们正在以非结构化的方式讨论过度使用goto. (3认同)
  • 获胜的`goto`.Kneejerk对语言关键词的反动态度是荒谬的. (3认同)
  • 真的吗?曾经听说Edsger Dijkstra的"Go To Considered Harmful" - http://en.wikipedia.org/wiki/Considered_harmful (2认同)
  • @hanifr.在你写完之前,至少要阅读Dijkstra的全文. (2认同)
  • 同意 - goto有它的位置.只需将它保持在真正有用的地方,而不是阻碍它. (2认同)
  • 把它作为一个函数并使用return.基本上类似于休息,但我认为这是更清晰的代码. (2认同)
  • 转到+1.如果正确使用goto并不是邪恶的,虽然它很自由可能很糟糕...... (2认同)

Foo*_*ole 49

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

  • 请注意,虽然这可以巧妙地避免使用明确的`goto`,但它实际上是在做同样的事情,所以如果你认为这是一个很好的解决方案,你真的不能对`goto`解决方案做任何论证.请注意,如果复杂的循环行为可能会使函数调用不那么清晰或简单,那么`goto`可能更可取. (8认同)
  • 在C++中,返回更好,因为它会尊重堆栈展开 - 因此会破坏在任何循环中声明的任何本地作用域变量. (7认同)
  • 不同之处在于你不能以滥用goto的方式滥用回报.顺便说一句,Java有一个标记的break语句,允许你打破嵌套循环,但没有goto. (4认同)
  • 它们可能基本上是相同的,但代码方面,我认为回报更清晰. (4认同)

Asa*_*aph 17

如果您正在使用Java,则可以将标签与每个块关联,然后在continue语句后引用标签.例如:

outerfor:
for (int i=0; i<5; i++) {
    innerfor:
    for (int j=0; j<5; j++) {
        if (i == 1 && j == 2) {
             continue outerfor;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Chr*_*utz 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:
Run Code Online (Sandbox Code Playgroud)

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

  • 我不知道如何重构这个,因为OP在他的代码中他的三个嵌套循环_doing_的内容并不是非常具体.他只想从其中一个内部打破所有这些,所以我提供了答案.一些操作_require_O(n ^ 3)时间完成,但最终在实践中足够快,因为它们通常在小数据集上操作和/或执行的操作简单且易于优化.不要试图重构那清晰干净且工作正常的东西. (3认同)

moo*_*ogs 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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是如果你确实需要这些循环,那么为了便于阅读,在每个循环中明确声明必须保持哪些条件才能继续循环.


小智 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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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