For loops can run forever too
A for loop ends only when its condition becomes false. The header makes the counter's update easy to see, but a loop can still be infinite when the update goes the wrong way, when the body undoes the update, or when the counter can jump over the stopping value.
The body that undoes the update
for (int i = 0; i < 10; i++) {
Console.WriteLine(i);
i--;
}
Follow one pass. The body prints 0 and then i-- makes i equal to -1. The iteration part i++ brings it back to 0. The condition 0 < 10 is true again, and the loop prints 0 again, forever. The net change per pass is zero, so the counter never reaches 10.
The rule is to treat the loop variable as owned by the header. Changing it inside the body is allowed in C#, but it is the most common source of surprises.
The exercise: odd numbers from 15 to 1
The lesson gives you a loop that should print 15, 13, 11, ..., 1 and then stop:
for (int number = 15; number != 0; number++) {
Console.WriteLine(number);
}
It prints 15, 16, 17 and so on, ever larger. There are two mistakes.
- The direction is wrong. The task counts down, but
number++counts up and moves away from any stopping point. The update must benumber -= 2: it goes downwards, and the step of 2 skips the even numbers. - The condition can be jumped over. Counting down by 2 from 15 gives 15, 13, ..., 3, 1 and then -1. The counter is always odd, so it never equals 0. With
number != 0the condition would stay true even after the update is fixed. A range check fixes this:number > 0stays true while there are positive numbers left, and becomes false at -1.
for (int number = 15; number > 0; number -= 2) {
Console.WriteLine(number);
}
This prints 15, 13, 11, 9, 7, 5, 3 and 1, one per line. The start value 15 is already odd, so it stays on odd numbers all the way down.
A C# detail: the count-up loop is not truly endless
An int in C# wraps around silently when it goes past its maximum. So the original loop does not run for ever in the strict sense: after about 2.1 billion more steps, number passes int.MaxValue, wraps to a large negative number and climbs back towards 0, where number != 0 is finally false. That is over four billion passes and as many lines of output, which is far more than anyone will wait for. For debugging, treat it as an infinite loop.
A checklist for any for loop
- Does the update move the counter towards the stopping value?
- Can the counter step over the stopping value? If so, use
<,<=,>or>=instead of!=. - Does the body change the counter in a way that cancels the update?
- Does the loop start on the right value for the step size?
Loops that are meant to run forever
Not every endless loop is a bug. A program that waits for input may use for (;;) or while (true) on purpose and leave the loop with break or return when a condition is met:
int count = 0;
for (;;) {
count++;
if (count == 3) {
break;
}
}
// count is 3 here
The difference is that this loop has a planned way out. The buggy loops in this lesson have none.
Key takeaways
- A
forloop is infinite when its condition never becomes false. - Check the direction of the update first: counting up cannot finish a countdown.
- Use range comparisons when a step larger than 1 might skip the exact stop value.
- Avoid changing the loop variable inside the body.