Dataslope logoDataslope

Control Flow

How programs make decisions and repeat work — if, switch, while, for, and how to think about them as flowcharts.

So far our programs have executed top to bottom, one line at a time. Real programs need to make decisions and repeat work. The constructs that let them do so — if, switch, while, for, break, continue, return — are collectively called control flow.

A useful mental model: at every moment, the CPU is following exactly one path through your program. Control-flow statements are forks and loops in that path.

Sequential flow

The simplest flow is straight-line execution: one statement after another.

Every program starts this way at main's opening brace.

if and else: decisions

An if statement tests a condition (a bool expression) and runs its block only when the condition is true. An optional else block runs when the condition is false.

Code Block
C++ 20 (202002L)

else can chain into another if, building a ladder:

Code Block
C++ 20 (202002L)

Two beginner footguns:

  1. = is assignment, == is comparison. if (x = 5) compiles (it assigns 5 to x, then tests truthiness), and it is almost never what you meant.
  2. Always use braces. Without braces, only the next single statement belongs to the if. This is a famous source of security bugs (the "goto fail" incident in Apple's TLS code).
// dangerous:
if (logged_in)
    grant_access();
    audit();         // <-- always runs, regardless of logged_in!

// safe:
if (logged_in) {
    grant_access();
    audit();
}

Boolean operators

Conditions can be combined with:

  • && — logical AND (true only if both sides are true)
  • || — logical OR (true if either side is true)
  • ! — logical NOT (flips true/false)

Both && and || are short-circuited: the right side is only evaluated if the left side could not already determine the answer. This is what lets you write if (p != nullptr && p->value > 0) safely.

Code Block
C++ 20 (202002L)

switch: multi-way dispatch

When the same expression should be compared against many specific constant values, switch is clearer than a ladder of else ifs.

Code Block
C++ 20 (202002L)

A few rules:

  • Each case must be a constant known at compile time (an int, a char, or an enum).
  • Without break, execution falls through to the next case. That is rarely what you want; almost always include break.
  • default handles any value not matched.

while: loop with a condition

A while loop runs its body as long as the condition is true. The condition is checked before each iteration; if it's false the first time, the body never runs at all.

Code Block
C++ 20 (202002L)

A do { ... } while (cond); variant exists where the body runs first, then the condition is checked. It is rarely needed but useful for prompt-and-validate loops.

for: counting loops

The for loop bundles three pieces of a typical counting loop (initialization, condition, increment) into a single header:

for (init; condition; update) {
    body
}
Code Block
C++ 20 (202002L)

The variable declared inside the for header (here i) is scoped to the loop only. After the loop, i is gone. Good — that's exactly the smallest-scope principle we mentioned earlier.

Range-based for

For containers (and anything with .begin() / .end()), the range-based for is cleaner:

Code Block
C++ 20 (202002L)

Notes:

  • const std::string& says "I'll just read each element, by reference." Without the &, each element would be copied, which would be wasteful for big strings.
  • You can also use auto: for (const auto& name : names) ...

break and continue

Inside any loop:

  • break exits the loop entirely.
  • continue skips the rest of the current iteration and jumps back to the condition (or to the update for for).
Code Block
C++ 20 (202002L)

Use these sparingly. A loop with three breaks and four continues is usually a sign that the condition could be rewritten more cleanly.

Infinite loops on purpose

Sometimes you do want a loop that runs forever and is exited by an internal condition. Two idiomatic forms:

while (true) { ... }
for (;;)     { ... }

Both compile to the same code. Use whichever you find clearer.

Mapping algorithms to control flow

When you turn an algorithm into code, every "for each" becomes a loop, every "if/then" becomes an if, and every "do until" becomes a while. Practice that translation by writing the algorithm in English first.

Algorithm: "Print the first 10 Fibonacci numbers."

  1. Start with a = 0, b = 1.
  2. Print a.
  3. Compute c = a + b. Set a = b, b = c.
  4. Repeat steps 2–3 nine more times.
Code Block
C++ 20 (202002L)

Common loop bugs

BugWhat happensFix
Off-by-oneLoop runs one too few or one too many times.Decide consciously: do you want < or <=? Test on small cases.
Infinite loopCondition never becomes false.Make sure the body actually modifies the variable in the condition.
Wrong loop variable updatedYou typed j instead of i.Use short, distinct names; let nested loops use i, j, k.
Mutating a container while iteratingCrash or weird output.Build a new container or use index-based iteration.

Challenges

Challenge
C++ 20 (202002L)
FizzBuzz to 15

Implement a loop from 1 to 15 (inclusive). For each number, print:

  • "FizzBuzz" if it is divisible by both 3 and 5,
  • "Fizz" if it is divisible by only 3,
  • "Buzz" if it is divisible by only 5,
  • otherwise the number itself.

Each output goes on its own line.

Challenge
C++ 20 (202002L)
Largest digit

Read the integer n = 729384 (already provided) and print the largest of its decimal digits. For 729384 the answer is 9. Use a loop that strips one digit at a time with % 10 and / 10. Print just the digit followed by a newline.

Test your understanding

QuestionSelect one

What is the difference between == and = in a condition?

They are interchangeable.

== compares two values; = assigns the right-hand side to the left-hand side.

= compares; == assigns.

Both compare values, but == is faster.

QuestionSelect one

Why does C++ short-circuit && and ||?

For backwards compatibility with Fortran.

So the right-hand side is only evaluated when needed, which lets you write safe guards like p != nullptr && p->value > 0.

To make code run faster on multi-core CPUs.

It is a quirk inherited from C with no real benefit.

QuestionSelect one

In a switch statement, what does it mean to "fall through" a case?

The switch matched no case and fell through to default.

The case threw an exception that fell through to a handler.

Without break, execution continues into the next case's body, running its code as well.

The compiler emitted a warning that the user can ignore.

QuestionSelect one

What is the scope of i in for (int i = 0; i < 10; ++i) { ... }?

The entire main function.

The current file.

Only inside the loop header and body; i ceases to exist after the loop ends.

All functions called from inside the loop.

Next: how to package code into reusable units — functions.

On this page