C/C++ do loops - good practice or bad?
I have been having some discussions on another forum about do loops.
I don't like them, and a lot guys in the beginners forum were having problems. So I was advising them not to use them, use while or for loops instead. However some of the senior members (with lots of posts)weren't agreeable. Then someone posted this: Quote:
Quote:
The other thing I see beginners doing all the time is this: Code:
while (Game != 'a' && Game != 'A' && Game != 'b' && Game != 'B' && Game != 'c' && Game != 'C') So I have offered this as a clue to doing it better. Also using the toupper function to reduce the testing. Code:
bool IsOperator(char symbol) I look forward to your replies |
Bad thing about do-while: it is executed at least once because the checking is done at the bottom of the loop (rather at the top as in for and while); can lead to all kinds of problems.
Nuff said. |
I don't share many of Stroustrup's opinions on maintainable code. If the logic of the situation fits a do loop, I would certainly use a do loop. Occasionally, when performance really matters, I might twist the logic of the program to fit a do loop when it would not initially fit.
But most loops I encounter in real programming require processing both before and after the decision. Structured programming fanatics tend to write either: Code:
BEFORE; Code:
bool flag = true; Code:
for (;;) { Quote:
Quote:
|
Quote:
Code:
do A perhaps useful "one-pass" may be the itoa function example presented on pp. 64 (left to the reader to explore). Begin a fairly competent programmer -- and preferring straight-forward code that is designed to take advantage of the features of individual loop functions; e.g., while and for (where the test is at the top), personally I cannot recall ever having use do-while in any programming I've ever done simply to avoid complex testing to "get around" the design function of the loop. Hope this helps some. |
My suggestion is very simple: "whatever you do, make whatever you do stupendously clear."
I frankly don't care too much about how you write a loop, as long as I can instantly, "at a glance," and with 150% accuracy understand, not only what you intended to do, but that your logic is correct. I want to see comments. I want to see consistent spacing and easy visual readability. "Anything else is either human preference or fashion." The Amazing Super-Optimizing Compiler™ will ultimately transform your source-code into "god-knows-what (and who-cares as long as it works and by-the-way it does)." So, the computer is really not the issue here. What's important is your fellow human beings ... not only your colleagues of today, but the blokes who just got back to the office after your funeral when you just got smooshed by an insane Windows programme... I mean, by a bread truck. ;) |
Thanks for your replies. @johnsfine: Always a real education - thankyou. Mind you I am not sure whether I am ready to go to the lengths that you do.
My philosophy is to use while or for loops, unless a do loop is necessary. An example, if I am remembering correctly from K&R: Code:
bool test = true; Code:
char option; The other thing is, I really don't like is single letters for variable names - even if it is just a loop counter. The problem is K&R do it all the time in their book. I would rather have a meaningful word or words as the name. Here is an example of what can happen: I was helping someone who had a problem with a 2d array - she was using i and j for the array subscripts. I suggested that she do a find replace changing i to Row and j to Col. She almost immediately spotted the error which was [Row][Row], which should have been [Row][Col]. Finally another style question: I like to use a very restricted Hungarian notation for my variable names. Before everyone goes Arrrrrrgh!!! #$@*# Hungarian notation - hear me out !! Some examples: Code:
int iDaysDateDifference = 0; //Num of days between 2 dates +ve Date2 is later than Date1, -ve Date2 is before than Date1 I am hoping that you guys might approve of this because: My convention is restricted to the basic types, and doesn't get carried away, which was a problem with some other notation styles; Is well defined; Hopefully pretty obvious. Am interested to hear your opinions. |
@sundialsvcs: Thanks for your post, I am always grateful for expert opinion.
Here is another angle on simplicity. Eienstein once said: Quote:
Note: My signature refers to time relativity, not necessarily to other things he said. |
My :twocents:
I do not want to restrict myself, if the language was capable to do that way: why not use that? From the other hand I would suggest (for the beginners) to know all the language elements, all the possibilities. Otherwise they will not be able to use all the features and they may implement inefficient code. So Quote:
|
I've never had any issues in C/C++ with do {} while (), while () {}, or for () {}, and I use all three all the time.
I'm just happy C/C++ does not have unless or if statements controlling execution of preceding statements. I also do not like OOXML, which exhibits the same kind of "logic" in its approach. |
Note: In non-trivial cases loops are often like this:
Code:
for (errc= 0; !errc ;) { Edit: in more non-trivial cases: Code:
volatile int interrupted= 0; |
Quote:
|
Quote:
BEFORE: Get input DECISION: Is input valid AFTER: Report problem As ntubski pointed out, you have treated a middle checked loop as if it were top checked, introducing the common nasty bug of depending on an uninitialized variable in a way that typically works during your testing and fails non reproducibly for the end user. 2) If you made it a middle checked loop and you cleaned it up to use a switch instead of a messy if, you hit the problem that it is hard to break out of a loop from inside a switch. One could (as you suggest) bury the switch in a function. But usually (and in this case) it is cleaner to make the whole middle checked loop a function. Once the loop is its own function, the return instruction is the simple method to break out of the loop from inside a switch that is inside the loop. 3) I often make a loop into its own (inline) function simply to allow easily breaking out of the loop from inside a switch. But in this case, there is an even better reason to make the whole loop into a function. Getting a chunk of valid input is a logical primitive from the point of view of the procedure that uses that input. A loop to retry after invalid input is a distraction from the flow of that procedure. Good modularization is key to good programming. A function to check whether input is valid might be a good modularization decision, but not if that is done to facilitate keeping the input retry loop in a larger function. The input retry loop should be its own function even if you also make the input validity check its own function. |
ntubski & johnsfine
It's not my code and it's code I don't like, but I am wrong because i didn't post all of it (hence no initialisation), below is the example I should have posted. It shows the whole thing with several examples of the logic that I don't like: johnsfine: However I am guessing that it might not alter your advice (which I appreciate), and the code that I offered on the other forum was similar to what you were suggesting. On the other forum there are lots of beginners posting code like this, and I guess that I was after some confirmation from experts, that this code is bad. Thanks to your advice I think that's what I have now, although I am not going to crow about it on the other forum. Code:
#include <iostream> |
Quote:
If you know what you are doing, it's a good thing. I.e. sometimes loop body needs always to be executed at least once. For example, I work with measured data in acoustics, and conceptually it looks this way: Code:
do{ ... Managers who insist on 'for' loops can be worked around using the following idiom: Code:
for(;;) |
Quote:
|
All times are GMT -5. The time now is 05:22 PM. |