Logical Operator s
C++’s logical operators enable you to combine relational operators into more powerful data-testing statements. The logical operators are sometimes called compound relational operators. As C++’s prece- dence table shows, relational operators take precedence over logical operators when you combine them. The precedence table plays an important role in these types of operators, as this chapter empha- sizes.
This chapter introduces you to
-
The logical operators
-
How logical operators are used
-
How logical operators take precedence
This chapter concludes your study of the conditional testing that C++ enables you to perform, and it illustrates many examples of i f statements in programs that work on compound conditional tests.
Defining Logical Operator s
There may be times when you have to test more than one set of variables. You can combine more than one relational test into a compound relational test by using C++’s logical operators, as shown in Table 10.1.
Table 10.1. Logical operators.
Operator Meaning
&& AND
| | OR
! NOT
Logical operators enable the user to compute compound relational tests.
The first two logical operators, && and || , never appear by themselves. They typically go between two or more relational tests. Table 10.2 shows you how each logical operator works. These tables are called truth tables because they show you how to achieve True results from an i f statement that uses these operators. Take
some time to study these tables.
Table 10.2. Truth tables.
The AND (&&) truth table (Both sides must be True) |
||
---|---|---|
True |
AND |
True = True |
True |
AND |
False = False |
False |
AND |
True = False |
False |
AND |
False = False |
The OR (|| ) truth table (One or the other side must be True) |
||
True |
OR |
True = True |
True |
OR |
False = True |
False |
OR |
True = True |
False |
OR |
False = False |
The NOT (! ) truth table (Causes an opposite relation)
NOT True = False NOT False = True
Logical Operators an d Their Use s
The True and False on each side of the operators represent a relational i f test. The following statements, for example, are valid i f tests that use logical operators (sometimes called compound relational operators).
If the variable a is less than the variable b*, and the variable* c *is greater than the variable* d*, then print* Resul t s ar e i nvali d. *to the screen.*
i f (( a < b) && ( c > d))
{ cout << “ Resul t s ar e i nvali d. ” ; }
The variable a must be less than b and, at the same time, c must be greater than d for the pr i ntf () to execute. The i f statement still requires parentheses around its complete conditional test. Consider this portion of a program:
The|| is sometimes called inclusive ORH*.* ere is a program segment that includes the not (! ) operator:
i f (( sal es > 5000) | | ( hr s_wor ked > 81))
{ bonus=500; }
The sal es must be more than 5000, or the hr s_wor ked must be more than 81, before the assignment executes.
i f ( ! ( sal es < 2500))
{ bonus = 500; }
If sal es is greater than or equal to 2500, bonus is initialized. This illustrates an important programming tip: Use ! sparingly. Or, as some professionals so wisely put it: “Do not use ! or your programs will not be ! (unclear).” It is much clearer to rewrite the previous example by turning it into a positive relational test:
i f ( sal es >= 2500)
{ bonus 500; }
But the ! operator is sometimes helpful, especially when testing for end-of-file conditions for disk files, as you learn in Chapter 30, “Sequential Files.” Most the time, however, you can avoid using ! by
! ( var 1 == var 2) is the same as ( var 1 ! = var 2)
! ( var 1 <= var 2) is the same as ( var 1 > var 2)
! ( var 1 >= var 2) is the same as ( var 1 < var 2)
! ( var 1 ! = var 2) is the same as ( var 1 == var 2)
! ( var 1 > var 2) is the same as ( var 1 <= var 2)
! ( var 1 < var 2) is the same as ( var 1 >= var 2)
Notice that the overall format of the i f statement is retained when you use logical operators, but the relational test expands to include more than one relation. You even can have three or more, as in the following statement:
i f (( a == B) && ( d == f ) | | ( l = m) | | ! ( k <> 2)) ...
This is a little too much, however, and good programming practice dictates using at most two relational tests inside a single i f statement. If you have to combine more than two, use more than one i f statement to do so.
As with other relational operators, you also use the following logical operators in everyday conversation.
“If my pay is high and my vacation time is long, we can go to Italy this summer.”
“If you take the trash out or clean your room, you can watch TV tonight.”
“If you aren’t good, you’ll be punished.”
C++’s Logical Efficienc y
C++ attempts to be more efficient than other languages. If you combine multiple relational tests with one of the logical operators, C++ does not always interpret the full expression. This ultimately makes your programs run faster, but there are dangers! For ex- ample, if your program is given the conditional test:
i f (( 5 > 4) | | ( sal es < 15) && ( 15 ! = 15)) ...
C++ only evaluates the first condition, ( 5 > 4) , and realizes it does not have to look further. Because (5 > 4) is True and because || (OR) anything that follows it is still True, C++ does not bother with the rest of the expression. The same holds true for the following state- ment:
i f (( 7 < 3) && ( age > 15) && ( i ni t i al == ‘ D’ )) ...
Here, C++ evaluates only the first condition, which is False. Because the && (AND) anything else that follows it is also False, C++ does not interpret the expression to the right of ( 7 < 3) . Most of the time, this doesn’t pose a problem, but be aware that the following expression might not fulfill your expectations:
i f (( 5 > 4) | | ( num = 0)) ...
The ( num = 0) assignment never executes, because C++ has to interpret only ( 5 > 4) to determine whether the entire expression is True or False. Due to this danger, do not include assignment expressions in the same condition as a logical test. The following single i f condition:
i f (( sal es > ol d_sal es) | | ( i nvent or y_f l ag = ‘ Y’ )) ...
should be broken into two statements, such as:
i nvent or y_f l ag) = ‘ Y’ ;
i f (( sal es > ol d_sal es) | | ( i nvent or y_f l ag)) ...
so the i nvent or y_f l ag is always assigned the ‘ Y’ value, no matter how the ( sal es > ol d_sal es) expression tests.
Examples
- The
summer Olympics are held every four years during each year that is divisible evenly by 4. The U.S. Census is taken every 10 years, in each year that is evenly divisible by 10. The following short program asks for a year, and then tells the user if it is a year of the summer Olympics, a year of the census, or both. It uses relational operators, logical opera- tors, and the modulus operator to determine this output.
/ / Fil ename: C10YEAR. CPP
/ / Det ermi nes i f i t i s Summer Ol ympi cs year ,
/ / U. S. Census year , or bot h. #i ncl ude <i ost r eam. h>
mai n( )
{
i nt year ;
/ / Ask f or a year
cout << “ What i s a year f or t he t est ? “ ; ci n >> year ;
/ / Test t he year
i f ((( year % 4) ==0) && (( year % 10) ==0))
{ cout << “ Bot h Ol ympi cs and U. S. Census! ” ;
r et ur n 0; } / / Qui t pr ogr am, r et ur n t o oper at i ng
/ / syst em.
i f (( year % 4) ==0)
{ cout << “ Summer Ol ympi cs onl y” ; } el se
{ i f (( year % 10) ==0)
{ cout << “ U. S. Census onl y” ; }
}
r et ur n 0;
}
- Now that you know about compound relations, you can write an
age-checking program like the one called C9AGE.CPP presented in Chapter 9, “Relational Operators.” That program ensured the age would be above 10. This is another way you can validate input for reasonableness.
The following program includes a logical operator in its i f to determine whether the age is greater than 10 and less than
100. If either of these is the case, the program concludes that the user did not enter a valid age.
/ / Fil ename: C10AGE. CPP
/ / Pr ogr am t hat hel ps ensur e age val ues ar e r easonabl e. #i ncl ude <i ost r eam. h>
mai n( )
{
i nt age;
cout << “ What i s your age? “ ; ci n >> age;
i f (( age < 10) | | ( age > 100))
{ cout << “ \ x07 \ x07 \ n” ; / / Beep t wi ce
cout << “ *** The age must be bet ween 10 and”
“ 100 *** \ n” ; }
el se
{ cout << “ You ent er ed a vali d age. ” ; } r et ur n 0;
}
- The following program could be used by a video store to calculate a
discount, based on the number of rentals people transact as well as their customer status. Customers are classified either R for Regular or S for Special. Special custom- ers have been members of the rental club for more than one year. They automatically receive a 50-cent discount on all rentals. The store also holds “value days” several times a year. On value days, all customers receive the 50-cent dis- count. Special customers do not receive an additional 50 cents off during value days, because every day is a discount for them.
The program asks for each customer’s status and whether or not it is a value day. It then uses the || relation to test for the discount. Even before you started learning C++, you would probably have looked at this problem with the following
“If a customer is Special or if it is a value day, deduct 50 cents from the rental.”
That’s basically the idea of the i f decision in the following program. Even though Special customers do not receive an additional discount on value days, there is one final i f test for them that prints an extra message at the bottom of the screen’s indicated billing.
/ / Fil ename: C10VI DEO. CPP
/ / Pr ogr am t hat comput es vi deo r ent al amount s and gi ves
/ / appr opr i at e di scount s based on t he day or cust omer st at us. #i ncl ude <i ost r eam. h>
#i ncl ude <st di o. h> mai n( )
{
f l oat t ape_char ge, di scount , r ent al _amt; char f i r st _name[ 15];
char l ast _name[ 15]; i nt num_t apes;
char val _day, sp_st at;
cout << “ \ n\ n *** Vi deo Rent al Comput at i on *** \ n” ; cout << “ \ n” ;
/ / Under li ne t i t l e
t ape_char ge = 2. 00;
/ / Bef or e- di scount t ape f ee- per t ape.
/ / Recei ve i nput dat a.
cout << “ \ nWhat i s cust omer ’ s f i r st name? “ ; ci n >> f i r st _name;
cout << “ What i s cust omer ’ s l ast name? “ ; ci n >> l ast _name;
cout << “ \ nHow many t apes ar e bei ng r ent ed? “ ; ci n >> num_t apes;
cout << “ I s t hi s a Val ue day ( Y/ N) ? “ ; ci n >> val _day;
cout << “ I s t hi s a Speci al St at us cust omer ( Y/ N) ? “ ; ci n >> sp_st at;
/ / Cal cul at e r ent al amount.
di scount = 0. 0; / / I ncr ease di scount i f t hey ar e eli gi bl e. i f (( val _day == ‘ Y’ ) | | ( sp_st at == ‘ Y’ ))
{ di scount = 0. 5;
r ent al _amt =( num_t apes* t ape_char ge)
( di scount * num_t apes) ; }
/ / Pr i nt t he bill .
cout << “ \ n\ n** Rent al Cl ub ** \ n\ n” ;
cout << f i r st _name << “ “ << l ast _name << “ r ent ed “
<< num_t apes << “ t apes\ n” ;
pr i ntf (“ The t ot al was %. 2f\ n” , r ent al _amt ) ;
pr i ntf (“ The di scount was %. 2f per t ape\ n” , di scount ) ;
/ / Pr i nt ext r a message f or Speci al St at us cust omer s. i f ( sp_st at == ‘ Y’ )
{ cout << “ \ nThank t hem f or bei ng a Speci al “
<< “ St at us cust omer \ n” ; }
r et ur n 0;
}
The output of this program appears below. Notice that Special customers have the extra message at the bottom of the screen. This program, due to its i f statements, performs differently depending on the data entered. No discount is applied for Regular customers on nonvalue days.
*** Vi deo Rent al Comput at i on ***
What i s cust omer ’ s f i r st name? Jerr y What i s cust omer ’ s l ast name? Par ker
How many t apes ar e bei ng r ent ed? 3 I s t hi s a Val ue day ( Y/ N) ? Y
I s t hi s a Speci al St at us cust omer ( Y/ N) ? Y
** Rent al Cl ub **
Jerr y Par ker r ent ed 3 t apes The t ot al was 4. 50
The di scount was 0. 50 per t ape
Logical Operators an d Their Precedenc e
The math precedence order you read about in Chapter 8, “Using C++ Math Operators and Precedence,” did not include the logical operators. To be complete, you should be familiar with the entire order of precedence, as presented in Appendix D, “C++ Precedence Table.”
You might wonder why the relational and logical operators are included in a precedence table. The following statement helps show you why:
i f (( sal es < mi n_sal * 2 && yr s_emp > 10 * sub) ...
Without the complete order of operators, it is impossible to determine how such a statement would execute. According to the precedence order, this i f statement executes as follows:
i f (( sal es < ( mi n_sal * 2)) && ( yr s_emp > ( 10 * sub))) ...
This still might be confusing, but it is less so. The two multipli- cations are performed first, followed by the relations < and >. The && is performed last because it is lowest in the precedence order of operators.
To avoid such ambiguous problems, be sure to use ample parentheses— even if the default precedence order is your intention. It is also wise to resist combining too many expressions inside a single i f relational test.
Notice that || (OR) has lower precedence than && (AND).
Therefore, the following i f tests are equivalent:
i f (( f i r st _i ni t i al ==’ A’ ) && ( l ast _i ni t i al ==’ G’ ) | | ( i d==321)) ...
i f ((( f i r st _i ni t i al ==’ A’ ) && ( l ast _i ni t i al ==’ G’ )) | | ( i d==321)) ...
The second is clearer, due to the parentheses, but the precedence table makes them identical.
Review Question s
The answers to the review questions are in Appendix B.
-
What
are the three logical operators?
-
The following compound relational tests produce True or False
comparisons. Determine which are True and which are False.
-
! ( Tr ue | | Fal se)
-
( Tr ue && Fal se) && ( Fal se | | Tr ue)
-
! ( Tr ue && Fal se)
-
Tr ue | | ( Fal se && Fal se) | | Fal se
-
-
Given
the statement:
i nt i =12, j =10, k=5;
What are the results (True or False) of the following state- ments? (Hint: Remember that C++ interprets any nonzero statement as True.)
- i && j
b. 12 - i | | k
c. j ! = k && i ! = k
- What
is the value printed in the following program? (Hint: Don’t be misled by the assignment operators on each side of the || .)
/ / Fil ename: C10LOGO. CPP
/ / Logi cal oper at or t est #i ncl ude <i ost r eam. h> mai n( )
{
i nt f , g;
g = 5;
f = 8;
i f (( g = 25) | | ( f = 35))
{ cout << “ g i s “ << g << “ and f got changed t o “ << f ; } r et ur n 0;
}
- Using the precedence table, determine whether the follow- ing
statements produce a True or False result. After this, you should appreciate the abundant use of parentheses!
a. 5 == 4 + 1 | | 7 * 2 ! = 12 - 1 && 5 == 8 / 2
b. 8 + 9 ! = 6 - 1 | | 10 % 2 ! = 5 + 0
c. 17 - 1 > 15 + 1 && 0 + 2 ! = 1 == 1 | | 4 ! = 1
d. 409 * 0 ! = 1 * 409 + 0 | | 1 + 8 * 2 >= 17
- Does the following cout execute?
i f ( ! 0)
{ cout << “ C++ By Exampl e \ n” ; }
Review Exercise s
-
Write
a program (by using a single compound i f state- ment) to determine whether the user enters an odd positive number.
-
Write
a program that asks the user for two initials. Print a message telling the user if the first initial falls alphabetically before the second.
-
Write
a number-guessing game. Assign a value to a variable called number at the top of the program. Give a prompt that asks for five guesses. Receive the user’s five guesses with a single scanf () for practice with scanf () . Determine whether any of the guesses match the number and print an appropriate message if one does.
-
Write a tax-calculation routine, as follows: A family pays no tax if
its income is less than $5,000. It pays a 10 percent tax if its income is $5,000 to $9,999, inclusive. It pays a 20 percent tax if the income is $10,000 to $19,999, inclusive. Otherwise, it pays a 30 percent tax.
Summary
This chapter extended the i f statement to include the &&, || , and
! logical operators. These operators enable you to combine several relational tests into a single test. C++ does not always have to look at every relational operator when you combine them in an ex- pression.
This chapter concludes the explanation of the i f statement. The next chapter explains the remaining regular C++ operators. As you saw in this chapter, the precedence table is still important to the C++ language. Whenever you are evaluating expressions, keep the pre- cedence table in the back of your mind (or at your fingertips) at all times!