tags:

views:

1199

answers:

16

There are 3 loops in C: for, while, do-while. What's the difference between them? For example, it seems nearly all while statement can be replaced by for statement, right? Then, what's the advantage using while?

+5  A: 

For the sake of readability

hoang
For that matter, you can also use goto as a loop.
WhirlWind
For another matter, there's recursion. And you can replace any style of loop with any other style.
WhirlWind
In fact... all loops are really just fancy GOTO branches.
Atømix
@WhirlWind Except that in languages without recursion you'll probably end up with stack overflows. (And you might end up here asking about stack overflows, which would make me smile a little bit.)
Sean Edwards
@Sean yeah, I was thinking about that, and if there's a way to get around the stack overflow. Of course, if there's tail recursion...
WhirlWind
@WhirlWind I remember a question on Stack Overflow asking about that. The guy was used to languages that supported tail recursion, so for some reason he just always wrote loops as recursive functions. He was confused when his C code broke. :) And the only way of recursively calling a function infinitely is to have infinite memory. If a recursive function goes that deep, the algorithm should probably be redesigned to use loops instead.
Sean Edwards
+60  A: 

A while loop will always evaluate the condition first.

while (condition) {
  //gets executed after condition is checked
}

A do/while loop will always execute the code in the do{} block first and then evaluate the condition.

do {
  //gets executed at least once
} while (condition); 

A for loop allows you to initiate a counter variable, a check condition, and a way to increment your counter all in one line.

for (int x = 0; x < 100; x++) {
   //executed until x >= 100
}

At the end of the day, they are all still loops, but they offer some flexibility as to how they are executed.

Here is a great explanation of the reasoning behind the use of each different type of loop that may help clear things up. Thanks clyfe

The main difference between the for's and the while's is a matter of pragmatics: we usually use for when there is a known number of iterations, and use while constructs when the number of iterations in not known in advance. The while vs do ... while issue is also of pragmatics, the second executes the instructions once at start, and afterwards it behaves just like the simple while.


For loops are especially nice because they are concise. In order for this for loop

for (int x = 0; x < 100; x++) {
   //executed until x >= 100
}

to be written as a while loop, you'd have to do the following.

int count = 0;
while (count < 100) {
  //do stuff
  count++;
}

In this case, there's just more stuff to keep up with and the count++; could get lost in the logic. This could end up being troublesome depending on where count gets incremented, and whether or not it should get incremented before or after the loop's logic. With a for loop, your counter variable is always incremented before the next iteration of the loop, which adds some uniformity to your code.


For the sake of completeness, it's probably meaningful to talk about break and continue statements here which come in handy when doing loop processing.

break will instantly terminate the current loop and no more iterations will be executed.

//will only run "do stuff" twice
for (int x = 0; x < 100; x++) {
  if (x == 2) {
    break;
  }
  //do stuff
}

continue will terminate the current iteration and move on to the next one.

//will run "do stuff" until x >= 100 except for when x = 2
for (int x = 0; x < 100; x++) {
  if (x == 2) {
    continue;
  }
  //do stuff
}

Note that in a for loop, 'continue' evaluates the 'part3' expression of 'for (part1; part2; part3)'; in contrast, in a while loop, it just jumps to re-evaluate the loop condition.

