Lesson 4 • Beginner
Control Flow
By the end of this lesson you'll be able to make your C++ programs decide what to do — branching with if/else if/else, choosing values with the ternary ?:, matching exact values with switch, and combining conditions with &&, || and !.
What You'll Learn
- Branch your code with if, else if and else
- Pick a value in one line with the ternary ?: operator
- Match exact values with switch / case / break / default
- Use fall-through deliberately (and avoid it by accident)
- Nest conditions and combine them with &&, || and !
- Scope a variable to one test with if (init; condition) (C++17)
>, <, ==) and printing with cout. We build directly on those here.💡 Real-World Analogy
Control flow is the signpost at a fork in the road. Your program walks up to a junction, reads a condition ("is it raining?"), and takes the matching path. An if/else if/else chain is a row of signs checked in order — you follow the first one that points your way and ignore the rest. A switch is the departures board at a station: it looks up your exact destination and sends you straight to the right platform. Without these signposts, the program can only ever walk in one straight line.
1. if / else if / else
An if statement runs a block of code only when a condition is true. The condition goes in (parentheses) and must evaluate to true or false. Add else for a fallback, and chain else if for extra options. The chain is checked top to bottom and the first true branch wins — every branch below it is skipped — so put your most specific conditions first. Read this worked example, run it, then you'll write your own.
Worked example: if / else if / else
Read every comment, run it, and check which branch fires.
#include <iostream>
using namespace std;
int main() {
int score = 82;
// An if statement runs its block ONLY when the condition is true.
// The condition lives in (parentheses) and must be true or false.
if (score >= 50) {
cout << "You passed!" << endl; // runs, because 82 >= 50 is true
}
// if / else — one of the two blocks ALWAYS runs.
if (score >= 90) {
cout << "Top of the class." << endl;
} else {
cout << "Not quite top, but well d
...⚠️ Always use braces {}. Without them, only the single line after the if is conditional — the next line runs every time, which is a classic, silent bug.
2. The Ternary Operator ?:
The ternary is a compact if/else that returns a value. The shape is condition ? valueIfTrue : valueIfFalse. Because it produces a value, you can assign it directly (string s = ok ? "yes" : "no";) or drop it inside a bigger expression. Reach for it on short either/or choices; if a branch needs several statements, a normal if/else reads more clearly.
Worked example: the ternary operator
See how ?: returns a value you can assign or print.
#include <iostream>
#include <string>
using namespace std;
int main() {
// The ternary operator is a one-line if/else that RETURNS a value:
// condition ? valueIfTrue : valueIfFalse
int age = 20;
string status = (age >= 18) ? "Adult" : "Minor";
cout << "Status: " << status << endl; // Status: Adult
// Great for picking the bigger of two numbers without a temp if-block.
int a = 42, b = 17;
int largest = (a > b) ? a : b;
cout << "Largest: " << largest <<
...Your turn. Fill in the two ___ blanks using the hints in the comments, then run it.
🎯 Your turn: write two ternaries
Fill in the ___ blanks, then check your output against the expected lines.
#include <iostream>
#include <string>
using namespace std;
int main() {
// 🎯 YOUR TURN — replace each ___ then press "Try it Yourself".
int temperature = 30;
// 1) Use a ternary to set "advice" to "Hot" when temperature >= 25,
// otherwise "Mild".
string advice = ___; // 👉 (temperature >= 25) ? "Hot" : "Mild"
// 2) Use a ternary to store the absolute value of -8 in "abs".
int value = -8;
int abs = ___; // 👉 (value >= 0) ? value : -value
co
...3. switch / case / break / default
When you're comparing one value against many exact options, a switch is cleaner than a long else if chain. It works with int, char and enum (not strings or ranges). Each case ends with break to jump out of the switch; default is the catch-all, like else. If you omit break, execution falls through into the next case — handy when you deliberately stack cases (case 6: case 7: sharing one block), but a bug when you forget it.
switch (variable) {
case value1:
// code for value1
break; // stop — without this it falls through
case value2:
case value3: // value2 and value3 share the next block
// code for value2 OR value3
break;
default: // optional — runs when nothing matched
// fallback code
}Worked example: switch, break, default & fall-through
Match days and a grade letter, and see deliberate fall-through.
#include <iostream>
using namespace std;
int main() {
// switch compares ONE value against many exact cases.
// It works with int, char and enum — NOT with strings or ranges.
int day = 3;
switch (day) {
case 1:
cout << "Monday" << endl;
break; // break = stop here, jump out of the switch
case 2:
cout << "Tuesday" << endl;
break;
case 3:
cout << "Wednesday" << endl; // matches -> this r
...Now you try. This vending machine is missing the keyword that stops fall-through and the catch-all label. Fill in the two blanks:
🎯 Your turn: finish the switch
Add the missing break and default, then check the output.
#include <iostream>
using namespace std;
int main() {
// 🎯 YOUR TURN — a tiny vending machine. Fill in the blanks.
int choice = 2; // 1 = Water, 2 = Cola, anything else = unknown
switch (choice) {
case 1:
cout << "Dispensing Water" << endl;
___ // 👉 add the keyword that stops fall-through here
case 2:
cout << "Dispensing Cola" << endl;
break;
___: // 👉 the catch-all label for unmatched
...4. Nesting, Logic & if-with-Initializer
Real decisions often depend on several things at once. Combine conditions with the logical operators: && (AND — both must be true), || (OR — either is enough), and ! (NOT — flips true and false). You can also nest an if inside another to make a second decision only when the first passed. Finally, C++17's if-with-initializer lets you declare and test a variable together — if (int x = f(); x > 0) — keeping x scoped to just that if/else.
Worked example: &&, ||, nesting & if (init; condition)
Combine conditions, nest a decision, and scope a variable to one test.
#include <iostream>
#include <string>
using namespace std;
// Returns how many items are left in stock for an order id.
int stockFor(int id) {
return (id == 7) ? 3 : 0; // only product 7 is in stock (3 left)
}
int main() {
int age = 22;
bool hasTicket = true;
bool isVip = false;
// Logical operators combine conditions:
// && AND -> true only if BOTH sides are true
// || OR -> true if EITHER side is true
// ! NOT -> flips true <-> false
cout
...Common Errors (and the fix)
- Missing
break(accidental fall-through): if acasehas nobreak, its code and the next case's both run. Addbreak;to every case unless you mean to fall through. =instead of==:if (x = 5)assigns 5 toxand is always true. Use==to compare; writingif (5 == x)turns the typo into a compile error.- No
defaultcase: if nocasematches and there's nodefault, theswitchsilently does nothing. Add adefault:to catch unexpected values. - Dangling else: an
elsebinds to the nearest unmatchedif, not the one you indented it under. Use braces{}on every nestedifso theelsepairs with the right one. - "error: '
x' was not declared in this scope": a variable from anif-with-initializer or acaseblock only lives inside that block. Declare it outside if you need it afterwards.
Pro Tips
- 💡 Handle edge cases first: deal with the unusual inputs early with simple
ifs, then write the normal path without deep nesting. - 💡 Use
switchfor menus: it's ideal for processing numbered choices (1, 2, 3…) in a console app. - 💡 Flatten deep nesting: 4+ levels of indentation is a smell — pull the inner logic into a small function.
- 💡 Scope tightly: prefer
if (auto v = lookup(); v)so short-lived variables can't leak into the rest of your function.
📋 Quick Reference
| Concept | Syntax |
|---|---|
| If | if (cond) { ... } |
| If / else | if (cond) { ... } else { ... } |
| Else if chain | if (...) {} else if (...) {} else {} |
| Ternary | result = cond ? a : b; |
| Switch | switch (x) { case 1: ...; break; default: ...; } |
| Logical AND / OR / NOT | a && b | a || b | !a |
| If with initializer (C++17) | if (int x = f(); x > 0) { ... } |
Frequently Asked Questions
Q: When should I use a switch instead of an if/else chain?
Use switch when you are comparing ONE variable against many exact, constant values (like menu numbers or a char grade). It is cleaner and shows your intent. Use if/else when you need ranges (score >= 80), combined conditions with && or ||, or anything other than an int, char or enum.
Q: What is fall-through in a switch?
If a case has no break, execution continues into the next case. Usually that is a bug — you forget the break and two messages print. But it is also a deliberate trick: stacking case 6: case 7: with one block lets several values share the same code.
Q: Why does if (x = 5) always run?
A single = is assignment, not comparison. if (x = 5) stores 5 in x and then tests that value, and any non-zero number counts as true in C++, so the branch always runs. Use == to compare. Putting the constant first — if (5 == x) — makes a typo a compile error.
Q: Is the ternary operator just a shortcut for if/else?
Almost. The key difference is that the ternary RETURNS a value, so you can assign it: string s = ok ? "yes" : "no";. A plain if/else does not return anything. Keep the ternary for short either/or choices; if a branch needs several statements, a normal if/else reads better.
Q: What is an if-with-initializer and why use it?
Since C++17 you can write if (int x = f(); x > 0) — declare x and test it in one line. The variable only exists inside the if/else, so it cannot leak into the rest of your function. It keeps short-lived variables tightly scoped and your code tidier.
Mini-Challenge: Ticket Price Calculator
No blanks this time — just a brief and a blank canvas (with an outline to keep you on track). Build it, run it, and check your output against the example in the comments. This combines an if/else if chain with a ternary, exactly like real code.
🎯 Mini-Challenge: build a ticket price calculator
Write the if/else chain and the ternary yourself.
#include <iostream>
#include <string>
using namespace std;
int main() {
// 🎯 MINI-CHALLENGE: Ticket price calculator
// 1. Make an int "age" and a bool "isStudent".
// 2. Decide the price with if / else if / else:
// under 5 -> 0 (free)
// 65 and over -> 8 (senior)
// isStudent is true -> 10 (student)
// everyone else -> 15 (standard)
// 3. Print: "Price: $X"
// 4. BONUS: use a ternary to print "Child" w
...🎉 Lesson Complete
- ✅
if/else if/elserun the first branch whose condition is true - ✅ The ternary
cond ? a : breturns a value you can assign or print - ✅
switchmatches exactint/char/enumvalues;breakstops fall-through;defaultis the catch-all - ✅ Combine conditions with
&&,||and!, and nestifs for layered decisions - ✅
if (init; condition)(C++17) scopes a variable to just that test - ✅ Next lesson: Loops — repeat code efficiently with
for,whileanddo-while
Sign up for free to track which lessons you've completed and get learning reminders.