¤ Home » Programming » C Tutorial » Elements of the C language - Operators and Expressions

In this article you will -

- Learn about operators and learn how to combine different types of arithmetic operators to form arithmetic expressions.
- Learn how to use available relational and logical operators to interpret true or false state of an expression.
- Understand the usage of pre/post increment/decrement operators.
- Learn about the assignment operator.
- Learn how to combine the increment/decrement and arithmetic operators with the assignment operator to form meaningful expressions.
- Learn about ternary or conditional operator.
- Understand the precedence of operators and how the precedence rules affect expression evaluation.
- Understand the meaning of type conversion.
- Learn how to state implicit type-conversion rules.
- Learn how to apply explicit type-conversion using casting operator.

The type of operations that can be performed on the data objects are specified by *operators*. The data items on which an operator acts are called its *operands*. An operator can be unary, binary or ternary depending upon whether it operates on one, two or three operands. An operator along with its operands constitute a simple expression. A compound expression can be formed by using simpler expressions as operands of the different types of operators. The evaluation order of the operators in an expression will be determined by the operator precedence rules followed in the C language. To begin with, let us first consider the arithmetic operators.

The binary arithmetic operators are `+, -, *, /`

, which correspond to addition, subtraction, multiplication and division respectively. The modulus operator `%`

returns the remainder after integer division. The % (modulus) operator cannot be applied to float or double type data. Arithmetic operators associate left to right.

The binary + and – operators have the same precedence when used in a calculation, but they have lower precedence than *, /, and % operators. To change the order of precedence brackets () are used.

- c = 3 + 5 * 2;

Will assign 13 to the variable c. The unary operator * has a higher order of precedence compared to +. - c = (3 + 5) * 3;

Will store 24 in the variable c

Note that the precedence of operator + here has become higher due to introduction of brackets. The brackets have changed the normal precedence order. - int c = 0; b = 8;

c = -b;

Will store -8 into c

Here is an example of a complex arithmetic expression, which involves multiple arithmetic operators.

int a = 2, b = 4, c = 8, d = 9, e;

e = a * b / c – a * 2 + d * 3;

e = a * b / c – a * 2 + d * 3;

Taking into account the operator precedence, the evaluation of the expression a * b / c – a * 2 + d * 3 will produce 24, which will be assigned to variable e.

Suppose x, y and z are integer variables that have been assigned the values x = 18, y = 3 and z = -3. Determine the value of each of the following arithmetic expressions.

(a) x + y * z | (b) 2 * x + 4 – (y – z) | (c) x / y + z | ||

(d) x % (y * x) | (e) x / z | (f) x % z + 1 | ||

(g) x + y / z | (h) x * (y / z) | (i) (x * z) % y – 1 | ||

(j) x * (z % y) |

The relational operators supported in C are

> | is greater than |

< | is less than |

== | is equal to |

!= | not equal to |

>= | is greater than or equal to |

<= | is less than or equal to |

The relational operators >, <, >=, <= have the same precedence. The equality operator == and the not equal to operator != have lower precedence than the remaining relational operators. The relational operators have lesser precedence than arithmetic operators, so an expression like i < j + 1 will always be evaluated as i < (j + 1).

In C, if an expression evaluation yields zero value it is interpreted as *false*. Similarly it will be treated as *true* if the evaluation of an expression results in a non-zero value.

Let i = 5, j = 6, k = 7, b = 0 The following table illustrates the results of evaluation of some relational expressions.

Expression | Interpretation | Value |
---|---|---|

i < j | true | 1 |

(j + k) < (i + 5) | false | 0 |

(j == 6) | true | 1 |

(!b) | true | 1 |

The **Logical operators** supported in C are **&&** (and) and **||** (or). Expressions connected by && and || are evaluated left to right, and evaluation stops as soon as the truth or falsehood of the condition is ascertained.

The **Unary negation operator** (**!**) returns true if the expression evaluates false (i.e. the evaluation produces zero), false otherwise.

`int i = 5, j = 6, k = 7, b = 0, e, f;`

With the above initialization of variables, let us understand how the below two expressions will evaluate.

`f = ((i + j) < 10) && (b > (k - j));`

In the above expression, first everything to the right of the assignment operator (=) will be evaluated and the result of evaluation will be assigned to f. This is because = has the lowest precendence amongst all other operators. Now if we look at the right side expression, due to the presence of brackets, there are two operands to the

*Logical AND*(&&) operator, viz. (i + j) < 10 and b > (k - j). Evaluation will begin from left to right (L->R). See see operator precendence table for &&. So, first the expression (i + j) < 10 will be evaluated. Since, it evaluates to false, no matter whatever be the result of the right operand b > (k - j), a false ANDed with any operand will always result in false. So, C will not evaluate the right operand and immediately return false. Since false is represented by integer value 0, f will be assigned a value 0.-
`e = (k == j +1) || (b > i);`

