Equivalent using for-loop instead do-while-loop - c

I was wondering instead of using a do-while loop, what is the equivalent for-loop or any other combination of loops in c?

Any sort of a loop can be constructed from a combination of an infinite "forever" loop, and a conditional break statement.
For example, to convert
do {
<action>
} while (<condition>);
to a for loop, you can do this:
for (;;) {
<action>
if (!<condition>) break;
}
You can use the same trick to convert a do/while loop to a while loop, like this:
while (true) {
<action>
if (!<condition>) break;
}
Moreover, the loop is not needed at all: any of the above can be modeled with a label at the top and a goto at the bottom; that is a common way of doing loops in assembly languages. The only reason the three looping constructs were introduced into the language in the first place was to make the language more expressive: the do/while loop conducts author's idea much better than any of the alternatives shown above.

There is no other loop that executes the loop content at least once, as do-while does. Of course you could emulate do-while with a flag and a while loop:
do {
A;
} while (B)
becomes
int flag=1;
while (flag || B) {
flag=0;
A;
}
but that's not really an alternative, it just obscures your original intent.

The following three loops are all equivalent:
#define FALSE (0)
#define TRUE (!(FALSE))
do
{
status = getStatus();
}
while(status == TRUE);
status = TRUE;
while(status == TRUE)
{
status = getStatus();
}
for(status = TRUE; status == TRUE; status = getStatus())
{
}

Related

How does the break statement work in this function? [duplicate]

Can you break out of an if statement or is it going to cause crashes? I'm starting to acquaint myself with C, but this seems controversial. The first image is from a book on C
("Head First C") and the snippet shows code written by Harvard's CS classes staff. What is actually going on and has it something to do with C standards?
breaks don't break if statements.
On January 15, 1990, AT&T's long-distance telephone system crashed, and 60,000 people lost their phone service. The cause? A developer working on the C code used in the exchanges tried to use a break to break out of an if statement. But breaks don't break out of ifs. Instead, the program skipped an entire section of code and introduced a bug that interrupted 70 million phone calls over nine hours.
for (size = 0; size < HAY_MAX; size++)
{
// wait for hay until EOF
printf("\nhaystack[%d] = ", size);
int straw = GetInt();
if (straw == INT_MAX)
break;
// add hay to stack
haystack[size] = straw;
}
printf("\n");
break interacts solely with the closest enclosing loop or switch, whether it be a for, while or do .. while type. It is frequently referred to as a goto in disguise, as all loops in C can in fact be transformed into a set of conditional gotos:
for (A; B; C) D;
// translates to
A;
goto test;
loop: D;
iter: C;
test: if (B) goto loop;
end:
while (B) D; // Simply doesn't have A or C
do { D; } while (B); // Omits initial goto test
continue; // goto iter;
break; // goto end;
The difference is, continue and break interact with virtual labels automatically placed by the compiler. This is similar to what return does as you know it will always jump ahead in the program flow. Switches are slightly more complicated, generating arrays of labels and computed gotos, but the way break works with them is similar.
The programming error the notice refers to is misunderstanding break as interacting with an enclosing block rather than an enclosing loop. Consider:
for (A; B; C) {
D;
if (E) {
F;
if (G) break; // Incorrectly assumed to break if(E), breaks for()
H;
}
I;
}
J;
Someone thought, given such a piece of code, that G would cause a jump to I, but it jumps to J. The intended function would use if (!G) H; instead.
This is actually the conventional use of the break statement. If the break statement wasn't nested in an if block the for loop could only ever execute one time.
MSDN lists this as their example for the break statement.
As already mentioned that, break-statement works only with switches and loops. Here is another way to achieve what is being asked. I am reproducing
https://stackoverflow.com/a/257421/1188057 as nobody else mentioned it. It's just a trick involving the do-while loop.
do {
// do something
if (error) {
break;
}
// do something else
if (error) {
break;
}
// etc..
} while (0);
Though I would prefer the use of goto-statement.
I think the question is a little bit fuzzy - for example, it can be interpreted as a question about best practices in programming loops with if inside. So, I'll try to answer this question with this particular interpretation.
If you have if inside a loop, then in most cases you'd like to know how the loop has ended - was it "broken" by the if or was it ended "naturally"? So, your sample code can be modified in this way:
bool intMaxFound = false;
for (size = 0; size < HAY_MAX; size++)
{
// wait for hay until EOF
printf("\nhaystack[%d] = ", size);
int straw = GetInt();
if (straw == INT_MAX)
{intMaxFound = true; break;}
// add hay to stack
haystack[size] = straw;
}
if (intMaxFound)
{
// ... broken
}
else
{
// ... ended naturally
}
The problem with this code is that the if statement is buried inside the loop body, and it takes some effort to locate it and understand what it does. A more clear (even without the break statement) variant will be:
bool intMaxFound = false;
for (size = 0; size < HAY_MAX && !intMaxFound; size++)
{
// wait for hay until EOF
printf("\nhaystack[%d] = ", size);
int straw = GetInt();
if (straw == INT_MAX)
{intMaxFound = true; continue;}
// add hay to stack
haystack[size] = straw;
}
if (intMaxFound)
{
// ... broken
}
else
{
// ... ended naturally
}
In this case you can clearly see (just looking at the loop "header") that this loop can end prematurely. If the loop body is a multi-page text, written by somebody else, then you'd thank its author for saving your time.
UPDATE:
Thanks to SO - it has just suggested the already answered question about crash of the AT&T phone network in 1990. It's about a risky decision of C creators to use a single reserved word break to exit from both loops and switch.
Anyway this interpretation doesn't follow from the sample code in the original question, so I'm leaving my answer as it is.
You could possibly put the if into a foreach a for, a while or a switch like this
Then break and continue statements will be available
foreach ([1] as $i) if ($condition) { // Breakable if
//some code
$a = "b";
// Le break
break;
// code below will not be executed
}
for ($i=0; $i < 1 ; $i++) if ($condition) {
//some code
$a = "b";
// Le break
break;
// code below will not be executed
}
switch(0){ case 0: if($condition){
//some code
$a = "b";
// Le break
break;
// code below will not be executed
}}
while(!$a&&$a=1) if ($condition) {
//some code
$a = "b";
// Le break
break;
// code below will not be executed
}

