I l @ ve RuBoard |
You've seen how if and while statements often use relational expressions as tests. Sometimes you will find it useful to combine two or more relational expressions. For instance, suppose you want a program that counts how many times the characters other than single or double quotes appear in an input sentence . You can use logical operators to meet this need, and you can use the period character (.) to identify the end of a sentence. Listing 7.6 presents a short program illustrating the method.
#include <stdio.h> #define PERIOD `.' int main(void) { int ch; int charcount = 0; while ((ch = getchar()) != PERIOD) { if (ch != `"' && ch != `\'') charcount++; } printf("There are %d non-quote characters.\n", charcount); return 0; }
Here's a sample run:
I didn't read the "I'm a Programming Fool" best seller. There are 50 non-quote characters.
The action begins as the program reads a character and checks to see whether it is a period, because the period marks the end of a sentence. Next comes something new, a statement using the logical AND operator && . You can translate the if statement thus: If the character is not a double quote AND if it is not a single quote, then increase charcount by 1.
Both conditions must be true if the whole expression is to be true. The logical operators have a lower precedence than the relational operators, so it was not necessary to use additional parentheses to group the subexpressions .
C has three logical operators:
Operator | Meaning |
---|---|
&& | and |
or | |
! | not |
Suppose exp1 and exp2 are two simple relational expressions, such as cat > rat or debt == 1000 . Then you can state the following:
exp1 && exp2 is true only if both exp1 and exp2 are true.
exp1 exp2 is true if either exp1 or exp2 is true or if both are true.
!exp1 is true if exp1 is false and is false if exp1 is true.
Here are some concrete examples:
5 > 2 && 4 > 7 is false because only one subexpression is true. 5 > 2 4 > 7 is true because at least one of the subexpressions is true. !(4 > 7) is true because 4 is not greater than 7.
The last expression, incidentally, is equivalent to the following:
4 <= 7
If you are unfamiliar or uncomfortable with logical operators, remember that
(practice && time) == perfection
The ! operator has a very high precedence, higher than multiplication, the same as the increment operators, and just below that of parentheses. The && operator has higher precedence than , and both rank below the relational operators and above assignment in precedence. Therefore, the expression
a > b && b > c b > d
would be interpreted as
((a > b) && (b > c)) (b > d)
That is, b is between a and c , or b is greater than d .
Aside from those cases in which two operators share an operand, C ordinarily does not guarantee which parts of a complex expression are evaluated first. For example, in the following statement, the expression 5 + 3 might be evaluated before 9 + 6 , or it might be evaluated afterward:
(5 + 3) * (9 + 6);
This ambiguity was left in the language so that compiler designers could make the most efficient choice for a particular system. One exception to this rule (or lack of rule) is the treatment of logical operators. C guarantees that logical expressions are evaluated from left to right. The && and operators are sequence points, so all side effects take place before a program moves from one operand to the next. Furthermore, it guarantees that as soon as an element is found that invalidates the expression as a whole, the evaluation stops. These guarantees make it possible to use constructions such as the following:
while ((c = getchar()) != ` ' && c != `\n')
This construction sets up a loop that reads characters up to the first space or newline character. The first subexpression gives a value to c , which then is used in the second subexpression. Without the order guarantee, the computer might try to test the second expression before finding out what value c had.
Here is another example:
if (number != 0 && 12/number == 2) printf("The number is 5 or 6.\n");
If number has the value , the first subexpression is false, and the relational expression is not evaluated any further. This spares the computer the trauma of trying to divide by zero. Many languages do not have this feature. After seeing that number is , they still plunge ahead to check the next condition.
Finally, consider this example:
while ( x++ < 10 && x + y < 20)
The fact that the && operator is a sequence point guarantees that x is incremented before the expression on the right is evaluated.
Summary: Logical Operators and ExpressionsLogical Operators: Logical operators normally take relational expressions as operands. The ! operator takes one operand. The rest take two ”one to the left, one to the right.
Logical Expressions: expression1 && expression2 is true if and only if both expressions are true. expression1 expression2 is true if either one or both expressions are true. !expression is true if the expression is false, and vice versa. Order of Evaluation: Logical expressions are evaluated from left to right. Evaluation stops as soon as something is discovered that renders the expression false. Examples: 6 > 2 && 3 == 3 is true. ! (6 > 2 && 3 == 3) is false. x != 0 && (20 / x) < 5 The second expression is evaluated only if x is nonzero. |
You can use the && operator to test for ranges. For example, to test for score being in the range 90 to 100, you can do this:
if (range >= 90 && range <= 100) printf("Good show!\n");
It's important to avoid imitating common mathematical notation, as in the following:
if (90 <= range <= 100) /* NO! Don't do it! */ printf("Good show!\n");
The problem is that the code is a semantic error, not a syntax error, so the compiler will not catch it (although it might issue a warning). Because the order of evaluation for the <= operator is left-to-right , the test expression is interpreted as follows :
(90 <= range) <= 100
The subexpression 90 <= range either has the value 1 (for true) or (for false). Either value is less than 100, so the whole expression is always true, regardless of the value of range . So use && for testing for ranges.
A lot of existing code uses range tests to see whether a character is, say, a lowercase letter. For instance, suppose ch is a char variable:
if (ch >= `a' && ch <= `z') printf("That's a lowercase character.\n");
This works for character codes such as ASCII, in which the codes for consecutive letters are consecutive numbers . However, this is not true for some codes, including EBCDIC. The more portable way of doing this test is to use the islower () function from the ctype .h family (refer to Table 7.1):
if (islower(ch)) printf("That's a lowercase character.\n");
The islower() function works regardless of the particular character code used. (However, some pre-ANSI implementations lack the ctype.h family.)
I l @ ve RuBoard |