Moeb
Moeb

Reputation: 10861

What is a neat way of breaking out of many for loops at once?

Suppose I need to break out of three or four nested for loops at once at the occurence of some event inside the innermost loop. What is a neat way of doing that?

what I do is use flags like this:

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

I don't think this is particularly neat.

How would you accomplish the same thing? (w/o using jumps)

Upvotes: 17

Views: 2960

Answers (14)

DaBler
DaBler

Reputation: 2850

If you are using GCC and this library, the break can accept the number of nested loops you want to exit:

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

Upvotes: 0

CAFxX
CAFxX

Reputation: 30301

If you absolutely don't want to use goto, set all loop conditions to 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;
            }
        }
    }
}

note: a smart optimizing compiler will turn the contents of the if in a jump to the end of the outer-most loop

Upvotes: 4

Paul
Paul

Reputation: 61

I'd do something like:

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

Upvotes: 0

Carson Myers
Carson Myers

Reputation: 38564

a little bit of silly self-documenting:

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

but really, you shouldn't have three nested for-loops. You should consider refactoring into different functions and improving your program's logic instead of doing this.

While I agree that sometimes goto really is the best solution, I think that any problem to which goto is the solution is a result of poor code.

Upvotes: 2

AnT stands with Russia
AnT stands with Russia

Reputation: 320431

If premature completion of any cycle always means that you have to break the enclosing cycle as well, then you don't need any extra flags. The whole thing might just look as follows

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

In my experience, this is what is needed in majority of cases.

Upvotes: 2

DV.
DV.

Reputation: 4603

Dividing by 0 is the surest method I know that will break you out of any number of loops. This works because the DIV assembly instruction doesn't like such silliness.

So, you can try this:

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

Getting back from the trap that happens on such events left as an exercise for the reader (it's trivial).

Upvotes: 0

ts4z
ts4z

Reputation: 61

goto. This is one of the very few places where goto is the appropriate tool, and is usually the argument presented why goto isn't complete evil.

Sometimes, though, I do this:

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

The idea is that I get a guaranteed free of bar, plus I get a clean two-level break out of the switch via return.

Upvotes: 5

Egon
Egon

Reputation: 1705

One way to do it is a state machine. But i would still use goto. It's much simpler. :)

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

Upvotes: -1

thethanghn
thethanghn

Reputation: 329

sometimes you can use trick like this:

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

}

or declare addition flag in your loop:

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

it costs only a line but clean, I think.

justin

Upvotes: 3

Chris Lutz
Chris Lutz

Reputation: 75399

How would you accomplish the same thing? (w/o using jumps)

Why? Nothing is universally evil, and every put-upon tool has its uses (except gets()). Using goto here makes your code look cleaner, and is one of the only choices we have (assuming C). Look:

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:

Much cleaner than all those flag variables, and it even shows more clearly what your code is doing.

Upvotes: 14

Foole
Foole

Reputation: 4850

Put all the loops in a function and just return instead of break.

Upvotes: 50

Test
Test

Reputation: 1727

use goto. it's clean and simple.

Upvotes: 88

moogs
moogs

Reputation: 8202

Just a wee bit better.

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

But if you really need to have those loops, then it makes sense explicitly declaring in each loop what conditions must hold for it to continue, for readability.

Upvotes: 5

Asaph
Asaph

Reputation: 162781

If you're using Java, you can associate labels with each for block and then reference the label after a continue statement. For example:

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

Upvotes: 18

Related Questions