Module 2. Basic components of ‘C’ programming language
Lesson 7
OPERATORS AND EXPRESSIONS – PART – I
(Arithmetic, Assignment and Relational Operators)
7.1 Arithmetic Operators
All the basic arithmetic operations such as addition, multiplication, division, subtraction and remainder of integer division calculation can be carried out in ‘C’. The arithmetic operators are given in Table -7.1.
Table 7.1 ‘C’ Arithmetic operators
Serial Number |
Operator |
Description |
|
+ |
Addition or Unary Plus |
|
- |
Subtraction or Unary Minus |
|
* |
Multiplication |
|
/ |
Division |
|
% |
Modulus Operator (Remainder after integer division) |
Note that there is no exponentiation operator in ‘C’. However, ‘C’ provides an inbuilt function, pow (see Table-14.1 for details) for the purpose. The operands connected through arithmetic operators must be numeric values, i.e., integer, floating-point or characters (recall that the character constants represent integer values as determined by the machine’s character set). The modulus operator expects both the operands to be integers as well as the second operand to be nonzero. Similarly, the division operator requires the second operand to be non-zero. Evidently, both unary as well as binary operators are supported by ‘C’. Unary operation is performed on a single operand, e.g., the unary minus (-) operator applied on the number 5 will produce the resultant value as -5. The operators follow certain precedence rules similarly as the rules of algebra in mathematics. For example, the following expressions demonstrate the use of various arithmetic operators:
|
|
|
|
|
Here a, b, c, x and y are known as operands. The modulus operator is a special operator in ‘C’, which evaluates the remainder of the operands after division.
7.2 Integer Arithmetic
When an arithmetic operation is performed on two whole numbers or integers then such an operation is called integer arithmetic. It always produces an integer (i.e., truncating the decimal portion of the quotient) as a result.
Illustration
Consider x = 27 and y = 5 be two integer numbers. Thus, the results of various arithmetic operations performed on these numbers are shown below.
Expression |
Value |
Expression |
Value |
Expression |
Value |
|
|
|
|
|
|
|
|
|
|
|
|
Note that the fractional part is truncated during integer division.
7.3 Floating-point Arithmetic
The process of applying an arithmetic operation on two real numbers is called floating-point arithmetic. The floating-point results can be truncated according to the properties requirement. Note that the modulus operator is not applicable to floating-point arithmetic operands.
Illustration
Consider x = 14.0 and y = 4.0 be two real numbers. Thus, the results of various arithmetic operations performed on these numbers are shown below.
Expression |
Value |
Expression |
Value |
Expression |
Value |
Expression |
Value |
|
|
|
|
|
|
|
|
Note that the interpretation of the remainder operation is ambiguous when one of the operands is negative. Most versions of ‘C’ assign the sign of the first operand to the remainder. Most versions of ‘C’ ascertain the sign of the remainder as a = ( (a/b) * b) + (a%b); however, this aspect is not mentioned in the formal definition of the language. Thus, the aforesaid condition will always be fulfilled regardless of the signs of the operands a and b. Novice programmers should be careful while using the modulus operator when one of the operands is negative.
Illustration
Consider a and b be two integer variables containing values 11 and -3, respectively. Several arithmetic expressions involving these variables and their resultant values are given below.
Expression |
Value |
Expression |
Value |
|
8 |
|
14 |
|
|
|
|
|
2 |
|
|
Operands with distinct data types commonly go through type conversion before the expression attains the final value. Generally, the final result is expressed in the highest precision possible, consistent with the data types of the operands. The following rules apply when neither operand is unsigned.
7.3.1 Conversion rules
These rules apply to arithmetic operations between two operators with dissimilar data types. There may be some variation from one version of ‘C’ to another.
1. If one of the operands is long double, the other will be converted to long double and the result will be long double.
2. Otherwise, if one of the operands is double, the other will be converted to double and the result will be double.
3. Otherwise, if one of the operands is float, the other will be converted to float and the result will be float.
4. Otherwise, if one of the operands is unsigned long int, the other will be converted to unsigned long int and the result will be unsigned long int.
5. Otherwise, if one of the operands is long int and the other is unsigned int, then:
a. If unsigned int can be converted to long int, the unsigned int operand will be converted as such and the result will be long int.
b. Otherwise, both operands will be converted to unsigned long int and the result will be unsigned long int.
6. Otherwise, if one of the operands is long int, the other will be converted to long int and the result will be long int.
7. Otherwise, if one of the operands is unsigned int, the other will be converted to unsigned int and the result will be unsigned int.
8. If none of the above conditions applies, then both operands will be converted to int (if necessary), and the result will be int.
Note that some versions of ‘C’ automatically convert all floating-point operands to double-precision.
Further, note that the ‘C’ operators are grouped hierarchically according to their precedence (i.e., the order of evaluation) as shown in Table-7.2.
Operations with higher precedence are evaluated prior to the lower precedence operations. However, the normal order of evaluation can be transformed by using parentheses, e.g., the expressions, a – b/c * d and (a – b)/(c * d) will produce different results. At times, it is a good practice to use parentheses to simplify an expression, even if the parentheses may not be required. On the other hand, very complex expressions should be avoided as these may be error-prone.
Table 7.2 ‘C’ operators in order of precedence (highest to lowest) along with their associativity that indicates in what order operators of equal precedence in an expression are applied
Operator Group |
Description |
Associativity |
() |
Parentheses (function
call) (see Note 1) |
Left-to-Right |
++
-- |
Prefix increment/decrement |
Right-to-Left |
* / % |
Multiplication/division/modulus |
Left-to-Right |
+ - |
Addition/subtraction |
Left-to-Right |
<< >> |
Bitwise shift left, Bitwise shift right |
Left-to-Right |
<
<= |
Relational less than/less
than or equal to |
Left-to-Right |
== != |
Relational is equal to/is not equal to |
Left-to-Right |
& |
Bitwise AND |
Left-to-Right |
^ |
Bitwise exclusive OR |
Left-to-Right |
| |
Bitwise inclusive OR |
Left-to-Right |
&& |
Logical AND |
Left-to-Right |
|| |
Logical OR |
Left-to-Right |
?: |
Ternary conditional |
Right-to-Left |
= |
Assignment |
Right-to-Left |
, |
Comma (separate expressions) |
Left-to-Right |
Note 1:
Parentheses are also used to group sub-expressions to force a different precedence; such parenthetical expressions can be nested and are evaluated from inner to outer.
Note 2:
Postfix increment/decrement have higher precedence, but the actual increment or decrement of the operand is delayed (to be accomplished sometime before the statement completes execution). So in the statement y = x * z++; the current value of z is used to evaluate the expression (i.e., z++ evaluates to z) and z only incremented after all else is done.
7.4 Mixed-mode Arithmetic
The process of executing an arithmetic expression involving two different kinds of operand, i.e., a real operand and an integer operand is called mixed-mode arithmetic. In case one of the operands is of floating-point type, the result is always of the type, real. For instance, 15/10.0 = 1.5.
7.5 Assignment Operators
‘C’ assignment operators are used to assign the value of an expression to an identifier. The syntax of assignment operators is:
Examples:
Following typical assignment expressions depict use of the commonly used
assignment operator, ‘=’.
(i) a = 3 (ii) delta = 0.001 (iii) area = length * breadth
The first assignment expression causes the integer value 3 to be assigned to the variable a, and the second assignment causes the floating-point value 0.001 to the variable delta. The third assignment causes the value of the RHS arithmetic expression being assigned to the Left Hand Side (LHS) variable, i.e., the value of the expression length * breadth is assigned to the variable area.
Note: The assignment operator ‘=’ and the equality operator ‘==’ are distinct. Hence, these operators are used for their specific purpose only and are not interchangeable. If the two operands in an assignment expression are of different data types, then the value of the expression on RHS will automatically be converted to the type of the identifier on LHS. In some cases, this automatic type conversion can cause an alteration of the data being assigned. Some instances for better comprehension of the students are:
· A floating-point value may be truncated if assigned to an integer identifier
· A double-precision value may be rounded if assigned to a single-precision floating-point identifier
· An integer quantity may be changed if assigned to a shorter integer identifier or a character identifier, i.e., some high-order bits are lost
· The value of a character constant assigned to a numeric-type identifier will be dependent upon the particular character set in use, which may cause inconsistencies from one version of ‘C’ to another version.
Hence, the careless use of type conversions is a frequent source of error among the beginners.
Examples
Consider i as an integer variable.
Assignment Expression |
Resultant Value |
|
|
|
|
|
|
Now, consider two integer variables, i and j; contains a value of 5. Several assignment expressions that make use of these variables are given below for illustration:
Assignment Expression |
Resultant Value |
|
|
|
|
|
|
|
|
Further, assume that i is an integer variable and ASCII character set is applicable.
Assignment Expression |
Resultant Value |
|
|
|
|
|
|
|
|
‘C’ supports multiple assignments as follows:
|
These assignment operations are performed from right to left. Thus, the aforementioned multiple assignment is equivalent to:
That is, right to left nesting of multiple assignments is possible.
An illustration
Let i and j are two integer variables. The multiple assignment expression
will cause the value 3 to be assigned to both i and j. To be more precise, the value 3 is first assigned to the variable j followed by the assignment to i. Similarly, the multiple assignment expression
assigns the integer value 3 to both the variables, i and j.
Beside ‘=’ operator,
‘C’ supports five more assignment operators such as +=, -=, *=, /= and %=.
All the five operators are discussed here. Consider the operator +=. The assignment expression
is
equivalent to
Similarly,
is equivalent
to
and so on for all these five assignment operators.
Note that expression 1 is usually a variable or an array element.
Example
Consider i and j
as integer variables containing values 5 and 7, respectively; and f and g
are floating-point variables having values 5.5 and -3.25,
respectively. Several assignment expressions making use of these variables are
shown below for illustration. Each expression utilises the values of the
variables, i, j, f
and g.
Expression |
Equivalent Expression |
Final Value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Each assignment operator has a priority and they are
evaluated from right to left based on its priority. The priority of assignment
operators is: +=, -=, *=, /= and %=.
Assignment operators have right to left associativity. The unary operations,
arithmetic operations, relational and equality operations and logical
operations are all carried out before assignment operations.
Example
Consider
that x, y
and z
are integer variables, which have been assigned the value 2, 3 and
4, respectively.
The expression
This
expression assigns the value of -8
to the variable, x.
It is interesting to note the order in which the
expression is evaluated. You know that the arithmetic operations precede the
assignment operation. Therefore, the expression (y+z) will be evaluated first of all thereby producing the
value, 7;
then this value is multiplied by -2,
yielding -14;
and this value is further divided by 3 and truncated due to integer division, resulting in -4. Finally, this truncated quotient is multiplied by
the original value of x
(i.e., 2)
to yield the final result of -8.
7.6 Relational Operators
Relational operators are used to compare two values. These
operators are used in Boolean conditions or expressions called logical
expressions. The resulting expressions will be of the integer type as TRUE is
represented by the integer value 1and FLASE is represented by the value 0. The
relational operators supported by ‘C’ are given in Table-7.3.
Table 7.3 ‘C’ Relational operators
Serial Number |
Operator |
Description |
Relational Operators |
||
|
< |
Less than |
|
<= |
Less than or equal to |
|
> |
Greater than |
|
>= |
Greater than or equal to |
Equality Operators |
||
|
== |
Equal to |
|
!= |
Not equal to |
The relational operators as shown at serial numbers, 1
to 4 under Table-7.3, fall within the same precedence group and this is lower than
the arithmetic as well as unary operators. The associativity of these operators
is left to right. There are two equality operators as mentioned at serial
numbers 5 and 6 under Table-7.3, which are closely associated with the
relational operators. The equality operators fall into a separate precedence
group beneath the relational operators. The associativity of these operators is
also left to right.
An illustration
Consider that it is required to compare, for equality, the marks
obtained by two students in a course on Computer Programming. Suppose, the
marks obtained by the first student (denoted by variable, student_1) are 50; and that of the second student (denoted by variable, student_2) are 47. Now, it is to compare the two for equality. This can be
realised by using an appropriate relational operator as follows:
student_1==student_2
Obviously, the resultant will be FALSE with resultant
value as
0.
Example
Suppose i, j
and k
are integer variables containing values 1, 2
and 3,
respectively. Several logical expressions involving these variables are given
below:
Expression |
Description |
Resultant Value |
|
true |
1 |
|
true |
1 |
|
false |
0 |
|
false |
0 |
|
true |
1 |
While carrying out relational and equality operations,
operands that differ in type will be converted in accordance with the
conversion rules discussed earlier (see Sub-section 7.3.1).
Example
Suppose that i i s an integer variable containing value as 7; f
is a floating-point variable having value a 5.5; and c is a character type variable that represents the
character ‘w’. Several logical expressions showing use of these
variables are given below. Each expression comprises of two different type
operands. Also, it is assumed that ASCII character set is applicable.
Expression |
Description |
Resultant Value |
|
true |
1 |
|
false |
0 |
|
true |
1 |
|
true |
1 |
|
false |
0 |
7.7 Structure of a Typical ‘C’ Programme
Every ‘C’ programme consists of one or more modules
called functions. One of the functions must be named as main.
The programme will always begin with executing the main function, which
may access other functions. Any other function definitions must be defined
separately; either ahead of or after the main function (refer
to the Module-IV for further details on functions). Each function must contain
a function heading, which consists of the function name followed by an optional
list of arguments enclosed in parentheses, a list of argument declarations if
arguments are included in the heading and a compound statement, which comprises
the remainder of the function.
An illustration
A typical ‘C’ programme demonstrating
various ‘C’ operators is given below.
/* A programme demonstrating ‘C’ arithmetic operators */
#include
<stdio.h>
void main()
{
int x = 10, y = 20;
printf("x = %d\n",x);
printf("y = %d\n",y);
/* demonstrates = and + operators */
y = y + x;
printf("y = y + x; y = %d\n",y);
/* demonstrates - operator */
y = y - 2;
printf("y = y - 2; y = %d\n",y);
/* demonstrates * operator */
y = y * 5;
printf("y = y * 5; y = %d\n",y);
/* demonstrate / operator */
y = y / 5;
printf("y = y / 5; y = %d\n",y);
/* demonstrates modulus operator % */
int remainder = 0;
remainder = y %3;
printf("remainder = y %% 3; remainder =
%d\n",remainder);
/* keeps console screen until a key stroke */
char key;
scanf(&key);
}
Output produced by the
above programme
x = 10
y = 20
y = y + x; y = 30
y = y - 2; y = 28
y = y * 5; y = 140
y = y / 5; y = 28
remainder = y % 3; remainder = 1
7.8 Types of Programme Error
There are three basic types of programme
error, viz., syntax error; semantic error and logical error. Programme
errors are also referred to as programme bugs. The term ‘bug’ was so coined
that one of the earliest programme errors ever detected involved a moth flying
into the computer causing short-circuiting of the electronics. Hence, the
process of removing programme errors is called debugging. While that goal is
laudable, every programmer, no matter how seasoned, writes programmes that
contain errors. However, a skilled programmer can detect, isolate and correct
programme errors more quickly than a less skilled programmer. Also, experienced
programmers do make fewer programming errors simply because of their
experience! The lesson here is that you should expect to make a lot of
programme errors in the beginning as every beginner does.
View
each programme error as a challenge and learn from the experience. Let us take
a quick overview of the three types of programme error.
Syntax Errors
The
first type of error is a syntax error. You already know that syntax errors are
caused when you don’t obey the syntax rules. A common syntax rule you might
make in the beginning is forgetting to terminate each programme statement with
a semicolon.
Logic Errors
Logic errors are those errors that remain
after all the semantic and syntax errors have been removed. Usually, logic
errors manifest themselves when the result the programme produces doesn’t match
the result your test data suggest it should produce. Generlly, logic errors are
found in the Process. Logic errors occur when you implement the algorithm for
solving the problem incorrectly.
The
key to fixing logic errors is to be able to reproduce the error consistently. A
repeatable logic error is much easier to track down and fix than an error that
appears to be occurring randomly.
Semantic Errors
A semantic error occurs when you obey the
syntax rules of the language but are using the statement out of context. For
example, a sentence in English is expected to have a noun and a verb. Consider
the sentence “The dog meowed”. This sentence does obey the rules of having
a noun and a verb, but the context of the sentence is out of whack. Dogs don’t
meow; therefore, the context of the statement is incorrect. The error message,
I showed you earlier: the name i does not exist in the current context refers to a type of semantic
error. There may well be a variable named i defined somewhere in the programme, but
it is not currently in scope. That is, you are trying to use i when it is out of scope.