In the above expression, first everything to the right of the assignment operator (=) will be evaluated and the result of evaluation will be assigned to e. This is because = has the lowest precendence amongst all other operators. Now if we look at the right side expression, due to the presence of brackets, there are two operands to the

*Logical OR*(||) operator, viz. k == j +1 and b > i. Evaluation will begin from left to right (L->R). See see operator precendence table for ||. So, first the expression k == j +1 will be evaluated. Since, it evaluates to true, no matter whatever be the result of the right operand b > i, a true ORed with any operand will always result in true. So, C will not evaluate the right operand and immediately return true. Since true is represented by integer value 1, e will be assigned a value 1.

There are two such operators **++** (for pre or post increment) and **--** (for pre or post decrement).

int i = 2, j = 0;

i++; or ++i; (these statements are equivalent to i = i+1;)

--i; or i--; (these statements are equivalent to i = i-1;)

int i = 2;

j = ++i;

Here the value of i will be incremented first and then j will be assigned the incremented value, so finally j will get the value 3.

int i = 2;

j = i++;

Here, the assignment will take place first and then i will be incremented. The variable j will therefore receive the initial value of i, viz. 2 and then i will be incremented. After the execution of the above statement, i will store the value 3.

Suppose a C program contains the following declarations and initial assignments.

`int i = 18, j = 3;`

`float x = 0.001, y = -0.05;`

`char c = 'c', d = 'd';`

What will be the value of each of the following expressions? Use the values initially assigned to the variables for each expression.

(a) 2 * (( i / 5) + (6 * (j + 4)) % (i - j - 2))

(b) (i -3 * j) % (c -2 * d) / (x -y)

(c) -(i + j)

(d) ++i

(e) j++

(f) --j

(g) --x

(h) i <= j + 1

(i) c + 1>d

(j) x <= y

(k) j != 9

(l) c = = 79

(m) 4 * (i + j) > 'e'

(n) (2 / x + y) = = 0

(o) 100 * x + (y = = 0)

(p) 100 * x + y = = 0

(q) !(i <= j)

(r) !(c = = 99)

(s) !(x > 0)

(t) (i > 0) && (j <= 6)

(u) (i >0) | | (j < 6) * (y) * (x > y) && (i > 0) | | (j < 4)

(v) ((x >= y) | | (i < 0)) && (j < 4)

Unlike other structured programming languages such as Pascal or FORTRAN, C treats assignment of values to a variable to be result of evaluation of the assignment operator(=). The assignment of values to an identifier is done in the following way:

*<identifier> = <expression>;*

i = 15;

j = 17;

m = 8;

x = i * 3 + j - 5; (x gets 57)

k = (i = i + j * 4) - (m / 2); (here assignment operator is used in the right expression too. k gets 79)

The following is an example of multiple assignment.

`i = j = 9; (is equivalent to j = 9; i = j;)`

Note that the associativity of assignment operators is from right to left, hence assignments are carried out from right to left.

The compound assignment operators help in writing compact expressions.

For example, the statement`c = c + 5;`

can be written as`c += 5;`

Similarly,`f = f * (g + h);`

can also be written as`f *= (g+h);`

or simply`f *= g+h;`

In C, when in an expression, an operator has operands of different data types, before expression evaluation, data type conversion takes place. The conversion is done in a manner so that all operands are converted to a common data type according to a defined set of rules. An operand, which can take up values of a narrower domain is automatically converted into another operand of wider domain without losing important information, such as converting an integer to floating point in an expression like f + i (where f is a floating point variable and i is of integer type).

Type conversion of operands helps in preventing data loss. Such data loss can occur when an attempt is made to assign a wider operand (like a floating data) into a narrower one (like int).

Since *char* is internally a small integer, the operands of char data type can be extensively used in character arithmetic allowing considerable flexibility in certain kinds of character conversions.

Many operators cause conversions and yield result types in a similar way. The effect is to bring operands into common type, which is also the type of the result. This approach is known as usual arithmetic conversion, and is carried out with the help of the following rules:

- if either operand is long/double, convert the other to long/double.
- if either operand is double, other operands are converted to double, and the result is a double.
- if either operand is float, convert the other to float.
- char and short get converted to int.
- if either operand is long, convert the other to long.

The automatic conversion of data type according to the above mentioned set of rules may cause data loss in some cases.Consider the following example:

If **f** is a float and **i** is an int, then

`f = i;`

would cause conversion of **i** to a floating point value before assigning to **f**.

