Skip to content
Conditionals
step 1/5

Reading — step 1 of 5

Learn

~3 min readControl Flow

Conditionals

C++ conditionals are C's — same shapes, same two famous traps — with a real bool type and a couple of civilizing touches. If the C track's warnings are fresh, skim for the C++ differences; if not, the traps get full introductions, because they don't care which language's syntax you typed them in.

The shape

if (score >= 90) {
    std::cout << "A\n";
} else if (score >= 80) {
    std::cout << "B\n";
} else {
    std::cout << "F\n";
}

Parentheses required, braces technically optional for single statements — brace anyway (the goto fail disaster was one unbraced if away from being impossible). Conditions are bool, and C++ has a true bool with true/false literals — but C's truthiness still applies underneath: numbers and pointers convert (if (n) means n != 0), so both idioms coexist. Convention: bare truthiness for pointers, explicit comparisons for meaningful values — if (s.find(x) != std::string::npos), never if (s.find(x)) (which is wrong: found-at-index-0 converts to false!). That npos example is real and bites; file it.

The two traps, restated for C++

Assignment in condition: if (x = 5) assigns, then tests 5 — always true, compiles clean. -Wall warns (suggest parentheses around assignment); heed it.

Dangling else / missing braces: an unbraced if owns exactly one statement, whatever the indentation claims. Braces everywhere ends the ambiguity.

Logical operators

if (n > 0 && sum / n > 5)      // && short-circuits: division guarded
if (a || b)                    // || stops at first true
if (!(x == y))                 // ! negates — though x != y reads better

Short-circuit evaluation is the load-bearing feature: the right operand doesn't run unless needed, making test-before-use one line — ptr != nullptr && ptr->valid(). (Note nullptr — C++'s typed null, preferred over C's NULL everywhere.) && binds tighter than ||; parenthesize mixtures rather than proving you know the table.

switch

switch (grade) {
    case 'A':
    case 'B':
        std::cout << "passing\n";
        break;
    case 'C':
        std::cout << "borderline\n";
        break;
    default:
        std::cout << "failing\n";
}

C's switch, inherited whole: integer/char/enum selectors only (no strings!), and fallthrough by default — omit a break and execution pours into the next case. Stacked labels (the 'A'/'B' above) are the one good use of fallthrough; every other omission is a bug so classic that compilers grew a warning for it. For string-shaped choices, chain if/else if with ==std::string's civilized comparison makes it natural.

Your exercise: FizzBuzz for one number

Multiples of 3 → Fizz, 5 → Buzz, both → FizzBuzz, else the number. The check-order rule is the whole kata: most specific firstn % 15 == 0 (or n % 3 == 0 && n % 5 == 0) before the singles, because the first true branch wins and a 3-first chain prints Fizz for 15, forever, while looking completely reasonable. Four branches, one if/else if chain, == everywhere, braces everywhere. Thirty seconds of algorithm, a career of check-order instinct.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…