Operators and Expressions
Operators and Expressions
Operators and Expressions
2.1 Introduction
In the previous unit, you learned about the various features and structure of
C programs. You also learned how the variables in C are declared. In this
unit, you will learn about the operators that are available in C and how the
expressions can be formed to get the solutions of any problems.
C supports a rich set of operators. An operator is a symbol that tells the
computer to perform certain mathematical or logical manipulations.
Operators are used in programs to manipulate data and variables. They
usually form a part of the mathematical or logical expressions.
C operator can be classified into a number of categories. They include:
1. Arithmetic operators
2. Unary operator
3. Relational operators
4. Logical operators
5. Conditional operator
6. Bitwise operators
7. Increment and Decrement operators
Objectives:
After studying this subject, you should be able to:
explain different categories of operators
use operators on many operands
distinguish precedence and associativity of operators
explain library functions and their use
write small programs using different types of operators
Unary Minus
The most well known unary operator is minus, where a minus sign precedes
a constant, variable or expression. In C, all numeric constants are positive.
Therefore, a negative number is actually a positive constant preceded by a
unary minus, for example:
-3
would not work. The expression 1 < i < 10 is parsed by the compiler
analogously to 1 + i + 10. The expression 1 + i + 10 is parsed as (1 + i) + 10
and means “add 1 to i, and then add the result to 10.'' Similarly, the
expression 1 < i < 10 is parsed as (1 < i) < 10 and means “see if 1 is less
than i, and then see if the result is less than 10.'' But in this case, “the result''
is 1 or 0, depending on whether i is greater than 1. Since both 0 and 1 are
less than 10, the expression 1 < i < 10 would always be true in C, regardless
of the value of i!
Relational and Boolean expressions are usually used in contexts such as an
if statement, where something is to be done or not done depending on some
condition. In these cases what's actually checked is whether the expression
representing the condition has a zero or nonzero value. As long as the
expression is a relational or Boolean expression, the interpretation is just
what we want. For example, when we wrote
if(x > max)
the > operator produced a 1 if x was greater than max, and a 0 otherwise.
The if statement interprets 0 as false and 1 (or any nonzero value) as true.
But what if the expression is not a relational or Boolean expression? As far
as C is concerned, the controlling expression (of conditional statements like
if) can in fact be any expression: it doesn't have to “look like'' a Boolean
expression; it doesn't have to contain relational or logical operators. All C
looks at (when it's evaluating an if statement, or anywhere else where it
needs a true/false value) is whether the expression evaluates to 0 or
nonzero. For example, if you have a variable x, and you want to do
something if x is nonzero, it's possible to write
if(x)
statement
and the statement will be executed if x is nonzero (since nonzero means
“true'').
This possibility (that the controlling expression of an if statement doesn't
have to “look like'' a Boolean expression) is both useful and potentially
confusing. It's useful when you have a variable or a function that is
“conceptually Boolean,'' that is, one that you consider to hold a true or false
A typical set of library functions will include a large number of functions that
are common to most C compilers, such as those shown in table 2.1.
Function Purpose
abs(i) Return the absolute value of ( i is integer)
ceil(d) Round up to the next integer value(the smallest integer that is
greater than or equal to d)
cos(d) Return the cosine of d
exp(d) Raise e to the power d(e=Naperian constant)
fabs(d) Return the absolute value of d(d is double)
floor(d) Round down to the next integer value(the largest integer that
does not exceed d)
getchar() Enter a character from the standard input device
log(d) Return the natural logarithm of d
pow(d1,d2) Return d1 raised to the power d2
putchar(c) Send a character to the standard output device
rand() Return a random positive integer
sin(d) Return sine of d
sqrt(d) Return the square root of d
tan(d) Return the tangent of d
toascii(c) Convert value of argument to ASCII
tolower(c) Convert letter to lowercase
toupper(c) Convert letter to uppercase
Table 2.1
Then you can “turn the verbose bit on'' in an integer variable flags by
executing
flags = flags | VERBOSE;
and turn it off with
flags = flags & ~VERBOSE;
and test whether it's set with
if(flags & VERBOSE)
The left-shift and right-shift operators << and >> let you shift an integer left
or right by some number of bit positions; for example, value << 2 shifts value
left by two bits.
The comma operator can be used to link the related expressions together.
The expressions are executed one after the other. The most common use
for comma operators is when you want multiple variables controlling a for
loop, for example:
for(i = 0, j = 10; i < j; i++, j--)
The distinction between the prefix and postfix forms of ++ and -- will
probably seem strained at first, but it will make more sense once we begin
using these operators in more realistic situations.
For example,
a[i] = c;
i = i + 1;
using the ++ operator, we could simply write this as
a[i++] = c;
We wanted to increment i after deciding which element of the array to store
into, so the postfix form i++ is appropriate.
Notice that it only makes sense to apply the ++ and -- operators to variables
(or to other “containers,'' such as a[i]). It would be meaningless to say
something like
1++
or
(2+3)++
The ++ operator doesn't just mean “add one''; it means “add one to a
variable'' or “make a variable's value one more than it was before.'' But
(1+2) is not a variable, it's an expression; so there's no place for ++ to store
the incremented result.
Another unfortunate example is
i = i++;
which some confused programmers sometimes write, presumably because
they want to be extra sure that i is incremented by 1. But i++ all by itself is
sufficient to increment i by 1; the extra (explicit) assignment to i is
unnecessary and in fact counterproductive, meaningless, and incorrect. If
you want to increment i (that is, add one to it, and store the result back in i),
either use
i = i + 1;
or
i += 1;
or
++i;
or
i++;
Did it matter whether we used ++i or i++ in this last example? Remember,
the difference between the two forms is what value (either the old or the
new) is passed on to the surrounding expression. If there is no surrounding
expression, if the ++i or i++ appears all by itself, to increment i and do
nothing else, you can use either form; it makes no difference. (Two ways
that an expression can appear “all by itself,'' with “no surrounding
expression,'' are when it is an expression statement terminated by a
semicolon, as above, or when it is one of the controlling expressions of a for
loop.) For example, both the loops
for(i = 0; i < 10; ++i)
printf("%d\n", i);
and
for(i = 0; i < 10; i++)
printf("%d\n", i);
will behave exactly the same way and produce exactly the same results. (In
real code, postfix increment is probably more common, though prefix
definitely has its uses, too.)
Operators Associativity
( ) -> . left to right
! ~ + - ++ -- & * right to left
*/% left to right
+- left to right
< <= > >= left to right
== != left to right
& left to right
| left to right
&& left to right
|| right to left
= *= /= %= += -= right to left
Table 2.2
Where the same operator appears twice (for example *) the first one is the
unary version.
Program 2.6: A program to illustrate evaluation of expressions
#include<stdio.h>
main()
/* Evaluation of expressions */
{
float a, b, c, x, y, z;
a=20;
b=2;
c=-23;
x = a + b / ( 3 + c * 4 - 1);
y = a – b / (3 + c) * ( 4 – 1);
z= a – ( b / ( 3 + c ) * 2 ) – 1;
printf( “x=%f\n”, x);
printf(“y=%f\n”, y);
printf(“z=%f\n”, z);
}
Execute the above program and observe the result.
2.11 Summary
C supports a rich set of operators. An operator is a symbol that tells the
computer to perform certain mathematical or logical manipulations.
Operators are used in programs to manipulate data and variables. A binary
operator acts on two operands. A unary operator acts upon a single operand
to produce a new value. Multiplication, division, and modulus all have higher
precedence than addition and subtraction. Relational and Boolean
expressions are usually used in contexts such as an if statement, where
something is to be done or not done depending on some condition. The C
language is accompanied by a number of library functions or built in
functions that carry out various commonly used operations or calculations.
The size of operator is normally used to determine the lengths of arrays and
structures when their sizes are not known to the programmer. It is also used
to allocate memory space dynamically to variables during execution of a
program. Associativity is the order in which consecutive operations within
the same precedence group are carried out.
3. true
4. Given expression is invalid because a floating point variable can not be
used in a modulus operation.
5. Associativity is the order in which consecutive operations within the
same precedence group are carried out.
2.15 Exercises
1. Suppose a=3, b=5, c=8 and d=4, give the output of the following:
a) x=a*b-c/d+4 b) z=a-b/d*c+10
2. Suppose i=5, j=8, k=10, then , what is the output of the following:
a) x=a++ -j b) y=k++ *j—
3. What is the precedence of operators? How expressions are evaluated
using the precedences?
4. Suppose a=7, b=11, find the output of the following:
a) x=(a>b)?b:a b) x=(a<b)?a:b
5. Explain the use of bitwise operators with suitable examples.