Which loop patterns solve common beginner tasks is a question worth answering early, because most programming problems are one of five shapes wearing different clothes: count something, accumulate something, search for something, repeat until a sentinel appears, or walk a grid. Recognising the shape tells you which loop to reach for before you write a line of code.
Pattern one: counting
Counting needs a counter and a known stopping point, which is exactly what a for loop is built for.
#include
int main() {
int pizzas_sold = 0;
const int daily_target = 12;
for (int i = 0; i < daily_target; ++i) {
++pizzas_sold;
}
std::cout << "sold " << pizzas_sold << " pizzas today\n";
return 0;
}The counter is often only a mechanism rather than the answer. When that is the case, reach for a while loop with a clearly named state variable instead.
Pattern two: accumulating
Accumulating means running a total through a sequence. The shape is always the same: start at zero, add each value, return the total.
#include
int main() {
const int daily_sales[5] = {12, 18, 9, 22, 15};
int total = 0;
int best = daily_sales[0];
for (int i = 0; i < 5; ++i) {
total += daily_sales[i];
if (daily_sales[i] > best) {
best = daily_sales[i];
}
}
std::cout << "total: " << total << '\n';
std::cout << "best day: " << best << '\n';
std::cout << "average: " << total / 5 << '\n';
return 0;
}The output shows the accumulated total, the maximum found along the way, and the derived average:
total: 76
best day: 22
average: 15Initialising the accumulator before the loop is not optional. Declaring it inside the loop and adding to it would throw the total away on every iteration.
Pattern three: searching
A search loop stops as soon as it finds what it wants. The break is the whole point.
#include
int main() {
const int order_numbers[4] = {4821, 5107, 3390, 6120};
const int wanted = 3390;
int position = -1;
for (int i = 0; i < 4; ++i) {
if (order_numbers[i] == wanted) {
position = i;
break;
}
}
if (position == -1) {
std::cout << "order " << wanted << " not found\n";
} else {
std::cout << "order " << wanted << " found at index " << position << '\n';
}
return 0;
}The pattern to remember is that a search needs both a "found it" signal and a "not found" signal. Initialising the position to -1 and checking it afterwards covers both cases cleanly.
Pattern four: sentinel-controlled repetition
Sometimes the end of the data is marked by a special value rather than by a count. A while loop is the natural fit, and the sentinel test must come *before* the body so the marker is never processed.
#include
int main() {
int order_total = 0;
int orders = 0;
const int SENTINEL = -1;
// In a real program the total would come from the keyboard.
int totals[5] = {250, 310, 180, 420, SENTINEL};
for (int i = 0; i < 5; ++i) {
if (totals[i] == SENTINEL) {
break;
}
order_total += totals[i];
++orders;
}
std::cout << "orders: " << orders << '\n';
std::cout << "revenue: " << order_total << '\n';
return 0;
}The output shows the loop stopping at the marker without counting it:
orders: 4
revenue: 1160Pattern five: nested iteration over a grid
When you need to visit every combination of two things — every row and every column, every size and every topping — you need two loops, one inside the other.
#include
int main() {
const char* sizes[3] = {"small", "medium", "large"};
const char* crusts[2] = {"thin", "deep"};
int combinations = 0;
for (int s = 0; s < 3; ++s) {
for (int c = 0; c < 2; ++c) {
++combinations;
std::cout << sizes[s] << " pizza, " << crusts[c] << " crust\n";
}
}
std::cout << "combinations: " << combinations << '\n';
return 0;
}The output lists all six combinations and counts them:
small pizza, thin crust
small pizza, deep crust
medium pizza, thin crust
medium pizza, deep crust
large pizza, thin crust
large pizza, deep crust
combinations: 6How to recognise the pattern before you code
The fastest way to get good at these is to read the problem and name the shape out loud before writing anything. Ask three questions. Is there a number that tells you how many times to repeat? Then it is counting and a for loop is right. Is there a value that has to be built up as you go? Then it is accumulating and you need a total initialised before the loop. Is there something you are looking for that would let you stop early? Then it is searching and the loop needs a break.
Two more patterns sit alongside those three. If the end of the data is marked by a special value rather than by a count, it is sentinel-controlled. If the work involves every pairing of two collections, it is nested iteration.
None of these patterns are hard on their own. What makes them hard is starting to code before you have decided which one you are writing, and then discovering halfway through that the loop needs a state variable you never initialised.
Five mini challenges to practise the patterns
- Sum of evens. Given an array of ten integers, use a loop to add only the even ones and print the total.
- Second largest. Find the second-largest value in an array without sorting it, using one pass and two variables.
- FizzBuzz. Print the numbers from 1 to 20, replacing multiples of 3 with "Fizz" and multiples of 5 with "Buzz".
- Sentinel sum. Read numbers until a zero appears, then report how many were read and their sum.
- Triangular numbers. Print the first ten triangular numbers, where each one is the sum of all integers up to that point.
Each challenge exercises a different pattern, and each has exactly one loop in the reference solution.
Quick reference
- Counting uses a
forloop with a counter; accumulating uses a total that starts at zero. - Searching uses a
breakthe moment the target is found, plus a not-found signal. - Sentinel loops test the marker before processing the value.
- Nested loops cover every combination of two collections.
- Always initialise an accumulator or a "found" flag before the loop starts.
- Avoid the double-loop anti-pattern of searching inside a search when a single pass will do.
Try it yourself: implement the five mini challenges above, one at a time, writing down which pattern each one matched before you start coding. Then time yourself: a challenge you can solve in under five minutes has been recognised properly, and one that takes longer usually means the pattern was misidentified or the loop state was not initialised correctly.