breaking out of multiple nested loops

T

Tagore

Hi,
How can I break out of multiple nested loops?
i.e if i have a program structure like
for(;;)
{
for(;;){
....
,,,,
for(;;){
//How can I break out of here
break; //it only breaks only from last for loop.
}
}
}
//I want to reach here directly here after breaking
 
N

Nick

Tagore said:
Hi,
How can I break out of multiple nested loops?
i.e if i have a program structure like
for(;;)
{
for(;;){
....
,,,,
for(;;){
//How can I break out of here
break; //it only breaks only from last for loop.
}
}
}
//I want to reach here directly here after breaking

You can' do it directly (there isn't - as I've heard proposed - a "break
3" to jump out three levels).

There are a few ways to make it work. The most structured is to create
a separate flag variable that you check in each loop and either end
looping (add it to the middle clause of the if) or test-and-break at the
top of each loop.

Eg:
int flag = 0;
for(;flag==0 && ;)
{
for(;flag==0 &&;){
....
,,,,
for(;flag==0;){
//How can I break out of here flag = 1;
}
}
}

or
int flag = 0;
if(flag == 1)
break;
if(flag == 1)
break;
....
,,,,
for(;;){
//How can I break out of here flag = 1;
break; //it only breaks only from last for loop.
}
}
}

My tendency is hated by many advocates of structured programming: I'd
put the whole thing in a function and return where you've got the
"break". You can even return a status code to say whether you finished
the nested loops or jumped out early. I still claim it's completely
obvious what it does and that's good enough for me.
 
K

Keith Thompson

Tagore said:
How can I break out of multiple nested loops?
i.e if i have a program structure like
for(;;)
{
for(;;){
....
,,,,
for(;;){
//How can I break out of here
break; //it only breaks only from last for loop.
}
}
}
//I want to reach here directly here after breaking

C has no multi-level break statement. Use a goto statement.

No, really.

It can also be argued (and undoubtedly will be) that if you find
yourself needing a multi-level break, your code is too complicated,
and you should restructure the code so it no longer needs it.
One alternative would be to put the outer for loop in a function and
use a return statement (though this might be difficult if the loop
shares local declarations with other code in the existing function).

Some people argue against the use of the break statement at all,
and say that each chunk of code should have a single entry point
and a single exit point. I don't feel very strongly about this,
but there are certainly advantages to that approach. In particular,
if you use break or goto, it's easy to accidentally skip over code
that needs to be executed at the end of the construct. I suspect
someone will be along shortly to make the argument more strongly.
 
B

Ben Bacarisse

Tagore said:
How can I break out of multiple nested loops?
i.e if i have a program structure like
for(;;)
{
for(;;){
....
,,,,
for(;;){
//How can I break out of here
break; //it only breaks only from last for loop.
}
}
}
//I want to reach here directly here after breaking

(1) Put a label there and "goto" that label.

(2) Use a Boolean/int variable "more_work" and set it to 0 where you
break the inner loop. Change the loop conditions to include it:
condition C become more_work && C.

(3) Make each loop into a function. This needs more work (there is no
recipe for doing it with every time) but many triple-nested loops
should really be re-written as a loop calling a function.

If you give a real example, you might get more practical help. If you
really have three loops with no terminating conditions, a re-design is
almost certainly called for!
 
K

Keith Thompson

Nick said:
You can' do it directly (there isn't - as I've heard proposed - a "break
3" to jump out three levels).

I hope "break 3" hasn't been *seriously* proposed.

I'd like to see a multi-level break (and continue) in C, but the
argument should be the name of the loop to be terminated, not the
number of nested loops to terminate. The name of the loop could be
specified by a label on the loop. For example:

PROCESS_INPUT: while ((c = getchar()) != EOF) {
/* ... */
if (some_condition) {
break PROCESS_INPUT;
}
/* ... */
}

There's precedent for this in other languages.

