12. How Do I Test Several Things at Once?

With Logical Operators

image

Sometimes the relational operators described in Chapter 11, “How Can I Compare Two Values?,” simply can’t express all the testing conditions. For example, if you wanted to test whether a numeric or character variable is within a certain range, you would have to use two if statements, like this:

image

Although there’s nothing wrong with using nested if statements, they’re not extremely straightforward and their logic is slightly more complex than you really need. By using the logical operators you’ll read about in this chapter, you can combine more than one relational test in a single if statement to clarify your code.

Note

image

Don’t let the terms logical and relational make you think these two groups of operators are difficult. As long as you understand how the individual operators work, you don’t have to keep track of what they’re called as a group.

Clue

image

A relational operator simply tests how two values relate (how they compare to each other). The logical operators combine relational operators.

Getting Logical

There are three logical operators (see Table 12.1). Sometimes logical operators are known as compound relational operators because they let you combine more than one relational operator. (See the previous Clue.)

Table 12.1. The logical operators.

image

Logical operators appear between two or more relational tests. For example, here are the first parts of three if statements that use logical operators:

if ((age >= 21) && (age <= 65)) {

and

if ((hrsWorked > 40) || (sales > 25000.00)) {

and

if (!(isCharterMember)) {

Clue

image

If you combine two relational operators with a logical operator or if you use the ! (not) operator to negate a relation, the entire expression following the if statement requires parentheses. This is not allowed:

if !isCharterMember {    /* Not allowed */

Of course, there is more to the preceding if statements than what is shown, but to keep things simple at this point, the if bodies aren’t shown.

Logical operators work just as they do in spoken language. For example, consider the spoken statements that correspond to the code lines just seen:

if ((age >= 21) && (age <= 65)) {

This could be worded in spoken language like this:

"If the age is at least 21 and no more than 65,..."
if ((hrsWorked > 40) || (sales > 25000.00)) {

This could be worded in spoken language like this:

image

This could be worded in spoken language like this:

"If you aren't a charter member, you must..."

As you have no doubt figured out, these three spoken statements describe exactly the same tests done by the three if statements. You often place an and be-tween two conditions, such as “If you take out the trash and clean your room, you can play.” Figures 12.1 and 12.2 show the difference between and and or.

Figure 12.1. The AND condition requires that both sides be true.

image

Figure 12.2. The OR condition requires that either side be true.

image

Note

image

Reread that stern statement you might say to a child. The and condition places a strict requirement that both of the jobs must be done before the result can take place. That’s what && does also. Both sides of the && must be true in order for the body of the if to execute.

Let’s continue with this same line of reasoning for the || (or) operator. You might be more lenient on the kid by saying this: “If you take out the trash or clean your room, you can play.” The or is not as restrictive. One side or the other side of the || must be true (and they both can be true as well). If either side is true, the result can occur. The same holds for the || operator. One or the other side of the || must be true (or they both can be true) in order for the body of the if to execute.

The ! (not) operator reverses a true or a false condition. True becomes false, and false becomes true. This sounds confusing, and it is! Limit the number of ! operators you use. You can always rewrite a logical expression to avoid using ! by reversing the logic. For example, the following if:

if ( !(sales < 3000)) {

is exactly the same as this if:

if ( sales >= 3000) {

As you can see, you can remove the ! and turn a negative statement into a positive test by removing the ! and using an opposite relational operator.

Clue

image

Suppose you wanted to write an inventory program that tests whether the number of a certain item has fallen to zero. The first part of the if might look like this:

if (count == 0) {

Because the if is true only if count has a value of 0, you can rewrite the statement like this:

if (!count) {  /* Executes if's body only if count is 0 */

Warning

image

Again, the ! adds a little confusion to code. Even though you might save some typing effort with a fancy !, clearer code is better than trickier code and if (count == 0) { is probably better to use, despite the microsecond your program might save by using !.

Using the && operator, the following program prints one message if the user’s last name begins with the letters P through S, and another message if the name begins with something else.

image

Note

image

How would the program be different if the && were changed to a ||? Would the first or the second message appear? The answer is the first one. Everybody would be sent to room 2432. Any letter from A to Z is either more than P or less than S. The test in the preceding program has to be && because room 2432 is available only to those people whose names are between P and S.

The following section of code asks the user for a Y or N answer. The code includes an || to ensure that the user enters a correct value.

image

Clue

image

You can combine more than two relational operators with logical operators, but doing too much in a single statement can cause confusion. This is a little too much:

if ((a < 6) || (c >= 3) && (r != 9) || (p <= 1)) {

Try to keep your combined relational tests simple so your programs remain easy to read and maintain.

The Order of Logical Operators

Because logical operators appear in the order of operators table, they have priority at times, just as the other operators do. Studying the order of operators will show you that the && operator has precedence over the ||. Therefore, the following logic

if (age < 20 || sales < 1200 && hrsWorked > 15) {

is interpreted by C like this:

if ((age < 20) || ((sales < 1200) && (hrsWorked > 15))) {

Use ample parentheses. Parentheses help clarify the order of operators. C won’t get confused if you don’t use parentheses, because it knows the order of operators table very well. However, a person looking at your program has to figure out which is done first, and parentheses help group operations together.

Suppose that a teacher wants to reward her students who perform well and have missed very few classes. Also, the reward requires that the students either joined three school organizations or were in two sports activities. Whew! You must admit, not only will that reward be deserved, but it’s going to be difficult sorting out the possibilities.

In C code, the following if statement would test true if a student met the teacher’s preset reward criteria:

if (grade > 93 && classMissed <= 3 && numActs >= 3 || sports >=
2) {

That’s a lot to decipher. Not only is the statement hard to read, but there is a subtle error. The || is compared last (because || has lower precedence than &&), but that || should take place before the second &&. (If this is getting confusing, you’re right! Long combined relational tests often are.) Here, in spoken language, is how the previous if operates without separating its pieces with proper parentheses:

“If the student’s grade is more than 93 and the student missed three or fewer classes and the school activities total three or more, OR if the student participated in two or more sports...”

Well, the problem is that the student only has to be in sports activities to get the reward. The last two relations (separated with the ||) must be compared before the third &&. The spoken description should read like this:

“If the student’s grade is more than 93 and the student missed three or fewer classes and EITHER the school activities total three or more OR the student participated in two or more sports...”

The following if, with correct parentheses, not only makes the if accurate but also a little more clear:

if ((grade > 93) && (classMissed <= 3) && ((numActs >= 3) ||
(sports >= 2)) {

If you like, you can break such long if statements into two or more lines like this:

if ((grade > 93) && (classMissed <= 3) &&
   ((numActs >= 3) || (sports >= 2)) {

Some C programmers even find that two if statements are clearer than four relational tests, such as these statements:

if ((grade > 93) && (classMissed <= 3)
   { if ((numActs >= 3) || (sports >= 2))
       { /* Reward the student */ }

The style you end up with depends mostly on what you like best, what you are the most comfortable with, and what appears to be the most maintainable.

Rewards

image

• Use logical operators to connect relational operators.

• Use && when both sides of the operator have to be true in order for the entire condition to be true.

• Use || when either one side or the other side (or both) have to be true in order for the entire condition to be true.

Pitfalls

image

• Don’t overdo the use of !. Most negative logic can be reversed (so < becomes >= and > becomes <=) to get rid of the not operator.

• Don’t combine too many relational operators in a single expression.

In Review

This chapter’s goal was to teach you the logical operators. Although relational operators test data, the logical operators, && and ||, let you combine more than one relational test into a single statement and execute code accordingly.

As you saw in this chapter, we often use logical-like operators in real life. Often, we make decisions based on several conditions.

Code Example

image

Code Analysis

The code’s intention is a simple example of another teacher’s program to give good students some encouragement. These two relations are tested: the student’s grade-point average and the number of hours the student took. The grade-point average alone is not enough to encourage the student because the student might have taken only a single course. Just because the student took a lot of courses doesn’t mean the student excelled, either.

Therefore, both the grade-point average and the number of hours taken are combined into one compound relational test using the && operator. If the student’s average is good and the student takes a lot of courses, the student is encouraged to continue.

This example is easier than the code in the last section of the book because you should keep if tests simple instead of combining three or more relational operations.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset