Lesson 1 of 6
A program that always does the same thing isn't much of a program. if is how it chooses.
#include <iostream>
int main() {
int temperature = 32;
if (temperature > 30) {
std::cout << "Hot\n";
} else if (temperature > 20) {
std::cout << "Warm\n";
} else {
std::cout << "Cool\n";
}
return 0;
}
Hot
The condition in parentheses must produce a bool. Conditions are checked top to bottom and
the first true branch wins — the rest are skipped entirely, even if they'd also be true.
Comparison operators
| Operator | Meaning |
| --- | --- |
| == | equal to |
| != | not equal to |
| < > | less / greater than |
| <= >= | less / greater than or equal |
== compares. = assigns. Confusing them is the classic C++ bug, and lesson 3.7 showed how
const helps the compiler catch it.
Logical operators
#include <iostream>
int main() {
int age = 25;
bool has_licence = true;
if (age >= 18 && has_licence) {
std::cout << "May drive\n";
}
if (age < 13 || age > 65) {
std::cout << "Discounted ticket\n";
} else {
std::cout << "Full price\n";
}
if (!has_licence) {
std::cout << "Needs a licence\n";
}
return 0;
}
May drive
Full price
&& is and, || is or, ! is not.
Both && and || short-circuit: they stop as soon as the answer is decided. In
a && b, if a is false, b is never evaluated. That's not just an optimization — it's a
safety mechanism you'll rely on constantly:
if (index < size && data[index] > 0) { /* ... */ }
If index is out of range the first test fails and data[index] — which would read invalid
memory — never runs. Order matters: swap those two and the program breaks.
Truthiness
Any number can be used as a condition. Zero is false; everything else is true:
#include <iostream>
int main() {
int count = 3;
int zero = 0;
if (count) {
std::cout << "count is nonzero\n";
}
if (!zero) {
std::cout << "zero is falsy\n";
}
return 0;
}
count is nonzero
zero is falsy
This is legal and common, but if (count > 0) says what you mean more clearly. Prefer the
explicit comparison unless the value is genuinely a flag.
The dangling-else trap
Here's the bug the lesson title promises. Braces are optional around a single statement:
if (x > 0)
std::cout << "positive\n";
That works. The trouble starts when someone adds a second line later:
if (x > 0)
std::cout << "positive\n";
std::cout << "definitely positive\n"; // NOT part of the if!
The indentation says both lines are conditional. The compiler disagrees — only the first
statement belongs to the if. The second runs unconditionally, and the code looks correct.
The name "dangling else" comes from the nastier version, where an else attaches to a different
if than the indentation suggests:
#include <iostream>
int main() {
int x = 5;
int y = -1;
if (x > 0)
if (y > 0)
std::cout << "both positive\n";
else
std::cout << "surprise\n";
return 0;
}
surprise
Read the indentation and you'd expect the else to pair with if (x > 0), so nothing should
print. It doesn't: else always binds to the nearest unmatched if, which is if (y > 0).
The fix is a habit, not a rule
Always use braces, even for one line.
#include <iostream>
int main() {
int x = 5;
int y = -1;
if (x > 0) {
if (y > 0) {
std::cout << "both positive\n";
}
} else {
std::cout << "x is not positive\n";
}
std::cout << "done\n";
return 0;
}
done
Now the structure is unambiguous to both the compiler and the reader, and adding a line later can't silently change the meaning. Every major C++ style guide says the same thing. It costs two characters.
Initializers in if (C++17)
You can declare a variable scoped to the if itself:
#include <iostream>
#include <string>
int main() {
std::string text = "evil genius society";
if (std::size_t pos = text.find("genius"); pos != std::string::npos) {
std::cout << "found at " << pos << "\n";
}
// pos does not exist here
return 0;
}
found at 5
The variable exists only inside the if and its else. That keeps the surrounding scope clean
and stops you accidentally using a search result you never checked. Lesson 4.6 covers scope
properly.
Try it
Write a program that classifies a score out of 100 into a letter grade: 90+ is A, 80+ is B, 70+ is C, 60+ is D, below that is F. Test it with 85.
Checkpoint
if/else if/elsechecks conditions in order; the first true branch wins.&&and||short-circuit, which lets you guard an unsafe operation with a check before it.- Zero is falsy and nonzero is truthy, but explicit comparisons read better.
- Always use braces, even around a single statement — this prevents both the added-line bug and the dangling-else bug.
elsebinds to the nearest unmatchedif, regardless of how the code is indented.- C++17 lets you declare a variable inside the
ifthat's scoped to that statement.
Questions about this lesson
Log in to ask a question.