if / else if / else
Conditional execution is what makes a program smart rather than just executing the same sequence every time. The if statement lets your program choose between different paths based on a condition: a boolean expression that evaluates to either true or false. Chaining else if and else blocks lets you handle multiple distinct cases in one clean structure.
The basic if statement
An if statement has a condition in parentheses and a body in curly braces. If the condition is true, the body executes; otherwise it is skipped. The condition can be any expression that produces a boolean value — a comparison, a logical expression, a variable of type bool, or even an integer (where 0 is false and any non-zero value is true).
int score = 85;
if (score >= 60) {
std::cout << "Pass\n";
}
// The else branch runs when the condition is false:
if (score >= 60) {
std::cout << "Pass\n";
} else {
std::cout << "Fail\n";
}Always use curly braces around the body, even for single-line bodies. Without braces, the very next statement is the body — which leads to the dangling-else trap and bugs when adding a second statement later.
Chaining conditions with else if
When you have more than two cases, chain else if blocks. The conditions are tested in order from top to bottom: the first one that is true runs its body, and the rest are skipped entirely. At most one branch executes. An optional final else(with no condition) handles everything that didn't match.
int score = 78;
char grade;
if (score >= 90) {
grade = 'A';
} else if (score >= 80) {
grade = 'B';
} else if (score >= 70) {
grade = 'C';
} else if (score >= 60) {
grade = 'D';
} else {
grade = 'F';
}
std::cout << "Grade: " << grade << "\n"; // Grade: CBecause the conditions are tested in order, each condition can assume that all earlier conditions were false. When score is 78, the first check (score >= 90) fails, the second (score >= 80) fails, and the third (score >= 70) succeeds — no need to write score >= 70 && score < 80.
Nested if statements
An if body can itself contain another if statement. This is called nesting. It is valid and sometimes necessary, but deep nesting (more than two or three levels) becomes hard to read. A common technique to reduce nesting is the early return pattern: if an early condition fails, return immediately rather than wrapping the rest of the function in an else block.
// Nested — works but gets deep quickly:
void process(int value) {
if (value > 0) {
if (value < 100) {
if (value % 2 == 0) {
std::cout << "Even number in [1,99]: " << value << "\n";
}
}
}
}
// Early-return style — flatter and easier to read:
void process(int value) {
if (value <= 0) return; // guard: must be positive
if (value >= 100) return; // guard: must be < 100
if (value % 2 != 0) return; // guard: must be even
std::cout << "Even number in [1,99]: " << value << "\n";
}The dangling-else trap
When you write nested if statements without braces, it is ambiguous which if an else belongs to. C++ resolves this by associating the else with the nearest preceding if — which is often not what the indentation suggests.
// DANGEROUS — indentation is misleading:
if (x > 0)
if (x < 10)
std::cout << "single digit\n";
else
std::cout << "not positive\n"; // This else belongs to the INNER if!
// It runs when x >= 10, not when x <= 0
// SAFE — braces make the structure explicit:
if (x > 0) {
if (x < 10) {
std::cout << "single digit\n";
}
} else {
std::cout << "not positive\n"; // now correctly tied to the outer if
}The fix is always the same: use curly braces. This is why style guides universally recommend braces even for single-statement bodies.
The conditional (ternary) operator
The ternary operator condition ? a : b is a compact expression form of an if/else that selects between two values. Unlike an if statement, it is an expressionand produces a value — so it can appear inside another expression or directly in an assignment or function call.
int x = 7; // if/else version: int abs_x; if (x >= 0) abs_x = x; else abs_x = -x; // Ternary version — equivalent, one expression: int abs_x2 = (x >= 0) ? x : -x; // Useful inline, e.g., choosing a label: std::cout << (x % 2 == 0 ? "even" : "odd") << "\n";
Use the ternary operator for simple value selections. Avoid nesting ternary operators inside each other — the result is hard to read.
if with initializer (C++17)
C++17 allows an initializer statement inside the if. The variable declared in the initializer exists only for the duration of the if and its else — it is scoped out automatically afterward. This is useful for lookup results or status codes that you only need inside the condition check.
#include <map>
std::map<std::string, int> scores;
scores["Alice"] = 95;
// C++17: init-if — 'it' is scoped to the if/else block
if (auto it = scores.find("Alice"); it != scores.end()) {
std::cout << "Found: " << it->second << "\n";
} else {
std::cout << "Not found\n";
}
// 'it' is no longer accessible hereKey rules to remember
Always use curly braces, even for single-statement bodies
Omitting braces causes the dangling-else bug and makes adding a second statement later silently wrong.
else if conditions can assume all earlier conditions failed
No need to repeat the lower bound: once score >= 90 has been tested and failed, score >= 80 implicitly means 80 <= score < 90.
Use early returns to avoid deep nesting
Check preconditions at the top of a function and return early if they fail. This keeps the happy path unindented and readable.
The ternary operator is for simple value selection, not complex logic
condition ? a : b is clean for picking between two values. Nest it and it becomes unreadable — use a full if/else instead.