如果达到结束条件,是否可以在 C++ 中退出 a for before 时间?

发布于 2024-07-10 20:32:04 字数 372 浏览 6 评论 0原文

我想知道当验证结束条件(与达到正确的迭代次数不同)时是否可以结束 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 循环?

谢谢。

I want to know if it is possible to end a for loop in C++ when an ending condition (different from the reacheing right number of iterations) is verified. For instance:

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.

I know that this is possible in Perl with the next LABEL or last LABEL calls and labeled blocks, is it possible to do it in C++ or I should use a while loop?

Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

素年丶 2024-07-17 20:32:05

根据上面的所有建议,我会避免使用 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 是糟糕的非结构化编程,但在某些情况下(像这样)它们非常有用。

From all of the suggestions above I would avoid using the try/catch mechanism because exceptions should be reserved for exceptional circumstances, and not normal control flow.

Using two breaks is alright if you can create the second condition appropriately. Using a boolean for this purpose would also be good, and you could even wire it into the condition of each for loop. For example:

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;
    }
}

Though if you're using more than two loops it might be more appropriate to wrap them in a function and just use return to exit the function (and all of the loops too). Then again you could refactor the code in a way that can eliminate all but one of the loops, be it by calling a function to perform the inner loop code, etc.

Lastly don't be afraid of using a goto in this circumstance, usually goto's are bad unstructured programming, but in some cases (like this) they are very useful.

玩物 2024-07-17 20:32:05
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 {
        }

或者你也可以直接去。 或不 :-)

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 {
        }

Or you could just goto. Or not :-)

野却迷人 2024-07-17 20:32:05

在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;
    }
  }
}

You can't jump out like this in C/C++:

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

without the use of goto. You need a construct like:

for (...)
{
  bool
    exit = false;

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

Alternatively, use throw and catch - but that's not great since throw should really be used for exceptions and not flow control.

A clean way is to make the inner loop a function:

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

void G ()
{
  for (...)
  {
    if (!F ())
    {
      break;
    }
  }
}
朮生 2024-07-17 20:32:05
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
}
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
}
凉世弥音 2024-07-17 20:32:05

您可以使用 goto 语句,但那是通常被认为是不好的做法。

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

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)

You could use a goto statement, but that's generally considered a bad practice.

Your other option is to do something like this

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)
所有深爱都是秘密 2024-07-17 20:32:05

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

一个例子:

Java:

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;
    }   
}

你不需要弄清楚break 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:;

如果您将 goto 和标签的

使用限制在仅这种代码,您将无法弄清楚其意图。 限制在此类代码上使用 goto 和标签将使您只是阅读代码,而不是分析或弄清楚它。 你不会被指责为邪恶的程序员。

如果你真的在这种代码中限制了你的 goto,你将能够养成一种习惯,不需要弄清楚那些该死的 goto 在你的代码中做了什么。 额外的好处是你不必引入布尔值并跟踪它们(恕我直言,这会导致你检测代码,使其变得有点不可读,这违背了避免 goto 的真正目的)

PS

将这些配对带注释的标签(在循环之前),当您使用 goto 语句阅读这些行时,您已经知道这些 goto 的意图

Reading code should not be like reading a detective book(which always need to be figured out)...

an example:

Java:

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;
    }   
}

You don't need to figure out what break iterate_rows do, you just read it.

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:;

goto break_iterate_rows is just a visible version of break iterate_rows

If you confine your use of goto and labels on this kind of code only, you will not be figuring out the intent. Limiting your use of goto and labels on this kind of code will make you just read the code, not analyzing or figuring it out. You'll not be accused of being an evil programmer.

And if you really limit your gotos in this kind of code, you'll be able to develop a habit of not needing to figure out what those darn gotos do in your code. Added benefit is you don't have to introduce booleans and track them(which imho, leads you to detecting the code, making it a bit unreadable, which defeats the very purpose of avoiding gotos)

P.S.

Pair those labels with comments(before the loop), by the time you read past those lines with goto statement you already know the intent of those gotos

℉服软 2024-07-17 20:32:05

我有一些建议:

  1. throw ....将两个循环放入“try {}”中,然后“捕获”条件上的“ throw”。

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

  3. Goto 并不是邪恶的,人们也这么说……你可以使用“goto”,它可以是最清晰的代码,尤其是在处理错误时。 我已经 20 年没用过了。

托尼

I have a few suggestions:

  1. throw.... put the two loops inside a "try {}" and then "catch" the "throw" on the condition.

  2. put the two loops in a method and return on the condition.

  3. Goto isn't evil its the use people put it too.... You can use "goto" it can be the clearest code, especially when handling errors. I haven't used one in 20 years.

Tony

假装爱人 2024-07-17 20:32:05

我一直试图远离 goto 语句(出于某种原因,它在学校和我的工作中总是受到轻视)。 我会使用 Daemin 建议的东西。

I've always tried to stay away from goto statements (it was always looked down upon at school and my job for some reason). I would use something like what Daemin suggested.

海未深 2024-07-17 20:32:05

你可以使用标签,类似于:

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