The meaning of "break 3;" is insufficiently obvious to the reader
and difficult to maintain. If you write "break 2;" where you meant
"break 3;", the error won't be recognized by the compiler, and may
not be recognized by the programmer. Don't make the programmer or
the reader count things; computers are really good at that.
There are a few ways to make it work. The most structured is to create
a separate flag variable that you check in each loop and either end
looping (add it to the middle clause of the if) or test-and-break at the
top of each loop.

Eg:
int flag = 0;

or
int flag = 0;
if(flag == 1)
break;
if(flag == 1)
break;

I'd replace each occurrence of "flag == 1" by "flag", and of
"flag == 0" by "!flag".

[...]
 
N

Nick

Keith Thompson said:
I'd replace each occurrence of "flag == 1" by "flag", and of
"flag == 0" by "!flag".

In truth, I'd use either the standard or my own boolean variables. But
because I use my own I've never bothered to learn the standards.
 
B

BGB / cr88192

Tagore said:
Hi,
How can I break out of multiple nested loops?
i.e if i have a program structure like
for(;;)
{
for(;;){
....
,,,,
for(;;){
//How can I break out of here
break; //it only breaks only from last for loop.
}
}
}
//I want to reach here directly here after breaking

strategy 1:
don't use multiply nested loops if avoidable (or if multi-level breaks are
needed);
strategy 2, re-check the loop condition from the prior loop, and if it is
still good, then re-break (if this strategy does not work, consider
reworking the code).

others like goto here, but myself and many others don't, and so my
preference is to either use continue/break, or restructure the code so that
a complex loop is unecessary (I generally like functions being atomic
operations, and complex loops with multi-level breaks often indicate
something which is not an atomic operation).

similarly, I don't normally like using a return within a loop, although in
some cases I have done so in performance-sensitive code.

personally, I prefer loops over the use of goto, since even an ugly loop
(with breaks and continues) is still usually cleaner that goto and labels,
and as well the block for the loop generally shows the region which is
within the loop, which may not be so clear with lots of gotos.

....
 
K

Kenny McCormack

Nick said:
A quick google shows a fair few people discussing it - with lots of
others leaping in with your suggestions. As you say, numbering it is an
appalling idea - sooner or later someone is going to stick another loop
in the middle.

The precedent for that is the shell (sh and derivatives).

And C/Unix is all about preserving precedent (just like the law).
 
S

Saurav Bhasin

...


The precedent for that is the shell (sh and derivatives).

And C/Unix is all about preserving precedent (just like the law).

Sure we can try multiple loops, I think we can use Flags for this
purpose. Goto and Label can make code difficult also.
 
B

bartc

Keith Thompson said:
I hope "break 3" hasn't been *seriously* proposed.

I'd like to see a multi-level break (and continue) in C, but the
argument should be the name of the loop to be terminated, not the
number of nested loops to terminate. The name of the loop could be
specified by a label on the loop. For example:

PROCESS_INPUT: while ((c = getchar()) != EOF) {
/* ... */
if (some_condition) {
break PROCESS_INPUT;
}
/* ... */
}

There's precedent for this in other languages.

The meaning of "break 3;" is insufficiently obvious to the reader
and difficult to maintain. If you write "break 2;" where you meant
"break 3;", the error won't be recognized by the compiler, and may
not be recognized by the programmer. Don't make the programmer or
the reader count things; computers are really good at that.

I use break 2, 3 and so on in other languages I use (or exit 2, 3 as it
would be).

It is really not a big deal.

I've just quickly looked at 250K lines of my code, and "exit 2" is used 4
times, and "exit 3" just twice.

If an extra looping level is added, this is likely to be an extra outer
level; this doesn't affect the validity of the exit 2 or 3.

(And anyway C would have the same problem with it's break statement when
extra loop levels are added, but in that case, you can't just change a
digit, but have to completely restructure! Even changing a statement from an
if-then-else chain to a switch will cause a problem if there is a break
inside.)

So having numbered multi-level break is not the end of the world, provided
it's not abused, just like anything else. It's just nice having it available
to quickly get you out of trouble.

