break inside of case- statement inside of loop

  • Thread starter Alexander Korsunsky
  • Start date
A

Alexander Korsunsky

Hi!

I have some code that looks similar to this:

--------------------------------------------

char array[10] = "abcdefghij";

for (int i = 0; i < 10; i++)
{
switch (array)
{
case 'a':
/* code */
break;
case 'b':
/* code */
break;
case 'c':
/* code */
break;

default:
/* code */
break;
}

}
 
B

Beej Jorgensen

for (int i = 0; i < 10; i++)
{
switch (array)
{
[code snipped all up]
break;
}

Is it possible to break out of the for loop from inside of one case-
statement, or do I have to use a workaround?


break only gets you out of the smallest enclosing switch or loop.

You could put another condition in the for:

for (i = done = 0; i < 10 && !done; i++) {
switch(array) {
case 'a':
done = 1;
break; // or "continue" to get right out
case 'b':
break;
}
}

Or you could use goto:

for (i = 0; i < 10; i++) {
switch(array) {
case 'a':
goto done;
case 'b':
break;
}
}
done:

-Beej--4am...hopefully I didn't screw that answer up too bad.
 
B

Bill Pursell

char array[10] = "abcdefghij";

It's unfortunate that this doesn't generate a
compiler warning in the same way that
int array[2] = { 1, 2, 3}; does.

Is it possible to break out of the for loop from inside of one case-
statement, or do I have to use a workaround?

There are at least 3 obvious ways:
1) increment the index to cause your condition on the
for loop to terminate the loop (a workaround.)
2) goto
3) fix the loop condition to more accurately reflect
whatever it is you are testing for. (Probably
the correct solution.)

There is no "break 3" type syntax in C, however.
 
B

Bob

Hi!

I have some code that looks similar to this:

--------------------------------------------

char array[10] = "abcdefghij";

for (int i = 0; i < 10; i++)
{
switch (array)
{
case 'a':
/* code */
break;
case 'b':
/* code */
break;
case 'c':
/* code */
break;

default:
/* code */
break;
}


// After the switch executes, control passes here.
// You could retest and break here to get out of the for loop.
// For example, breaking if case 'b'.

if(array == 'b')
break;

I'm not aware of a double break command. A break statement stops
execution of the smallest enclosing switch statement. I would break
out of each as above. You might rethink the switch statement and
recast it as a if-else series.

Best wishes,

Bob
 
A

Alexander Korsunsky

Bill said:
char array[10] = "abcdefghij";

It's unfortunate that this doesn't generate a
compiler warning in the same way that
int array[2] = { 1, 2, 3}; does.

I agree. I will use array[] = "abcde"; in future.
There are at least 3 obvious ways:
1) increment the index to cause your condition on the
for loop to terminate the loop (a workaround.)

Doesn't seem to me, that this is good style... Correct me if I'm mistaken.

I've heard that goto should not be used (anymore) because there are
better ways.
But in my situation it looks like that would be the best possibility,
because I don't have to set up a variable and test it to be false, to
continue the loop.
3) fix the loop condition to more accurately reflect
whatever it is you are testing for. (Probably
the correct solution.)

In my case, it isn't because I am checking a letter, and then executing
different code for each different letter. This code calls functions
which return error codes if they fail. To prevent the program to fail,
the loop has to be stopped.

Thanks for your help,
Alexander Korsunsky
 
E

Eric Sosman

Alexander said:
Hi!

I have some code that looks similar to this:

--------------------------------------------

char array[10] = "abcdefghij";

for (int i = 0; i < 10; i++)
{
switch (array)
{
case 'a':
/* code */
break;
case 'b':
/* code */
break;
case 'c':
/* code */
break;

default:
/* code */
break;
}

}


