views:

3668

answers:

11

I have two for loops nested like this:

for(...) {
    for(...) {

    }
}

I know that there is a break; statement. But I am confused about if it breaks both loops or just the one in which it was called? I need to break both ones as soon as I see that it doesn't make sense to iterate more times over.

+9  A: 

break breaks out of one loop, but you can add a check to the outer loop which breaks when the inner breaks.

bool dobreak = false;
for ( ..; !dobreak && ..; .. ) {
   for ( ... ) {
      if (...) {
         dobreak = true;
         break;
      }
   }
}
zilupe
IMHO, using goto is much cleaner.
sigjuice
ephemient
Thank you for point to the error in for statement. Fixed.
zilupe
This would still execute possible code in the outer loop that would come after the inner loop
Martijn
+1  A: 

If a break is executed from within a set of nested loops, only the innermost loop in which the break is executed is terminated. (Just like standard C)

Mitch Wheat
+2  A: 

The break statement will only break out of the loop in scope, which is the parent loop. If you want to break out of the second loop as well you could use a boolean variable which is in scope of both loops

bool isTerminated = false;

for (...)
{
    if (!isTerminated)
    {
        for(...)
        {
            ...

            isTerminated = true;
            break;
        }
    }
    else
    {
        break;
    }
}
Nick Allen - Tungle139
+1  A: 

The break statement breaks out of the innermost loop. An additional test and break statement would be needed to break out of the outer loop.

Lance Richardson
+1  A: 

Probably the easiest way is to use a "flag" variable

for(i=0; i<10 && (done==false); i++)
  for(j=0;j< 10; j++){
     ..
     ..
     if(...){done=true; break;}
  }
Yogi
A: 

Change top loop's counter before break

for(i=0; i<10 ; i++)
  for(j=0;j< 10; j++){
     ..
     ..
     i = 10; 
     break;
  }
oxigen
I don't like this too much. The risk is that someone changes the exit condition in one place, and forget the other.
kotlinski
+5  A: 

The break statement only gets you out of the innermost loop. If you don't want the added overhead in code, memory and performance of a dedicated state variable, I recommend refactoring the code out into a function or method of its own, and using return to get out of all the loops:

void do_lots_of_work(void)
{
  int i, j;

  for(i=0; i<10 ; i++)
  {
    for(j=0;j< 10; j++)
    {
     ..
     ..
     if(disaster_struck())
      return; /* Gets us out of the loops, and the function too. */
    }
  }
}
unwind
I'd be very surprised if a function call in a loop managed to perform as well as a dedicated state variable, especially if you need to pass arguments in order to have access to variables in the outer function. Maybe if the compiler copies the function inline...
ephemient
What's worse, in my opinion, is the loss of the ability to understand the algorithm by reading it in one place. All this to avoid a goto?
Ori Pessach
I've run into this break/continue problem as well, sometimes wanting to continue the loop 2-3 levels up. Best thing to do IMHO is to refactor the nested loops into a method so that method can return whether to continue to parent loop.
Jason
+19  A: 

If using goto simplifies the code, then it would be appropriate.

for (;;) 
{
    for (;;) 
    {
        break; /* breaks inner loop */
    } 
    for (;;) 
    {
        goto outer; /* breaks outer loop */
    }
} 
outer:;
Ori Pessach
To expand on this, `for (;;) {for (;;) {break; /* breaks inner loop */} for (;;) {goto outer; /* breaks outer loop */}} outer:;`
ephemient
ephemient: Thanks. I added your code snippet to the answer.
Ori Pessach
+1  A: 

Others have mentioned how you can set a flag or use a goto, but I'd recommend refactoring your code so that the inner loop is turned into a separate method. That method can then return some flag to indicate that the outer loop should break. If you name your methods appropriately, this is much more readable.

for (int i = 0; i < 10; i++) {
   if (timeToStop(i)) break;
}

-(bool) timeToStop: (int) i {
    for (int j = 0; j < 10; j++) {
        if (somethingBadHappens) return true;
    }

    return false;
}

Pseudocode, not tested, but you get the idea.

Caffeine Coma
+1  A: 

Other than the already mentioned flag variable or goto you could throw an objective C exception

@try {
  for() {
    for() {
       @throw ...
    }
  }
}
@catch{
  ...
}
lothar
Wow, just as I was about to modify my answer to point out how people will suggest every single convoluted solution except using exceptions for flow control just to avoid a goto...
Ori Pessach
@Ori Pessach Well Exceptions are the modern OO versions of goto ;-)
lothar
They do clean up the stack nicely, at least.
Ori Pessach
A: 

another solution is to factor out the second loop in a function

int i;

for(i=0; i<10 ; i++){
  if !innerLoop(i) {
    break;
  }
}


bool innerLoop(int i)
  int j;
  for(j=0;j< 10; j++){
    doSomthing(i,j);
    if(endcondtion){
      return false;
    }
  }
}
Martijn