Lesson-4 Expression

4.1 INTRODUCTION

Expressions in C are basically operators acting on operands. Statements like a = b + 3, ++z, a-- and 300 > (8 * k) are all expressions. Strictly speaking, even a single variable or constant can be considered an expression. You have seen several expressions in the previous C tutorial on Operators in which the examples involved expressions.

4.2 Arithmetic Instruction

A C arithmetic instruction consists of a variable name on the left hand side of = and variable names & constants on the right hand side of =. The variables and constants appearing on the right hand side of = are connected by arithmetic operators like +, -, *, and /.

Example:-

 int ad ;

float kot, deta, alpha, beta, gamma ;

ad = 3200 ;

kot = 0.0056 ;

deta = alpha * beta / gamma + 3.2 * 2 / 5 ;

Here,

*, /, -, + are the arithmetic operators.

= is the assignment operator.

2, 5 and 3200 are integer constants.

3.2 and 0.0056 are real constants.

ad is an integer variable.

kot, deta, alpha, beta, gamma are real variables.

The variables and constants together are called ‘operands’ that are operated upon by the ‘arithmetic operators’ and the result is assigned, using the assignment operator, to the variable on left-hand side.

A C arithmetic statement could be of three types. These are as follows:

4.2.1 Integer mode arithmetic statement:

This is an arithmetic statement in which all operands are either integer variables or integer constants.

Ex.: int i, king, issac, noteit ;

i = i + 1 ;

king = issac * 234 + noteit - 7689 ;

4.2.2 Real mode arithmetic statement

This is an arithmetic statement in which all operands are either real constants or real variables.

Ex.: float qbee, antink, si, prin, anoy, roi ;

qbee = antink + 23.123 / 4.5 * 0.3442 ;

si = prin * anoy * roi / 100.0 ;

4.2.3 Mixed mode arithmetic statement

This is an arithmetic statement in which some of the operands are integers and some of the operands are real.

Ex.: float si, prin, anoy, roi, avg ;

int a, b, c, num ;

si = prin * anoy * roi / 100.0 ;

avg = ( a + b + c + num ) / 4 ;

It is very important to understand how the execution of an arithmetic statement takes place. Firstly, the right hand side is evaluated using constants and the numerical values stored in the variable names. This value is then assigned to the variable on the left-hand side.

4.3 Integer and Float Conversions

In order to effectively develop C programs, it will be necessary to understand the rules that are used for the implicit conversion of floating point and integer values in C. These are mentioned below. Note them carefully.

(a) An arithmetic operation between an integer and integer always yields an integer result.

(b) An operation between a real and real always yields a real result.

(c) An operation between an integer and real always yields a real result. In this operation the integer is first promoted to a real and then the operation is performed. Hence the result is real.

I think a few practical examples shown in the Table 4.1 would put the issue beyond doubt.

Table 4.1 Integer and Float Conversions

Operation

Result

Operation

Result

5 / 2

2

2 / 5

0

5.0 / 2

2.500000

2.0 / 5

0.400000

5 / 2.0

2.500000

2 / 5.0

0.400000

5.0 / 2.0

2.500000

2.0 / 5.0

0.400000

4.4 Type Conversion in Assignments

It may so happen that the type of the expression and the type of the variable on the left-hand side of the assignment operator may not be same. In such a case the value of the expression is promoted or demoted depending on the type of the variable on left-hand side of =.

For example, consider the following assignment statements.

int i ;

float b ;

i = 3.5 ;

b = 30 ;

Here in the first assignment statement though the expression’s value is a float (3.5) it cannot be stored in i since it is an int. In such a case the float is demoted to an int and then its value is stored. Hence what gets stored in i is 3. Exactly opposite happens in the next statement. Here, 30 is promoted to 30.000000 and then stored in b, since b being a float variable cannot hold anything except a float value.

Instead of a simple expression used in the above examples if a complex expression occurs, still the same rules apply. For example, consider the following program fragment.

float a, b, c ;

int s ;

s = a * b * c / 100 + 32 / 4 - 3 * 1.1 ;

Here, in the assignment statement some operands are ints whereas others are floats. As we know, during evaluation of the expression the ints would be promoted to floats and the result of the expression would be a float. But when this float value is assigned to s it is again demoted to an int and then stored in s.

Observe the results of the arithmetic statements shown in Table 4.2. It has been assumed that k is an integer variable and a is a real variable.

Table 4.2 Type Conversion in Assignments

Arithmetic Instruction

Result

Arithmetic Instruction

Result

k = 2 / 9

0

a = 2 / 9

0.000000

k = 2.0 / 9

0

a = 2.0 / 9

0.222222

k = 2 / 9.0

0

a = 2 / 9.0

0.222222

k = 2.0 / 9.0

0

a = 2.0 / 9.0

0.222222

k = 9 / 2

4

a = 9 / 2

4.000000

k = 9.0 / 2

4

a = 9.0 / 2

4.500000

k = 9 / 2.0

4

a = 9 / 2.0

4.500000

k = 9.0 / 2.0

4

a = 9.0 / 2.0

4.500000

Note that though the following statements give the same result, 0, the results are obtained differently.

k = 2 / 9 ;

k = 2.0 / 9 ;