(And yes I also have a named exit statement on a newer design, but I haven't
got round to implementing it yet. Maybe I never will)
 
K

Keith Thompson

bartc said:
Keith Thompson said:
I hope "break 3" hasn't been *seriously* proposed.
[big snip]

I use break 2, 3 and so on in other languages I use (or exit 2, 3 as it
would be).

It is really not a big deal.

I've just quickly looked at 250K lines of my code, and "exit 2" is used 4
times, and "exit 3" just twice.

If an extra looping level is added, this is likely to be an extra outer
level; this doesn't affect the validity of the exit 2 or 3.

(And anyway C would have the same problem with it's break statement when
extra loop levels are added, but in that case, you can't just change a
digit, but have to completely restructure! Even changing a statement from an
if-then-else chain to a switch will cause a problem if there is a break
inside.)

So having numbered multi-level break is not the end of the world, provided
it's not abused, just like anything else. It's just nice having it available
to quickly get you out of trouble.

(And yes I also have a named exit statement on a newer design, but I haven't
got round to implementing it yet. Maybe I never will)

It's probably unlikely that any kind of multi-level break will be
added to C.

If such a feature were to be added, yes, if it were defined to take a
numeric argument (presumably a constant expression), we could deal
with it. Any features can be used correctly if you're sufficiently
careful, or incorrectly if you're not. And if your code is so complex
that you're likely to use "break 3;" rather than "break 4;", or vice
versa, the answer is almost certainly to restructure the code.

But since neither "break <number>" nor "break <LABEL>" would, ahem,
break any existing code, I really can't think of any sane reason to
*prefer* the "break <number>" to "break <LABEL>".

Can you?
 
B

bartc

It's probably unlikely that any kind of multi-level break will be
added to C.

No. Committees don't seem to like new syntax.
If such a feature were to be added, yes, if it were defined to take a
numeric argument (presumably a constant expression), we could deal
with it. Any features can be used correctly if you're sufficiently
careful, or incorrectly if you're not. And if your code is so complex
that you're likely to use "break 3;" rather than "break 4;", or vice
versa, the answer is almost certainly to restructure the code.

You might notice your code not working right if you get it wrong.

And any alternatives that don't involve goto are likely to be more
error-prone.
But since neither "break <number>" nor "break <LABEL>" would, ahem,
break any existing code, I really can't think of any sane reason to
*prefer* the "break <number>" to "break <LABEL>".

I have preference for break <no>, even though it looks crude, as break
<label> is not actually much different from goto <label>, and it means
thinking up a label in the first place and then remembering to add it at one
end of the loop or the other.

But either (or both) will do the job.

At present C barely has an ordinary break statement, because of the problem
with using it inside switch.
 
R

Richard Tobin

bartc said:
I have preference for break <no>, even though it looks crude

This would be a really bad idea, since it would often have to be fixed
up when the program was changed, and there would be no way to detect
most errors. What's more, a good name lets you express what you
mean very directly; for "break customer_loop" expresses that you
are breaking out of the loop over customers, without the reader
having to look back or forward through the code.
as break
<label> is not actually much different from goto <label>,

I cannot see any force in that argument. What is the bad thing about
"goto label" that makes "break label" be bad too?
and it means
thinking up a label in the first place and then remembering to add it at one
end of the loop or the other.

Well, you *could* give up variable names and just use a single array.

-- Richard
 
S

Seebs

I cannot see any force in that argument. What is the bad thing about
"goto label" that makes "break label" be bad too?

I actually like break <label> much better. The thing about
goto <label> that I don't like is that label may be anywhere in
or out of a loop, etcetera.

By constrast, consider a hypothetical break/continue <label> such that:

foo: while(1) {
...
}

means that, inside the loop, "continue foo" jumps to the test at the
top of the loop, while "break foo" jumps immediately past the end of
the loop, regardless of the number of intervening levels -- I think
that's a lot more useful than break <n>, while much more predictable
and controlled than a goto.