You cannot `break' from the inside of the `switch' to
the outside of the `for'. Here is one alternative:

for (int i = 0; i < 10; ++i) {
switch(array) {
case 'a':
/* code */
continue;
case 'b':
/* code */
if (want_to_break_out)
break;
continue;
default:
/* code */
continue;
}
break;
}

I cannot recommend this dodge for all circumstances.
Code is read by compilers and by people; the former are the
less important audience.
 
K

Kenny McCormack

There are at least 3 obvious ways:
1) increment the index to cause your condition on the
for loop to terminate the loop (a workaround.)

Doesn't seem to me, that this is good style... Correct me if I'm mistaken.[/QUOTE]

The point is that the "short answer" to your question is "No, you can't
do it (you have to do a workaround)". The slightly longer answer is
"Yes, it is a mis-design in the language, but we have to live with it".
The problem isn't so much the *lack* of "break 2" (as exists in shell),
but rather the use of "break" in the syntax of "switch". "break" should
be (i.e., have been) reserved for the looping constructs and "switch"
clearly isn't a looping construct.

I've asked this same question here in the past and have been told that
"goto" is the best workaround (one of the few situations where "goto" is
"permissible").
 
B

Bob

Bill Pursell wrote:

Doesn't seem to me, that this is good style... Correct me if I'm mistaken.

Sounds like a hard to maintain work around to me.
I've heard that goto should not be used (anymore) because there are
better ways.

goto, continue, and break are all jump statements. IMHO, they all
share some of the same issues although goto is the worst.
But in my situation it looks like that would be the best possibility,
because I don't have to set up a variable and test it to be false, to
continue the loop.


In my case, it isn't because I am checking a letter, and then executing
different code for each different letter. This code calls functions
which return error codes if they fail. To prevent the program to fail,
the loop has to be stopped.

Then I would not use a switch statement at all. I'm not sure how many
cases you are worrying about, but perhaps something like this:

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

function returns an error code and may contain the switch as well, if
needed.

Best wishes,

Bob
 
F

Flash Gordon

Bob wrote, On 25/02/07 13:21:
Sounds like a hard to maintain work around to me.

Not something I would like.
goto, continue, and break are all jump statements. IMHO, they all
share some of the same issues although goto is the worst.

setjmp/longjmp is worse IMHO. Which does not mean to say it isn't needed
sometimes.
But in my situation it looks like that would be the best possibility,
because I don't have to set up a variable and test it to be false, to
continue the loop.

In my case, it isn't because I am checking a letter, and then executing
different code for each different letter. This code calls functions
which return error codes if they fail. To prevent the program to fail,
the loop has to be stopped.

Then I would not use a switch statement at all. I'm not sure how many
cases you are worrying about, but perhaps something like this:

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

function returns an error code and may contain the switch as well, if
needed.


Or include the for in the function as well and use an early return in
the switch.
 
B

Bill Pursell

In my case, it isn't because I am checking a letter, and then executing
different code for each different letter. This code calls functions
which return error codes if they fail. To prevent the program to fail,
the loop has to be stopped.

You might consider something like:
for( ; !err_flag; ) {
switch(value) {
case 0:
err_flag = do_something();
break;
....
 
S

santosh

Alexander said:
Hi!

I have some code that looks similar to this:

char array[10] = "abcdefghij";

for (int i = 0; i < 10; i++)
{
switch (array)
{
case 'a':
/* code */
break;
case 'b':
/* code */
break;
case 'c':
/* code */
break;

default:
/* code */
break;
}

}


Is it possible to break out of the for loop from inside of one case-
statement, or do I have to use a workaround?


Essentially a workaround. C doesn't have multilevel breaks. You can do
one of the following:

1.
int done = 0;
for(i = 0; i < 10 || !done; i++) {
switch {
case 'a':
/* do something */
done = 1;
break;
/* ... */
}
}

2.
int done = 0;
for(i = 0; i < 10; i++) {
switch {
case 'a':
/* do something */
done = 1;
break;
/* ... */
}
if(done) break;
}

3.
for(i = 0; i < 10; i++) {
switch {
case 'a':
/* do something */
if(FINISHED) goto proceed;
else break;
/* ... */
}
}
proceed:
/* ... */
 
C

CBFalconer

Alexander said:
I have some code that looks similar to this:

--------------------------------------------
char array[10] = "abcdefghij";

for (int i = 0; i < 10; i++)
{
switch (array)
{
case 'a':
/* code */

goto label;
break;
case 'b':
/* code */
break;
default:
/* code */
break;
}
} label: /* some code */;

Very easy. Just use a goto as illustrated above.
 
K

Kenny McCormack

vicky said:
apart it answer above. no need and solved have break with his from in
for of get by never is others problem it any break the two to enough
key is in problem their is and as result, ways programming, use the
explained say no words already you single co-ordination of

Makes about as much sense like that as before, doesn't it?
 
D

Default User

Bill said:
char array[10] = "abcdefghij";

It's unfortunate that this doesn't generate a
compiler warning in the same way that
int array[2] = { 1, 2, 3}; does.

I think the latter is a constraint violation. That's not true for the
first, it's perfectly legal, although questionable and of course a
warning could be issued if the compiler felt like it.



Brian
 
K

Keith Thompson

Bill Pursell said:
There is no "break 3" type syntax in C, however.

For which I'm extremely grateful.

A multi-level break that requires you to specify the number of levels
would lead to numerous hard-to-find bugs. Why force the programmer
and the reader to *count* something? That's what computers are for.

I'd like C to have a multi-level break construct, but the argument
should refer to the *name* of the construct, perhaps a label. A
number of other languages do this (Ada, Perl, et al).
 
K

Keith Thompson

CBFalconer said:
Alexander said:
I have some code that looks similar to this:

--------------------------------------------
char array[10] = "abcdefghij";

for (int i = 0; i < 10; i++)
{
switch (array)
{
case 'a':
/* code */

goto label;
break;
case 'b':
/* code */
break;
default:
/* code */
break;
}
} label: /* some code */;

Very easy. Just use a goto as illustrated above.


Agreed. C should, IMHO, have a multi-level break construct. Given
that it doesn't, a goto that does exactly the same thing that a
multi-level break would have done is the best workaround. Distorting
the code (e.g., by replacing a switch with an if/else chain) just to
avoid the dreaded goto is a bad idea.

I'd also use a more mnemonic name for the label. "label" is fine for
an example, but not for real-world code. I might use something like
"BREAK_OUTER_LOOP:".
 
K

Keith Thompson

Default User said:
Bill said:
char array[10] = "abcdefghij";

It's unfortunate that this doesn't generate a
compiler warning in the same way that
int array[2] = { 1, 2, 3}; does.

I think the latter is a constraint violation. That's not true for the
first, it's perfectly legal, although questionable and of course a
warning could be issued if the compiler felt like it.

For those not aware of the rule:

char s[] = "abc";
/* char s2[2] = "abc"; */
char s3[3] = "abc";
char s4[4] = "abc";
char s5[5] = "abc";

s is a 4-byte array containing { 'a', 'b', 'c', '\0' }.
s2, I believe, is a constraint violation.
s3 is a 3-byte array containing { 'a', 'b', 'c' }; it is *not* a string.
s4, like s, is a 4-byte array containing { 'a', 'b', 'c', '\0' }.
s5 is a 5-byte array containing { 'a', 'b', 'c', '\0', '\0' }.

The only way (I think) for a string literal to specify a non-string
(i.e., an array with no '\0' terminator) is to use it as the
initializer for an array of exactly the right size. I suspect we'd be
better off without this rule, which often leads to incorrect code
where the programmer *meant* to create a valid string. Perhaps a
special syntax to indicate that a string literal represents an array
not terminated with a '\0' would have been useful.

If you just want a string with no additional space, use the "[]" form
and let the compiler figure out the required size. As I recently said
here in another thread, counting is what computers are best at; let
the compiler do it for you.
 
M

matevzb

Default User said:
Bill said:
On Feb 25, 11:16 am, Alexander Korsunsky <[email protected]>
wrote:
char array[10] = "abcdefghij";
It's unfortunate that this doesn't generate a
compiler warning in the same way that
int array[2] = { 1, 2, 3}; does.
I think the latter is a constraint violation. That's not true for the
first, it's perfectly legal, although questionable and of course a
warning could be issued if the compiler felt like it.

For those not aware of the rule:

char s[] = "abc";
/* char s2[2] = "abc"; */
char s3[3] = "abc";
char s4[4] = "abc";
char s5[5] = "abc";

s is a 4-byte array containing { 'a', 'b', 'c', '\0' }.
s2, I believe, is a constraint violation.
s3 is a 3-byte array containing { 'a', 'b', 'c' }; it is *not* a string.
s4, like s, is a 4-byte array containing { 'a', 'b', 'c', '\0' }.
s5 is a 5-byte array containing { 'a', 'b', 'c', '\0', '\0' }.
And, to continue in this manner, it should probably be noted that e.g.
s1024[1024] = "";
should not be used for string initialization, as it will set all 1024
characters to '\0'. Not usually noticed, but it may turn out to cause
a major performance degradation.
<snip>
 
D

Default User

Keith said:
Default User said:
Bill said:
On Feb 25, 11:16 am, Alexander Korsunsky <[email protected]>
wrote:
char array[10] = "abcdefghij";

It's unfortunate that this doesn't generate a
compiler warning in the same way that
int array[2] = { 1, 2, 3}; does.

I think the latter is a constraint violation. That's not true for
the first, it's perfectly legal, although questionable and of
course a warning could be issued if the compiler felt like it.

For those not aware of the rule:

char s[] = "abc";
/* char s2[2] = "abc"; */
char s3[3] = "abc";
char s4[4] = "abc";
char s5[5] = "abc";

s is a 4-byte array containing { 'a', 'b', 'c', '\0' }.
s2, I believe, is a constraint violation.

That's my reading of the standard.
s3 is a 3-byte array containing { 'a', 'b', 'c' }; it is not a string.
Right.

The only way (I think) for a string literal to specify a non-string
(i.e., an array with no '\0' terminator) is to use it as the
initializer for an array of exactly the right size. I suspect we'd be
better off without this rule, which often leads to incorrect code
where the programmer meant to create a valid string.

C++ decided to remove that feature, so that's another of those subtle
differences in the languages.




Brian
 
P

Peter Nilsson

...
And, to continue in this manner, it should probably be noted that
e.g.
s1024[1024] = "";
should not be used for string initialization, as it will set all
1024 characters to '\0'. Not usually noticed, but it may turn out
to cause a major performance degradation.

The golden rule is not to (micro-)optimise until there's a proven
bottleneck.

The real question is whether you actually need to initialise or
not. I find it extremely rare that I actually need to initialise
a character buffer to an empty string.

Given the choice, most programmers will not initialise an object
if they don't have to. [A notable exception is Richard Heathfield,
though I believe he is more likely to use {0} than "".]
 

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

Members online

No members online now.

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top