Making Decisions with if
Programs constantly react to data: pass or fail, in stock or sold out, valid or not. The if statement is how C++ chooses which code to run based on a condition.
An if takes a condition in parentheses and runs the block in braces only when that condition is true:
The condition score >= 60 is true, so the message prints. The line after the closing brace always runs - it sits outside the if. Change score to 40 and the "passed" line is skipped entirely.
The condition is converted to bool. Comparisons like >, >=, ==, != already yield a bool, but C++ also treats any non-zero number as true and 0 as false - so if (count) means "if count is not zero." That implicit conversion is convenient but also the source of a few classic bugs you will see below.
Adding an else
else gives you the "otherwise" path - code that runs only when the condition is false:
Exactly one of the two blocks runs - never both, never neither. else has no condition of its own; it simply catches everything the if did not.
Chaining with else if
When there are more than two outcomes, chain conditions with else if. C++ checks them top to bottom and runs the first block whose condition is true, then skips the rest:
Order matters. Because 84 is tested against >= 90 first (false), then >= 80 (true), it stops at B and never checks the lower bounds. That is also why you do not need score >= 80 && score < 90 - reaching the second branch already guarantees score was below 90. Put your narrowest or highest-priority condition first.
Note there is no elif keyword in C++ - else if is literally an else whose body is another if. The braces just make it read like one ladder.
A Big Gotcha: = vs ==
The single most common if-statement bug in C and C++ is writing = (assignment) where you meant == (comparison):
x = 5 assigns 5 to x and the whole expression evaluates to 5, which converts to true - so the branch always runs and you have silently clobbered x. This compiles; most compilers only emit a warning. Two defenses: turn warnings on (-Wall) so the compiler flags it, and consider putting the constant on the before side - if (5 == x) - because if (5 = x) is a hard error the compiler catches immediately.
The same trap hides with bool: if (ready = true) compiles and assigns, while if (ready == true) (or just if (ready)) compares.
Combining and Nesting Conditions
Combine conditions with && (and), || (or), and ! (not), or nest one if inside another when a check only makes sense after a prior one passed:
&& and || short-circuit: in a && b, if a is false C++ never evaluates b. That is essential for guarding against bad memory access - if (ptr != nullptr && ptr->ready) is safe because the dereference of the pointer is skipped when ptr is null. Prefer flattening with && over deep nesting when you can; a flat condition reads more clearly than a pyramid of braces.
Watch out for comparison chaining that doesn't mean what it looks like: if (0 < x < 10) does not test a range. It evaluates 0 < x to a bool (0 or 1), then compares that against 10 - always true. Write if (0 < x && x < 10) instead.
The Ternary Operator
When all you want is to pick between two values, the ternary operator ?: is a compact one-liner. Read condition ? a : b as "if condition then a else b":
The ternary produces a value you can assign, pass, or print directly - something a plain if cannot do. Keep it for simple selection: if either branch needs multiple statements or real logic, a full if-else stays readable where a nested ternary quickly becomes a puzzle. (One subtlety: both branches must share a common type, so don't mix, say, a string and an int.)
if with an Initializer (C++17)
Since C++17 you can declare a variable right inside the if, scoped to just the if/else. This keeps short-lived helpers from leaking into the surrounding code:
The part before the ; runs once and its result is visible in both the condition and the else. This is great for "compute a thing, then branch on it" patterns - and because the result casting/conversion happens once up front, you avoid recomputing or accidentally reusing a stale value later. Reach for it whenever a temporary is only needed for the branch.
A Gotcha: the Dangling Brace Trap
C++ lets you skip braces when a branch has a single statement, but this invites a subtle bug - the indentation lies:
if (loggedIn)
cout << "Welcome\n";
cout << "Loading dashboard\n"; // NOT part of the if!
Only the first line is controlled by the if; the second always runs regardless of loggedIn, despite the indentation suggesting otherwise. A related classic is the stray semicolon: if (x > 0); ends the if with an empty body, so the block that follows runs unconditionally. Always use braces - even for one line - and most of this class of mistake disappears.
Next: switch
if-else if chains are perfect when each branch tests a different condition. But when you are checking one value against many fixed possibilities - a menu choice, an enum, a status code - a long else if ladder gets repetitive and easy to mis-order. The switch statement is built for exactly that, and that is the next page.
Frequently Asked Questions
How do you write an if-else statement in C++?
Put a condition in parentheses after if, the code to run in braces, and an optional else block for when the condition is false: if (score >= 60) { cout << "Pass"; } else { cout << "Fail"; }. The condition is converted to bool, so any non-zero number counts as true and 0 counts as false.
What is the difference between = and == in a C++ if statement?
== compares two values for equality, while a single = assigns. Writing if (x = 5) assigns 5 to x and then tests 5 (always true) - a classic bug. It compiles with only a warning, so enable warnings and consider writing the constant first: if (5 == x).
What is the ternary operator in C++?
The ternary operator condition ? valueIfTrue : valueIfFalse is a compact if-else that produces a value. For example string label = age >= 18 ? "adult" : "minor"; picks one of two values. Use it for simple value selection; reach for a full if-else when each branch has real logic.