Break, continue and nested loops shape the flow of a C++ program by letting you leave a loop early or skip to the next iteration. [[break]] exits the innermost loop, [[continue]] skips to its next iteration, and nesting puts one loop inside another so you can work with pairs of values. Used carefully they remove duplication; used carelessly they turn a readable loop into a tangle.
break leaves the loop immediately
A break statement ends the loop it appears in and hands control to the statement after that loop.
#include
int main() {
for (int order = 1; order <= 5; ++order) {
if (order == 4) {
std::cout << "kitchen closed, stopping at order " << order << '\n';
break;
}
std::cout << "cooking order " << order << '\n';
}
std::cout << "orders remaining: " << 0 << '\n';
return 0;
}The output shows the loop stopping before the fourth order:
cooking order 1
cooking order 2
cooking order 3
kitchen closed, stopping at order 4
orders remaining: 0A common use is searching a collection: once you have found what you were looking for, there is no reason to keep looking.
continue skips to the next iteration
A continue statement ends the current iteration and starts the next one. Any code below it in the body is skipped.
#include
int main() {
int made = 0;
for (int order = 1; order <= 6; ++order) {
if (order % 2 != 0) {
continue; // skip the odd orders
}
std::cout << "making even order " << order << '\n';
++made;
}
std::cout << "even orders made: " << made << '\n';
return 0;
}The output confirms that only the even orders were made:
making even order 2
making even order 4
making even order 6
even orders made: 3Note that continue in a for loop still runs the update expression, so the counter advances correctly. In a while loop it does not, which is a classic infinite loop: the increment must be placed before the continue.
Nested loops multiply the work
A nested loop is one loop inside another. The outer loop runs once per iteration of the inner loop, so the total number of executions is the product of the two counts.
#include
int main() {
int small_pizzas = 3;
int slices_each = 4;
for (int p = 1; p <= small_pizzas; ++p) {
for (int s = 1; s <= slices_each; ++s) {
std::cout << "pizza " << p << " slice " << s << '\n';
}
}
return 0;
}Three pizzas with four slices each produce twelve lines of output. That product is also the reason nested loops are expensive: ten by ten is a hundred iterations, a thousand by a thousand is a million.
break only affects the innermost loop
This is the detail that catches everyone. A break inside the inner loop leaves the inner loop, and the outer loop carries on as if nothing happened.
#include
int main() {
for (int p = 1; p <= 3; ++p) {
for (int s = 1; s <= 3; ++s) {
if (s == 2) {
break; // leaves the inner loop only
}
std::cout << "pizza " << p << " slice " << s << '\n';
}
std::cout << "pizza " << p << " done\n";
}
return 0;
}The output makes the behaviour obvious:
pizza 1 slice 1
pizza 1 done
pizza 2 slice 1
pizza 2 done
pizza 3 slice 1
pizza 3 doneC++ also has a labelled break. A label is a name attached to a statement, and break outer; leaves every level of loop at once by naming the outer one. The syntax is short, but it couples the inner loop to the outer one and it is easy to misread:
outer:
for (int p = 1; p <= 3; ++p) {
for (int s = 1; s <= 3; ++s) {
if (p == 2 && s == 2) {
break outer; // leaves both loops at once
}
}
}The same effect can be reached with a flag that the outer loop checks, which keeps both loops independent:
#include
int main() {
bool found = false;
for (int p = 1; p <= 3 && !found; ++p) {
for (int s = 1; s <= 3; ++s) {
if (p == 2 && s == 2) {
std::cout << "found at pizza " << p << " slice " << s << '\n';
found = true;
break;
}
}
}
if (!found) {
std::cout << "nothing found\n";
}
return 0;
}The flag version is longer but it says what is happening in plain words, and it is the form that survives being edited six months later.
Where break and continue do not apply
A break inside a switch statement leaves the switch, not a surrounding loop. The two features look identical in the source but do completely different things, and mixing them up is a common source of confusion. If you need to leave a loop from inside a switch, the cleanest answer is usually to compute a result in the switch and act on it after the switch finishes.
A continue inside a switch has the same ambiguity. It applies to the enclosing loop, not to the switch, because a switch is not a loop at all. The switch simply finishes and the loop carries on with its next iteration.
When deep nesting is the wrong answer
Three or more levels of nesting usually means the logic wants to be a function. Extracting the inner loop into a named function turns a tangle into a call, and it gives the inner logic a name that explains itself.
#include
bool has_cheese(const int toppings[], int count, int wanted) {
for (int i = 0; i < count; ++i) {
if (toppings[i] == wanted) {
return true;
}
}
return false;
}
int main() {
int order[3] = {1, 4, 7};
if (has_cheese(order, 3, 4)) {
std::cout << "order includes extra cheese\n";
} else {
std::cout << "no extra cheese on this order\n";
}
return 0;
}Returning from inside the loop is cleaner than breaking out of it, and it means the caller does not need to know anything about the loop structure.
Quick reference
breakleaves the innermost loop;continueskips to its next iteration.- In a
forloop,continuestill runs the update expression; in awhileloop it does not. - A
breakin a nested loop only leaves the inner loop. - To leave several levels at once, use a flag the outer loop checks, or extract the inner loop into a function.
- Nested loops cost the product of their iteration counts — keep them small.
- Extract deep nesting into a function and
returninstead of breaking.
Try it yourself: write a nested loop over a 3 by 3 grid of pizza toppings that stops at the first duplicate and prints where it was found. Then add a flag so the outer loop stops as well, and compare the two outputs. Finally, refactor the inner search into its own function and confirm the program behaves identically.