C++ Control Flow
π§ What this note covers
Control flow refers to the tools that let a program make decisions and repeat actions rather than simply running from top to bottom in one single straight line. This note covers if and else statements, the switch statement, and the three loop types C++ provides, building directly on the operators explained in C++ Operators & Expressions.
β if, else if, and else
int score = 85;
if (score >= 90) {
std::cout << "Grade: A" << std::endl;
} else if (score >= 80) {
std::cout << "Grade: B" << std::endl;
} else if (score >= 70) {
std::cout << "Grade: C" << std::endl;
} else {
std::cout << "Grade: F" << std::endl;
}
// prints "Grade: B"Curly braces are technically optional for a single statement
If an
ifblock contains only one single statement, the curly braces{ }are technically optional in C++. Nearly every style guide still strongly recommends always including them regardless, since it is far too easy to later add a second line inside what you believe is still the conditional block, without noticing that only the very first line was actually ever controlled by theifstatement, a genuinely common and sometimes quite subtle source of bugs.
π The switch statement
switch provides a cleaner alternative to a long chain of else if statements, specifically when comparing one single variable against several possible fixed values.
int day = 3;
switch (day) {
case 1:
std::cout << "Monday" << std::endl;
break;
case 2:
std::cout << "Tuesday" << std::endl;
break;
case 3:
std::cout << "Wednesday" << std::endl;
break;
default:
std::cout << "Some other day" << std::endl;
}Forgetting break causes "fall through," a classic C++ pitfall
Without a
breakstatement at the end of each case, execution does not stop there, it simply continues running directly into the next case below it, a behavior called βfall through.β This is genuinely one of the most common and notorious sources of bugs for people newer to C++, since forgetting even a singlebreaksilently executes code from a case you never intended to run at all. Some C++ code deliberately makes use of fall through as an intentional technique, typically clearly marked with a comment explaining the choice, but leaving it in by accident is a real and frequent mistake worth being deliberately careful about.
switch (day) {
case 6:
case 7:
std::cout << "Weekend" << std::endl;
break;
default:
std::cout << "Weekday" << std::endl;
}
// an intentional use of fall through, treating both case 6 and case 7 identicallyπ The for loop
for (int i = 0; i < 5; i++) {
std::cout << i << std::endl;
}
// prints 0, 1, 2, 3, 4, each on its own lineBreaking down the three semicolon separated parts inside a traditional for loop:
int i = 0runs exactly once, right at the very start, initializing the loop counter.i < 5is checked before every single iteration; the loop continues only while this remains true.i++runs at the end of every single iteration, after the loop body has finished running for that pass.
C++ arrays and most containers are zero indexed
This traditional
forloop pattern deliberately starts counting from0, not1, reflecting the fact that arrays and most standard containers in C++, covered further in C++ Arrays & Strings and C++ STL Containers, are themselves zero indexed, meaning the very first element sits at position0, not position1. This is a foundational convention worth internalizing early, since it affects loop boundaries constantly throughout C++ code.
The range based for loop
C++11 introduced a simpler loop specifically for iterating directly over every element of a container, without needing to manually manage an index variable at all.
std::vector<int> numbers = {10, 20, 30, 40};
for (int num : numbers) {
std::cout << num << std::endl;
}
for (const auto& num : numbers) {
std::cout << num << std::endl;
}Why const auto& is often the preferred form
Writing
for (const auto& num : numbers)avoids actually copying each element as the loop runs, instead referring to it directly in place, which matters for performance once elements are larger or more expensive to copy than a simpleint, such as a fullstd::stringor a custom class object. Theconstadditionally signals clearly that the loop has no intention of modifying the original containerβs contents at all. This exact pattern connects directly to the concept of references, covered fully in C++ Pointers & References.
π The while loop
int count = 1;
while (count <= 5) {
std::cout << count << std::endl;
count++;
}A while loop checks its condition before every single iteration, including the very first one, meaning it is entirely possible for its body to never run at all if the condition is already false right from the very start.
Watch out for infinite loops
A
whileloop only ever stops once its condition genuinely becomes false. Forgetting to update the variable being checked inside the loop body, such as forgetting thecount++;line above, causes the loop to run forever, hanging the entire program. Always double check that the condition being tested is truly guaranteed to eventually become false under normal execution.
π The do-while loop
A do-while loop is closely related to a regular while loop, but checks its condition after each iteration instead of before, guaranteeing the body runs at least one time, no matter what the condition initially evaluates to.
int count = 1;
do {
std::cout << count << std::endl;
count++;
} while (count <= 5);When a do-while loop is genuinely the better structural fit
A
do-whileloop is the natural choice specifically when a task genuinely needs to happen at least once regardless of any condition, such as prompting a user for input and then validating it afterward, where you obviously need to actually ask at least once before you have anything at all to check against the condition.
β break and continue
for (int i = 0; i < 10; i++) {
if (i == 5) {
break; // immediately exits the loop entirely, skipping everything remaining
}
std::cout << i << std::endl;
}
// prints 0, 1, 2, 3, 4, then stops
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
continue; // skips just this one single iteration, moving straight to the next
}
std::cout << i << std::endl;
}
// prints only the odd numbers: 1, 3, 5, 7, 9break exits the loop, continue skips just one pass
A simple way to remember the difference is that
breakis like leaving a room entirely, whilecontinueis like skipping ahead to the next item on a checklist without leaving the room at all. Both work identically acrossfor,while, anddo-whileloops.
π Where to go next
With decision making and repetition covered, continue to C++ Functions to start packaging this kind of logic into genuinely reusable, named blocks of code, or move to C++ Arrays & Strings to see loops applied directly to real collections of data.