But in

`i = f;`

the conversion of floating point value of **f** to int will cause truncation of its fractional part.

Consider another example:

float f;

int i=5, j=2;

f = i/j;

int i=5, j=2;

f = i/j;

The above expression will evaluate as follows. First i/j will be evaluated. Since both i & j are int type operands around the operator /, there will be no type conversion and as you know integer division results in the quotient being returned (remainder is truncated), hence the result of i/j will be 2 and not 2.5.

Now, this result becomes the right operand for the operator =, with its left operand being f. Since, f is float and the result of i/j (viz. 2) is int, the right operand will be converted to float before assignment. Thus 2 converted to float will become 2.0 and not 2.5. So the fractional part of the integer division is lost despite type conversions.

Explicit type conversion can be forced in any expression, using a unary operator called a **cast**. Such type casting is expressed as,`(cast data type) expression`

. When the expression is converted to the named data type it may be treated as if the expression was assigned to a variable of the specified type.

If **i** and **f** are floating point variables, the expression`(i + f) % 2;`

is invalid since modulus (%) operator operates only on integer operands. Since in this expression, the first operand, viz. (i+f), is of type float rather than an int, you need to do explicit type conversion to convert it to type int before expression evaluation. To do this, the left operand can be explicitly type casted as shown here`(int)(i + f) % 2`

. This forces the result of the left operand (i + f) to become int, making it valid for modulus operation.

Consider a C program having the following declarations:

`int a, b;`

long l;

short k;

float x;

double d;

char c;

Identify the data type of each of the following expressions:

(a) a * c | (d) (int)d +l | (g) a + l + b | ||

(b) x + c | (e) a * x | (h) –k + c | ||

(c) d + x | (f) k - b | (i) l + c |

Simple conditional operations can be performed with a conditional operator`? :`

. A conditional expression uses the conditional operator and is written in the following manner.

`(expression 1) ? (expression 2) : (expression 3);`

The evaluation of such an expression begins with the evaluation of expression 1. If the evaluation of expression 1 returns true (i.e. returns a non-zero value) then expression 2 is evaluated, otherwise expression 3 is evaluated.

max = (a > b) ? a : b; (compares a and b and returns the higher value to max)

result = (a == 0) ? 0: b/a; (prevents division by zero)

For a C program having the following declarations and initial assignments:

`int i = 9, j = 5, k;`

float x = 0.05, y = -0.001, z;

char a, b = 'b', c = 'c', d = 'd';

Determine the value of each of the following assignment expressions. Use the values originally assigned to the variable for each expression.

(i) | k = (i + j) / y | (ii) | i += (j - 3) | |

(iii) | z = (x + y)/ y | (iv) | k = z = y | |

(v) | k = (j ==6) ? i : j | (vi) | i = -j | |

(vii) | k = (j>3) ? i : j | (viii) | k *= (x * y) | |

(ix) | y -= -x | (x) | z = (x > 0.1) ? x : d | |

(xi) | x *= 2 | (xii) | z = k / (j +1) | |

(xiii) | i /= j | (xiv) | a = (c < d) ? c : d | |

(xv) | a = b = d | (xvi) | i -= (j >= 3) ? j : i |

The following table shows operator precedence (in decreasing order) and also associativity of the operators. As you will see, the unary operators have highest precedence whereas assignment operator has least precedence. The operator precedence can be changed in an expression by enclosing the operation and its operand(s) in a parenthesis.

Operator Category | Operators | Associativity |
---|---|---|

unary operator | - ++ -- ! sizeof (type) | R –> L |

arithmetic operator multiply, divide and remainder | * / % | L –> R |

arithmetic operator add and subtract | + - | L –> R |

relational operators | < <= > >= | L –> R |

equality operators | == != | L –> R |

logical and | && | L –> R |

logical or | || | L –> R |

conditional operator | ? : | R –> L |

assignment operator | = += -= *= /= %= | R –> L |

Enter compile and run the following C programs and check the output they produce.

/* this program demonstrates expression evaluation */ #include <stdio.h> main() { int i,j,resint; float f,resflt; double d,resdbl; i = 10; j = 4; resint = i * j - i / j + i % j + i - j; printf("\nThe result is %d\n", resint); resint = i * ((j - i) / j) + (i % j + i) - j; printf("The result, after using parenthesis, is %d\n",resint); d = 1295.5; f = 5.5; resdbl = d/f; printf("The result is (LHS is double) %f\n",resdbl); resdbl = d/f; printf("The result is (LHS is int) %d\n",resint); resdbl = (float)i /j; /*usage of type cast operator */ resint = i / j; printf("The result is (using type cast) : %f\n",resdbl); printf("The result is (integer division) : %d\n",resint); }

