What you'll learn
A loop repeats work while preserving a contract: state starts valid, each iteration makes progress, and the condition eventually becomes false. C++ also lets you iterate directly over elements, avoiding indexes when the index itself is not meaningful.
By the end, you'll be able to:
- Select between
while,do-while, classicfor, and range-basedfor - Iterate over elements by value or reference intentionally
- Apply counting, accumulation, search, and validation patterns
- Prevent off-by-one errors with half-open ranges and invariants
while loops
A while loop checks its condition before every iteration. Use it when repetition depends on a changing condition and the number of iterations is not naturally a fixed count.
#include <iostream>
int main() {
int fuel{3};
while (fuel > 0) {
std::cout << "Fuel: " << fuel << '\n';
--fuel;
}
std::cout << "Engine stopped\n";
}Key idea
--fuel moves the state toward fuel == 0. Without it, the loop never terminates.do-while loops
A do-while executes the body before checking its condition, so it always runs at least once. Menus and retry prompts are common uses.
#include <iostream>
int main() {
char command{};
do {
std::cout << "[p]lay [h]elp [q]uit: ";
std::cin >> command;
if (command == 'p') std::cout << "Starting game\n";
else if (command == 'h') std::cout << "Choose p or q\n";
} while (std::cin && command != 'q');
std::cout << "Goodbye\n";
}Watch out
do-while syntax ends with a semicolon after the condition. Also include stream state in interactive conditions so end-of-input cannot trap the program in a loop.Classic for loops
A classic for keeps initialization, condition, and advancement together. It is a strong fit when a counter or iterator defines progress.
#include <iostream>
int main() {
int total{};
for (int number{1}; number <= 5; ++number) {
total += number;
std::cout << number << (number < 5 ? " + " : " = ");
}
std::cout << total << '\n';
}| Part | Runs | Responsibility |
|---|---|---|
| initializer | once | Create loop state |
| condition | before every iteration | Decide whether the body may execute |
| body | when condition is true | Perform the repeated work |
| advancement | after each completed body | Move toward termination |
Range-based for
A range-based for visits every element in a range. Iterate by value when a cheap copy is useful, by reference when modifying elements, and by const reference when reading larger objects without copying.
#include <cctype>
#include <iostream>
#include <string>
int main() {
std::string language{"Modern C++"};
for (char& character : language) { // reference modifies each element
unsigned char safe{static_cast<unsigned char>(character)};
character = static_cast<char>(std::toupper(safe));
}
for (const char character : language) { // read each value
std::cout << character;
}
std::cout << '\n';
}| Declaration | Effect |
|---|---|
auto element | Copy each element |
auto& element | Refer to and potentially modify each element |
const auto& element | Read each element without copying |
Note
unsigned char. The conversion prevents undefined behavior when plainchar is signed and contains a negative value.break & continue
continue skips the rest of the current iteration;break exits the nearest loop. Both are useful when they make the main path clearer, but several scattered exits can obscure the loop's contract.
#include <iostream>
int main() {
for (int value{1}; value <= 10; ++value) {
if (value % 2 != 0) continue; // skip odd values
std::cout << value << ' ';
if (value == 6) break; // stop the nearest loop
}
std::cout << '\n';
}Tip
while (true) plus a focused break when the exit decision occurs only after reading or computing state inside the body.Core loop patterns
| Pattern | State maintained |
|---|---|
| Count | How many elements satisfy a condition |
| Accumulate | A running sum, product, or combined result |
| Search | Whether or where a target was found |
| Transform | A changed output for each input element |
| Validate | Repeat until input satisfies syntax and domain rules |
#include <iostream>
#include <string>
int main() {
std::string text{"resource safety"};
int vowels{};
bool found_space{false};
for (const char character : text) {
if (character == ' ') found_space = true;
if (character == 'a' || character == 'e' ||
character == 'i' || character == 'o' || character == 'u') {
++vowels;
}
}
std::cout << "vowels=" << vowels
<< " space=" << std::boolalpha << found_space << '\n';
}Key idea
vowels and found_space—so the loop reads as a maintained contract rather than a collection of counters.Nested loops
A nested loop completes all inner iterations for each outer iteration. This naturally models rows and columns, combinations, grids, and repeated grouped output.
#include <iomanip>
#include <iostream>
int main() {
for (int row{1}; row <= 4; ++row) {
for (int column{1}; column <= 4; ++column) {
std::cout << std::setw(4) << row * column;
}
std::cout << '\n';
}
}Note
Boundaries & invariants
C++ ranges conventionally use half-open boundaries: include the beginning, exclude the end. For a sequence of size n, valid indexes are[0, n).
#include <iostream>
#include <string>
int main() {
std::string word{"C++"};
// Valid indexes form the half-open range [0, word.size()).
for (std::size_t index{0}; index < word.size(); ++index) {
std::cout << index << ':' << word[index] << '\n';
}
}- Write
index < size, notindex <= size - Keep the index type compatible with the size type
- State what is already true before each iteration—the loop invariant
- Prove the body preserves the invariant
- Identify why progress must reach termination
Watch out
Recap & quick check
Key takeaways
- while checks before iteration; do-while guarantees one body execution.
- Classic for centralizes counter state; range-for expresses element traversal directly.
- References let a range loop modify original elements; const references avoid copies while reading.
- break exits the nearest loop and continue skips to its next iteration.
- Half-open ranges, progress, and loop invariants prevent common boundary defects.
Quick check
1. Which loop always executes its body at least once?
2. Which range-for declaration can modify original elements?
3. What are valid indexes for a sequence of size n?
4. What must every terminating loop do?
You can now repeat work with explicit boundaries. Next: Module 6 — Functions, Scope, References & Program Structure, where repeated logic becomes reusable design.