Robert Greiner
Should you discuss the behaviour of 'continue;' in a 'for' loop vs a 'while' loop? Otherwise, good answer.
Jonathan Leffler
+1 for excellent answer. Worth noting: for loops don't require a counter variable. In C-style languages, they are actually for (<start statement>; <continuation>; <execute after each iteration>). It just happens to be that the most common usage is counter variable: for (int x = 0 [start]; x < 100 [continue?]; ++x [post-iteration])
Sean Edwards
@Sean agreed, I started out just putting `condition` for that exact reason, but the simplest examples I could come up with involved counting. Probably because they are straightforward and easy to understand.
Robert Greiner
@Jonathan see edits.
Robert Greiner
The main difference between the `for's` and the `while's` is a matter of pragmatics: we usually use `for` when there is a *known number of iterations*, and use `while` constructs when *the number of iterations in not known in advance*. The `while` vs `do ... while` issue is also of pragmatics, the second executes the instructions *once* at start, and afterwards it behaves just like the simple `while`.
clyfe
@clyfe very well said, I'm going to add this to my answer if you don't mind.
Robert Greiner
+1 well-written answer, and sometimes revisiting the "basics" is good for everyone
JYelton
I love the answer, esplly the part where you talk about uniformity in incrementing the counter in case of a 'for' versus potentially anywhere in the iteration in case of a 'while'. To be honest, I would have never put it so eloquently albeit there is not much new here
Shravan
This is a good answer.One situation where it may be less obvious which type of loop to use is when using iterators. You don't know how many times the loop will execute, but for loops can be pretty concise ways of processing a list.std::list<int> foo_list;std::list<int>::const_iterator iter;for (iter = foo_list.begin(); iter != foo_list.end(); ++iter) { int a = *iter; if (a % 2) { std::cout << "The number is odd" << std::endl; }}
Michael Mathews
I actually learnt that there is a `continue` keyword. To think some people tried to close this question!
Callum Rogers
specifically in C, FOR loops do not have to use a counter, but it other languages like pascal they do. C uses a more flexible FOR loop structure than other languages, in C one (or more) parts of the FOR expression can even be left blank, and conditions can be more complex or simple, something that's not always possible in other languages, for example you can do:for (; (i<4) i++) or even: for (;;). just thought it might be worth mentioning.
Bob
It is true though that `while (x)` could be replaced with `for (;x;)` - I suppose the former is just a bit nicer to look at.
caf
53 upvotes for a while loop question!!! Why can't answers to really difficult questions get this much!
Atømix
+3  A: 

If you want a loop to execute while a condition is true, and not for a certain number of iterations, it is much easier for someone else to understand:

while (cond_true)

than something like this:

for (; cond_true ; )
Justin Ethier
I don't know about *much* easier. I would hazard a guess that if C didn't have the first form, we would all be quite used to seeing the second by now.
caf
Fair enough, but I guarantee I would be thinking "WTF" if I saw the second version in any code I was maintaining...
Justin Ethier
+8  A: 

They're all interchangeable; you could pick one type and use nothing but that forever, but usually one is more convenient for a given task. It's like saying "why have switch, you can just use a bunch of if statements" -- true, but if it's a common pattern to check a variable for a set of values, it's convenient and much easier to read if there's a language feature to do that

Michael Mrozek
Not really. Both for and while can execute the body zero times - a do-while cannot.
anon
@Neil `do {if(!cond) break; /* do stuff */ } while(cond);`. Ugly and repetitive, but that's kind of my point about why variations exist :)
Michael Mrozek
@Neil: You can use an additional flag to skip the first execution. Interchangeable says nothing about how easy or useful it is. ;)
Secure
The body of the loop is still entered - this is not the case for while and for.
anon
@Neil Well, for certain definitions of "body of the loop". It causes the same behavior either way -- it doesn't run the `/* do stuff */` part if `cond` is false
Michael Mrozek
Also, a switch statement can be implemented more efficiently than a series of if-statements in many cases (see http://stackoverflow.com/questions/449273).
Judge Maygarden
+1  A: 

A for suggest a fixed iteration using an index or variants on this scheme.

A while and do... while are constructions you use when there is a condition that must be checked each time (apart from some index-alike construction, see above). They differ in when the first execution of the condition check is performed.

You can use either construct, but they have their advantages and disadvantages depending on your use case.

Pieter
A: 

They are all the same in the work they do. You can do the same things using any of them. But for readability, usability, convenience etc., they differ.

rahmivolkan
A: 

A difference between while and do-while is that while checks the loop condition and if this is true, the body is executed and the condition checked again. The do-while checks the condition after execution of the body, so with do-while the body is executed at least one time.

Of course you can write a while loop as a do-while and vv, but this usually requires some code duplication.

muksie
+2  A: 

Remember, a for loop is essentially a fancy while loop. They're the same thing.

while <some condition is true> {
   // do some stuff
   // possibly do something to change the condition
}


for ( some var, <some condition is true>; increment var ) {

}

The advantage of a for loop is that it's harder to accidentally do an infinite loop. Or rather, it's more obvious when you do one because you generally put the loop var in the initial statement.

A while loop is more clear when you're not doing a standard incrementing pattern. For example:

int x = 1;
while( x != 10 ) {
  if ( some condition )
     x = 10;
  else 
     x += 5;
}
Atømix
There's one subtle difference between for() and writing it out as a while(), though: you change the behaviour of continue. For the for() case continue executes the increment step before checking the condition whereas in the while() continue will jump straight back to the condition.
Rup
Yes, very good point. Also, I think what people forget is that when it comes down it, all loops are compiled into GOTO statements.
Atømix
I think this is why while loops more often lead to infinite loop bugs -- the increment step can be skipped by a continue somewhere.
Michael Mathews
@Michael: Yep, very true. `for` loops were probably introduced as convenience and productive methods.
Atømix
@Rup A very good point. I've always regarded for as syntactic sugar for while, but the continue behaviour means it is not true.
JeremyP
+1  A: 

You should use such a loop, that most fully conforms to your needs. For example:

for(int i = 0; i < 10; i++)
{
    print(i);
}

//or

int i = 0;
while(i < 10)
{
    print(i);
    i++;
}

Obviously, in such situation, "for" looks better, than "while". And "do while" shoud be used when some operations must be done already before the moment when condition of your loop will be checked.

Sorry for my bad english).

