tags:

views:

533

answers:

11

I am preparing some code:

for(int a = 1; a <= 100; a++)    //loop a (main loop)
{
    for(int b = 1000; b <= 2000; b++)    //loop b
    {
       if(b == 1555)
          break;
    }

    for(int c = 2001; c <= 3000; c++)    //loop c
    {
       .
       .
       .
    }
}

I want to break the main loop (loop variable int a) by using a break; statement in the b loop (loop variable int b).

How can I do it?

+25  A: 

Use a goto.

for(int a = 1; a <= 100; a++)    //loop a (main loop)
{
    for(int b = 1000; b <= 2000; b++)    //loop b
    {
       if(b == 1555)
          goto loopDone;
    }

    for(int c = 2001; c <= 3000; c++)    //loop c
    {
       .
       .
       .
    }
}
loopDone:
Carl Norum
+1: This is exactly the extordinary condition that `goto` was left in the language for.
James Curran
+1 @James. And people still fear it unnecessarily. Oh well....
Carl Norum
@sundowatch, until you have more nested loops.... That method also uses an extra variable and has more lines of code (which means more room for typo-related bugs).
Carl Norum
I'm grabbing a box of pop corn some soda and and leaning back in the chair to watch the upcoming flame war between goto proponents and goto opponents!
Laserallan
@Laserallan, I have no doubt that it's coming...
Carl Norum
@Carl: You think flags are going to be a source of problems with a multi-level loop? Don't ignore the terrible code mess multi-level loops are in the first place. I consider both a flag and a goto hacks around the real problem: organization.
GMan
Owch, and now a downvote? This is clearly a correct solution, whatever your philosophical disagreements with the technique are...
Carl Norum
This is a good method but we don't need it. Because the method in Justin Ethier's comment is much easy.
sundowatch
@James Curran - +1 as well, but there is nothing really extordinary about needing to do this. Other languages support this without resorting to gotos. C is just badly designed. For instance, Ada allows loops to be named, and the equivalent to "break" in Ada allows you to specify the name of the loop being broken out of.
T.E.D.
@T.E.D. `goto` comes in handy for grouping error logic in one spot at the end of a function, too.
Carl Norum
@Carl Norum: There are better mechanisms for that in C++. One of which is exceptions. Your answer would have been fine for C (not su much for C++)
Martin York
@Carl Norum - Yup. But the real need for it is in the situations where you truly have unstructured control flow. One example would be the implementation of a state machine. This is why lex output is filled with gotos.
T.E.D.
Make little functions and returns. As others have said in other answers: Refactor! Intricated code is bad for readability and understanding.
Stephane Rolland
+4  A: 
for(int a = 1; a <= 100; a++)    //loop a (main loop)
{
    for(int b = 1000; b <= 2000; b++)    //loop b
    {
       if(b == 1555)
          goto end;
    }

    for(int c = 2001; c <= 3000; c++)    //loop c
    {
       .
       .
       .
    }
}
end:
adamk
+4  A: 

The only way to head out of two such loops at a time is a goto or a throw or a return, and throw and return may not be appropriate (particularly throw, if the condition isn't exceptional). Alternately, you could set some sort of condition (bool breakout;), and keep breaking if it's true.

David Thornley
You may also use `return` if the code is refactored. Also, since `throw` raises an exception this seems like a bad practice unless the break is being made for an "exceptional" reason such as corrupt data, etc.
Justin Ethier
@Justin: Thanks - incorporated that into my answer.
David Thornley
+1  A: 

Use this kind of pattern

for(int a = 1; a <= 100; a++)
{
    int breakMain = 0;
    for(int b = 1000; b <= 2000; b++)
    {
       if(b == 1555)
       {
           breakMain = 1;
           break;
       }
    }

    if(breakMain)
         break;

    for(int c = 2001; c <= 3000; c++)
    {
       .
       .
       .
    }
}
Bang Dao
+18  A: 

By using a condition variable:

for(int a = 1; a <= 100; a++)    //loop a (main loop)
{
    bool cond = false;

    for(int b = 1000; b <= 2000; b++)    //loop b
    {
       if(b == 1555){
          cond = true;
          break;
       }
    }

    if (cond) break;

    .
    .
    .
}

Alternatively, you could place all of this code inside a function, and just return from that function instead of using break. Perhaps this - or a more involved refactoring of your code - would lend itself to a cleaner solution.

Justin Ethier
This works for two levels, but don't scale well beyond that. This is the case where you grit your teeth and use `goto`.
James Curran
@James: Or refactor your nasty multi-level code and do neither.
GMan
@GMan: Agreed. My typical solution would be to put the outer loop body into a subroutine, and use "return".
T.E.D.
If you're writing multiply nested loops then extracting to a function is a much more readable alternative to a `goto`.
Joe Gauterin
@Joe I agree. [Keep functions short and with limited indentation] : Just following this simple idioms resolves tons of problems.
Stephane Rolland
+3  A: 
  1. Use a goto:

    for(int a = 1; a <= 100; a++)    //loop a (main loop)
    {
        for(int b = 1000; b <= 2000; b++)    //loop b
        {
           if(b == 1555)
              goto done;
        }
        for(int c = 2001; c <= 3000; c++)    //loop c
        {
           .
           .
           .
        }
    }
    done:
    
  2. set a sentinel value tested by each loop:

    bool sentinel = true ;
    for(int a = 1; a <= 100 && sentinel ; a++)    //loop a (main loop)
    {
        for(int b = 1000; b <= 2000 && sentinel; b++)    //loop b
        {
           if(b == 1555)
              sentinel = false;
        }
        for(int c = 2001; c <= 3000 && sentinel; c++)    //loop c
        {
           .
           .
           .
        }
    }
    
tpdi
you've forgot to break loop after sentinel is false
Miro
Miro, all the loops end 9or do not begin) if sentinel is false.
tpdi
+4  A: 

