Lesson 5 of 6
Sometimes a loop needs to stop before its condition says so, or skip the rest of one pass.
break: leave the loop now
#include <iostream>
int main() {
int values[] = {4, 8, 15, 16, 23, 42};
int target = 16;
int found_at = -1;
for (int i = 0; i < 6; ++i) {
if (values[i] == target) {
found_at = i;
break;
}
}
std::cout << "found at index " << found_at << "\n";
return 0;
}
found at index 3
Without break the loop would keep checking indices 4 and 5 pointlessly. On six elements that's
nothing; on six million it matters.
You met break in lesson 4.2 ending a switch case. Same keyword, same meaning: leave the
enclosing loop or switch.
continue: skip to the next iteration
#include <iostream>
int main() {
for (int i = 1; i <= 10; ++i) {
if (i % 3 != 0) {
continue;
}
std::cout << i << " ";
}
std::cout << "\n";
return 0;
}
3 6 9
continue abandons the rest of the body and jumps to the loop's update step. It's most useful as
a guard clause — filtering out cases you don't care about at the top, so the interesting code
isn't buried inside nested ifs:
for (const Record& r : records) {
if (!r.valid) continue;
if (r.amount == 0) continue;
// the real work, at one level of indentation
}
Compare that to wrapping everything in if (r.valid && r.amount != 0) { ... }. With three or
four conditions, guard clauses win clearly.
One trap: in a while loop, continue jumps to the condition check — skipping any increment
you wrote at the bottom of the body:
int i = 0;
while (i < 5) {
if (i == 2) continue; // i never changes — infinite loop
std::cout << i;
++i;
}
In a for loop this can't happen, because the update is part of the loop header and always runs.
That's one more reason to prefer for when you have a counter.
break only leaves one level
In nested loops, break exits the innermost loop only:
#include <iostream>
int main() {
for (int row = 0; row < 3; ++row) {
for (int col = 0; col < 3; ++col) {
if (col == 1) {
break;
}
std::cout << row << col << " ";
}
}
std::cout << "\n";
return 0;
}
00 10 20
The inner loop breaks at col == 1 every time, but the outer loop keeps going. C++ has no
break 2;. To leave both, use a flag or — better — put the loops in a function and return:
#include <iostream>
bool contains(int grid[3][3], int target) {
for (int row = 0; row < 3; ++row) {
for (int col = 0; col < 3; ++col) {
if (grid[row][col] == target) {
return true; // leaves both loops at once
}
}
}
return false;
}
int main() {
int grid[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
std::cout << std::boolalpha;
std::cout << contains(grid, 5) << " " << contains(grid, 99) << "\n";
return 0;
}
true false
return leaves the entire function regardless of nesting depth. Extracting a nested search into
its own function is usually the cleanest answer, and you'll meet functions properly in Module 5.
goto
C++ has goto. It jumps to a label anywhere in the same function:
#include <iostream>
int main() {
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
if (i * j == 2) {
goto done;
}
}
}
done:
std::cout << "finished\n";
return 0;
}
finished
That compiles and works. Don't use it.
The objection isn't superstition. goto destroys the property that makes code readable: that you
can understand a block by reading it top to bottom. With arbitrary jumps, understanding any line
means knowing every label that could have jumped to it — from anywhere in the function.
The historically legitimate use — breaking out of deeply nested loops, or jumping to cleanup code on error — is better served in C++ by:
- extracting the loops into a function and using
return, - RAII (lesson 8.2), which handles cleanup automatically,
- exceptions (Module 15) for error paths.
You will see goto in C code, especially kernel and embedded code where those alternatives
aren't available. Recognise it; don't reach for it.
pass? No such thing
Python programmers look for pass. C++ doesn't need it — an empty block is just {}, and an
empty statement is a lone ;:
#include <iostream>
int main() {
for (int i = 0; i < 3; ++i) {
// deliberately nothing
}
std::cout << "loop finished\n";
return 0;
}
loop finished
Beware the accidental version: for (int i = 0; i < 3; ++i); — note the semicolon — is a
complete loop with an empty body, and the block after it runs once. -Wall warns about it
(-Wempty-body).
Try it
Write a program that loops over the numbers 1 to 20 and prints only those divisible by 4,
stopping entirely as soon as it finds one greater than 15. Use both continue and break.
Checkpoint
breakleaves the innermost enclosing loop or switch immediately.continueskips the rest of the body and moves to the next iteration.- In a
whileloop,continuecan skip your increment and hang —foris immune. breakexits only one level; to leave nested loops, extract them into a function andreturn.gotoexists, works, and should not be used — prefer functions, RAII, and exceptions.
Questions about this lesson
Log in to ask a question.