Three loops, one decision
C offers three looping constructs. They are interchangeable in principle — anything one can do the others can — so the choice is about which expresses the intent most clearly.
Use for when the number of repetitions is known in advance, or when a counter is being stepped through a range. Use while when the loop continues until some condition changes and the count is unknown. Use do-while when the body must run at least once before the condition can be tested at all.
| for | while | do-while | |
|---|---|---|---|
| Condition tested | before each pass | before each pass | after each pass |
| Minimum passes | 0 | 0 | 1 |
| Best for | a known count | an unknown count | menus and input validation |
| Counter | built into the header | managed by you | managed by you |
The for loop in three parts
A for header does three separate jobs, separated by semicolons, and understanding when each runs removes most confusion about loops.
The initialisation runs once, before anything else. The condition is tested before every pass, including the first — so a for loop can execute zero times. The update runs after every pass, before the condition is tested again.
Step through for loop and watch i. It reaches 5 — one beyond the last value used — because the test at i <= 4 has to fail in order to end the loop.
The off-by-one
for (i = 0; i < 10; i++) runs ten times, with i taking 0 to 9. for (i = 1; i <= 10; i++) also runs ten times, with i taking 1 to 10. But for (i = 0; i <= 10; i++) runs eleven times, which is almost never what was wanted. When counting from 0 use <; when counting from 1 use <=.
while and do-while
A while loop tests before it runs, so it may execute zero times — which is usually correct. Processing a list of ten records should do nothing at all if the list is empty.
A do-while tests afterwards, so the body always runs at least once. That is exactly right for a menu, which must be displayed before the user can choose to leave it, and for input validation, where a value must be read before it can be checked.
Write a loop that repeatedly asks for a mark until a value between 0 and 100 is entered.
- The prompt must appear at least once, so this is a do-while.A while loop would have to read a value before the loop as well, duplicating the input line.
do { printf("Enter mark: "); scanf("%d", &marks);The prompt and the read are both inside the body, so they repeat together.if (marks < 0 || marks > 100) printf("Invalid\n");A message telling the user what was wrong, or they will simply type the same thing again.} while (marks < 0 || marks > 100);The condition describes when to KEEP LOOPING, which is the opposite of the acceptance rule — a frequent source of confusion.- After the loop, marks is guaranteed valid.Reaching that line means the condition failed, so no further check is needed.
A do-while whose condition is the invalid range, so the loop repeats while the value is unacceptable.
Nesting, and the ways loops go wrong
Loops nest, and a loop inside a loop runs its inner body outer × inner times — nested tens execute the innermost statement a hundred times. Printing a table or processing a grid is the standard use.
Three faults recur. An infinite loop occurs when nothing inside changes what the condition tests. An off-by-one runs once too many or too few. And a misplaced statement — a total printed inside the loop rather than after it, or reset inside rather than before — produces output that looks almost right, which is worse than output that is obviously wrong.
break and continue
break leaves the loop immediately, which is useful when a search has found its answer and further looking is pointless. continue abandons the current pass and moves to the next. Both are legitimate but should be used sparingly: a loop with three exits is much harder to reason about than one whose condition says everything.
Before you leave this chapter
- for when the count is known, while when it is not, do-while when the body must run at least once.
- A for header initialises once, tests before every pass, and updates after every pass.
- Count from 0 with
<, from 1 with<=. Mixing them gives the off-by-one. - A while loop must change what its condition tests, or it never ends.
- Nested loops multiply: 10 × 10 executes the inner body 100 times.
Loops over arrays
The commonest use of a loop in C is stepping through an array, and the two are designed to fit together: an array of size n has indices 0 to n−1, and for (i = 0; i < n; i++) produces exactly those values.
That is why counting from 0 with a strict < is the standard C idiom. Using <= here would access marks[n], which is past the end of the array — and C will not stop you.
Find the largest value in int marks[5].
int largest = marks[0];Start with an actual element, not with 0 — starting at zero would give the wrong answer for an array of negative values.for (int i = 1; i < 5; i++) {Start at 1 because element 0 has already been used as the initial value.if (marks[i] > largest) largest = marks[i];Replace the running best only when a bigger value is found.} printf("%d", largest);Printed after the loop, or it would print a partial answer on every pass.- Changing
<to<=would readmarks[5], outside the array.C performs no bounds checking, so the program would compare against whatever memory follows and may report a value that was never in the array.
Initialise from marks[0], loop from 1 to 4, and print after the loop.