abespalov
A: 

One peculiarity of the do while is that you need a semi-colon after the while to complete. It is often used in macro definitions to execute several statements only once while constraining the impact of the macro. If macros where defined as blocks, some parsing errors may occur.

One explanation among others

LB
That's terribly hackish though, that's not a big reason `do-while` exists
Michael Mrozek
nop, i never said that, but that's one usage really particular for do-while, which is pretty pervasive.
LB
@Michael yeah it's a hack but it is a really commonly used one that makes a macro containing multiple statements behave completely as expected in all syntactic contexts.
JeremyP
@JeremyP I know, I use it too, but it's not a real use-case for `do-while`, it's just used because it happens to create a block and still require a semi-colon at the end
Michael Mrozek
i just wanted to point this particular usage of do-while. Part of the question was, what are the differences... and that's one difference. (but i agree, that's hackish)
LB
A: 

For loops (at least considering C99) are superior to while loops because they limit the scope of the incremented variable(s).

Do while loops are useful when the condition is dependant on some inputs. They are the most seldom used of the three loop types.

Helper Method
A: 

Between for and while: while does not need initialization nor update statement, so it may look better, more elegant; for can have statements missing, one two or all, so it is the most flexible and obvious if you need initialization, looping condition and "update" before looping. If you need only loop condition (tested at the beginning of the loop) then while is more elegant.

Between for/while and do-while: in do-while the condition is evaluated at the end of the loop. More confortable if the loop must be executed at least once.

ShinTakezou
A: 

WHILE is more flexible. FOR is more concise in those instances in which it applies.

FOR is great for loops which have a counter of some kind, like

for (int n=0; n<max; ++n)

You can accomplish the same thing with a WHILE, of course, as others have pointed out, but now the initialization, test, and increment are broken across three lines. Possibly three widely-separated lines if the body of the loop is large. This makes it harder for the reader to see what you're doing. After all, while "++n" is a very common third piece of the FOR, it's certainly not the only possibility. I've written many loops where I write "n+=increment" or some more complex expression.

FOR can also work nicely with things other than a counter, of course. Like

for (int n=getFirstElementFromList(); listHasMoreElements(); n=getNextElementFromList())

Etc.

But FOR breaks down when the "next time through the loop" logic gets more complicated. Consider:

initializeList();
while (listHasMoreElements())
{
  n=getCurrentElement();
  int status=processElement(n);
  if (status>0)
  {
    skipElements(status);
    advanceElementPointer();
  }
  else
  {
    n=-status;
    findElement(n);
  }
}

That is, if the process of advancing may be different depending on conditions encountered while processing, a FOR statement is impractical. Yes, sometimes you could make it work with a complicated enough expressions, use of the ternary ?: operator, etc, but that usually makes the code less readable rather than more readable.

In practice, most of my loops are either stepping through an array or structure of some kind, in which case I use a FOR loop; or are reading a file or a result set from a database, in which case I use a WHILE loop ("while (!eof())" or something of that sort).

Jay
+1  A: 