-s
 
J

James Dow Allen

It may be true that "break label" is so unbelievably similar
to "goto label" that even proposing the former suggests a
religious aversion to writing "goto" (perhaps much like the
Jewish aversion to pronouncing "Yahweh").

However I don't think the suggested form is eguivalent to "goto".
Rather than locating the label at the place where the break
would, err, go to, the user-friendly suggestion is to locate
the label at the place where "break" breaks out of!
And rather than allowing the coder to goto where and when he
wants, the user-friendly break would allow another user-friendly
diagnostic: "Error: breaking to a label that isn't breakable."
I cannot see any force in that argument.  What is the bad thing about
"goto label" that makes "break label" be bad too?

Richard, would you be willing to cast your vote on the
constructions as
http://james.fabpedigree.com/gotoalt.htm

James Dow Allen
 
R

Richard Tobin

I have never had a problem using a break inside a switch.

You may never have had a problem with it, but I have more than once
taken code like this:

while(...)
{
if(...)
{
...;
continue;
}
else if(...)
break;
else
...
}

and changed the if-else chain to a switch. This has the annoying
result that the break no longer works. The non-orthogonality is
particularly clear from the fact that the continue does not need to be
changed.

Of course a "break label" construct would not remove this issue,
but it would at least mean that the fix did not require a change
to the structure of the code.

-- Richard
 
B

bartc

Richard Tobin said:
This would be a really bad idea, since it would often have to be fixed
up when the program was changed, and there would be no way to detect
most errors.

Is that really true?

C has already has a break 1 (or break 0 if you prefer); what happens now
when this:

while (...) {
...
break;
...
}

turns into this:

while (...) {
...
while (...) {
...
break;
...
}
}

?

Either you only really wanted to break out of that inner loop, and nothing
changes (in which cases break 2 would be also stay the same), or or wanted
to break out of all loops, in which case you have to change the break to
something entirely different; break 2 on the other hand just becomes break
3...

The only difference might be if you started with 2 nested loops,
containing a break 2 in the inner one, decided to put an extra loop
in-between, and intended that break 2 to break out of all loops. Then and
only then, you might have to change a 2 to a three. But how often is that
going to happen?

And in most of those cases, you can use a 'break all' to break out of all
nested loops, if having a number really bothers you.
I cannot see any force in that argument. What is the bad thing about
"goto label" that makes "break label" be bad too?

I didn't say goto was bad.
Well, you *could* give up variable names and just use a single array.

Imagine *every* loop had to have it's own name, whether you'd intended to
break out of it or not. You might quickly get fed up.
 
E

Eric Sosman

bartc said:
No. Committees don't seem to like new syntax.

A review of the differences between C90 and C99 suggests
that their distaste is not overpoweringly strong.
 
E

Eric Sosman

Seebs said:
I actually like break <label> much better. The thing about
goto <label> that I don't like is that label may be anywhere in
or out of a loop, etcetera.

By constrast, consider a hypothetical break/continue <label> such that:

foo: while(1) {
...
}

means that, inside the loop, "continue foo" jumps to the test at the
top of the loop, while "break foo" jumps immediately past the end of
the loop, regardless of the number of intervening levels -- I think
that's a lot more useful than break <n>, while much more predictable
and controlled than a goto.

This is how Java does it, and I for one find it repugnant.
Although `continue foo;' reads reasonably well, `break foo;' is
just plain awful: It says "transfer control to somewhere *not*
close to the label foo." To discover where the destination is,
you've got to find the label and then search for the other end
of its block -- and we must assume that the block is non-trivial,
or a multi-level break wouldn't have been needed in the first
place ... (On a labelled do-while, `continue foo;' shares the
same problem of misdirected attention.)

But since there's precedent, somebody will probably follow
it, alas. Java adopted some of C's infelicities; why shouldn't
C incorporate the unpleasant features of Java?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,744
Messages
2,569,480
Members
44,900
Latest member
Nell636132

Latest Threads

Top