The for loop is good when the iteration count is known in advance. A lot of real work does not fit that mold: reading items from a customer until they type "done", retrying a flaky payment until it succeeds, or draining a queue of pending orders. In all of those cases the count is not known ahead of time. Only the condition that keeps the loop going is known. That is what while is for.
A while loop has two parts: a condition in parentheses and a body in braces. As long as the condition is true, the body runs. The moment the condition becomes false, the loop stops and execution continues with whatever comes after.
A small useful example counts down the stock of a product as it sells out:
The flow is straightforward. Check stock > 0. If true, run the body. After the body, jump back and check again. When the body finally makes stock reach 0, the condition is false and the loop ends.
Two important points. The condition is checked before the body runs. And the body must eventually make the condition false. Failing on either creates problems, both covered shortly.
while Actually ExecutesWalking through the control flow once helps the rest of the lesson click. A while loop is a pre-test loop: the test runs first, then maybe the body, then back to the test.
The diagram shows the loop reaching the condition first. When the condition is already false on the first check, the body never runs. A while loop can iterate zero times. Compare that to do-while, where the body always runs at least once.
The zero-iteration case made concrete: a customer arrives at an empty cart and the code tries to total it up:
The body never runs because the condition was false on the first check. The program prints $0.00 and moves on, no crash, no warning. That is the right behavior. An empty cart has nothing to sum.
while Is the Natural ChoiceThe single best signal for while instead of for: the iteration count is not known in advance. The queue length is unknown. The number of typed inputs before "done" is unknown. The number of payment retries is unknown. Only the rule that keeps the loop alive is known.
A handful of patterns show up over and over in real C++ code:
Consider an order processing routine. A list of pending orders gets handled one at a time until the list is empty. The number of orders is not fixed, and new orders can arrive from sources outside the routine's control. A while loop fits naturally.
The loop reads almost like English. "While there are still pending orders, take the next one and process it." The body advances the state (the pop() call). When the queue is empty, pendingOrders.empty() returns true, the negation makes the condition false, and the loop exits.
A sentinel is a special value that means "stop." A common pattern asks the customer to enter cart items one by one and uses a special word like "done" to mark the end. The loop runs until the sentinel appears.
Sample input:
Two things are doing work in the condition. The std::cin >> item part both reads a word and evaluates to std::cin, which converts to true when the read succeeded. The item != "done" part checks for the sentinel. The && short-circuits, so a read failure (end of input, for example) never evaluates the comparison. That is not strictly required here, but it is a clean pattern that handles end-of-input the same way it handles the sentinel.
Some operations can fail and might work on retry: a payment to a slow gateway, a network call, a file open. The goal is to retry a few times before giving up. A while loop with a counter and a success flag handles this cleanly.
The loop has two ways to exit. Either paid becomes true (success) or attempt exceeds maxAttempts (give up). The combined condition attempt <= maxAttempts && !paid keeps the loop alive only when both are satisfied: attempts left, and not yet paid. As soon as either changes, the loop ends and the code after it decides what to print.
Asking the user for a number and refusing to move on until they give a sensible one is another while job. The number of wrong answers is unknown.
Sample run:
The first read happens outside the loop, then the loop only re-prompts while the value is out of range. As soon as the user types something valid, the condition fails and the loop ends. A clean way to say "keep asking until the answer is good."
Sometimes the condition is best expressed as a single boolean variable that summarizes "are we still going?" This is a stylistic choice, but it can make the intent obvious when the rule for stopping involves several pieces of state.
Sample run:
The flag pattern is useful when the stopping condition is set in more than one place, or when the logic for "are we done?" is complex enough that a single boolean reads better than a long expression in the parentheses.
while (true)Some loops should not have an exit condition in the header at all. An event loop that runs forever, or one where the exit condition depends on something deep inside the body, fits this shape. The standard idiom is while (true) with an explicit break to leave.
Sample run:
The header advertises that the condition is not where the exit lives. That is the point. A reader scanning the code sees while (true) and knows to look inside the body for the break. Hiding an early exit inside what looks like a normal conditional loop is harder to read than this.
break is used here without full introduction. For now, it exits the nearest enclosing loop immediately.
Some codebases write for (;;) instead of while (true). Both compile to the same thing. while (true) is generally clearer, so prefer it unless a team's style guide says otherwise.
The most common bug in a while loop is forgetting to change the state that the condition depends on. The loop body has to make progress toward making the condition false. Without that progress, the loop runs forever.
What is wrong with this code?
stock starts at 5, the condition stock > 0 is true, the body prints Sold one!, and control returns to the condition. Nothing in the body changed stock. So stock > 0 is still true. The loop prints Sold one! again. And again. Forever, until the program is killed.
Fix:
The fix is one line. Every while loop's body must do something that eventually makes the condition false. When writing a while loop, mentally trace one full iteration: which variable in the condition gets modified, and is the modification heading in the right direction? If that question has no answer, the loop has a bug.
An infinite loop does not "slow down" the program. It uses 100 percent of one CPU core forever and never produces output past the first iteration. Always check that the body advances state.
A subtle bug worth seeing once. Floating-point numbers (float, double) cannot represent most decimal values exactly. Adding 0.1 ten times does not yield exactly 1.0. So comparing a double to a specific value with == or != in a loop condition is almost always wrong.
What is wrong with this code?
The expected result is ten iterations and a tidy zero at the end. What actually happens: balance works its way down through 0.9, 0.8, and so on, but never lands exactly on 0.0. After the expected ten subtractions balance holds something like -2.77556e-17 rather than 0.0. The condition balance != 0.0 stays true, the loop keeps subtracting, and either runs forever or eventually drifts off into garbage.
Fix: Loop on an integer count, or use a tolerance for the comparison.
Integer counters are exact. They count down predictably. To drive a loop by a floating-point quantity, use a tolerance instead of equality:
The rule of thumb: never use == or != to compare floating-point values in a loop condition. Use <, >, or a tolerance instead. Better still, count iterations with an integer when possible.
while Over for (and Vice Versa)Both while and for can solve the same problems in principle. A for loop can be rewritten as a while loop and the other way around. But each is clearer than the other in particular situations, and using the right one makes the code easier to read.
| Situation | Better choice | Why |
|---|---|---|
| Iteration count is known up front (e.g., process 10 items) | for | The counter, condition, and update all live together in the header. |
| Iterating over a container of known size | for (or range-based for) | The counter and bound are part of the structure. |
| The exit condition is not a simple counter | while | Reads more naturally without a fake counter in the header. |
| Reading until a sentinel or end-of-input | while | The condition is the read result, not a count. |
| Draining a container or queue | while | The condition is "is there anything left?", which fits naturally. |
| Retrying until success or a limit | while | Two conditions combine cleanly in the header. |
| Looping forever (event loop, server loop) | while (true) with break | Standard idiom, signals "look inside for the exit." |
A useful test: a loop described with "until" or "while" fits while. A loop described with "for each" or "for the next N" fits for. The English used to explain the loop usually tells which construct fits.
A second useful test: when writing the loop header, ask whether there is a single variable being counted up or down. If yes, for is usually cleaner because that variable, its starting point, its bound, and its update all sit together. If no, while reads better because there is nothing useful to put in a for header.
A short list of the most common mistakes with while. Most are easy to spot once flagged.
while (i < n) runs n times, starting at 0. while (i <= n) runs n + 1 times. Pick the right one.while (paid = false) assigns false to paid and then tests false, so the loop never runs. while (paid == false) (or better, while (!paid)) is the intended form.while (!std::cin.fail() && ...) is fragile. Prefer while (std::cin >> x), which evaluates to false on read failure.while is a pre-test loop. A body that must run at least once needs do-while (next lesson).The general posture for writing while loops: figure out the exact condition that keeps the loop alive, write it, ensure the body advances some variable that the condition depends on, and trace through one or two iterations on paper for confidence. The discipline pays off because runaway loops are unpleasant to debug.
10 quizzes