Last question for today all...I will get back with tomorrow..I have a lot to follow up on...
I am looking in Reilly Java text- talking about counter controlled loop patterns..(does not matter what language..)
The author for counter controlled loops (for, while, etc) and with nesting loops...uses the != for test...Now I realize != is used for certain situations with event controlled loops-like sentinel or EOF type of loops- but to me- using it with a counter controlled loop is a bad idea...very prone to errors..
Examples:
x = 0;
while (x != 100) {
y = 0;
while (y != 100) {
...
y++;
}
x++;
}
Would it be better to just say..using the other relational operators...
x = 0;
while (x < 100) { //or even better some defined constant...
y = 0;
while (y < 100) {
...
y++;
}
x++;
}
Which from what I have seen is usually the way presented in texts..classes.etc..
Once again- would all you considered this bad- or just a different way of doing it... Thanks...
A counter-controlled loop (or counting loop) is a loop whose repetition is managed by a loop control variable whose value represents a count. Also called a while loop.
A common logic error with counter-controlled repetition is an off-by-one error. For example, if the above condition is changed to counter < 10, the loop would iterate only nine times. The general format of the for statement is. for ( initialization; loopContinuationCondition; increment ) statement.
A while loop can be used for a count-controlled loop. Although the while loop can be complicated to write correctly, it is possible to simplify its structure and thus improve its readability.
You want your loop condition to be the exact inverse of the desired post-condition.
i= 0;
while( i != 100 ) {
i += 1;
}
assert i == 100;
You can trivially see that the loop post-condition exactly matches the loop termination condition. No mysteries.
Further, you can prove from the initial condition and the body that it will reach 100 without "somehow" magically skipping a value.
In the case when you have a really complex loop body, that simple parallel structure is essential.
If you use Weakest Precondition techniques for deriving the loop from the post-condition, the loop condition will be the simple matching condition as shown above.
The i < 100
is a bad idea because your loop could have an incorrect body that incremented the variable badly and still "appeared" to work.
I would only use
while (x != 100)
if I wanted the loop to terminate when x was exactly 100. So in the vast majority of cases I would use
while (x < 100)
which is a lot more common for counter controlled loops.
EDIT: On second thought, I would always use for-syntax in a counter-controlled loop, so that example should be
for(int i=0; i < 100; ++i)
Using <
is more common in Java. Modern C++ uses !=
.
!=
is more likely to catch errors in your code. In most circumstances this is a good thing. If for some reason the counter has not only reached but gone past the bound (usually on the first iteration), then the body will execute with an illegal value. So long as the body of the loop is not hiding errors, then you'll get an exception. If the body is hiding errors, the loop will execute billions of times and it should be obvious there is a bug.
As an example, an interesting vulnerability was found in the implementation of Adobe Flash last year. A pointer used as array could be caused to be initialised as null
. Usually not a problem - the process safely crashes out whenever it is first dereferenced. However, a loop with <
was used, allowing the body to never executed which then allows the execution to continue. After that, memory could be written at an attacker specified location. Because the value of null
is always 0
, the attacker knows exactly which memory locations are being written to. This would not have happened if the loop has used !=
.
as other answers have shown,while(i < 100)
is safe*
,while(i != 100)
is precise**
.
As an aside, you may want to try while(i++ < 100)
or for(i = 0; i < 100; ++i)
instead of the simpler while loop you have shown--forgetting to increment the counter at the end of the loop is a real pain. Note that, if i=0
, i++
will equal 0, and then increment i for next time, and ++i
will increment i and then equal 1, so for while(i++ < 100)
, the postfix ++ operator is necessary.
Also note, that if i
was 0 when it got tested in the condition, then it will be 1 in the loop body (for the while example), so if i
is an index for an array or something, and not just keeping track of loop iterations, you'd be better to stick with just a for loop (which increments i after each iteration).
*
: safe here meaning less likely to enter an infinite loop. It is also unsafe in that it can hide potential errors, if the loop isn't trivial
**
: precise in that if it doesn't do exactly what you expect it to, it will fail, and you will notice. Some other answers have also described how to protect you from errors even more in this kind of loop.
The main advantage of use "!=" over "<" is that is something is going to fail, it should fail big.
For example, if a bug somewhere caused x to enter the loop set to 110, then x < 100
will never enter the loop --- a fact you might miss in debugging. OTOH, if you use x!=100
, it will never exit the loop -- something which could not be missing in debugging.
I don't think < necessarily offers you more protection than !=. If you have a case where i
is being incremented in way that is unanticipated by you, you should be throwing an exception, not sweeping it under the rug with a <.
For example, if you're really worried about your while loops messing up, you could do something like this:
x = 0;
while (x != 100)
{
assert x >= 0;
assert x < 100;
y = 0;
while (y != 100)
{
assert y >= 0;
assert y < 100;
...
y++;
}
x++;
}
That way, the moment your loop goes out of bounds, your program dies right away (crash early, crash often) and you know your code is messed up.
I suspect this may have something to do with C++ iterators.
If you're using integers or pointers, <
has a clearly defined meaning. If you're using C++ iterators in a loop, <
may not be defined, or may be hard to calculate.
For example, in running through a list, the C++ way would be:
for(std::list<foo>::const_iterator i = bar.begin(); i != bar.end(); ++i)
and really the only way to see if i is before bar.end() is to increment i indefinitely and see if it's ever equal to bar.end().
There's a considerable amount of value in doing minor things the same way all the time.
I believe they are semantically the same, the only difference being with != numbers above 100 would obviously also meet the condition where as the < will prevent any number larger than 100 from making it through.
However in the case given, both operators will result in the same output. Now, if somehow the x and y variables were being acted on outside that code, the "<" would be a better way to make sure there was a cutoff at 100 even if they entered with a value of 90, and were not able to continue at all if they entered with a value of 4000. Obviously, the intent on what you are doing at the time would dictate which operator you chose, there are usually several methods to achieve the same result and not always one "correct" way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With