Course outline

C++ / Basic / Lesson 3

Control flow and validated input

Turn requirements into branches and loops with explicit boundaries, then keep invalid input from entering your calculation.

About 4 min readContent reviewed
On this page

Lesson goals

  • Write complete branch partitions and terminating loops.
  • Use short-circuit logic without hidden side effects.
  • Validate stream extraction and application constraints separately.

Give every boundary a home

An if statement selects a statement using a condition converted to bool. An else if chain checks alternatives in order and stops at the first true condition. Before writing code, partition the accepted domain into non-overlapping regions. A quantity can be negative, zero, or positive; a score threshold must place equality on exactly one side. Use braces even for short branches so later edits do not accidentally escape the branch. Keep invalid states separate from ordinary classifications rather than quietly treating them as the lowest category.

Order checks by dependency

Built-in && evaluates its right operand only when the left operand is true, and built-in || skips the right operand when the left is true. This supports guards such as denominator != 0 && numerator / denominator > 2, provided the remaining arithmetic is also valid. Avoid modifying a value in a complicated condition; separate validation from action. The first example checks a bounded score and then applies its threshold. It prints one classification because the if and else statements describe mutually exclusive outcomes.

cpp Equality belongs to the passing branch
#include <iostream>
int main() {
    const int score{70};
    if (score < 0 || score > 100) {
        std::cout << "invalid\n";
    } else if (score >= 70) {
        std::cout << "pass\n";
    } else {
        std::cout << "retry\n";
    }
}
Expected output
pass

Seventy is inside the accepted range and satisfies the inclusive passing threshold; the remaining branches are skipped.

Explain what a loop preserves

A loop needs initialization, a continuation condition, a progress step, and a reason to terminate. A useful invariant describes the state before each iteration. In the sum example, total equals the sum of positive integers strictly smaller than next. Adding next and incrementing it preserves that statement. When next reaches five, the loop ends with the sum through four. This reasoning exposes off-by-one errors earlier than a collection of guesses. For user-controlled counts, validate a practical upper bound and the accumulator range before looping.

cpp A loop with a traceable invariant
#include <iostream>
int main() {
    int total{};
    for (int next{1}; next <= 4; ++next) {
        total += next;
    }
    std::cout << total << "\n";
}
Expected output
10

The additions are 1, 2, 3, and 4. The final total is ten; next is local to the loop.

Parsing is not domain validation

Formatted extraction with std::cin >> count attempts a conversion and records stream state. Check the stream result before using count, then check whether the converted number is permitted by your application. A successful extraction of negative three is still invalid for a nonnegative stock count. If a whole line must contain exactly one integer, extraction alone also permits a valid numeric prefix followed by extra text; parse a line and reject leftovers deliberately. Decide whether a malformed line ends the operation or is cleared and discarded before retrying.

Keep exits and states readable

Use break for a deliberate early exit and continue to skip the rest of the current iteration. Excessive exits can obscure the invariant, so name the success and failure conditions first. A while loop suits repetition with no known count; a for loop keeps counted progress together. A do-while executes once before testing, which matters when input may already be invalid. For a finite set of named states, enum class and a switch can document alternatives; include a deliberate policy for invalid external numeric representations.

Common errors and fixes

A loop never reaches its exit.

Why it happens
The progress step is missing or moves away from the bound.
How to fix it
Trace initialization, condition, and update for three iterations.
Prevent it next time
State a decreasing distance to termination before coding.

The threshold value is misclassified.

Why it happens
A strict comparison was used where equality was required.
How to fix it
Assign equality to the intended branch and retest neighbors.
Prevent it next time
Test below, exactly at, and above each boundary.

Invalid input causes repeated failures.

Why it happens
The failed stream state and offending characters remain.
How to fix it
End the operation or clear state and discard the bad line.
Prevent it next time
Specify a complete retry policy rather than blindly looping.

Check your understanding

1. Classify scores 69, 70, 100, and 101 using the first program. Explain why range validation must precede the passing threshold.

Show worked solution

The lines are retry, pass, pass, and invalid respectively. If score >= 70 were tested first, 101 would incorrectly pass. The domain check rejects all values outside zero through one hundred before the ordinary classification. Add negative one and zero to the test set to cover the lower boundary too.

2. Change the sum example to include zero through five. Give the result and a loop invariant that explains it, including the empty-prefix case.

Show worked solution

Initialize next to zero, keep total at zero, and continue while next <= 5. Before every iteration total is the sum of integers from zero up to but excluding next. At next == 0 that sum is empty and equals zero. The loop ends at six with total equal to fifteen.

Key takeaways

  • Partition boundaries before writing branches.
  • A loop invariant explains both progress and final results.
  • Check parsing, domain rules, and retry behavior separately.

Official references