⚙️ Unit 04 • C++ Systems Engineering

Control Flow & Iteration Statements

Architecting program logic execution paths: branching mechanisms (if, if-else, nested if, else-if ladder), switch jump table internals and fallthrough rules, iterative control loops (for, while, do-while), nested 2D loops, architectural pattern generation, loop interruptions (break, continue), and structured cleanup with goto.

🔀 Branching: if-else, else-if ladder & switch-case
🔁 Loops: for, while & do-while (Entry vs Exit)
📐 Algorithms: Nested Loops & Pattern Matrices
🛑 Jumps: break, continue & structured goto
01

Conditional Branching: if, if-else, Nested if & else-if Ladder

Control flow statements alter the linear top-to-bottom sequence of instruction execution in the CPU program counter. The if family of statements evaluates a condition expression convertible to bool:

1. if & if-else Statements

Executes a block of code if the test condition evaluates to true. The optional else branch executes if the condition evaluates to false.

if (packet.isValid()) {
    processPacket(packet);
} else {
    logError("Corrupted packet dropped");
}
2. Nested if & Dangling Else Ambiguity

An if block placed inside another if or else block. In C++, an else clause is always syntactically bound to the closest preceding unclosed if unless overridden by explicit curly braces {}.

3. The else-if Ladder (Multi-Way Decision)

Evaluates sequential mutually exclusive conditions from top to bottom. The moment any condition evaluates to true, its statement block executes and the entire remainder of the ladder is skipped:

if (httpStatusCode == 200) {
    status = "OK: Request Succeeded";
} else if (httpStatusCode == 404) {
    status = "Client Error: Resource Not Found";
} else if (httpStatusCode == 500) {
    status = "Server Error: Internal Failure";
} else {
    status = "Unknown Protocol Code";
}
1
Condition 1 Evaluation: httpStatusCode == 200
If True → Execute Block 1 → Jump directly past final else to next statement.
2
Condition 2 Evaluation: httpStatusCode == 404
Evaluated ONLY if Condition 1 was False. If True → Execute Block 2 → Exit ladder.
3
Default else Fallback
Executes if and only if all preceding conditions evaluate to False.
02

The switch Statement, Fallthrough & Jump Table Optimization

The switch statement tests an expression against a list of constant integer or enumeration values. Unlike an else-if ladder which checks conditions linearly in O(N) time, modern C++ compilers optimize dense switch statements into an O(1) Jump Table (a precomputed array of function addresses indexed directly by the switch value):

switch Statement Rules & Constraints
  • Integral / Enum Only: The switch condition must evaluate to an integral type (int, char, short, long) or an enum. Strings, floats, and objects are illegal syntax!
  • Compile-Time Constant Cases: Each case label must be a compile-time constant literal or constexpr.
  • Unique Labels: Duplicate case values trigger a compile-time error.
  • The default Case: Optional fallback executing if no case constant matches.
Fallthrough & C++17 [[fallthrough]]

If a case block does not terminate with an explicit break statement, execution continues seamlessly into the next case below it. This is called fallthrough.

In modern C++17, intentional fallthrough should be annotated with the standard attribute [[fallthrough]]; to suppress compiler warnings.

switch_jump_table.cpp
#include <iostream>

enum class NetworkState { Idle, Connecting, Connected, Disconnecting };

void handleNetworkState(NetworkState state) {
    switch (state) {
        case NetworkState::Idle:
            std::cout << "Socket idle, waiting for connection.\n";
            break;
        case NetworkState::Connecting:
            std::cout << "Negotiating TLS handshake...\n";
            break;
        case NetworkState::Connected:
            std::cout << "Connection active. Streaming data.\n";
            break;
        case NetworkState::Disconnecting:
            std::cout << "Flushing buffer and closing socket.\n";
            break;
        default:
            std::cout << "Unknown network state.\n";
            break;
    }
}
03

Loops: for, while & do-while (Entry vs Exit Controlled)

Loops repeat a block of statements until a termination condition is met. C++ provides three fundamental looping constructs:

Loop Type Control Category Evaluation Timing Minimum Iterations Best Use Case
for Entry-Controlled Condition checked before loop body executes 0 iterations Definite iterations (fixed count, stepping through ranges)
while Entry-Controlled Condition checked before loop body executes 0 iterations Indefinite iterations (reading streams until EOF, polling flags)
do-while Exit-Controlled Condition checked after loop body executes 1 iteration (Guaranteed) Interactive menus, input validation (execute prompt first, then check)
1. The for Loop
for (init; cond; update) {
    // Body
}

Scoped variables: for (int i = 0; ...) confines i to loop scope.

2. The while Loop
while (sensor.isBusy()) {
    std::this_thread::yield();
}

Best for loops where update frequency is event-driven or asynchronous.

3. The do-while Loop
do {
    std::cin >> choice;
} while (choice < 1 || choice > 5);

Always terminated by a mandatory semicolon (;) after the while condition!

A
Entry-Controlled (for / while)
Check Condition → [If True] Execute Body → Update → Loop back | [If False] Exit immediately.
B
Exit-Controlled (do-while)
Execute Body first → Check Condition → [If True] Loop back | [If False] Terminate. (Guarantees at least 1 run).
04

Nested Loops & Algorithmic Pattern Generation

A nested loop is a loop placed inside the body of an outer loop. In a 2D nested loop, for every single iteration of the outer loop, the inner loop executes its complete cycle of iterations. This is fundamental for traversing 2D matrices, image pixel grids, and generating geometric patterns:

pattern_generation.cpp
#include <iostream>