/* demonstrate operators ++, --, compound assignment operator */ #include <stdio.h> main() { int a, b,c,d; a = 18; b = 6; c = 3; d = d + (c + 1); /* expression A */ printf("\nExpression A generates result %d\n\n",d); d += (c + 1); /* compound assingnment (Expression B)*/ printf("Expression B generates result %d\n\n",d); d = c++; /* Expression C */ printf("Expression C generates result %d\n",d); printf("At the end of expression C the content of variable c is %d\n\n",c); d = c++; /*Expression D*/ printf("Expression D generates result %d\n",d); printf("At the end of expression D the content of variable c is %d\n\n",c); d = a++ - --b + --a + --c; /*Expression E */ printf("Expression E generates result %d\n",d); }

Execute the C program given below with the following data and examine the result:

Name | Basic Salary | Grade |
---|---|---|

Navin | 5000.00 | M |

Rajdeep | 3500.00 | E |

Arun | 4000.00 | M |

Prashanna | 2500.00 | C |

Where **M** is for *Manager*, **E** for *Engineer* and **C** for *Clerk*.

/* This program demonstrates the usage of relational operators in a C program */ # include<stdio.h> main() { char name[21]; //name of the employee(maximum 20 characters) float basic; //basic salary of an employee char grade; //grade are like A, B and C printf("\nEnter name :"); gets(name); fflush(stdin); printf("\nEnter basic :"); scanf("%f",&basic); fflush(stdin); printf("\nEnter grade :"); scanf("%c",&grade); fflush(stdin); /* Now increase basic by 500 for employees of grade E & C if their current basic is less than 5000 */ basic = (grade == 'E' || grade == 'C') && basic < 5000 ? basic + 500:basic; printf("\nName : %s \nGrade : %c\nBasic : %.2f\n", name,grade,basic); }

Enter, compile and run the following programme in C. Justify the output produced by the programs based on the precedence of operators and conversion rules in C.

# include<stdio.h> main() { int a; float b,c; a = 100 + 5/10 * 100/4 -25; b = 5* 5/10 * (100 + 25 % 4) - (200 + 2); c = -5 * 90/10 + ((4/2 + 59 % 15) + (30 * 2 + 5.5)) /16; printf("a = %d, b = %f, c = %f\n", a,b,c); }

# include<stdio.h> main() { int a = 10, p; float b = 10.25, q; double c = 5.78521, r; p = (int) b/2; q = (float) a * 2.5; r = (double)(b * 3./7); printf("%d %f %f\n",p,q,r); }

//Program to find the minimum of 4 numbers # include<stdio.h> main() { int a,b,c,d,e,f,min; printf("Enter the four numbers \n"); scanf("%d %d %d %d", &a, &b, &c, &d); e = (a < b)? a:b; f = (c < d)? c:d; min = (e < f)? e:f; printf("\nThe minimum among four values given is %d\n", min); }

//Another approach to find the minimum of 4 numbers # include<stdio.h> main() { int a, b, c, d, e, f, min; printf("Enter the four numbers \n"); scanf("%d %d %d %d", &a, &b, &c, &d); if(a < b) e = a; else e = b; if(c > d) f = c; else f = d; if(e < f) min = e; printf("The min value is %d\n", min); }

//Find the number between 1 to 50 that is divisible by both 5 and 7 #include<stdio.h> main() { int i; for(i = 1; i <= 50; i++) { if(( i % 5 == 0) && (i % 7 == 0)) printf("The number divisible by both 5 and 7 is %d\n",i); } }

comments powered by Disqus

Elements of the C Language - Identifiers, Keywords, Data types and Data objects

How to move your Email accounts from one hosting provider to another without losing any mails?

Self Referential Data Structure in C - create a singly linked list

How to resolve the issue of receiving same email message multiple times when using Outlook?

Moving Email accounts from one cPanel server to another

Elements of the C Language - Identifiers, Keywords, Data types and Data objects

Mosquito Demystified - interesting facts about mosquitoes

What is a Firewall and why is it important for network security?

**Rajeev Kumar**

CEO, Computer Solutions

Jamshedpur, India

Rajeev Kumar is the primary author of How2Lab. He is a B.Tech. from IIT Kanpur with several years of experience in IT education and Software development. He has taught a wide spectrum of people including fresh young talents, students of XLRI, industry professionals, and govt. officials.

Rajeev has founded Computer Solutions & WebServicesWorldwide.com, and has hands-on experience of building variety of web applications and portals, that include - SAAS based ERP & e-commerce systems, independent B2B, B2C, Matrimonial & Job portals, and many more.

Copyright © How2Lab.com. All rights reserved.