Uses for never-ending loops

What are some uses of never-ending loops? They are usually bad news in programming, but is there ever a time when you want a loop to never end?
Infinite loops are only bad news when they are not intended or their use has unintended consequences. If you use them with intent there is no difference from any other classification of loop you might consider. However you will still end up breaking things despite intentional use. It is common to use this form when you want to access the iterator or index component after the loop has been terminated, for example:
index = 0;
result = null;
for (;;)
result = foo(index);
if (bar(result))
break;
index += result;
use(index, result);
Note that mutating data outside of the loop's scope may be very undesirable depending on the context, so whether or not this is a good use case really depends on the context. For another similar example, an actual iterator may be the object desired outside of the loop, but initializing it within the loop header would not allow access outside of the loop. An infinite loop would resolve this problem.
for (foo.iterator(); foo.hasNext(); ) {
use(foo.next());
}
keep_using(foo.next()); // throws an error
Additionally, infinite loops can in some cases improve readability, especially if there are many break conditions but they might not all derive from mutually exclusive units. For example, imagine we have the following:
for (;;) {
if (condition1)
break;
else if (condition2)
do_stuff();
else if (condition3)
break;
else
do_something();
}
This can be rewritten using the three components of a loop as:
for (condition = true; condition; iteration) {
if (condition1 || condition3)
condition = false;
else if (condition2)
do_stuff();
else
do_something();
}
However if we introduce a small amount of change (at least in terms of characters on the screen) to the original code:
for (;;) {
if (condition1);
break;
if (condition2);
do_stuff();
if (condition3);
break;
else
do_something();
}
The rewrite becomes this thing that requires us to lug around this extra variable:
for (condition = true; condition; iteration) {
if (condition1)
condition = false;
if (condition2) {
do_stuff();
condition = true;
}
if (condition3)
condition = false;
else {
do_something();
condition = true;
}
}
This can quickly become difficult to read and maintain as the loop body, and especially the complexity grows, for example if condition were actually many different conditions such as a || b || c < d || (e > f) && (a > f); or, the loop contained several nested loops. Though you might apply the same logic to other the original changed version.
Another readability related example involves verbose initialization, though admittedly not a very good use case:
for (more_long = some_ridiculously_long.initialization_statement.longer_than.Long_Long_Mans_Sakeru_gummy();
more_long < lots_of && more_long < break_conditions
maybe_even_an_update_that_hangs_at_ninety_nine_percent) {
...
}

