If Statements
Now that we know how to evaluate conditions using booleans and relational and logical operators, we can explore how to control the flow of our programs based on these conditions. This is where conditional statements come into play.
Conditional logic in programming is often represented in the following structure, common to most languages, including C++:
- If a specific condition is satisfied/true, then execute a particular sequence of operations (A).
- Else, if the first condition is not satisfied, check another condition, and if it’s satisfied/true, then execute a different sequence of operations (B).
- … (repeat as necessary)
- Else, none of the conditions being satisfied/true, then execute a default sequence of operations.
Here’s a flowchart to help visualize the steps:
Source
graph TD A{IF Condition A} -->|True| B[THEN Sequence of operations A] A -->|False| C{ELSE IF Condition B} C -->|True| D[THEN Sequence of operations B] C -->|False| E{ELSE IF Condition C} E -->|True| F[THEN Sequence of operations C] E -->|False| G[ELSE Default sequence of operations]
This chain of “if…else if…else” logic ensures that only one sequence of operations is executed, creating a mutually exclusive set of actions. You can include as many else if conditions as necessary—or omit them entirely if not needed.
If Statements in C++
Here’s how you can represent this logic in C++:
if (condition_A) { // Sequence of operations A} else if (condition_B) { // Sequence of operations B} else if (...) { // Sequence of operations ...} else { // Default sequence of operations}
Replace condition_X
with an expression that evaluates to a boolean (or can be converted to one, such as an integer). Replace // Sequence of operations X
with the code you want to execute when the respective condition is satisfied.
In summary, the key points to remember about this structure are:
- Only one sequence of operations is executed.
- If the first condition is
true
, the first block of code runs, and the rest of the conditions are ignored. - If the first condition is
false
, the program evaluates the second condition, and so on. - If all conditions are
false
, the defaultelse
block is executed.
- If the first condition is
- Each
if
,else if
, andelse
block is enclosed in curly braces ({}
), meaning each has its own scope.
Below is a basic example of using if statements in C++:
#include <iostream>
/* * Function: prompt_for_integer * Description: Prompts the user for an integer * Returns (int): Integer entered by the user */int prompt_for_integer() { std::cout << "Enter an integer: "; int user_input; std::cin >> user_input; return user_input;}
int main() { // Prompt user for a number int number = prompt_for_integer();
// Check the value of the number if (number < 10) { std::cout << "You entered a number less than 10" << std::endl; } else if (number > 10) { std::cout << "You entered a number greater than 10" << std::endl; } else { std::cout << "You entered 10!" << std::endl; }}
- The program first prompts the user to input an integer by calling the
prompt_for_integer
function. - The user’s input is stored in the variable
number
. - The program evaluates the value of number using the following conditional logic:
- If the number is less than
10
, it outputs:"You entered a number less than 10"
. - If the number is greater than
10
, it outputs:"You entered a number greater than 10"
. - If the number is exactly
10
, it outputs:"You entered 10!"
.
- If the number is less than
Dropping else if
and else
Statements
Sometimes, your program may require conditional logic that executes operations only in one or two specific scenarios. If no conditions are met, you might want the program to simply proceed to the next set of instructions without performing any specific operations. In such cases, you can omit the else if
and else
statements entirely.
Let’s modify the earlier example so that the program does nothing if the user enters a value greater than 10. The main function would look like this:
int main() { // Prompt user for a number int number = prompt_for_integer();
// Check the value of the number if (number < 10) { std::cout << "You entered a number less than 10" << std::endl; } else if (number == 10) { std::cout << "You entered 10!" << std::endl; }}
- If the user enters a number less than
10
, it prints:"You entered a number less than 10"
. - If the user enters exactly
10
, it prints:"You entered 10!"
. - If the user enters a number greater than
10
, the program prints nothing, as there is noelse
statement to handle this case.
What’s the difference between ending with an else if
statement and not ending with an else
statement?
- A chain of conditional logic ending with an
else
statement ensures that exactly one sequence of operations will execute. - A chain ending with
else if
(without a finalelse
) ensures that at most one sequence of operations will execute, but it is possible that none will.
It’s important to note that code written outside any if, else if, or else statements is unconditional and will always execute. For example:
int main() { // Prompt user for a number int number = prompt_for_integer();
// Check the value of the number if (number < 10) { std::cout << "You entered a number less than 10" << std::endl; } else if (number == 10) { std::cout << "You entered 10!" << std::endl; }
// Unconditional code std::cout << "Goodbye!" << std::endl;}
- If the user enters a number less than
10
, it prints"You entered a number less than 10"
followed by"Goodbye!"
. - If the user enters exactly
10
, it prints"You entered 10!"
followed by"Goodbye!"
. - If the user enters a number greater than
10
, it simply prints"Goodbye!"
.
You can also omit else if
statements if they are unnecessary. For example:
int main() { // Prompt user for a number int number = prompt_for_integer();
// Check if the number is exactly 10 if (number == 10) { std::cout << "You entered 10!" << std::endl; }
// Unconditional code std::cout << "Goodbye!" << std::endl;}
- If the user enters exactly
10
, it prints"You entered 10!"
followed by"Goodbye!"
. - For all other inputs, it simply prints:
"Goodbye!"
.
It’s also valid to have an if
statement immediately followed by an else
statement without any else if
blocks in between. This creates two mutually exclusive operations, where exactly one will execute. For example:
int main() { // Prompt user for a number int number = prompt_for_integer();
// Check the value of the number if (number < 10) { std::cout << "You entered a number less than 10" << std::endl; } else { std::cout << "You entered 10 or greater!" << std::endl; }}
- If the user enters a number less than
10
, it prints"You entered a number less than 10"
. - If the user enters a number
10
or greater, it prints:"You entered 10 or greater!"
.
If Statements Style
When writing if statements, the DRY principle (Don’t Repeat Yourself) encourages us to avoid duplicating boundary conditions. By taking advantage of the mutual exclusivity provided by else if
and else
semantics, we can write clearer and more concise code.
Here’s an example of a program that demonstrates repeated boundary conditions:
#include <iostream>
/* * Function: prompt_for_grade * Description: Prompts the user for a grade percentage as an integer * Returns (int): Grade percentage entered by the user */int prompt_for_grade() { std::cout << "Enter your grade percentage: "; int grade_percentage; std::cin >> grade_percentage; return grade_percentage;}
/* * Function: print_pass_or_fail * Description: Prints whether the user passed or failed based on the grade percentage * Parameters: * grade (int): Grade percentage */void print_pass_or_fail(int grade) { if (grade < 60) { std::cout << "You failed!" << std::endl; }
if (grade >= 60) { std::cout << "You passed!" << std::endl; }}
int main() { // Prompt user for grade int grade = prompt_for_grade();
// Print pass/fail print_pass_or_fail(grade);}
- If the grade is less than
60
, the program prints:"You failed!"
. - If the grade is
60
or greater, the program prints:"You passed!"
.
While this program works correctly, the implementation has stylistic issues:
- The two
if
statements check mutually exclusive conditions, but they are written as separate, independentif
statements. This could imply (incorrectly) that both conditions might execute, which is not the case. - The program unnecessarily checks the boundary (
grade >= 60
) explicitly, even though it’s logically implied by the first condition (grade < 60
beingfalse
).
To address one these concerns, the second if
statement can be replaced with an else if
statement. This makes it explicitly clear that only one of the conditions will execute:
/* * Function: print_pass_or_fail * Description: Prints whether the user passed or failed based on the grade percentage * Parameters: * grade (int): Grade percentage */void print_pass_or_fail(int grade) { if (grade < 60) { std::cout << "You failed!" << std::endl; } else if (grade >= 60) { std::cout << "You passed!" << std::endl; }}
By using else if
, the code now explicitly reflects the mutual exclusivity of the conditions. It’s clear that only one of the two blocks of code will execute, making the program easier to understand.
Since the conditions grade < 60
and grade >= 60
are complementary (i.e., if one is false
, the other must be true
), there’s no need to explicitly check the second condition. Instead, the else if
can be replaced with an else
:
/* * Function: print_pass_or_fail * Description: Prints whether the user passed or failed based on the grade percentage * Parameters: * grade (int): Grade percentage */void print_pass_or_fail(int grade) { if (grade < 60) { std::cout << "You failed!" << std::endl; } else { std::cout << "You passed!" << std::endl; }}
Using else
makes it even clearer that exactly one of the two blocks will execute. The program no longer repeats the boundary condition, resulting in cleaner and more efficient code.
The problem with the original program is that it redundantly checked the same boundary twice:
- It checked if
grade < 60
. - It then checked if
grade >= 60
.
By leveraging mutual exclusivity, you can avoid such repetition, resulting in:
- Cleaner, more concise code.
- Syntax that better aligns with the intended logic, improving readability and maintainability.
- Improved performance, as the program doesn’t need to evaluate the same condition twice.
Implied Curly Braces
In C++, it’s legal to omit curly braces from the body of an if
statement (or an else if
or else
statement). When you do so, C++ automatically assumes that the single statement immediately following the condition (or the else
keyword, in the case of an else
statement) is enclosed within implied curly braces.
The following program demonstrates this behavior and will print "Two plus two is four!"
:
if (2 + 2 == 4) std::cout << "Two plus two is four!" << std::endl;else if (2 + 2 == 5) std::cout << "What?! Two plus two is five?!" << std::endl;else std::cout << "Oh no! Math is so hard! :(" << std::endl;
Unlike some programming languages, C++ does not rely on indentation to determine code structure. This means that the way your code is indented has no effect on its behavior (though proper indentation is critical for human readability). We say that C++ is not whitespace-sensitive.
For example, consider the following program:
if (2 + 2 == 100) std::cout << "Woo! Two plus two is 100!" << std::endl; std::cout << "Hello, World!" << std::endl;
At first glance, the indentation might suggest that both std::cout
statements are part of the if
condition. However, in reality, only the first statement is part of the if
block. The second statement (std::cout << "Hello, World!" << std::endl;
) is unconditional—it will execute regardless of whether the if
condition is true
.
The above program is equivalent to:
if (2 + 2 == 100) std::cout << "Woo! Two plus two is 100!" << std::endl;
std::cout << "Hello, World!" << std::endl;
While the corrected indentation does not change the behavior of the program, it makes it clearer that the second std::cout
statement is not part of the if
condition. This distinction is vital for understanding the program’s flow.
Although omitting curly braces is syntactically valid, it can lead to confusion and errors, particularly in situations like the example above. Here’s why:
- Unintended Behavior: Without curly braces, only the first statement immediately following the
if
condition is considered part of the conditional block. Any subsequent statements will execute unconditionally, which might not be what you intended. - Readability: While C++ is indifferent to whitespace and indentation, humans are not. Proper indentation helps developers quickly understand the structure of a program. Omitting curly braces can lead to misleading indentation, making the code harder to read and debug.
- Maintainability: When modifying code that lacks curly braces, it’s easy to accidentally break logic. For example, adding a new line to an
if
block without adding curly braces could unintentionally make that line unconditional.
To avoid these pitfalls, it’s best to always use curly braces for if
statements, even when the body contains only a single statement. This practice ensures that the code is clear, unambiguous, and less prone to errors.
For example, the program above would be safer and clearer if written as:
if (2 + 2 == 100) { std::cout << "Woo! Two plus two is 100!" << std::endl;}
std::cout << "Hello, World!" << std::endl;
Nested If Statements
In C++, you can nest if
statements, meaning you can place one if
statement inside another. This creates a structure similar to a logical AND operation, where both conditions must be satisfied for a particular block of code to execute.
if (i_like_spaghetti) { if (i_like_broccoli) { std::cout << "I like both spaghetti AND broccoli!" << std::endl; }}
- The outer
if
statement checks ifi_like_spaghetti
istrue
. - If the condition is
true
, the innerif
statement is evaluated. - If
i_like_broccoli
is alsotrue
, the program prints:"I like both spaghetti AND broccoli!"
.
If either condition is false
, the program does nothing. This behavior is analogous to the logical &&
operator with short-circuiting (i.e., the second condition is not evaluated unless the first condition is true
).
if (i_like_spaghetti) { if (i_like_broccoli) { std::cout << "I like both spaghetti AND broccoli!" << std::endl; } else { std::cout << "I only like spaghetti!" << std::endl; }}
- If
i_like_spaghetti
istrue
andi_like_broccoli
istrue
, the program prints"I like both spaghetti AND broccoli!"
. - If
i_like_spaghetti
istrue
buti_like_broccoli
isfalse
, the program prints"I only like spaghetti!"
. - If
i_like_spaghetti
isfalse
, the program prints nothing, regardless of the value ofi_like_broccoli
.
You can rewrite nested if
statements using the logical&&
operator. For example:
if (i_like_spaghetti && i_like_broccoli) { std::cout << "I like both spaghetti AND broccoli!" << std::endl;} else { std::cout << "I'm not sure about what I like!" << std::endl;}
- This version prints
"I like both spaghetti AND broccoli!"
if both conditions aretrue
. - If either condition is
false
, it prints"I'm not sure about what I like!"
. - Unlike the nested version, this code always prints something.
To replicate the behavior of the nested if
statements, you can use an else if
statement:
if (i_like_spaghetti && i_like_broccoli) { std::cout << "I like both spaghetti AND broccoli!" << std::endl;} else if (i_like_spaghetti) { std::cout << "I only like spaghetti!" << std::endl;}
- If both
i_like_spaghetti
andi_like_broccoli
aretrue
, the program prints"I like both spaghetti AND broccoli!"
. - If only
i_like_spaghetti
istrue
, it prints"I only like spaghetti!"
. - If neither condition is satisfied, the program does nothing.
This version is functionally identical to the nested version but uses logical operators instead of nesting.
Trade-Offs
- Readability:
- Nested if statements can be easier to understand because they handle one condition at a time. For example:
- The outer if deals with
i_like_spaghetti
. - The inner if deals with
i_like_broccoli
.
- The outer if deals with
- Logical operators can make the code more compact but harder to interpret, especially when conditions are complex.
- Nested if statements can be easier to understand because they handle one condition at a time. For example:
- Scope Management:
- Nested if statements introduce additional scopes, which can complicate the program structure.
- Logical operators avoid this issue but require clear understanding of how the conditions interact.
- Clarity with else and else if:
- Nested if statements paired with
else
blocks can lead to confusion if not properly indented. - Logical operators eliminate ambiguity about which condition the
else
orelse if
applies to.
- Nested if statements paired with
More Problems with Implied Curly Braces
When you omit curly braces in nested if statements, C++ associates any else
or else if
with the most recent preceding if
. This can lead to misleading indentation and incorrect assumptions about the code’s behavior.
For example:
if (2 + 2 == 4) if (4 + 5 == 8) std::cout << "A" << std::endl;else std::cout << "B" << std::endl;
At first glance, it might seem like the program will print nothing because both conditions are false. However, this program actually prints "B"
. Here’s why:
- The
else
statement is associated with the most recentif
(i.e.,if (4 + 5 == 8)
), not the outerif
. - The indentation has no impact on program behavior because C++ is whitespace-insensitive.
To make this clearer, rewrite the program with proper indentation:
if (2 + 2 == 4) if (4 + 5 == 8) std::cout << "A" << std::endl; else std::cout << "B" << std::endl;
Or better, use curly braces to avoid ambiguity:
if (2 + 2 == 4) { if (4 + 5 == 8) { std::cout << "A" << std::endl; } else { std::cout << "B" << std::endl; }}
Short Circuiting
As we’ve seen, in C++, the logical operators &&
and ||
have similar counterparts: &
and |
. However, they differ in how they evaluate expressions.
- The
&&
operator is known as the logical AND operator with short circuiting. - The
&
operator is the logical AND operator without short circuiting. - Similarly,
||
is the logical OR operator with short circuiting, while|
is the logical OR operator without short circuiting.
This raises the question: what is short circuiting?
Short circuiting occurs when a logical operation terminates early after evaluating the left operand because evaluating the right operand is unnecessary.
- The
&&
operator only returnstrue
if both operands aretrue
. Therefore:- If the left operand is
false
, there’s no need to evaluate the right operand because the overall result will always befalse
. - Logical evaluation in C++ is performed left-to-right, so the
&&
operator short circuits as soon as it encounters afalse
left operand.
- If the left operand is
- The
||
operator returnstrue
if at least one operand istrue
. Therefore:- If the left operand is
true
, there’s no need to evaluate the right operand because the overall result will always betrue
. - Again, the evaluation is performed left-to-right, so the
||
operator short circuits as soon as it encounters atrue
left operand.
- If the left operand is
- The
&
and|
operators always evaluate both operands, regardless of the value of the left operand. - The only difference between
&&
and&
(or||
and|
) is whether short circuiting occurs.
Short circuiting offers performance improvements by skipping the evaluation of the second operand when it is unnecessary.
(1 > 100) && (sqrt(pow(2, 5)) * 3.141592 + pow(2.71, 9.81) > abs(-sqrt(100)))
Here, the second operand of the &&
operator involves complex calculations, including function calls like sqrt
, pow
, and abs
. Evaluating this operand could take time (albeit minimal for a single operation). However:
- The left operand (
1 > 100
) isfalse
. - Because the left operand is evaluated first, the
&&
operator short circuits and skips the computation of the second operand entirely.
If you replaced the &&
operator with the &
operator, short circuiting would be disabled, and the second operand would always be evaluated, potentially slowing down the program.
However, the real importance of short circuiting lies in its ability to prevent or allow side effects during the evaluation of the second operand. Let’s examine two examples.
bool i_like_spaghetti = true;int some_integer = 1;int some_other_integer = 100;
if (i_like_spaghetti || (some_integer = some_other_integer) == 100) { std::cout << some_integer << std::endl;}
- The right operand
(some_integer = some_other_integer) == 100
includes an assignment operation. - Because
i_like_spaghetti
istrue
, the||
operator short circuits, and the right operand is never evaluated. - As a result,
some_integer
remains unchanged, and the program prints1
.
If you replaced ||
with |
, the right operand would always be evaluated:
- The assignment operation would execute, updating
some_integer
to100
. - The program would then print
100
.
This demonstrates how short circuiting can influence the state of a program.
int numerator;int denominator;std::cin >> numerator;std::cin >> denominator;
if (denominator != 0 && numerator / denominator > 10) { std::cout << "The value of your fraction is greater than 10" << std::endl;}
- If the user enters
0
for the denominator, the conditiondenominator != 0
evaluates tofalse
. - The
&&
operator short circuits, so the second operandnumerator / denominator > 10
is never evaluated. This prevents a division-by-zero error.
Without short circuiting (using the &
operator), the second operand would always be evaluated, resulting in a runtime error (e.g., “floating point exception”).
Use &&
and ||
for logical operations unless you have a specific need to evaluate both operands.
Common Mistakes
Incomplete Logical Operands
When translating logical conditions from English to C++, it’s important to ensure the operands in your expressions are complete and valid. Sometimes, a logical operation that seems straightforward in English may not directly translate into C++ without introducing unintended bugs.
Suppose your goal is to express the condition: “x is equal to 2 or 0”, where x is some numeric expression (e.g., an int variable or a more complex expression).
A naive attempt to write this condition in C++ might look like this:
x == 2 || 0
The above expression contains a bug. Recall that the ||
operator requires two operands, each of which must be evaluated as a boolean. In this case:
- The left operand is
x == 2
, which is a valid boolean expression. - The right operand is
0
, which is not a boolean but an int literal.
In such situations, C++ implicitly converts the int to a boolean using its boolean conversion rules: 0
is converted to false
.
As a result, the above expression is interpreted as:
x == 2 || false
Applying a logical OR ||
operation to false has no effect because it’s equivalent to an identity operation. Therefore, the expression simplifies further to:
x == 2
Clearly, this is not the logic you intended to express. Instead of checking whether x
is equal to 2
or 0
, the expression only checks if x
is equal to 2
.
To correctly express the logic “x is equal to 2 or 0”, ensure that both operands are complete boolean expressions. This means explicitly stating each comparison:
x == 2 || x == 0
- The first operand,
x == 2
, evaluates whetherx
is equal to2
. - The second operand,
x == 0
, evaluates whetherx
is equal to0
. - The
||
operator then combines these two boolean results.
Chaining Inequalities
When expressing conditions like “x is between 1 and 10”, it’s common in mathematics to write this as a succinct chained inequality:
At first glance, you might think this could be directly translated into C++ as:
1 <= x <= 10
However, this approach introduces a bug because C++ does not evaluate chained inequalities the way mathematics does. Let’s break this down.
In C++, operators are evaluated one at a time, from left to right, unless parentheses explicitly change the order of operations. Therefore, the above expression is equivalent to:
(1 <= x) <= 10
The parentheses here clarify that the expression is not treated as a single compound range check. Instead:
- The leftmost inequality
(1 <= x)
is evaluated first. - The result of that evaluation (
true
orfalse
) is then treated as an integer (withtrue
converted to1
andfalse
converted to0
) and compared to10
.
To express the condition “x is between 1 and 10” in C++, you need to use a logical AND &&
to combine two separate inequalities:
1 <= x && x <= 10
This ensures that:
- The first condition (
1 <= x
) checks whetherx
is greater than or equal to1
. - The second condition (
x <= 10
) checks whetherx
is less than or equal to10
.
Only if both conditions are true
will the entire expression evaluate to true
.
You can reverse the order in different ways, for example:
x >= 1 && x <= 10x <= 10 && x >= 1
Both are functionally equivalent to the first example. The key point is that you cannot use a chained inequality like you would in mathematics; you must explicitly write out each comparison and combine them with a logical operator.
Else without If and Vice Versa
In C++, an else if
or else
statement must immediately follow a preceding if
or else if
statement. This is because the “otherwise” logic of an else if
or else
statement is directly tied to the immediately preceding sequence of if
and else if
statements.
Simply put, an else
or else if
cannot exist as a standalone statement—it must always be associated with a corresponding if
.
Consider the following incorrect code:
#include <iostream>int main() { else { std::cout << "Hello!" << std::endl; }}
This code will fail to compile. The compiler expects an if statement preceding the else but does not find one. Here is the resulting compiler error:
else_error.cpp:4:5: error: expected expression 4 | else { | ^1 error generated.
To fix this, ensure that the else is preceded by an if. For example:
#include <iostream>int main() { if (true) { std::cout << "Condition is true!" << std::endl; } else { else { std::cout << "Condition is false!" << std::endl; }}
In this corrected example, the else
statement is directly tied to the preceding if
statement, making it valid.
If you have two adjacent if
statements and want to make them mutually exclusive, you must use an else if
statement for the second condition. Consider the following example:
#include <iostream>int main() { int number = 5;
// Incorrect: Two independent `if` statements if (number < 10) { std::cout << "Number is less than 10." << std::endl; } if (number > 10) { std::cout << "Number is greater than 10." << std::endl; }}
What’s wrong with this code snippet?
- Both conditions are independent and not mutually exclusive.
- If the first if condition is
false
, the program will still evaluate the secondif
, even though it may logically belong as part of the same conditional chain.
To make the conditions mutually exclusive, rewrite the second if
as an else if
:
#include <iostream>int main() { int number = 5;
// Correct: Use `else if` to ensure mutual exclusivity if (number < 10) { std::cout << "Number is less than 10." << std::endl; } if (number > 10) { } else if (number > 10) { std::cout << "Number is greater than 10." << std::endl; }}
- The
else if
ensures that the second condition(number > 10)
is only evaluated if the first condition(number < 10)
isfalse
. - This creates a logical chain where only one block of code can execute.
Assignment Instead of Equality (and “Yoda notation”)
Accidentally using the assignment operator (=
) instead of the equality operator (==
) is a common mistake in C++. Some programming languages address this issue by using entirely different symbols for assignment and equality, but in C++, the similarity between =
and ==
can lead to subtle logic errors.
These errors are particularly tricky because:
- They often do not result in syntax errors.
- They may not cause runtime crashes.
- Instead, they lead to unexpected program behavior, which can be difficult to diagnose.
If your program contains if
statements that don’t behave as expected, this is one of the first things to check.
A popular way to prevent this error is to use “Yoda Notation”, which involves writing constant values on the left-hand side of an equality check. For example:
if (5 == x)
Instead of:
if (x == 5)
If you accidentally use the assignment operator (=
) instead of the equality operator (==
) in Yoda Notation, the compiler will produce a syntax error.
Exact Equality for Floating Point Numbers
Floating point numbers (e.g., float
and double
) cannot represent all fractional values with perfect precision. This is due to the way these values are stored in memory, which involves rounding and approximations.
If you perform a series of mathematical operations on floating point numbers, rounding errors can accumulate. This means the final result may differ slightly from your expectations. For example, a calculated value might be off by a tiny amount, such as a trillionth.
Because of these precision issues, comparing floating point numbers for exact equality often fails. Consider the following problematic if statement:
if (some_floating_point_value == some_other_floating_point_value) { // Code here}
This condition will likely evaluate to false
, even if the two values are “close enough.”
Instead of checking for exact equality, compare the difference between the two values and ensure it falls within an acceptable range (or “tolerance”). For example:
if (abs(some_floating_point_value - some_other_floating_point_value) < 0.000001) { // Code here}
- The
abs
function calculates the absolute difference between the two values. - If this difference is smaller than a chosen threshold (e.g.,
0.000001
), the values are considered “close enough.” - The threshold depends on the precision required for your specific application.
This approach applies to both float
and double
types. While double
provides higher precision than float
, it still cannot store certain fractional values perfectly.
Scope Issues
In C++, if
statements define their own scope, regardless of whether curly braces ({}
) are explicitly used. This means:
- Any variables declared inside an
if
statement (or anelse if
orelse
statement) are local to that block. - Once the block ends, the variables declared within it go out of scope and become inaccessible.
The following code contains a scope error:
std::cout << "Is 777 your favorite number? Enter 1 for yes or 0 for no: ";int favorite_is_777;std::cin >> favorite_is_777;
if (favorite_is_777 == 0) { int favorite_number = 777; std::cout << "Oh! Okay, then. What IS your favorite number?: "; std::cin >> favorite_number;}
std::cout << "Okay, so your favorite number is " << favorite_number << std::endl;
What’s wrong with this code snippet?
- The variable
favorite_number
is declared inside theif
statement’s body. - Once the
if
block ends,favorite_number
falls out of scope, making it inaccessible to thestd::cout
statement outside the block. - This results in a compile-time error.
To fix this, declare the variable outside the if block so that it remains accessible throughout the program:
std::cout << "Is 777 your favorite number? Enter 1 for yes or 0 for no: ";int favorite_is_777;std::cin >> favorite_is_777;
// Declare the variable outside the `if` statement int favorite_number = 777;
if (favorite_is_777 == 0) { int favorite_number = 777; std::cout << "Oh! Okay, then. What IS your favorite number?: "; std::cin >> favorite_number;}
std::cout << "Okay, so your favorite number is " << favorite_number << std::endl;