A loop tends to fail for one of a few reasons. Usually, these problems stem from a condition that doesn't eventually go to false, from a boundary that is off by one, or from a variable that isn't incrementing as expected.
Spotting these typical loop mistakes ahead of time could save considerable debugging time.
An easy way to end up in an infinite loop is when a variable checked by the loop's condition is never modified in the loop's body. Initially true, the condition may remain true forever, since nothing is pushing the variable closer to the termination point.
int n{0};
while (n < 5)
{
std::cout << n << '\n';
// n is never incremented
}
This can be just as easily done with a for loop if the loop's third expression, the update, is omitted and its body also fails to update the counter. A related issue could occur with a continue.
If the update expression comes after a continue statement that repeatedly gets hit, the update is skipped, and the same variable is tested yet again for a true condition.
int i{0};
while (i < 10)
{
if (i % 2 == 0)
{
continue;
}
std::cout << i << '\n';
// Increment the value before the expression uses it
++i;
}
The solution is either placing the update before the continue test, or restructuring the condition.
int i{0};
while (i < 10)
{
++i;
if (i % 2 == 0)
{
// Skip the rest of this iteration
continue;
}
std::cout << i << '\n';
}
This category of loop error is similar to the preceding one, but it comes from a bad comparison. It means the boundaries are either exclusive where they should be inclusive or vice versa.
For instance, a loop is meant to count 1 to 5 inclusive. If the test is less than 5, the loop will stop at 4. A successful test would need to be less than or equal to 5.
// Stop before the upper boundary is reached
for (int i{1}; i < 5; ++i)
{
std::cout << i << '\n';
}
// Include the upper boundary in this loop
for (int i{1}; i <= 5; ++i)
{
std::cout << i << '\n';
}
Conversely, an off-by-one error will occur when the inclusive boundary should actually be exclusive; an intended range of 1 to 5 inclusive will count up to 6 inclusive. This can be a much more serious problem as it may be accessing array elements outside of their valid range.
for (int i{1}; i <= 6; ++i)
{
std::cout << i << '\n';
}
A downward count has its own versions of this mistake. Depending on whether the comparison is "greater than or equal to" zero or "greater than" zero will make the loop test 1 once too many or once too few.
// Decrement the value before the expression uses it
for (int i{5}; i > 0; --i)
{
std::cout << i << '\n';
}
// Include the lower boundary while counting down
for (int i{5}; i >= 0; --i)
{
std::cout << i << '\n';
}
This is one of the most subtle mistakes one could make in a loop. When the programmer tries to use an assignment with =, he or she actually uses an assignment.
Because in C, this is perfectly legitimate syntax that returns the value that was assigned, it tests that value.
int i{5};
// This assigns inside the loop condition instead of comparing
while (i = 0)
{
std::cout << i << '\n';
}
An assignment like i = 0 will test zero, or false, and make the loop body never execute.
When this takes place with multiple, ANDed conditions, it can be very difficult to spot.
int i{5};
bool ready{true};
// Require both conditions joined by logical AND to be true
while ((i = 0) && ready)
{
std::cout << i << '\n';
}
Most for loops will have one or zero updates specified in the third section of the header. However, it is possible to update a variable elsewhere in the loop body. This would, for instance, skip values like:
for (int i{0}; i < 10; ++i)
{
std::cout << i << '\n';
i = i + 2;
}
A do while or while loop can yield many unexpected errors if the variable that is checked is not initialized. Its value will likely be non-zero (in a positive or negative way depending on random circumstances), which can lead the condition to be tested as both true and false for various lengths of time, yielding different results with each run of the program.
int value;
while (value < 5)
{
std::cout << value << '\n';
++value;
}
A properly working loop will have a starting value, a boundary condition that specifies when to terminate, and an increment to progress. If the program is using continue, the update must occur before returning to the condition.
If a boundary should be inclusive, the greater-than-or-equal-to comparison must be used; if exclusive, then "greater than." If all of these are checked against the range, any discrepancy will usually highlight the mistake.
#include <iostream>
int main()
{
std::cout << "Values 1 to 5:\n";
for (int i{1}; i <= 5; ++i)
{
std::cout << i << ' ';
}
std::cout << '\n';
std::cout << "Odd numbers below 10:\n";
int n{0};
while (n < 10)
{
++n;
// Use the remainder operator to keep what division leaves over
if (n % 2 == 0)
{
continue;
}
std::cout << n << ' ';
}
std::cout << '\n';
}
Exercise: Common Loop ErrorsStarter code, hints and solutionOpenClose
Practice: Common Loop Errors
Work through the mission, reveal hints only when needed, and compare your result with the model solution.
Your challenge
Make the first loop print 1 through 6 and update its heading. Keep the second loop safe when continue runs and explain where its update happens.
Mission checklist
- Run the starter as a baseline, then predict the change requested in Your challenge.
- Make that change in your editor; use the lesson-specific hints if you need help.
- Compile and run your answer, then compare with the worked solution and explain the result.
Starter program
This is the working baseline, not the completed answer. Compile as C++20, then make the change described above.
#include <iostream>
int main()
{
std::cout << "Values 1 to 5:\n";
for (int i{1}; i <= 5; ++i)
{
std::cout << i << ' ';
}
std::cout << '\n';
std::cout << "Odd numbers below 10:\n";
int n{0};
while (n < 10)
{
++n;
// Use the remainder operator to keep what division leaves over
if (n % 2 == 0)
{
continue;
}
std::cout << n << ' ';
}
std::cout << '\n';
}Hints
The first loop includes 5 because its condition is i <= 5. Count the values from its initial 1 before extending the upper bound.
In the while loop, ++n happens before the even-number test. Keep that update reachable even when continue runs, or the loop may stop making progress.
Worked solution
The first loop now includes 6, giving one more iteration. Its heading is updated accordingly. The while-loop update still occurs before continue, so even values cannot prevent progress.
#include <iostream>
int main()
{
std::cout << "Values 1 to 6:\n";
for (int i{1}; i <= 6; ++i)
{
std::cout << i << ' ';
}
std::cout << '\n';
std::cout << "Odd numbers below 10:\n";
int n{0};
while (n < 10)
{
++n;
// Use the remainder operator to keep what division leaves over
if (n % 2 == 0)
{
continue;
}
std::cout << n << ' ';
}
std::cout << '\n';
}
Example output
Values 1 to 6:
1 2 3 4 5 6
Odd numbers below 10:
1 3 5 7 9
0 comments
No comments yet. Be the first.