Skip to main content

Section 7.7 Logical Operators

In addition to the relational operators, C++ also has three logical operators: &&, ||, and !, which respectively stand for and, or, and not. They are called logical operators because they operator on β€œlogical” (Boolean) values. The results of these operators are similar to their meanings in English. For example:
  • x > 0 && x < 10 is true when x is greater than 0 and less than 10.
  • x < 0 || x > 10 is true if either condition is true; that is, if x is less than 0 or greater than 10.
  • !(isEven) is true if isEven is not true (if it is false).

Subsection 7.7.1 And

In order for an expression with && to be true, both sides of the && operator must be true. The && operator is equivalent to using nested if statements. For example, the following code:
if (x == 0) {
    if (y == 0) {
        cout << "Both x and y are zero";
    }
}
Is equivalent to this single if statement:
// combined
if (x == 0 && y == 0) {
    cout << "Both x and y are zero";
}
If our goal is to have the one statement depend on testing both x and y, this version using && is shorter and more clearly communicates our intent.

Warning 7.7.1.

C++ does not allow compound conditions like you would write in math. In C++, 0 < x < 10 does NOT test to see if if x is between 0 and 10. Instead, it tests if 0 is less than x, and produces a result of 0 or 1 (true or false). It then tests that value to see if it is less than 10, which will always be true. You MUST write this as two conditions combined with &&: 0 < x && x < 10`.

Subsection 7.7.2 Or

In order for an expression with || to be false, both sides of the || operator must be false. If either part is true, the entire expression is true.
The || operator can simplify our logic where multiple different tests all should result in the same behavior. For example, there are two ways for this code to print the message:
if (x == 0) {
    cout << "Either x or y is zero";
} else if (y == 0) {
    cout << "Either x or y is zero";
}
But we can combine the two conditions into one using ||:
// combined
if (x == 0 || y == 0) {
    cout << "Either x or y is zero";
}

Warning 7.7.2.

C++ also does not allow us to directly translate β€œx is equal to 3 or 4” as x == 3 || 4. Instead, you must write x == 3 || x == 4. The first expression would be interpreted as x == 3 or 4. Since 4 is always true, the expression would always be true.

Insight 7.7.3.

The expression on each side of || or && MUST be a complete boolean expression that will evaluate to true or false.

Subsection 7.7.3 Not

The not operator ! is used to produce the opposite of a boolean value. It can be used directly on boolean variables as shown in this sample:
bool isEven = true;
if (!isEven) {
    // we know it's odd...
That if statement is equivalent to if (isEven == false), but most programmers prefer the version using !. It can also be used to reverse the value calculated by some other logical operation. For example, to test if health is not less than 0 we could do: !(health < 0). Notice that we need the parentheses to make it clear that we want to FIRST calculate β€œis health less than 0” and then calculate the opposite of that value. Of course we could also write that expression as (health >= 0) which more clearly expresses what we are looking for.

Subsection 7.7.4 Short Circuit Evaluation

Logical operators evaluate the second expression only when necessary. For example, true || anything is always true, so C++ does not need to evaluate the expression anything. Likewise, false && anything is always false.
Ignoring the second operand, when possible, is called short-circuit evaluation, by analogy with an electrical circuit. Short-circuit evaluation can save time, especially if anything takes a long time to evaluate. It can also avoid unnecessary errors, if anything might fail. For example, dividing an integer by 0 is a runtime error that will stop a program. This code avoids that by testing b before dividing a by it. If a is 0, then the a != 0 is false and the second clause which involves division never gets executed:
Listing 7.7.1.
Normally you don’t have to worry about short circuit evaluation (other than possibly to use it as a guard). But if the second part of a conditional has a side effectβ€”if it changes some valueβ€”, the logic can be tricky to follow:
if (x > 0 || y++ > 0) {
  // do something
}
Here, if x is greater than 0, the y++ is never executed. But if x is less than or equal to 0, then y is incremented. It would be easy to expect that y always increases. A good rule of thumb is to avoid doing anything in a complex conditional that has a side effect.

Checkpoint 7.7.1.

Multiple Response: How could you re-write the following code using a single conditional?
if (x > 0) {
  if (x < 10) {
    cout << "x is a positive single digit" << endl;
  }
}
  • if (x > 0 && x < 10) {...
  • This is exactly what the nested conditionals are saying.
  • if (x > 0 || x < 10) {...
  • || represents "or", but we need both sides of the conditional to be true.
  • if (x > 0 ! x < 10) {...
  • The ! operator cannot be used to compare two sides of a conditional.
  • if ( !(x < 0) && !(x > 10) ) {...
  • If x = 0 or if x = 10, this expression will return true when it shouldn’t.
  • if ( !(x <= 0) && !(x >= 10) ) {...
  • If it IS NOT what we don’t want, then it IS what we want!

Checkpoint 7.7.2.

Checkpoint 7.7.3.

You have attempted of activities on this page.