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 ! .
Part of the free C++ course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn
💡 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.
⚠️ 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.
Your turn. Fill in the two ___ blanks using the hints in the comments, then run it.
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.
Now you try. This vending machine is missing the keyword that stops fall-through and the catch-all label. Fill in the two blanks:
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 .
Common Errors (and the fix)
- Missing break (accidental fall-through): if a case has no break , its code and the next case's both run. Add break; to every case unless you mean to fall through.
- = instead of == : if (x = 5) assigns 5 to x and is always true. Use == to compare; writing if (5 == x) turns the typo into a compile error.
- No default case: if no case matches and there's no default , the switch silently does nothing. Add a default: to catch unexpected values.
- Dangling else: an else binds to the nearest unmatched if , not the one you indented it under. Use braces { } on every nested if so the else pairs with the right one.
- "error: ' x ' was not declared in this scope": a variable from an if -with-initializer or a case block 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 if s, then write the normal path without deep nesting.
- 💡 Use switch for 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
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.
🎉 Lesson Complete
- ✅ if / else if / else run the first branch whose condition is true
- ✅ The ternary cond ? a : b returns a value you can assign or print
- ✅ switch matches exact int / char / enum values; break stops fall-through; default is the catch-all
- ✅ Combine conditions with && , || and ! , and nest if s for layered decisions
- ✅ if (init; condition) (C++17) scopes a variable to just that test
- ✅ Next lesson: Loops — repeat code efficiently with for , while and do-while
Practice quiz
In an if / else if / else chain, which branch runs?
- All branches whose condition is true
- Only the else branch
- The first branch whose condition is true
- The last branch whose condition is true
Answer: The first branch whose condition is true. The chain is checked top to bottom and the first true branch wins; the rest are skipped.
What is the shape of the ternary operator?
- condition ? valueIfTrue : valueIfFalse
- condition : a ? b
- if condition then a else b
- condition && a || b
Answer: condition ? valueIfTrue : valueIfFalse. The ternary is condition ? valueIfTrue : valueIfFalse and returns a value.
Which types can a switch statement compare against exact cases?
- Only std::string
- Only double
- Any type including ranges
- int, char and enum
Answer: int, char and enum. switch works with int, char and enum — not strings or ranges.
What happens in a switch case that has no break?
- The program crashes
- Execution falls through into the next case
- It jumps to default
- Nothing prints
Answer: Execution falls through into the next case. Without break, execution falls through into the next case's code.
What role does 'default' play in a switch?
- It is the catch-all when no case matched (like else)
- It runs first
- It must come before all cases
- It stops fall-through
Answer: It is the catch-all when no case matched (like else). default runs when no case matched, like an else clause.
Why does 'if (x = 5)' always run its block?
- 5 is special
- if always runs once
- = assigns 5 to x and the non-zero value is treated as true
- It compares x to 5 and they match
Answer: = assigns 5 to x and the non-zero value is treated as true. = is assignment; it stores 5 in x and any non-zero value counts as true.
What is the key advantage of the ternary over a plain if/else?
- It is faster at runtime
- It returns a value you can assign
- It allows more statements
- It works on strings only
Answer: It returns a value you can assign. The ternary returns a value, so you can assign it: string s = ok ? "yes" : "no";.
Given int score = 82, which grade prints in the lesson's if/else if chain (A>=90, B>=80, C>=70)?
- Grade: A
- Grade: C
- Grade: F
- Grade: B
Answer: Grade: B. 82 >= 80 is the first true branch, so Grade: B prints (A was skipped).
What does an if-with-initializer 'if (int x = f(); x > 0)' give you (C++17)?
- A faster loop
- x scoped to just that if/else
- A global variable x
- Automatic break
Answer: x scoped to just that if/else. The variable declared in the initializer only exists inside that if/else, keeping it tightly scoped.
When stacking 'case 6: case 7:' with one block and a break, what does it achieve?
- A compile error
- Only 7 runs the code
- Both values 6 and 7 share the same code
- It skips both cases
Answer: Both values 6 and 7 share the same code. Deliberate fall-through lets several case values share one block of code.