In the first statement, since both 2 and 9 are integers, the result is an integer, i.e. 0. This 0 is then assigned to k. In the second statement 9 is promoted to 9.0 and then the division is performed. Division yields 0.222222. However, this cannot be stored in k, k being an int. Hence it gets demoted to 0 and then stored in k.

4.5 Hierarchy of Operations

While executing an arithmetic statement, which has two or more operators, we may have some problems as to how exactly does it get executed. For example, does the expression 2 * x - 3 * y correspond to (2x)-(3y) or to 2(x-3y)? Similarly, does A / B * C correspond to A / (B * C) or to (A / B) * C? To answer these questions satisfactorily one has to understand the ‘hierarchy’ of operations. The priority or precedence in which the operations in an arithmetic statement are performed is called the hierarchy of operations. The hierarchy of commonly used operators is shown in Table 4.3.

Table 4.3 Hierarchy of commonly used operators

Priority

Operators

Description

1st

* / %

Multiplication, division, modular division

2nd

+ -

addition, subtraction

3rd

=

assignment

Following  example would clarify the issue further.

Example Determine the hierarchy of operations and evaluate the following expression:

i = 2 * 3 / 4 + 4 / 4 + 8 - 2 + 5 / 8

Stepwise evaluation of this expression is shown below:

i = 2 * 3 / 4 + 4 / 4 + 8 - 2 + 5 / 8

i = 6 / 4 + 4 / 4 + 8 - 2 + 5 / 8            operation: *

i = 1 + 4 / 4 + 8 - 2 + 5 / 8                 operation: /

i = 1 + 1+ 8 - 2 + 5 / 8                       operations:/

i = 1 + 1 + 8 - 2 + 0                           operation: /

i = 2 + 8 - 2 + 0                                 operation: +

i = 10 - 2 + 0                                     operation: +

i = 8 + 0                                             operation: -

i = 8                                                  operations: +

Note that 6 / 4 gives 1 and not 1.5. This so happens because 6 and 4 both are integers and therefore would evaluate to only an integer constant. Similarly 5 / 8 evaluates to zero, since 5 and 8 are integer constants and hence must return an integer value.

All operators in C are ranked according to their precedence. And mind you there are as many as 45 odd operators in C, and these can affect the evaluation of an expression in subtle and unexpected ways if we aren't careful. Unfortunately, there are no simple rules that one can follow, such as “BODMAS” that tells algebra students in which order does an expression evaluate. We have not

encountered many out of these 45 operators, so we won’t pursue the subject of precedence any further here. However, it can be realized at this stage that it would be almost impossible to remember the precedence of all these operators. So a full-fledged list of all operators and their precedence is given in Appendix A. This may sound daunting, but when its contents are absorbed in small bites, it becomes more palatable.

So far we have seen how the computer evaluates an arithmetic statement written in C. But our knowledge would be incomplete unless we know how to convert a general arithmetic statement to a C statement. C can handle any complex expression with ease. Some of the examples of C expressions are shown in Table 4.4.

Table 4.4 Algebraic Expression and its equivalent C Expression

Algebric Expression

C Expression

a x b – c x d

a * b – c * d

(m + n) (a + b)

(m + n) * (a + b)

3x2 + 2x + 5

3 * x * x + 2 * x + 5

( a + b + c ) / ( d + e )

2 * b * y / ( d + 1 ) – x / 3 * ( z + y )

4.6 Associativity of Operators

When an expression contains two operators of equal priority the tie between them is settled using the associativity of the operators. Associativity can be of two types—Left to Right or Right to Left. Left to Right associativity means that the left operand must be unambiguous. Unambiguous in what  sense? It must not be involved in evaluation of any other sub-expression. Similarly, in case of Right to Left associativity the right operand must be unambiguous. Let us understand this with an example.

Consider the expression

a = 3 / 2 * 5 ;

Here there is a tie between operators of same priority, that is between / and *. This tie is settled using the associativity of / and *. But both enjoy Left to Right associativity. Figure 4.1 shows for each operator which operand is unambiguous and which is not.

Figure 4.1 Associatively of Operators

Operator

Left

Right

Remark

/

3

2 or 2 * 5

Left operand is unambiguous, Right is not

*

3 / 2 or 2

5

Right operand is unambiguous, Left is not

Since both / and * have L to R associativity and only / has unambiguous left operand (necessary condition for L to R associativity) it is performed earlier.

Consider one more expression

a = b = 3 ;

Here both assignment operators have the same priority and same associativity (Right to Left). Figure 4.2 shows for each operator which operand is unambiguous and which is not.

Figure 4.2 Associatively of Operators

Operator

Left

Right

Remark

=

a

b or b = 3

Left operand is unambiguous, Right is not

=

b or a = b

3

Right operand is unambiguous, Left is not

Since both = have R to L associativity and only the second = has unambiguous right operand (necessary condition for R to L associativity) the second = is performed earlier.

Consider yet another expression

z = a * b + c / d ;

Here * and / enjoys same priority and same associativity (Left to Right). Figure 4.3 shows for each operator which operand is unambiguous and which is not.

Figure 4.3 Associatively of Operators

Operator

Left

Right

Remark

*

a

b

Both operands are unambiguous

/

c

d

Both operands are unambiguous

Here since left operands for both operators are unambiguous Compiler is free to perform * or / operation as per its convenience since no matter which is performed earlier the result would be same.

Last modified: Friday, 25 October 2013, 6:24 AM