// 1. Pyramid Star Pattern (N = 5)
void printPyramid(int n) {
    for (int i = 1; i <= n; ++i) {
        // Leading spaces: n - i
        for (int s = 1; s <= n - i; ++s) {
            std::cout << " ";
        }
        // Stars: 2*i - 1
        for (int j = 1; j <= 2 * i - 1; ++j) {
            std::cout << "*";
        }
        std::cout << "\n";
    }
}

// 2. Floyd's Number Triangle
void printFloydsTriangle(int n) {
    int counter = 1;
    for (int row = 1; row <= n; ++row) {
        for (int col = 1; col <= row; ++col) {
            std::cout << counter++ << " ";
        }
        std::cout << "\n";
    }
}

int main() {
    std::cout << "--- Centered Pyramid ---\n";
    printPyramid(5);

    std::cout << "\n--- Floyd's Triangle ---\n";
    printFloydsTriangle(4);
    return 0;
}
pattern_output.ascii
[ Centered Pyramid (N=5) ]      [ Floyd's Triangle (N=4) ]
        *                       1
       ***                      2 3
      *****                     4 5 6
     *******                    7 8 9 10
    *********
05

Jump Statements: break, continue & goto Basics

1. The break Statement

Immediately terminates the enclosing switch or nearest enclosing loop (for, while, do-while). Execution jumps to the statement directly following the loop block.

2. The continue Statement

Skips the remainder of the current iteration and jumps directly to the loop's update step (in a for loop) or condition check (in a while loop).

3. The goto Statement

Performs an unconditional jump to a labeled statement (label:) within the same function. Widely discouraged in general logic due to "spaghetti code" hazards.

⚠️ When is goto Legitimate in Systems C++?

While Edsger Dijkstra famously declared "Go To Statement Considered Harmful", there is one recognized, legitimate use case in low-level systems programming: multi-level loop breakout. A standard break only exits the innermost loop; breaking out of a 4-deep nested search loop cleanly requires either a boolean flag or a single forward goto cleanup; jump.

jump_statements_demo.cpp
#include <iostream>

void searchGrid(int grid[4][4], int target) {
    for (int r = 0; r < 4; ++r) {
        for (int c = 0; c < 4; ++c) {
            if (grid[r][c] == -1) {
                // Skip invalid negative cells
                continue;
            }
            if (grid[r][c] == target) {
                std::cout << "Target found at [" << r << "][" << c << "]!\n";
                // Multi-level breakout using goto:
                goto found_exit; 
            }
        }
    }
    std::cout << "Target not found in grid.\n";
    return;

found_exit:
    std::cout << "Clean multi-level loop exit completed.\n";
}
06

Viva Voce & Engineering Interview Questions

Q1 • Architecture How does the C++ compiler optimize a switch statement compared to an else-if ladder?
An else-if ladder evaluates conditions sequentially in O(N) linear time. If a switch statement has a dense cluster of case values, the compiler generates a Jump Table (an array of code address pointers). At runtime, the CPU calculates the offset via a single subtraction and jumps directly to the matching address in O(1) constant time, regardless of the number of cases.
Q2 • Syntax Why cannot floating-point types (like float or double) be used as switch conditions?
The switch statement requires exact, discrete equality matching between the control expression and case constants. Floating-point numbers representation (IEEE 754) is subject to binary rounding errors and precision imprecisions (e.g., 0.1 + 0.2 != 0.3). Allowing floating-point cases would lead to non-deterministic, hardware-dependent branch mismatches.
Q3 • Language Rules What is the "Dangling Else" problem in C++, and how does the grammar resolve it?
The dangling else problem occurs when an else branch follows nested if statements without explicit curly braces (e.g., if (cond1) if (cond2) s1; else s2;). The C++ language grammar strictly resolves this ambiguity by associating the else with the closest preceding open if statement (attaching it to if (cond2)).
Q4 • Execution What is the key difference between a while loop and a do-while loop?
A while loop is an entry-controlled loop: the test condition is evaluated before entering the loop body; if the condition is false initially, the body executes zero times. A do-while loop is an exit-controlled loop: the body executes first, and the condition is tested at the end, guaranteeing that the body executes at least once.
Q5 • Jump Semantics How does break differ from continue inside a for loop?
break terminates the entire loop immediately, transferring control to the first statement following the loop's closing brace. continue terminates only the current iteration, jumping directly to the loop's update step (e.g., ++i), after which the condition is re-evaluated for the next iteration.
Q6 • Best Practices Why is the goto statement generally prohibited in software engineering standards (e.g., MISRA C++)?
Arbitrary goto statements create non-linear, unpredictable control flow ("spaghetti code") that bypasses variable initialization, breaks RAII destructor scoping, complicates formal verification, and prevents compiler branch prediction optimizations. Modern structured programming constructs (functions, loops, exceptions) eliminate the need for goto in virtually all application logic.
Q7 • Modern C++ What is the purpose of the C++17 [[fallthrough]] attribute?
In a switch statement, omitting a break causes execution to cascade into the next case, which is usually a developer bug. Modern compilers issue warnings when they detect fallthrough. The [[fallthrough]] attribute explicitly documents that the cascade was intentional, instructing the compiler to suppress the warning.
Q8 • Scope Can a variable be declared directly inside an if condition in modern C++?
Yes! Since C++17, C++ supports if with initializer: if (init; condition). For example: if (auto it = cache.find(key); it != cache.end()) { /* use it */ }. This restricts the scope of it strictly to the if/else block, preventing variable leakage into the outer function scope.