They are pretty much same except for do-while loop. The for loop is good when you have a counter kind of variable. It makes it obvious. while loop makes sense in cases where a flag is being checked as show below :

while (!done) {
   if (some condtion) 
      done = true;
}
fastcodejava
A: 

One common misunderstanding withwhile/for loops I've seen is that their efficiency differs. While loops and for loops are equally efficient. I remember my computer teacher from highschool told me that for loops are more efficient for iteration when you have to increment a number. That is not the case.

For loops are simply syntactically sugared while loops, and make iteration code faster to write.

When the compiler takes your code and compiles it, it is translating it into a form that is easier for the computer to understand and execute on a lower level (assembly). During this translation, the subtle differences between the while and for syntaxes are lost, and they become exactly the same.

Cam
"For loops are simply syntactically sugared while loops": as has already been pointed out in one of the comments above, this is not strictly correct. A continue inside a for does not bypass the loop expression (e.g. the i++ in `for (i = 0 i < limit ; i++)`.
JeremyP
+1  A: 

If there is a strong concern about speed & performances, the best approach is to verify at assembly level the code produced by the compiler.

For instance, the following code shows that the "do-while" is a bit faster. This because the "jmp" istruction is not used by the "do-while" loop.

BTW, in this specifc example, the worst case is given by the "for" loop. :))

int main(int argc, char* argv[])  
{     
int i;  
char x[100];  

//"FOR" LOOP:
for(i=0; i<100; i++ )  
{ x[i] = 0; 
}  

//"WHILE" LOOP:  
i=0;  
while(i<100 )  
{ x[i++] = 0;  
}  

//"DO-WHILE" LOOP:  
i=0;  
do  
{ x[i++] = 0;   
}  
while(i<100);  

return 0;  
}  

// "FOR" LOOP:

    010013C8  mov         dword ptr [ebp-0Ch],0     
    010013CF  jmp         wmain+3Ah (10013DAh)     

  for(i=0; i<100; i++ )   
  { x[i] = 0;  
    010013D1  mov         eax,dword ptr [ebp-0Ch]  <<< UPDATE i 
    010013D4  add         eax,1     
    010013D7  mov         dword ptr [ebp-0Ch],eax   
    010013DA  cmp         dword ptr [ebp-0Ch],64h  <<< TEST  
    010013DE  jge         wmain+4Ah (10013EAh)     <<< COND JUMP   
    010013E0  mov         eax,dword ptr [ebp-0Ch]  <<< DO THE JOB..
    010013E3  mov         byte ptr [ebp+eax-78h],0   
    010013E8  jmp         wmain+31h (10013D1h)     <<< UNCOND JUMP 
  }  

// "WHILE" LOOP:

  i=0;  
  010013EA  mov         dword ptr [ebp-0Ch],0   
  while(i<100 )   
  { x[i++] = 0;   
    010013F1  cmp         dword ptr [ebp-0Ch],64h   <<< TEST
    010013F5  jge         wmain+6Ah (100140Ah)      <<< COND JUMP 
    010013F7  mov         eax,dword ptr [ebp-0Ch]   <<< DO THE JOB..
    010013FA  mov         byte ptr [ebp+eax-78h],0   
    010013FF  mov         ecx,dword ptr [ebp-0Ch]   <<< UPDATE i 
    01001402  add         ecx,1   
    01001405  mov         dword ptr [ebp-0Ch],ecx   
    01001408  jmp         wmain+51h (10013F1h)      <<< UNCOND JUMP
  }  

// "DO-WHILE" LOOP:

i=0;  
.  0100140A  mov         dword ptr [ebp-0Ch],0   
  do  
  { x[i++] = 0;   
    01001411  mov         eax,dword ptr [ebp-0Ch]   <<< DO THE JOB..
    01001414  mov         byte ptr [ebp+eax-78h],0   
    01001419  mov         ecx,dword ptr [ebp-0Ch]   <<< UPDATE i
    0100141C  add         ecx,1   
    0100141F  mov         dword ptr [ebp-0Ch],ecx   
    01001422  cmp         dword ptr [ebp-0Ch],64h   <<< TEST
    01001426  jl          wmain+71h (1001411h)      <<< COND JUMP
  }
  while(i<100);  
psanzani