Programming Fundamentals Using C++

L07 · `if`, `if/else`, and Nested Selection

Module 4 — Decision-Making Statements · Week 4 · Lecture 7 of 32 · 120 minutes Outcomes: CLO-3 · PF-4.1, PF-4.2 · LEARNING_OUTCOMES.md

Learning objectives

  1. Evaluate relational (< <= > >= == !=) and logical (&& || !) expressions, including short-circuit behavior and the !-of-comparison form (PF-4.1).
  2. Implement if, if/else, and if/else if/else chains whose branches jointly cover every case of a specification, with no unreachable or contradictory conditions (PF-4.2).
  3. Rewrite nested selections as guard clauses (early exit) and justify which form is clearer for a given rule set (PF-4.2).

Prerequisites

L06 (bool conversion rule: nonzero → true); L03 (const, comparisons of computed values).

Concept sequence

  1. From straight-line to branching programs
  2. Conditions as bool-producing expressions
  3. == vs = — the assignment-in-condition trap
  4. &&, ||, ! + short-circuit evaluation with side-effect-free demos
  5. if / else if / else as ordered rule sets
  6. Nesting vs guard clauses

Teaching topics (detailed)

C++ examples required

FileRole
decisions_grade.cpp ✅grade classifier: naive → corrected → guard-clause refactor, all three kept in the file for comparison
(live) short_circuit_demo.cppprinted evaluation trace showing which side of &&/`` ran

Conceptual explanation (beginner-first)

Everything so far ran top to bottom, unconditionally. Real decisions need the program to ask yes/no questions and take different paths. In C++, a "yes/no question" is an expression whose value is true or false — built from comparisons (>=, ==) and combined with and/or/not (&&, ||, !). The if statement then runs (or skips) a block based on that answer.

Two ideas make branch-writing safe. First, short-circuit evaluation: in A && B, if A is false, B is never evaluated — C++ promises this. That turns (n != 0) && (total / n > 10) into a safety pattern: the guard n != 0 protects the division behind it. Second, branch order matters in if / else if chains: the first matching branch wins, so ranges must run from most specific (highest) to least, with the else catching everything left. A chain whose branches are mutually exclusive and collectively exhaustive covers every case — the property the branch- coverage workshop drills.

Terminology and definitions

TermDefinition
ConditionAn expression of type bool controlling a branch
Relational operators< <= > >= == != — produce bool
Logical operators&& (and), ` (or), !` (not)
Short-circuit evaluation&&/`` skip the right side when the left decides
GuardA check placed before a risky operation, enabled by short-circuiting
else if chainOrdered multi-way selection; first match wins
Guard clauseEarly return/branch for invalid cases, flattening nesting
Mutually exclusiveConditions that cannot both be true
Collectively exhaustiveSome branch matches for every possible input
Range checklo <= x && x <= hi — never math-style lo <= x <= hi

Syntax and C++ examples

if (score >= 90)                  // condition in parentheses, ALWAYS
{
    std::cout << "A\n";           // runs when condition is true
}
else if (score >= 80)             // checked only if the first was false
{
    std::cout << "B\n";
}
else                              // everything left lands here
{
    std::cout << "keep going\n";
}

// combining conditions
if (age >= 13 && age <= 19) { }            // teenager
if (day == "Sat" || day == "Sun") { }      // weekend
if (!(score >= 60)) { }                    // failing (same as score < 60)

// the short-circuit guard
if (n != 0 && total / n > 10) { }          // safe: division only when n != 0

Line-by-line code explanation

examples/decisions_grade.cpp:

  1. Input is validated first (if (!(std::cin >> score))) — decisions on unvalidated data are decisions on garbage.
  2. Version 1 (commented) is deliberately wrong: score >= 60 first means 95 matches immediately and prints "D". The lesson: an if/else if chain is an ordered rule set.
  3. Version 2 (active) runs from 90 down to 60, ending in else — mutually exclusive by construction (each branch implies all later conditions are false), collectively exhaustive (the else catches all).
  4. Version 3 shows the correct range check score >= 0 && score <= 100 beside the commented math-notation bug 0 <= score <= 100 — which C++ reads as (0 <= score) <= 100, i.e. a bool compared to 100: always true.
  5. Style: every branch uses braces even for one statement — the dangling-

else insurance.

Output prediction questions (with answers)

  1. int x{7}; if (x = 5) { ... } — runs? — Yes, ALWAYS: x = 5 assigns (value 5 → true) and clobbers x. == compares; -Wall warns here.
  2. int n{0}; (n != 0) && (10 / n > 2) — value? crash? — false, and the division never runs (short-circuit) — no crash.
  3. if (0 <= s && s <= 100) with s = 150 — ? — false (correct range form).
  4. (true || anything) and (false && anything) — ? — true / false — the right side is not even evaluated.
  5. Chain: score = 85 in the corrected grade program — ? — "B" (80 branch; the 90 test failed first).

Common errors and debugging examples

ErrorSymptomFix
= instead of ==Condition always (or never) true; variable clobbered==; compile with -Wall
Math range notation 0 <= x <= 100Always true — silent logic bug0 <= x && x <= 100
Ascending else if chainHigh scores classified as low gradesOrder descending; else catches the rest
Missing else when neededBoth messages print (two independent ifs)Chain with else if when paths are exclusive
Dangling elseThe else binds to the nearest ifBraces on every branch
Un-protected divisionRuntime crash when n = 0Short-circuit guard first

Common student misconceptions

Classroom demonstrations

  1. Order-of-branches autopsy: run version 1 (buggy) with 95, watch "D" print; then version 2 — the ordering lesson needs no lecture notes.
  2. Short-circuit proof: a function that prints before dividing, placed after && — the print does not appear when the guard fails.
  3. Coverage hunting: feed the corrected program the boundary values 0, 59, 60, 89, 90, 100, 101 — students see every branch fire.

Guided student activities

Branch-coverage workshop (20 min): teams receive a bugged ticket-pricing rule set (child/adult/senior, weekend multiplier, discount stacking); they write the if/else chain, then adversarially list inputs that break other teams' chains (coverage hunting). Best "killer input" wins.

Practice problems

Summary

Decisions are bool-valued expressions: comparisons joined by &&/||/ !, with short-circuiting making guards possible. if / else if / else is an ordered rule set — descending ranges, else as the catch-all, braces always. The three classic bugs (= for ==, math-range notation, ascending chains) are silent, so branch coverage discipline is the defense. Next (L08): the other half of selection — switch for discrete cases and the ?: operator for choosing values.

Exit ticket / formative assessment

  1. Evaluate with short-circuit order: int n{0}; n != 0 && 10 / n > 2 — value? did the division run?
  2. Why is if (x = 5) always true?
  3. Write the range check for a valid percentage (0–100 inclusive) the way the course requires.

Estimated time allocation (120 min)

SegmentMinutes
Recall (conversions quiz) + branching motivation10
Conditions: relational/logical operators, short-circuit35
Break10
if/else if/else design + guard clauses (grade example)35
Branch-coverage workshop20
Exit ticket + L08 preview10
Programming Fundamentals Using C++ · C++17 · 16 weeksBack to top ↑