This lesson is a continuation of lesson 7.2 -- If statements and blocks. In this lesson, we’ll take a look at some common problems that occur when using if statements
.
Nested if statements and the dangling else problem
It is possible to nest if statements
within other if statements
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <iostream> int main() { std::cout << "Enter a number: "; int x{}; std::cin >> x; if (x >= 10) // outer if statement // it is bad coding style to nest if statements this way if (x <= 20) // inner if statement std::cout << x << "is between 10 and 20\n"; // which if statement does this else belong to? else std::cout << x << "is greater than 20\n"; return 0; } |
The above program introduces a source of potential ambiguity called a dangling else problem. Is the else statement
in the above program matched up with the outer or inner if statement
?
The answer is that an else statement
is paired up with the last unmatched if statement
in the same block. Thus, in the program above, the else
is matched up with the inner if statement
.
To avoid such ambiguities when nesting if statements
, it is a good idea to enclose the inner statement within a block. Here is the above program written without ambiguity:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <iostream> int main() { std::cout << "Enter a number: "; int x{}; std::cin >> x; if (x >= 10) { if (x <= 20) std::cout << x << "is between 10 and 20\n"; else // attached to inner if statement std::cout << x << "is greater than 20\n"; } return 0; } |
Now it is much clearer that the else statement
belongs to the inner if statement
.
Encasing the inner if statement
in a block also allows us to explicitly attach an else
to the outer if statement
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <iostream> int main() { std::cout << "Enter a number: "; int x{}; std::cin >> x; if (x >= 10) { if (x <= 20) std::cout << x << "is between 10 and 20\n"; else // attached to inner if statement std::cout << x << "is greater than 20\n"; } else // attached to outer if statement std::cout << x << "is less than 10\n"; return 0; } |
The use of a block tells the compiler that the else statement
should attach to the if statement
before the block. Without the block, the else statement
would attach to the nearest unmatched if statement
, which would be the inner if statement
.
Flattening nested if statements
Nested if statements
can often be flattened by either restructuring the logic or by using logical operators (covered in lesson 5.7 -- Logical operators). Code that is less nested is less error prone.
For example, the above example can be flattened as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <iostream> int main() { std::cout << "Enter a number: "; int x{}; std::cin >> x; if (x < 10) std::cout << x << "is less than 10\n"; else if (x <= 20) // x must be at least 10 std::cout << x << "is between 10 and 20\n"; else std::cout << x << "is greater than 20\n"; return 0; } |
Here’s another example that uses logical operators to check multiple conditions within a single if statement
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <iostream> int main() { std::cout << "Enter an integer: "; int x{}; std::cin >> x; std::cout << "Enter another integer: "; int y{}; std::cin >> y; if (x > 0 && y > 0) // && is logical and -- checks if both conditions are true std::cout << "both numbers are positive\n"; else if (x > 0 || y > 0) // || is logical or -- checks if either condition is true std::cout << "One of the numbers is positive\n"; else std::cout << "Neither number is positive\n"; return 0; } |
Null statements
A null statement is a statement that consists of just a semicolon:
1 2 |
if (x > 10) ; // this is a null statement |
Null statements
do nothing. They are typically used when the language requires a statement to exist but the programmer doesn’t need one. For readability, null statements
are typically placed on their own lines.
We’ll see examples of intentional null statements
later in this chapter, when we cover loops. Null statements
are rarely intentionally used with if statements
. However, they can unintentionally cause problems for new (or careless) programmers. Consider the following snippet:
1 2 |
if (nuclearCodesActivated()); blowUpTheWorld(); |
In the above snippet, the programmer accidentally put a semicolon on the end of the if statement
(a common mistake since semicolons end many statements). This unassuming error compiles fine, and causes the snippet to execute as if it had been written like this:
1 2 3 |
if (nuclearCodesActivated()) ; // the semicolon acts as a null statement blowUpTheWorld(); // and this line always gets executed! |
Warning
Be careful not to “terminate” your if statement
with a semicolon, otherwise your conditional statement(s) will execute unconditionally (even if they are inside a block).
Operator== vs Operator= inside the conditional
Inside your conditional, you should be using operator==
when testing for equality, not operator=
(which is assignment). Consider the following program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <iostream> int main() { std::cout << "Enter 0 or 1: "; int x{}; std::cin >> x; if (x = 0) // oops, we used an assignment here instead of a test for equality std::cout << "You entered 0"; else std::cout << "You entered 1"; return 0; } |
This program will compile and run, but will produce the wrong result in some cases:
Enter 0 or 1: 0 You entered 1
In fact, this program will always produce the result You entered 1
. This happens because x = 0
first assigns the value 0
to x
, then evaluates to the value of x
, which is now 0
, which is Boolean false
. Since the conditional is always false
, the else statement
always executes.
![]() |
![]() |
![]() |
is it better to practice if statements this way ;
is it readable or also a bad practice ?
if ( x == 1 )
{ std::cout << "it is ONE"; }
else
{ std::cout << "it is NOT ONE"; }
so that if i add more lines of codes in either statement i could just do a carriage return
if ( x == 1 )
{
std::cout << "it is ONE";
// more code
}
else
{ std::cout << "it is NOT ONE"; }
Yes please always braces. Alex doesn't do that.
thank you very much
The first example under ‘Using logical operators inside the conditional’ is wrong. It’ll display « 30 is less than 10 », for example.
Good catch. Updated the examples and lesson text a bit. Thanks!
Section "Using logical operators inside the conditional":
Last snippet, lines 9-11:
[code]
std::cout << "Enter another integer: ";
int y; // Line 10; should be initialized for consistency with other examples
std::cin >> y;
[code]