If it is appropriate, you could make a function who's contents are the a loop, and use return.

public void bigLoop()
{
    for(int a = 1; a <= 100; a++)
    {
        for(int b = 1000; b <= 2000; b++)
        {
            if(b == 1555)
                return;
        }

        for(int c = 2001; c <= 3000; c++)
        {
            .
            .
            .
        }
    }
}//bigLoop
Willfulwizard
+2  A: 

One simple strategy is to put the loop in a separate function and do a return at the selected point:

void func()
{
    for(int a = 1; a <= 100; a++)    //loop a (main loop)
    {
        for(int b = 1000; b <= 2000; b++)    //loop b
        {
           if(b == 1555)
              return;
        }

        for(int c = 2001; c <= 3000; c++)    //loop c
        {
           .
           .
           .
        }
    }
}

Any kind of result may also be returned with a return value, or with a reference parameter for the function.

Stefan Rådström
This would be my solution. The code (three loops, two embedded in the first) is nasty enough to justify abstracting off into a subroutine anyway.
T.E.D.
+21  A: 

Either do one of four things: use goto, use throw, use a flag, or refactor.

Many will disagree with using goto, but sometimes it's a clean solution. (Most times, it isn't, but it exists for a reason.) However, I find the use of goto warrants a refactor.

The second solution is to throw some special exception and then catch it just outside the main loop. This is an abuse of the exception system and basically a worse goto; use a goto instead of this.

The third solution would be to use a flag of some sort. This is basically a "safer" goto, but some might argue it's a bit uglier. (Especially with multiple-levels. Though in such a case your concern is how ugly your code is.)

The solution I would recommend is refactor. Whatever you're doing, it's too much. You should move the inner loops into a function, and call that function. Returning to the main loop is simply a return from that function. (In other words "My work is done.")

GMan
+1, nice clean summary of the available options.
Justin Ethier
+1 for refactor suggestion. That solves a lot more problems than people would think!
Platinum Azure
There is nothing wrong with goto (if used correctly) This is one of these places. Its the abuse of goto that should be feared and the ability to recognize the abuse is so lacking in our higher education facilities.
Martin York
@Martin of course... but if for-loops and intricated goto's make a function long, then indeed it's really a bad idea.In this example we have three intricated for-loops and a goto... I think it is too much. My personnal view.
Stephane Rolland
+2  A: 

The ideal way would be to re-factor your code so that you no longer need such a complicated nested-loop structure. Depending on what the rest of your code looks like, your b and c loops may be candidates for becoming individual functions, if not the entire a loop.

Since it looks like loops b and c iterate over adjacent ranges, why not combine them and reduce your loop nesting a bit?

for (int a = 1; a <= 100; a++)    //loop a (main loop)
{
    int count = 1000;
    while (count <= 3000) // combined loops 'b' and 'c'
    {
        if (count <= 2000)
        {
            // Old loop 'b' code
            if (b == 1555)
                goto fullbreak;
        }
        else
        {
            // Old loop 'c' code
            ...
        }
        count++;
    }
}
fullbreak:

You can also use a condition variable instead of the goto. If you want to break out of the old b loop but still process the old c loop, simply set count = 2001 inside the old b loop code.

Ideally, you would at least be able to re-factor this to something more like

for (int a = 1; a <= 100; a++)    //loop a (main loop)
{
    if (process_inner_loop(pass, required, args))
        break;
}

where the function process_inner_loop wraps up your original two loops and returns non-zero if you want to break out of the enclosing loop. Now, instead of using goto or condition variables, you can simply return 1;.

bta
+2  A: 

\ (◕ ◡ ◕) /

[]() {
    for(int a = 1; a <= 100; a++)    //loop a (main loop)
    {
        for(int b = 1000; b <= 2000; b++)    //loop b
        {
           if(b == 1555)
              return;
        }

        for(int c = 2001; c <= 3000; c++)    //loop c
        {
           .
           .
           .
        }
    }
}();
Gunslinger47
Would optimizing compilers inline lambas in cases like this?
Gunslinger47
@Gunslinger47: Typically, any modern compiler will inline all but the complex/long functions, *especially* if the function definition is visible. (Link-time optimization is relatively new, and more difficult.) With that, note the lambda's are unique hidden structs, and the full definition is always available wherever it's used. So you're pretty much guaranteed lambda's will be inlined.
GMan