Loop through array, find zero, perform action, stop

I am relatively new at programming, and I'm having trouble figuring out how to loop through an array until the counter finds zero, and when it finds zero once, performs an action and exits the loop. Here is the loop I have so far:
for (int i = 0; i<13; i++)
{
if(pHand[i] == 0)
{
pHand[i] = deal(numArray);
printf("%d\n", i);
printHand(pHand, "Your");
}
}
Currently, this loops through the array until it finds zero, calls deal(), prints the value of pHand, and then loops back through the same sequence until i=0. Please help. I am completely stumped on how to fix this.
The break statement can be used to exit an enclosing loop (e.g., a while, do-while, or for) or switch.
for (int i = 0; i<13; i++)
{
if(pHand[i] == 0)
{
pHand[i] = deal(numArray);
printf("%d\n", i);
printHand(pHand, "Your");
break;
}
}
// code will continue executing here if the for loop condition becomes
// false (i is 13) or if the break statement is reached.
In your code, if you encountered ZERO value cell, you just call "deal" function and printf, but you don't exit the loop, your are continuing to the next iteration.
In order to exit the loop, add "break" statement in the "if" scope and you will go out the loop once you fulfill the condition.
Some consider break to be harmful. I've used it plenty, but some people have issues with it. If you wanted to avoid using break, you could do the following:
int i = 0;
char finished = 0;
while (i < 13 && !finished)
{
if(pHand[i] == 0)
{
pHand[i] = deal(numArray);
printf("%d\n", i);
printHand(pHand, "Your");
finished = 1;
}
i++;
}
You could also rework it to use do-while. Some would say that this kind of solution is a little nicer, semantically.

What is the priority with nested case, for and if loop?

