Beginner

Control Flow in C++

Master control flow in C++ - conditionals, switch statements, loops, and loop control with practical Docker-ready examples

Control flow determines the order in which statements execute. Instead of running top to bottom every time, your program can branch on conditions, repeat work, and skip or stop iterations. These constructs turn a list of instructions into actual logic.

As a multi-paradigm language with deep C roots, C++ inherits the familiar structured control flow of if/else, switch, and the three loop forms (for, while, do-while). On top of that foundation, modern C++ adds quality-of-life features: the range-based for loop (C++11) for iterating containers, and if/switch statements with initializers (C++17) that scope a variable to the branch where it’s used.

In this tutorial you’ll learn how to make decisions with conditionals and the ternary operator, branch on discrete values with switch, repeat work with each loop type, and steer iterations with break and continue. Every example compiles cleanly with g++ and runs in the official gcc:14 Docker image.

Conditionals: if, else if, else

The if statement runs a block only when its condition is true. Chain else if for additional cases and else for a fallback. C++ also offers the ternary operator ?: for compact expressions and, since C++17, an init-statement that scopes a variable to the if.

Create a file named conditionals.cpp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <string>

int main() {
    int score = 85;

    // if / else if / else chain
    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;
    }

    // Ternary conditional operator: condition ? value_if_true : value_if_false
    int number = 7;
    std::string parity = (number % 2 == 0) ? "even" : "odd";
    std::cout << number << " is " << parity << std::endl;

    // Logical operators combine conditions
    int age = 25;
    bool hasLicense = true;
    if (age >= 18 && hasLicense) {
        std::cout << "Allowed to drive" << std::endl;
    }

    // if with initializer (C++17): remainder only exists inside this if
    if (int remainder = score % 10; remainder == 5) {
        std::cout << "Score ends in 5 (remainder " << remainder << ")" << std::endl;
    }

    return 0;
}

The init-statement form (if (init; condition)) keeps short-lived variables out of the surrounding scope, which prevents accidental reuse and keeps code tidy.

Switch Statements

When you’re branching on a single integer or character value with many discrete cases, switch is clearer than a long if/else if chain. Each case needs a break to stop execution from “falling through” into the next case — but deliberate fall-through is also useful for grouping cases that share behavior.

Create a file named switch_statement.cpp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>

int main() {
    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;
        case 4:
            std::cout << "Thursday" << std::endl;
            break;
        case 5:
            std::cout << "Friday" << std::endl;
            break;
        default:
            std::cout << "Weekend" << std::endl;
            break;
    }

    // Intentional fall-through groups cases that share an action
    char grade = 'B';
    switch (grade) {
        case 'A':
        case 'B':
        case 'C':
            std::cout << "Passing grade" << std::endl;
            break;
        case 'D':
        case 'F':
            std::cout << "Failing grade" << std::endl;
            break;
    }

    return 0;
}

The default case handles any value not matched by a case label. Because 'A', 'B', and 'C' have no break between them, they all flow into the same std::cout statement.

Loops: for, while, and do-while

C++ provides three loop forms. The classic for loop bundles initialization, condition, and update in one line. The while loop checks its condition before each iteration. The do-while loop checks after, so its body always runs at least once. C++11 added the range-based for loop for clean iteration over containers.

Create a file named loops.cpp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <string>
#include <vector>

int main() {
    // Classic for loop: init; condition; update
    std::cout << "Counting up: ";
    for (int i = 1; i <= 5; ++i) {
        std::cout << i << " ";
    }
    std::cout << std::endl;

    // While loop: checks the condition before each pass
    int countdown = 3;
    while (countdown > 0) {
        std::cout << "T-minus " << countdown << std::endl;
        --countdown;
    }

    // Do-while loop: body runs once before the condition is tested
    int n = 0;
    do {
        std::cout << "Runs once even though n == " << n << std::endl;
    } while (n > 0);

    // Range-based for loop (C++11): iterate a container directly
    std::vector<std::string> langs = {"C++", "Rust", "Go"};
    for (const auto& lang : langs) {
        std::cout << "Language: " << lang << std::endl;
    }

    return 0;
}

Using const auto& in the range-based loop avoids copying each element and signals that the loop won’t modify the container — the idiomatic choice for read-only iteration.

Loop Control: break and continue

Two keywords steer execution inside loops. break exits the enclosing loop immediately. continue skips the rest of the current iteration and jumps to the next one.

Create a file named loop_control.cpp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>

int main() {
    // break: stop the loop as soon as a condition is met
    std::cout << "Searching for 4:" << std::endl;
    for (int i = 1; i <= 10; ++i) {
        if (i == 4) {
            std::cout << "Found " << i << ", stopping" << std::endl;
            break;
        }
        std::cout << "Checking " << i << std::endl;
    }

    // continue: skip even numbers, keep going with odd ones
    std::cout << "Odd numbers from 1 to 7: ";
    for (int i = 1; i <= 7; ++i) {
        if (i % 2 == 0) {
            continue;
        }
        std::cout << i << " ";
    }
    std::cout << std::endl;

    return 0;
}

Running with Docker

Each example is a standalone program. Compile and run them with the official gcc:14 image — no local toolchain required.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# Pull the official GCC image (includes g++)
docker pull gcc:14

# Conditionals
docker run --rm -v $(pwd):/app -w /app gcc:14 \
    sh -c "g++ -o conditionals conditionals.cpp && ./conditionals"

# Switch statement
docker run --rm -v $(pwd):/app -w /app gcc:14 \
    sh -c "g++ -o switch_statement switch_statement.cpp && ./switch_statement"

# Loops
docker run --rm -v $(pwd):/app -w /app gcc:14 \
    sh -c "g++ -o loops loops.cpp && ./loops"

# Loop control
docker run --rm -v $(pwd):/app -w /app gcc:14 \
    sh -c "g++ -o loop_control loop_control.cpp && ./loop_control"

To use a specific standard (the init-statement and range-based examples need C++11 or later, which is the gcc:14 default), add the -std flag, for example g++ -std=c++17 -o conditionals conditionals.cpp.

Expected Output

Running conditionals:

Grade: B
7 is odd
Allowed to drive
Score ends in 5 (remainder 5)

Running switch_statement:

Wednesday
Passing grade

Running loops:

Counting up: 1 2 3 4 5 
T-minus 3
T-minus 2
T-minus 1
Runs once even though n == 0
Language: C++
Language: Rust
Language: Go

Running loop_control:

Searching for 4:
Checking 1
Checking 2
Checking 3
Found 4, stopping
Odd numbers from 1 to 7: 1 3 5 7 

Key Concepts

  • if/else if/else evaluate conditions top to bottom; the first true branch runs and the rest are skipped.
  • Ternary operator ?: is an expression, not a statement — it returns a value, making it ideal for compact assignments.
  • switch branches on integral or character values; remember break to prevent unintended fall-through, but use intentional fall-through to group cases that share an action.
  • Three loop forms: for for counted iteration, while for pre-checked loops, and do-while when the body must run at least once.
  • Range-based for (C++11) iterates containers cleanly; prefer const auto& for read-only access to avoid copies.
  • Init-statements in if and switch (C++17) scope a variable to the branch, keeping the surrounding scope clean.
  • break exits the enclosing loop entirely, while continue skips to the next iteration — both apply to the innermost loop only.
  • Truthiness: any non-zero numeric or non-null pointer value is treated as true in a condition, a behavior C++ inherits from C.

Running Today

All examples can be run using Docker:

docker pull gcc:14
Last updated:

Comments

Loading comments...

Leave a Comment

2000 characters remaining