在Java中你可以传递标签来打破我认为?

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

You can use labels, something along the lines of:

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

In Java you can pass labels to break I think?

Edit - Changed the goto to End rather than Outer, however I don't think the negative rep is justified. This answer gives the simplest way to do it.

故事未完 2024-07-17 20:32:05

完全重新考虑 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 来确定是否找到了所需的值。

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

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

我看到更多较新的语言(尤其是面向功能的语言)放弃旧的“计数”循环构造; 这可能是一件好事,因为它鼓励我们思考循环的含义,而不是简单地计数。

Another reason for reconsidering the for construct entirely is that its scoping prevents access to the controlled variables after the loop has terminated. The value(s) of the variable(s) being mutated in the loop may useful for a variety of reasons (e.g. to distinguish success from failure in a search) which would otherwise require extra variables to preserve that information after scope exit. Here's a small example that searches a square array named a for a target value (assuming that SIZE is non-zero, otherwise no search is necessary!):

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;
    }
}

The subsequent code can use i < SIZE to determine whether the desired value was located.

Another advantage of the above is the flexibility. Suppose we're now informed that the values in rows of a are ascending, so the remainder of a row is irrelevant if a value larger than target is encountered. It's easy to know exactly what change to make, and where to make it. Because that new information allows us to abandon the current row, only the inner decision is affected, becoming:

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

I'm seeing more of the newer languages (especially functionally-oriented ones) abandoning the old "counting" loop construct; that's probably a good thing, as it encourages us to think about the meaning of the loop, rather than simply counting.

黑白记忆 2024-07-17 20:32:05

我见过的最好的方法涉及宏和 goto,但它实际上相当不错(链接到帖子首先讨论 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);
        }
    }
}

The best way I've seen involves macros and gotos, but it's actually quite nice (the linked to post starts by talking about Perl, but the last paragraph or so introduces the macros).

It allows you to write code like:

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);
        }
    }
}
新雨望断虹 2024-07-17 20:32:04

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

You can use the return keyword: move the nested loop into a subroutine, invoke the subroutine to run the nested loops, and 'return' from the subroutine to exit [all] the loops.

本王不退位尔等都是臣 2024-07-17 20:32:04

尽管“goto 被认为是有害的”论点,但这似乎是 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
    }
}

goto


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

最后一张是不是不太清楚? 我不相信是这样。 是不是更脆弱了? 恕我直言,与 goto 版本相比,其他版本非常容易出错且脆弱。 很抱歉站在肥皂盒上,但这件事已经困扰了我一段时间了;)

您唯一需要注意的是 goto 和异常非常相似。 它们都为泄漏资源提供了机会,因此请谨慎对待它们。

Despite the "goto considered harmful" arguments, this seems like the perfect place for goto. That's essentially what you are doing in Perl. Seriously... consider the alternatives:

Extra State Variables


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
    }
}

Leave by Exception


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&) {
}

Complex Logic


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
    }
}

goto


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

Is the last one less clear? I don't believe that it is. Is it any more fragile? IMHO, the others are quite error prone and fragile compared to the goto version. Sorry to be standing on the soapbox here but this is something that has bothered me for a while ;)

The only thing that you have to be congnizent of is that goto and exceptions are pretty similar. They both open up the opportunity for leaking resources and what not so treat them with care.

笔落惊风雨 2024-07-17 20:32:04

让我尽可能强调(但礼貌地;-):类 C 语言中的 for 结构与计数无关。

测试表达式决定是否continue 可以是与循环目的相关的任何内容; 更新表达式不必是“向计数器加一”。

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

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

要点是,如果建立某个条件是交互的点,通常可以以声明 continue 的方式编写一个循环(使用 whilefor) /终止条件更明确。

(如果您可以发布实际发生的情况的描述,那么它可能会写出一些看起来不像上面那样随意的内容。)

Let me say this as emphatically (but politely ;-) as I can: The for construct in c-like language is not about counting.

The test expression which determines whether to continue can be anything which is relevant to the purpose of the loop; the update expression doesn't have to be "add one to a counter".

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

would be one (fairly arbitrary) way to rewrite.

The point is that if establishing some condition is the point of an interation, it's usually possible to write a loop (using either while or for) in a way that states the continue/terminate condition more explicitly.

(If you could post a description of what's actually happening, it would likely to write something that doesn't look as arbitrary as the above.)

萝莉病 2024-07-17 20:32:04

您无法使用单个中断指令跳出两个循环,但您可以使用 goto 从内部循环直接跳转到外部。

如果 goto 是本地化的,并且意味着逻辑比其他情况少,我认为这是完全可以接受的代码。 拥有额外的标志变量,或者将迭代器变量提升到内部循环之外以便您可以在外部循环中比较它,并不会使代码更容易理解。

You can't jump out of two loops with a single break instruction, but you could use a goto to jump from the inner loop right outside.

If the goto is localized, and means there is less logic than otherwise I think it is perfectly acceptable code. Having extra flag variables, or hoisting the iterator variable out of the inner loop so you can compare it in the outer loop does not make for easier to understand code IMHO.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文