Control Flow

Reviewed & published by Brayan K

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 worked examples and the output they print, 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.

#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 done." << endl;  // this one runs
    }

    // if / else if / else — checked top to bottom; the FIRST true branch wins.
    // Once one branch runs, the rest are skipped — so order matters.
    if (score >= 90) {
        cout << "Grade: A" << endl;
    } else if (score >= 80) {
        cout << "Grade: B" << endl;      // 82 >= 80 -> this runs, A was skipped
    } else if (score >= 70) {
        cout << "Grade: C" << endl;
    } else {
        cout << "Grade: F" << endl;      // the catch-all when nothing matched
    }

    return 0;
}

// ✅ Expected output:
//    You passed!
//    Not quite top, but well done.
//    Grade: B

⚠️ 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.

#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 << endl; // Largest: 42

    // You can drop it straight inside a larger expression.
    int n = 7;
    cout << n << " is " << ((n % 2 == 0) ? "even" : "odd") << endl; // 7 is odd

    // Use it for SHORT either/or choices. If a branch needs several
    // statements, a normal if/else is clearer — don't force the ternary.
    return 0;
}

// ✅ Expected output:
//    Status: Adult
//    Largest: 42
//    7 is odd

Your turn. Fill in the two ___ blanks using the hints in the comments, then run it.

#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

    cout << "Advice: " << advice << endl;
    cout << "Absolute: " << abs << endl;

    // ✅ Expected output:
    //    Advice: Hot
    //    Absolute: 8
    return 0;
}

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.

#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 runs, then break
            break;
        // Intentional fall-through: case 6 has no break, so when day is 6
        // execution "falls" into case 7 and they share the same code.
        case 6:
        case 7:
            cout << "Weekend!" << endl;
            break;
        default:            // runs when NO case matched (like else)
            cout << "A weekday" << endl;
    }

    // Same idea with a char.
    char grade = 'B';
    switch (grade) {
        case 'A': cout << "Excellent" << endl; break;
        case 'B': cout << "Good" << endl;      break;  // this runs
        default:  cout << "Keep practising" << endl;
    }

    return 0;
}

// ✅ Expected output:
//    Wednesday
//    Good

Now you try. This vending machine is missing the keyword that stops fall-through and the catch-all label. Fill in the two blanks:

#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 choices
            cout << "Unknown choice" << endl;
    }

    // ✅ Expected output:
    //    Dispensing Cola
    return 0;
}

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.

#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 << "=== Entry ===" << endl;
    if (age >= 18 && hasTicket) {
        // Nested if: a second decision INSIDE the first.
        if (isVip || age >= 65) {
            cout << "Welcome — priority lane!" << endl;
        } else {
            cout << "Welcome — general entry." << endl;   // this runs
        }
    } else {
        cout << "Entry denied." << endl;
    }

    // if-with-initializer (C++17): declare a variable, then test it, in one
    // line.  Pattern:  if (init; condition).  "left" only exists inside the if.
    cout << "=== Stock ===" << endl;
    if (int left = stockFor(7); left > 0) {
        cout << "In stock: " << left << " left" << endl;   // In stock: 3 left
    } else {
        cout << "Out of stock" << endl;
    }
    // 'left' is gone here — that tidy scoping is the whole point.

    return 0;
}

// ✅ Expected output:
//    === Entry ===
//    Welcome — general entry.
//    === Stock ===
//    In stock: 3 left

Common Errors (and the fix)

Pro Tips

📋 Quick Reference

ConceptSyntax
Ifif (cond) { ... }
If / elseif (cond) { ... } else { ... }
Else if chainif (...) {} else if (...) {} else {}
Ternaryresult = cond ? a : b;
Switchswitch (x) { case 1: ...; break; default: ...; }
Logical AND / OR / NOTa && b | a || b | !a
If with initializer (C++17)if (int x = f(); x > 0) { ... }

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.

#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" when age < 18, else "Adult".
    //
    // ✅ Expected (age = 20, isStudent = true):
    //    Price: $10
    //    Adult

    // your code here
    return 0;
}

🎉 Lesson Complete

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.

Continue this course

Frequently asked questions

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.

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.

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.

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.

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.