I have a program similar to this:
switch(x)
{ case 1:
for(i=0; i<10; i++)
{
if ((i==3) || (i==4) || (i==5) || (i==6) || (i==7))
{
if (foobar[i])
break; // i am talking about this break
}
}
...further program
break; /not this break
if foobar[i] is true, would the program break out of the case label or the for loop?
The break follows a LIFO type nature, that is, the last break will come out of the first control structure. So, the break that you chose would break out of the for-loop, not the case.
The for loop.
Please see: break Statement (C++):
The break statement ends execution of the nearest enclosing loop or
conditional statement in which it appears. Control passes to the
statement that follows the ended statement, if any.
break will only break out of the for loop. If you have nested statements, it will only break out one level
Is the for loop. The break will bubble up until find the first for, while or a switch.
So you can just write your program like this:
switch(x){
case 1:
int loopBreaked = 0; //If you want to know if the loop has breaked
for(int i=0; i<10; i++) {
if (i <= 7 && i >= 3 && foorbar[i]) {
loopBreaked = 1;
break; //breaks the loop
}
}
break; //breaks the switch
}
How about:
for(i=3; i<=7 && !foobar[i]; i++) {}
For the sake of completeness, break will break out of the innermost statement of the type for do while, or switch. There is no need to break out of an if statement, since simply ending the code block will do the same job.
Your break will break the for loop. And the break you using later, break the switch. You can consider this code sample:
for(int i=0;i<len;i++)
{
for(int j=0;j<len;j++)
{
//statements
break;
}
//statements
break;
}
the break inside the inner loop break the inner loop and the following break statement will break the outer loop. In your code sample, the break you noticed is inside the for loop. So, the for loop will break.

What does for(;;) mean?

I am confused by the for(;;) construct. I think it is a form of shorthand for an unlimited for loop but I can't be sure.
Here is the code:
for(;;)
{
//whatever statements
}
Your guess is correct; it's an infinite loop.* This is a common C idiom, although many people (including me) believe the following to be less cryptic:
while (1) { whatever statements; }
* It's infinite assuming there are no break/return/etc. statements inside the loop body.
It's an un-terminated loop. It is sometimes written with a while:
while (1)
or even better:
while (true)
I would expect to see a break or return inside any such loop, no matter whether it is written with for or while. There has to be some abnormal control flow or it really will be an infinite loop.
Yes, that's the for C syntax with blank fields for initialization expression, loop condition and increment expression.
The for statement can also use more than one value, like this sample :
for (i=0, j=100, k=1000; j < 500 || i<50 || k==5000; i++, j+=2, k*=6) {};
Maybe one step beyond in for understanding ? =)
Yes, the expressions in the for loop are just optional. if you omit them, you will get an infinite loop. The way to get out is break or exit or so.
This statement is basically equal to:
while(1) {}
There is no start, no condition and no step statement.
As I understand it, for(;;) creates a deliberate non-exiting loop. Your code is expected to exit the loop based on one or more conditions. It was once provided to me as a purer way to have a do while false loop, which was not considered good syntax. Based on the exit condition, it is easier to dispatch to a function to handle the result, failure, warning, or success, for example.
My explanation may not be the reason someone used that construct, but I'll explain in greater detail what it means to me. This construct may be someone's "Pure C" way of having a loop in which you can serially perform multiple steps, whose completion mean something like your application has performed all steps of initialization.
#define GEN_FAILURE -99
#define SUCCESS 0
/* perform_init_step1() and perform_init_step2() are dummy
place-holder functions that provide a complete example.
You could at least have one of them return non-zero
for testing. */
int perform_init_step1();
int perform_init_step2();
int perform_init_step1()
{
return 0;
}
int perform_init_step2()
{
return 0;
}
int ret_code = GEN_FAILURE;
for(;;)
{
if(SUCCESS != perform_init_step1())
{
ret_code = -1;
break;
}
if(SUCCESS != perform_init_step2())
{
ret_code = -2;
break;
}
break;
}
If part of the initialization fails, the loop bails out with a specific error code.
I arrived at using C having done a lot of firmware work, writing in assembly language. Good assembly language programmers taught me to have a single entry point and single exit. I took their advice to heart, because their creed helped them and me immensely when debugging.
Personally, I never liked the for(;;) construct, because you can have an infinite loop if you forget to break; out at the end.
Someone I worked with came up with do..until(FALSE), but the amount of proper C furvor this caused was not to be believed.
#define GEN_FAILURE -99
#define SUCCESS 0
/* perform_init_step1() and perform_init_step2() are dummy
place-holder functions that provide a complete example.
You could at least have one of them return non-zero
for testing. */
int perform_init_step1();
int perform_init_step2();
int perform_init_step1()
{
return 0;
}
int perform_init_step2()
{
return 0;
}
int ret_code = GEN_FAILURE;
do
{
if(SUCCESS != perform_init_step1())
{
ret_code = -1;
break;
}
if(SUCCESS != perform_init_step2())
{
ret_code = -2;
break;
}
}
until (FALSE);
This runs once, no matter what.

Resources