C++ Hand Notes
C++ Hand Notes
* Memory Unit
* Input Unit
* Output Unit
Ever since the inception of computers, hundreds of programming languages have been
designed and implemented. Most programmers never use more than a few languages.
However, a study of the broad concepts, underlying programming language design helps
a programmer.
3
The design and implementation of programming languages has undergone rapid evolution.
There are several aspects that determine the preference of programmers.
- Clarity.
- Simplicity.
- Standards compliance.
Those languages that are suitable for a wide range of applications are called general
purpose languages. Specific purpose languages are tailor made for particular application
domains. These languages have notations that cater to domain specific applications. Hardware
Description Languages used to describe electronic circuits are examples for specific purpose
languages. This lesson focuses on general purpose programming languages.
4
- Hardware
- Operating environment.
- Applications.
- Standardisation.
Table 1.1 traces evolution or programming languages highlighting the major influences
at each stage.
1956-1960 Small, Slow and Expensive computers. mass storage devices, Compilers,
Interpreters code optimization Dynamic Storage management, Notations
for grammars, List processing
1966-1970 Instruction sets for computers with varying Size, Speed, expensive mass
storage, Time sharing, Interactive operative environment, Micro
programming, Optimizing compilers, Standard languages flexibility.
Today programming languages cater to wide ranging operating environment. Table 1.2
Outlines the influence of Operating Environment on language design.
The distributed and real-time environments are categorized under embedded systems.
The software industry witnessed a rapid increase in the complexity of software problems. Today,
thousands of programmers are needed to solve a given problem. As a consequence, different
models for expressing the solution have been evolved. The object-oriented methodology caters
to large programming have been evolved. The object-oriented methodology caters to large
programming efforts. Also, special considerations play an important role in designing languages
for interacting databases.
When a Central Processing Unit (CPU) comes off the assembly line, the built-in capabilities
are arithmetic and logical operations, input and output and some control functions. A
corresponding set of instructions is also supported. It is to be noted that every brand of CPU
can have a distinct set of instructions.
These languages also known as machine languages are closest to the machine
interpretable form. The interpretable of the machine was represented using binary codes called
‘opcods.’ The data was required by the instruction is called an operand’. There are a few
6
standard formats to specify the requisite operand (s). The operands are also expressed as
string of binary sequences.
Programming and usage of the machine was only for people well versed with the machine.
Moreover it was highly error prone and tedious. For example a Machine language segment is
as follows:
0100 01010000
0101 01010010
0109 01011010
It was a feeble attempt in making programming friendly. The ‘opcode and the operands
are represented as pre-specified symbolic names. These names which look like English words
are called mnemonics. Every mnemonic has a one-to-one correspondence to the machine
instructions (opcodes).
The operands are specified using symbolic addresses. A software program called
assembler converts the program in assembly language into machine language. The mnemonics
can be unique for a given brand of the CPU. For example an language segment is as follows:
7
Mnemonic Operands
PUSH AX
PUSH DX
MOV AH,9
INT 21H
These are usually called high level languages. Ever since the inception of computers,
efforts were on to design programming language that resemble natural language. These
language would permit ease of learning, natural ability to express solutions and team efforts.
Moreover, they are hardware independent. A compiler or an interpreter translates the programs
into machine language. Every high level language statement is translated into a sequence of
machine language instructions. Some of the popular third generation languages are BASIC,
FORTRAN, COBOL, PASCAL, C, ADA, C+ + etc.
Every high level language programme is also a sequence of statements. Each statement
has a specific format or syntax. The grammar of a language is a notation to specify the syntax
of various legal sentences of the language. The meaning of the sentence in terms of the
machine instruction sequence is called ‘semantics’ of the statement.
the programmer. Standard compiler writing tools and techniques ensured that they get correctly
translated into the machine code.
Interactions with databases are typically in the form of short and specific enquiries. A
standard sequence of operations are clubbed together in the form of a statement called ‘Query’.
A collection of such query formats is called a query languages. As the target applications are
database oriented these languages have nice applications base.
The problem in application domains such as Intelligence are complex and require special
supporting features to efficiently express the solutions. Fifth generation languages are designed
to cater to these needs. Some popular fifth generation languages are LISP, PROLOG,
SMALLTALK etc.
6) Database Methodology
The reduction in price of computer systems and availability of inexpensive mass storage
mechanisms paved way for extensive database applications. These databases form the life-
line of organizations across the globe.
CREATE a database
MODIFY data
9
GENERATE reports
SECURITY of access
Interactions with database are typically in the form of short and specific enquiries. A
standard sequence of operations are clubbed together in the form of a statement called ‘Query’.
Often the types of queries are also innumerable. A collection of such query formats is called a
Query language. An easy interface called the front-end of a database helps naive users in
constructing queries.
The languages confining to this paradigm are the fourth generation languages. The Chief
characteristics of these languages are as follows:
Non-procedural code
Automated documentation
10
Fast prototyping
Standards conformance
Ease of maintenance
a) A prescribed set of well - defined rules or processes for the solution of a problem in
a series of step is Flow Chart.
This flexibility allows C to be used for systems programming (e.g. for writing operating
systems) as well as for applications programming (e.g. for writing a program to solve a
complicated system of mathematical equations, or for writing a program to bill customers)
11
C is characterized by the ability to write very concise source programs, due to the large
number of operators included within the language. It has a relatively small instruction set,
though actual implementations include extensive library functions which enhance the basic
instructions. Furthermore, the language encourages users to write additional library functions
of their own. Thus, the features and capabilities of the language can easily be extended by the
user.
C compilers are commonly available for computers of all sizes, and C interpreters are
becoming increasingly common. The compilers are usually compact, and they generate object
programs that are small and highly efficient when compared with programs compiled from
other high-level languages. The interpreters are less efficient, though they are easier to use
when developing a new program. Many programmers begin with an interpreter, and then switch
to a complier once the program has been debugged (once all of the programming errors have
been removed).
Another important characteristic of C is that its programs are highly portable, even more
so than with other high-level languages. The reason for this is that C relegates most computer
dependant features to its library functions. Thus, every version of C is accompanied by its own
set of library functions, which are written for the particular characteristics of the host computer.
These library function are relatively standardized. However, each manner from one version of
C to another. Therefire, most C programs can be processed on many different computers with
little or no alteration.
1) History of C
C was originally developed in the 1970’s by Dennins Ritchie at Bell Telephone Laboratories.
It is an outgrowth of two earlier languages, called BCPL and B, which were also developed at
Bell Laboratories. C was largely confined to use within Bell Laboratories until 1978, when Brian
Kernighan and Ritchie published a definitive description of the language (K&RC)
Following the publication of the K&R description, computer professionals, with C’s many
describable features, began to promote the use of the language. By the mid 1980’s the popularity
of C had become widespread. Numerous C compilers and interpreters had been written for
12
computers of all sizes and many commercial application programs had been developed.
Moreover, many commercial software products that were originally written in other languages
were rewritten in C in order to take advantage of its efficiency and its portability.
2) Structure of a C Program
Every C program consists of one or more functions, one of which must be called main.
The program will always begin by executing the main function. Additional function definitions
may precede or follow main.
(a) A function heading, which consists of the function name, followed by an optional list of
argument enclosed in parentheses.
The arguments are symbols that represent information being passed between the function
and other parts of the program. (Arguments are also referred to as parameters).
Each compound statement is enclosed within a pair of braces, i.e.{and}. The braces may
contain combination of elementary statements (called expression statements) and other
compound statements. Thus, Compound statements may be nested, one within another. Each
expression statement must end with a semicolon(;).
Comments may appear anywhere within a program, as long as they are placed within
delimiters /*and*/
13
such statement are helpful in identifying the program’s principal features or in explaining
the underlying logic of various program features.
Example:
This is an elementary C program that reads the temperature in centigrade and converts
it into Fahrenheit.
1. The program is typed in lower case. Most comments are typed in upper case.
2. The first line contains a reference to a special file (called stdio.h) which must be included
in the program when it is compiled.
3. The second line is comment that identifies the purpose of the program.
4. The third line is a heading for the function main. The empty parentheses following the
name of the functions indicate that this function does not include any arguments.
5. The remaining five lines of the program are indented and enclosed within a pair of braces.
These five lines comprise the compound statement within main.
6. The first indented line is a variable declaration. It establishes the symbolic names c and f
as floating point variables which are used to represent centigrade and Farenheit.
14
7. The remaining four indented lines are expression statements. The second indented line
(printf) generates a request for information (namely centigrade).
8. The fourth indented line is a particular type of expression statement called an assignment
statement. This statement cause the conversion of temperature in centigrade to
temperature in fareheit.
9. The last indented line (printf) causes the calculated value for the fareheit to be displayed.
The numerical value will be preceded by a brief label.
10. Note that each expression statement within the compound statement ends with a semicolon.
This is required of all expression statements.
11. Finally, the liberal use of spacing and indentation separate different parts of the program
into logically identifiable components, and the indentation indicates subordinate
relationships among various instructions. These features are not grammatically essential
but their presence is strongly encourages as a matter of good programming practice.
Execution of the program results in an interactive dialog such as that shown below:
Before concluding this lesson let us briefly examine some important characteristics of
well-written computer programs. These characteristics apply to programs that are written in
any programming language. They can provide us with a useful set of guidelines.
1. Integrity. This refers to the accuracy of the calculations. It should be less if the calculations
are not carried out correctly. Thus the integrity of the calculations is an absolute necessity
in any computer program.
2. Clarity. This refers to the overall readability of the program, with particular emphasis on
its underlying logic. If a program is clearly written, it should be possible for another
programmer to follow the program logic without undue effort. It should also be possible
for the original author to follow his or her own program after being away from the objectives
in the design of C is the development of clear, readable programs through an orderly and
disciplined approach to programming.
15
3. Simplicity. The clarity and accuracy of a program are usually enhanced by keeping thing
as simple as possible, consistent with the overall program objectives. In fact, it may be
desirable to sacrifice a certain amount of computational efficiency in order to maintain a
relatively simple, straight forward program structure.
4. Efficiency. This is concerned with execution speed and efficient memory utilization. These
are generally important goals, though they should not be obtained at the expense of
clarity or simplicity. Many complex programs require a trade off between these
characteristics. In such situations, experience and common sense are key factors.
5. Modularity. Many programs can be broken down into a series of identifiable subtasks. It
is good programming practice to implement each of these subtasks as a separate program
module. In C, such modules are written as functions. The use of a modular programming
design enhances the accuracy and clarity of a program, and if facilitates future program
alterations.
a) Every C program consists of one or more functions, one of which must be called
main.
1.5 Summary
(2) Discuss the major influences on programming languages in different time frames?
(4) What are the desirable program characteristics that enhance the program development
effectively?
17
LESSON - 2
VARIABLES AND EXPRESSION
Structure
2.1 Introduction
2.4 Constants
2.5 Summary
2.1 Introduction
In c, a quantity which may vary during program execution is called a variable. Variable
names are names given to the locations in memory of a computer where different constant are
stated. There locations can contain character, integer, real or any such constant.
- Constants.
The C character set consists of upper and lower case alphabets digits, special characters
and white spaces. The alphabets and digits are together called the alphanumeric characters.
Alphabets:
ABCDEF ............................... X Y Z
abcdef ............................... x y z
18
Digits:
0123456789
Special Characters:
* Identifier names must be a sequence of letters and digits, and must begin with a letter
* Name should not be the same as a keyword (such a int, char, void, if for, while, etc.).
Keywords are predefined by the language, and cannot be used by the programmer in any
19
way other than that specified by the syntax. The following keywords are predefined by the
C language.
do if static while
* C is case sensitive (i.e. upper and lower case letters are treated differently). Thus, the
names rate, Rate and RATE denote different identifiers. It is a general practice to use
lower or mixed case for variable and functions names, and upper case for symbolic
constants.
* For any internal identifier name ( an identifier declared in the same file or in a header
included in the current file), atleast the first 31 characters are significant in any ANSI C, C
compiler (it may be more in certain compilers, but never less)
2) Variables
A variable is an entity that has a value and is known to the program by a name. A variable
definition associates a memory location with the variable name. A variable can have only one
value assigned to it at any given time during the execution of the program. Its value may
change during the execution of the program.
Variable names are identifiers used to name variables. They are symbolic names given
to memory locations. A variables name consists of a sequence of letter and digits, the first
20
character being a letter. The rules that apply to identifiers (given above) also apply to variable
names. Examples of valid variable names are:
int an integer
Note: Precision refers to the number of significant digits after the decimal point.
Further, applying qualifiers to the above data types yield additional data types. A qualifier
alters the characteristics of the data type, such as its size or sign. The qualifiers that alter the
size are short and long. These qualifiers are applicable to integers, and yield two more data
types:
The exact sizes of these data types depend on the compiler. Details are given later in this
lesson. The qualifiers long can also be used along with double precision floating point type:
21
The sign qualifiers are signed and unsigned. The sign qualifiers are combined with the
integer data types (int, short int and long m) resulting in six more data types given below:
signed int
signed char
unsigned char
Normally, size qualifiers (short and long) cannot be applied to the data types char and
float, and sign qualifiers (signed and unsigned) cannot be applied to float, double and long
double.
4) Declare Variables
In C, you always have to declare a variable before using it. Before going into the details
of declaring and using the variable types, we need to understand how to input and output
simple strings. The following example illustrates the use of printf to output an integer.
void main ()
{int val;
val = 10;
The program is now explained line by line: int val; is the first statement in the function
main (). it declares the identifier val to be a variable of integer type. In declare a variable of
some type. Precede its name of the data type (float, char and so on). For instance, if a variable
f_val is to be declared a floating point number, then declare f_val as:
float f-val;
Coming back to the program, having declared val an integer, assign a value to it with the
statement:
val = 10;
Let us now examine the third statement inside the function main ( ):
This outputs, the value of the integer variable val. In the discussion that follows, we shall
use the word parameter to refer to any variable or constant that is passed to a function. Thus,
in the printf statement above, the first parameter is “%d” and the second parameter is val.
The first parameter passed to the function printf is always a string called the format string
enclosed in double quotes. In the above case “%d” is the format string. It tells printf that the
output is an int. The second parameter val provides the actual value to output.
Similarly, %f must be used as the format string to output floating point numbers, %c for
single characters, and so on. All the format types are discussed in detail in the next lesson.
Inside the format string, the % sign followed by a letter informs printf about the type of the
parameter to be output. But the contents of the format string are not restricted to this kind of
type-specifies. Let us examine the previous example again, this time adding something more
to the message.
# include <stdio.h>
void main ( )
23
{int i_var;
float f_var;
i_var = 10;
f_var = 100.3125;
From the program, it is observed that more than one parameter can be present, following
the format string in a printf statement. Inside the format string, %d and %f specify the type of
the variables to be output. They are called format specifiers. The first format specifier, %d
corresponds to the first parameter that follows the format string, i_var. It informs printf that
i_var is an integer. Similarly, the second one, %f specifies that f_var is a floating - point number.
The above example illustrates the fact that the output produced by printf is the same as
the format string, except that %d is replaced by the value of the parameter i_var, and %f by the
value of f_var. The first parameter passed to printf, “i_var is the format string, while %d and %f
inside it are the format specifiers.
To summarize, the parameters passed to the printf statement consist of a format string,
followed by any number of parameters. However, each parameter must have a format specifier
(%sign followed by a letter) corresponding to it, inside the format string.
In addition to specifying the type of the parameter, the format specifier in printf can also
perform the function of specifying how parameter must be output (for example, in decimal or
hexadecimal). The specifiers %d and %i can be used interchangeably to output integers. Thus,
the statement,
to get the same output. Also, note that % u and % x are used to output unsigned integers,
but there is a difference, % u outputs it in decimal, while %x outputs it in hexadecimal. To
illustrate this concept, a simple example that converts unsigned decimal numbers to hexadecimal
is given below. Underlined data in this book indicate user input. The function scanf in this
program is new, and is examined in the next section.
void main ()
RUN : 45
6) Reading Variables
The scanf function reads the values of variable from the standard input device (keyboard)
and stores them in variables. The example below inputs the again years and computes the
numbers of seconds you have lived. For simplicity, leap years have been ignored.
# include <stdio.h>
void main ( )
A sample session with the program is given below, where the user has input 21.
The statement
performs the task of reading the value of the variable years. Like the printf function, the
scan function accepts a format string as its first parameter. But, the second parameter years
(the variable whose value we want to read) is preceded by an ampersand (&). An ampersand
is not required in the case of printf. To understand this, it is necessary to consider a crucial
difference between the two functions. The function printf, whose task is to output, needs only
the value which has to be output. On the other hand, the scanf function stores the input value
in a memory location. To perform this, it must know the location of the variable in memory
(called the memory address of the variable) where the value has to be stored.
To understand the concept of memory address clearly, recall that the computer’s memory
consists of bytes. These bytes are numbered, starting with zero (i.e., the first byte is byte
number of, the second one is byte number 1, and so on). These numbers are called the address
of the bytes.
Each variable in a program occupies a certain number of 1 bytes of the memory. Consider
the floating point variable years in the above example. Assume that it occupies four consecutive
bytes numbered 3064, 3065 and 3067 in the memory. So, the address of years is 3064 (the
lowest numbered memory location). It is this address that scanf requires. In C. the address of
any variable is obtained by preceding the variable name by an ampersand (&)
26
The statement
The first parameter “%f” instructs scanf that a floating point numbers must be read. The
second parameter & years informs scanf the location in the memory where the value of the
floating point number entered by the user must be stored.
A character variable can hold one character, which can be any alphabet or symbol.
Characters in C are enclosed within single quotes. The following example illustrates the task of
assigning values to character variables.
void main ( )
chare c;
c = ‘#’;
which may be a letter, a digit, a punctuation mark, and so on. These character are represented
in the memory by a number, called the code of the character. For example, the code of the
letter A may be 65, that of letter B may be 66, and so on.
Actually, any number can represent the letter A, any other number can be used for B and
so on, but these numbers should be fixed by a coding convention. For example, when the
computer wants the printer to print the letter A, it actully sends the number 65 to the printer. The
important point here is that the printer must see the number 65 and print the letter A, and not
something else. Hence, the printer must also use the same codes as the computer, for all the
symbols. This led to the establishment of ASCII codes (ASCII: American Standard Code for
Information Interchange). ASCII codes are widely used all over the world to represent various
symbols in a computer. In C, the size of one character is 8 bits (one byte).
Here is a simple example that reads the ACII code of a number and prints out the symbol
associated with the code.
# include <stdio.h>
void main ()
{int code;
char symbol;
symbol = code
Run 1 :
Run 2 :
Input an ASCII code (0 to 127) : 50
The second run shows that just as the letter A is a symbol having as ASCII code, the digit
2 is also a symbol having an ASCII code of the digit 0 is 48, that of 1 is 49 and so on. To
illustrate, let us say that the computer has to print the number 3210. It sends the following
codes to the printer: 51 50 49 48
These are the ASCII codes of the digits 3,2.1 and 0, respectively.
symbol = code;
Assigns the value of the integer variable code to the character variable symbol. In the
printf statement,
%d is used to output its ASCII code contained in the integer code. The format specifier %
c is used to output the actual symbol corresponding to the value contained in the character
variable symbol.
char my_string [ 20 ]
Strings are enclosed within double quotes. Consider an example that assigns a string
and prints it on the screen. The format specifier for a string is % s, which can be observed in
the printf statement in the example below:
29
# include <stdio.h>
void main ( )
The format specifier % s is replaced by the value of the string constant. The output of the
program is as shown below:
my_string: 13 is unlucky.
The variable my_string is just a sequence of bytes in memory whose values are the
ASCII codes of each symbol of the string. The null character (a byte with value zero) is placed
at the end of the string. Giben below are the character of my_string and their values in memory.
String : 1 3 i s u n l u
String : c k y . /0
The number are the ASCII codes of the individual characters of the string (the ASCII
code of the letters is 115, that of y is 121 and so on). The value 0 appearing at the end is the
null character. It serves to terminate the string (i.e., marks the end of the string).
8) Qualifiers
Qualifiers modify the behavior of the variable type to which they are applied. We have
seen declarations such as
int i ;
This declaration specifies that i is an integer which takes both positive and negative
values, that is, i is a signed integer by default. The above declaration could also be written as
30
singed int i ;
but the qualifier signed is not necessary, since int is signed by default. If the variable i is
used to hold only positive values (for example, to hold the number of students in a class), we
declare:
unsigned int i ;
Here, the qualifier unsigned is applied to the data type int. This qualifier modifies the
behavior of the integer so that the number contained in a variable of this type is unsigned.
- Size qualifiers
- Sign qualifiers
Size qualifiers alter the size of the basic data type. There are two size of the basic data
type. There are two size qualifiers that can be applied to integers (i.e., to the basic type int):
short and long. In any ANSI C compiler, the sizes of short int, int and long int follow the restrictions
given below:
The size of an int must be greater than or equal to that of a short int
The size of a long int must be greater than or equal to that of an int
In most compilers available on DOS, the size of a short int and an int are the same, both
occupying 16 bits. A long int occupies 32 bits. But in 32 - bit compilers such as GNU C, an int
and a long int are of the same size (32 bits), while short int is 16 bits. On the other hand, almost
all UNIX compilers have short int of size 16 bits, int and long int being 32 bits.
Size of Operator
To find out the size of each type on your compiler, try the example below. It uses the size
of operator, that gives the size of any data type in bytes.
31
# include <stdio.h>
void main ( )
The output of this program when compiled with Borland’s compiler (Borland C Version
3.0) and run, gives the following output:
Size of an int is 2
On almost all UNIX systems, the program gives the following output:
Size of an int is 4
The name of the variable type is passed to the size of operator in closed parentheses.
The number of bytes occupied by a variable of that type is given by the size of operator. The
size of operator is very useful in developing portable programs. It is a bad practice to assume
the size of a particular type since its size may very from compiler to compiler.
The size of operator also takes variable names and returns the size of the variable given,
in bytes.
int i;
The size of i is 2
32
The result would have been the same if size of (int) had been used instead of size of (i),
since i is an int. But passing the variable name to size of is a better practice. If the type of i has
to be changed later, the rest of the program need not be modified.
What are the format specifiers used in the printf format string for short and long integers?
For short integers, kit is %hd (or % hi) and for long integers, it is %d (or % li). The following
example illustrates input-output statement for short and long integers.
# include main ()
——————
limits.h
The header file limits.h contains the largest and smallest values that each of the various
data types can hold. The name of the constant, the meaning, and the smallest acceptable
magnitude is given in lesson 7.
33
The type qualifier long can also be applied to the data type double. A variable of the type
long double has more precision than a variable of the type double. Observe that C provides
three data types for real numbers: float, double and long double. In any C compilers, you can
be sure that the precision of a double is greater than or equal to that of float, and that the
precision of a long double is greater than or equal to that of a double, i.e.,
Regarding the range that a floating point number can hold, the ANSI standard does not
specify whether one type of floating point number can hold more than the other. So different
compilers may provide different ranges for floating point numbers. The standard guarantees
that the maximum floating point number is at 37 least 102.
Some compilers may provide a greater range. To find out the actual range that compiler
offers, a program may refer to the constants defined in float.
Sign Qualifiers
The keywords signed and unsigned are the two sign qualifiers that specify whether a
variable can hold both negative and positive numbers, or only positive numbers. These qualifiers
can be applied to the data types int and char only.
As mentioned before, signed int is the same as int ( i.e., int is signed by default). The type
char may be the same as either signed chare or unsigned char. This varies from compilers give
the option of treating a char as singed or fact, many compilers give the option of treating a char
as singed or unsigned. This fact (whether a char is signed or unsigned) does not matter when
we use a variable of the type char to hold a single character. But when used as an 8-bit integer,
it does matter whether the variable type dealt with is signed or unsigned.
9) typedef Statement
The typedef statement is used to give new names to existing types. For example, the
statement
34
declares ulong a new type. Equivalent to unsigned long. It can be used just as any other
type in a program For example the statement,
ulong u;
declares u to be of the type ulong. Also sizeof (ulong) gives the size of the new variable
type in bytes.
int i;
float f;
i = 5;
f = i;
The last statement assigns i to f. Since i is an integer while f is a floating point variable,
the integer i is converted to float automatically. This type of conversion, when the variable of
lower type (which holds lower precision) is converted to higher type (which holds higher range
of values or has higher precision) is converted to a higher precision is called promotion.
int i;
char c;
c = ‘a’;
i = c;
The value present in the character variable c, i.e., the ASCII code of the character a is
assigned to the character a is assigned to the integer i. If an integer is represented by sixteen
bits, the lower eight bits will have the value of the while the upper eight bits will be filled with
zeros. In some cases, the upper bits are filled with ones instead of zeros. To understand this,
let us examine the concept of sign extension.
35
Conversion to a signed integer involves extending the sign. In case of signed numbers,
the most significant bit is assumed to be the sign. If this bit is l, the number is assumed to be
negative, and if it is 0, it is assumed to be positive. When a character having its most significant
bit set to one is assigned to a signed integer, the lower eight bits will be filled with l’s. On the
other hand, if the character value has its most significant bit set property of filling the upper bits
of the higher type with 0’s. This of the lower type is called sign extension. Sign extension takes
place only if the variable of the higher type is signed. If the variable of the higher type is
unsigned, its upper bits will always be filled with 0’s
Assignments of variable of higher types of lower types result in truncation. For example,
the sequence,
f = 7.5;
i = f;
results in the fractional part (.5) discarded. The value 7 is assigned to the integer i.
In addition to automatic conversions, we can forcibly convert one type to another. The
following example illustrates the need for forcible conversion.
int i, j;
float f;
i = 12;
j = 5;
f = i/j;
This is inspite of the fact that 12/5 is 2.4 and it can be assigned to f. Since both i and j are
integers in the expression,
f = i/j
Integer division takes place, and the quotient 2 is assigned to f. Though the variable on
the left-hand side of the assignment operator is a floating point variable, it does not cause
36
floating point division to take place. One of the operands involved in the division must be a
floating point number. We can achieve this by temporarily converting either i or j to a floating
point number. The division expression must be changed to
f = (float) i/j;
We are explicitly converting i to floating point number in the above expression. Explicit
type conversions are called typecasting. The general syntax of typecasting given below:
The type name to which conversion is to be done is placed in closed parentheses preceding
the variable name.
Typecasting can also be used to convert a higher type to a lower type. For example, if f
is a float whose value is 2.7, the expression,
(int) f
evaluates to 2.
int i;
In order to initialize the variable i we can use two statements as shown below:
int i;
i = 5;
and then use the variable i. A simpler way to achieve this is to combine them into a single
statement as given below:
int i = 5
A statement like the one above is preferred, since it is simpler, less prone to mistakes,
and often leads to more efficient programs. When multiple variable are being declared in a
single statement, initialization is done in the following way:
int i = 10, j = 5 ;
37
Also, the right side of the = symbol can have an expression. For following is a valid
sequence of statement:
int i = 10, j = 5;
int k = i/j;
2.4 Constants
A constant does not change its value during the entire execution of the program. Constants
can be classified as integer constants, floating point constants, character constants and
enumeration constants. Additionally, string literal can specify strings.
Example
Valid constants 48 6432 001
1) Integer Constants
Integer constants can be specified in three ways: (i) Ordinary decimal numbers (base
10). For example, 175 is an integer constant specified in base 10. (ii) Octal numbers (base8).
Octal numbers are specified with a leading zero, rest of the digits consists of those lying between
0 and 7. For example, 0175 is an integer consist specified in octal whose base 10 or decimal
38
value is 125. (iii) Hexadecimal numbers (base 16). Hexadecimal numbers are specified with 0x
or OX the beginning. The digits that follow Ox must be numbers in the range 0-9 or one of the
letters a-f or A-F example, OX175 is the same as Ox175, i.e., either a lower case or an upper
cans x can used.
A size or sign qualifier can be appended at the end of the constant. The suffix u is used
for unsigned int constants, l for long int constants and s for short int constants. Either of the
cases can be used.
Example
1. unsigned integer constants
56789U
56789u
7689909L
7689909l
0x34ADL (A long integer constant in hexadecimal with upper and lower case letters)
6578890994Ul
6578890994ul
We can use smaller integer constants that are stored with fewer bits for which the qualifiers
used are s and us.
120S - 1000s
120US
1000us
39
Ordinarily, these suffixes are not needed. The compiler considers large integer constants
to be of the type long automatically. These suffixes are useful in situations where the value
may fit in an int but you want to treat it as long.
As another example, the number 75000000000 can be written as 75e9 or 75e11. Similarly
0,00000000045 can be written as 0.45e-9.
2000.0434
3.4e4
3e8
Normalized exponential representation is the one in which the value of the mantissa is
adjusted to a value between 0.1 and 0.99. For example, the number 75000000000 is written as
0.75e11 after normalization.
40
By default, real constants are assumed to be double. Suffixes for F can be used to
specify the float values. For example, 0.257 is assumed to be a double constant, while 0.257f
is a float constant. l or L can be used to specify long double values. For example, 0.257L is a
long double constant.
3) Character Constants
Example 2.4
Note: Multiple characters can also be enclosed within single quotes. The compiler will
not report any error. The value of the constant however, depends upon the compiler used. This
notation of having multiple characters within single quotes is practically never used.
In side the single quotes, a backslash character starts an escape sequence. \xhh specifies a
character constant in hexadecimal, where his any hexadecimal digit. The hexadecimal digits hh
give the ASCII value of the character. For example, the character constant \xo7 represents the BEL
character. Run the following program to hear a beep on the computer.
# include <stdio.h>
void main ( )
\0ooo specifies a character constant in octal where, o is any octal digit. As before, ooo is
the ASCII value of the number specified in octal. For example the ASCII code of K is 75. the
character constant \0113 specifies this character in octal.
\a Beep (Alert)
\b Backspace
\f Formfeed
\n Newline
\t Horizontal tab
\r Carriage return
\\ Backslash
\’ Single quote
\” Double quote
\v Vertical tab
\? Question mark
\0 Null
Hence, \xo7 in the printf statement in the above example can be replaced by \a.
Example
\ is a backslash.
4) Enumeration Constants
An enumeration is a user defined type with value ranging over a finite set of identifiers
called enumeration constants. For example,
defines color as a new type having three values. red, blue and green. Each of these is an
enumeration constant. In the program, color can be used as a new type. A variable of type
color can have any one of the three values: red, blue or green. For example, the statement,
color c;
declares C to be of type color. Internally the C compiler treats an enum type (such as
color) as an integer itself. The identifiers red, blue and green above represent the consecutive
integer values of 0, 1 and 2 respectively. So, the statement,
c = blue;
will print,
Constant values can be explicitly specified for the identifiers. When the value of one
identifier is specified in this manner, the value of the next element is the next higher integer.
Then the statement c = red will assign the value 10 to c.c = blue will assign the value 11
to c, and c= green will assign the value 34. If no value is specified for green, it will assume the
value 12.
Enumerations are a convenient way to associate constant integers with meaningful names.
They have the advantage of generating the values automatically. Use of enumeration constants,
in general, makes the program easy to read and change at a later date.
43
It is not difficult to see why the above declarations are invalid It is because, the name hot
has the value 1 in enum emotion and the value 0 in weather. In the program, if you use the
name hot, there is an ambiguity as to which value to use. On the other hand, values need not
be distinct in the same enumeration. For example, the following declaration is perfectly valid.
The names hot and warm can be interchangeably used, since both represent the value 0.-
Consider the variable days_of_week. is declared as the declaration of this enum. The
enumeration constants are Sun Mon Tues Wed Thu Fri Sat. These constants are separated by
commas.
5) String Literals
A string literal is a sequence of characters enclosed within double quotes. The character
may consist of letters, numbers, escape sequences and space. To make it easier to write long
strings, string constants are concatenated at the compile time. For example, the strings:
The notations ‘A’ and “A” have an important difference: the first (‘A’) is a character constant,
while the second (“A”) is a string constant. The notation ‘A’ is a constant occupying a single
byte containing the ASCII code of the character A. The notation “A” on the other hand, is a
constant that occupies two bytes, one for the ASCII code of A and another for the null character
with the value 0, that terminates all strings.
44
6) const Qualifier
To understand the necessity of const identifiers, consider the following program which
calculates tax on the given salary, assuming that the rate of taxation is 30%.
# include <stdio.h>
void main ( )
printf ( “ salary: “ );
The program works correctly. It uses the numeric constant 0.3 to calculate the tax sinc
the rate of taxation is 30%. But assume that the program computes the tax at many different
points. If the tax rate changes, all the statements that computer the tax will have to be modified.
An obvious solution to this problem is to declare a variable called tax_rate that will have the
current tax rate. In case the tax rate changes, we only need to update the variable tax_rate.
The modified program is given below.
# include <stdio.h>
void main ( )
printf ( “ salary: “ )
The statement,
in the earlier one. This disadvantage is that any statement written carelessly can modify
its value. Then, all subsequent calculations of the tax will yield wrong results. In a very long
program, if such a problem is encountered, it could be very difficult to find where exactly is has
been modified. To avoid suffering the consequences of such carelessness, declare the variable
tax_rate as const. The statement that declared tax_rate would now be changed to:
This informs the compiler that tax_rate is a constant floating-point number, its value is
0.3 and it cannot be modified anywhere in the program. A statement, such as
tax_rate = 0.99;
Will cause a compile-time error, enabling you to detect the mistake early and save
debugging time. The complete program using a constant identifier tax_rate is given below.
# include <stdio.h>
void main ( )
printf ( “ salary: “ );
Another way to achieve the effect of const identifiers is by the use of # define preprocessor
directive as shown below:
46
# include <stdio.h>
void main ( )
printf ( “ salary: “ );
This is the key difference between the use of constant identifiers and the #define directive.
The compiler treats the former as a value that cannot change in the program, while the latter is
handled by the preprocessor that replaces all instances of tax_rate by 0.3.
Note that conventionally, such constants are specified in the upper case. Normally the #
define directive would be:
Programming Examples
Example
interest */
47
# include <stdio.h>
void main ( )
{float p, t, r, ncmp_year;
printf ( “principal: “ );
printf ( “Rate: “ );
printf ( “Time: “ );
simple = p * t * r/100;
interest. */
ncmp_year * t);
/* Compute the compound interest from the amount and principal */ compound =
cmp_amount - p;
Run:
principle: 1000
——
Rate: 10
Time: 2
48
The first number passed to pow is 1+r/ (ncmp_year*100). The second number is
ncmp_year * t. The two are separated by a comma, as in the case of printf where the variables
to be output that are passed to printf are separated by commas. Observe that the interest
values are printed with 6 digits after the compiler. Whereas, it is sufficient if they are printed
with the precision operations are given in the next lesson.
Example
# include <stdio.h>
void main ( )
{float c, f;
f = 1.8 * c + 32;
c = (f - 32) / 1.8;
#include <stdio.h>
void main ( )
{float a, b, c;
peri = a + b + c;
s = peri / 2;
---
In the above example, the library function sqrt is used to find the square root. This function
accepts of a floating point number and returns its square root.
Example
/* triangle 2.c: Area of the triangle given the base and height */
#include <stdio.h>
void main ( )
{float b, h;
float area;
area = b * h / 2;
2.5 Summary
In this lesson we have covered variable and expression. We have also covered character
set, special characters, Identifiers and keyword.
LESSON - 3
OPERATORS AND EXPRESSIONS
Structure
3.1 Introduction
3.3 Operators
3.4 Summary
3.1 Introduction
Operators are c’s forte. It is extremely rich in operators. It has as many as 45 different
operators. We are going to discuss most of there operator and their interaction with are another
in this lesson.
3.3 Operators
An operator, in general, is a symbol that operates on a certain data type. For example,
the operator is the addition operation. It can operate on integer, character and real (float,
double and long double) numbers. An expression is a combination of variables, constants and
operators written according to the syntax of the language. In C, every expression evaluates to
a value, i.e., every expression results in some value of a certain type that can be assigned to a
variable.
Let us take the simple example of an assignment operator and analyses the concept of
evaluation. In C, the ‘=’ symbol is the assignment operator. Its duty is to set the value of the
variable on the left hand side to that of the right hand side. The left hand side of the assignment
operator (=) and the right hand side together form an expression.
53
For example, if the variables i and j have been declared by the statement,
int i, j;
i = 5;
The above statement assigns the value 5 to i. In addition, the whole expression evaluates
to the value that has been assigned (i.e., 5). So, the statement,
j = i = 5;
Will first execute i = 5. This expression evaluates to 5. When we say that i=5 evaluates to
5, what we actually mean is that the i = 5 part (inside the expression j = i = 5) can be replaced
by the number 5. So you can imagine that at the run time, the value 5 is first assigned to i.
Then, the statement becomes
j=5
and 5 is assigned to j. Thus, the value of both i land j after the above statement is
executed, is 5.
1) Types of Operators
In C, operators can be classified into various categories based on their utility and action.
A list of operator types is given below:
Arithmetic operators
Relational operators
Logical operators
Assignment operators
Increment and decrement operators
Conditional operators
Comma operator
2) Arithmetic Operators
The arithmetic operators perform arithmetic operations and can be classified into unary
and binary arithmetic operators. The arithmetic operators can operate on any built-in data
type/ A list of arithmetic operators and their meanings are given below:
54
Operator Meaning
* multiplication
/ division
Note: .C has no operator for exponentiation. However, a function y pow (x,y) exists in
math.h which returns X. The unary minus operator has the effect of multiplying its operand
by - 1
Integer arithmetic: When two operands such as x and y are declared integers, an
arithmetic performed on these integers is called integer arithmetic. It always yields an integer
value.
Example
Let x and y be declared by the statement: int x = 16, y = 5, (x and y are integers with
values 16 and 5, respectively)
x + y = 21
x – y = 11
x * y = 80
x % y = 1 The result is the remainder of the integer division and the sign of the result is
always the sign of the first operand.
Note: In integer division operation, the result is truncated towards zero if both the operands
are of the same sign, and is dependent on the machine if one of the operands is negative.
55
Example
6/8=0 -6 / -8 = 0 -6 / 8 = 0 or -1
Floating point arithmetic: Floating point arithmetic involves operands of real type
in decimal or exponential notation. The floating point results are rounded off to the number of
significant digits specified and hence, the final value is only an approximation of the correct
result. The remainder operator % is not applicable to floating point arithmetic operands.
Example
Let a and b be declared by the statement float a = 14.0, b = 4.0; (a and b are float
variables with values 14.0 and 4.0 respectively) and p, q and r be floating point variables: then
the floating point arithmetic operations will yield the following results:
p = a / b = 3.500000 q = b / a = 0.285714
r = a + b = 18.00000
Mixed mode arithmetic: In mixed mode arithmetic, if either of the operands is real,
the resultant value is always a real value. For example, 35 / 5.0 = 7.0. Here, since 5.0 is a
double constant, 35 is converted to a double and the result is also a double.
3) Relational Operators
Operator Meaning
== equal to
!= not equal to
In order to study the relational operators in the right perspective, it is necessary to know
the fundamentals of an if statement. Consider a simple example that uses a relational operator
in an if statement. Details of the if statement are dealt with in the next lesson, but presently we
need to have a basic idea of its function. The if statement evaluates an expression and executes
the next statement only if the expression evaluates to true (a non-zero integer). The following
example inputs two integers and tests for equality.
# include <stdio.h>
void main ( )
{ int i, j;
if ( i = = j )
The if statement in the above example needs special mention. A pair of round braces
follow the if statement. If the condition within these braces (which is i = = j here ) is true, the
statement just after the if statement is executed, otherwise it is skipped. Let us now run the
program, enter two equal number and see what happens.
——
if ( i = = j )
is executed. Thereafter, the execution continues normally, and the last statement of the
program
is executed finally.
If the program is run with unequal numbers the output appears as follows:
——
Since i and j are not equal, the condition i = = j in the if statement evaluates to 0. The
statement that follows the if statement is skipped, and the message They are equal is not
displayed.
Note that in C, the operator for testing equality is = = (two = signs placed together). One
of the most common mistakes is to use single = sign to test for equality. For example, consider
the following sequence of statements:
int i = 3, j = 70;
if ( i = = j )
On the other hand, here is the wrong version that uses single = for comparison.
58
int i = e, j = 70;
if ( i = j )
else
Since i = = j evaluates to false (0), the statement following the else keyword is executed.
The above sequence of statements cause the following (erroneous) output to be printed:
This happens because the result of an assignment operator is the assigned value itself.
Here, since the condition used in the if statement is i = j, the value of j (70), is assigned to i, and
the assignment expression evaluates to 70, which is non-zero. Since any non-zero value is
considered to be true, the statement following if is executed, printing a message that the two
values are equal.
Examples of other relational operators are given below. Suppose i and j are declared
with
i>j
is false (because i is not greater than j). Recall that every expression evaluates to a value
in C. The above expression evaluates to false. But in C, there is no special data type to represent
true of false. Integers are used for this purpose. The integer zero represents false and any
non-zero integer represents true. So, the expression i > j evaluates to zero. The expressions i <
j and i < = j evaluate to 1, since the relations are true.
t = (i < j );
printf ( “%d\n”, t );
When using relational operators, the signed or unsigned nature of the numbers being
compared becomes important. Neglecting this fact can lead to hard-to find errors. For example,
here is a program that uses the varable type char as an 8-bit integer. Whether char is signed or
unsigned depends on the compiler used.
#include <stdio.h>
void main ( )
char c = 255;
char d = -1;
if ( c < 0 )
else
if ( d < 0 )
else
If the compiler used to compile the above program treats a char as signed, then the
output of the program will be:
c is less than 0
d is less than 0
The second lined is true, since the number assigned to d, which is -1 is indeed less than
0. The first line is false, since the number we have assigned to c is 255, and is definitely greater
than 0. But the catch is that both -1 and 255 have same binary representation in 2’s complement
arithmetic. Treating char as signed has the effect that both are treated as signed numbers (
i.e., as -1 in this case).
60
On the other hand, if the compiler treats a char as unsigned, the output will be:
The first line is now correct, but the second is not. Again, when a char is treated as
unsigned, both numbers ( c and d ) are assumed to be 255, and hence not less than 0. This is
certainly an obstacle to writing portable programs. The solution lies in explicitly declaring variables
of type char as signed or unsigned when using them as 8-bit integer values. Similarly, the
signed or unsigned nature of numbers is important even in case of normal integers. Making the
above program portable lies in changing the declaration of the characters.
#include <stdio.h>
void main ( )
if ( c < 0 )
else
if ( d < 0 )
else
d is less than 0
61
4) Logical Operators
A logical operator is used to compare or evaluate logical and relational expressions. There
are three logical operators in C language. They are:
Operator Meaning
Logical OR
! Logical NOT
a > b && x = = 10
The expression on the left is a a>b and that on the right is x = = 10. The whole expression
evaluates to true ( 1) only if both expressions are true ( if a is greater than b and the value of x
is equal to 10)
The expression is true one them is true, or if both of them are true. That is, if the value of
a is less than that of m or n. Needless to say, it evaluates to true in case a is less than both m
and n.
Logical NOT: The ! (NOT) operator takes single expression and evaluates to true (1) if
the expression if false (zero), and evaluates to false (0) if the expression is true. In other words,
it just reverses the value of the expression. For example, consider:
! (x > = y)
62
The expression after the ! operator, in this case is x >= y. The not expression evaluates
to true only if the value of x is neither greater than nor equal to y (i.e., only if x is less than y).
Therefore, the whole expression including the ! operator is the same as:
x<y
So what is the use of this operator? The ! operator is convenient to use when you want to
test whether the value of a variable is zero. For example,
if (!i )
5) Bitwise Operators
A bitwise operator operates on each bit of data. These operators are used for testing,
complementing or shifting bits to the right of left. Usually bitwise operators are not useful in
cases of float and double variables. A list of bitwise operators are given below.
Operator Meaning
bitwise OR
¦
^ bitwise XOR
~ bitwise complement
To experiment with these operators, assume that a, b and c are integers declared by the
statement.
int a = 13, b = 7, c;
Also, for convenience, let us assume that an integer occupies 16 bits (2 bytes).
63
(The space appearing after every 4 bits are only for clarity. Actually, the integers are
merely 16 continuous bits).
c = a & b;
make use of the bitwise AND operator. After this statement is executed, each bit in c will
be 1 only if the corresponding bits in both a and b are 1. For example, the right most bit of both
integers is 1, and hence the right most bit in c is 1. The next bit is 0 in a and 1 in b. Hence the
second bit (from the right) in c is 0. Applying this reasoning to all the bits in each integer, the
value of c after the above statement is executed, will be 0000 0000 0000 0101 which, in decimal
is 5 and is illustrated below:
c = a b;
¦
make use of the bitwise OR operator. After this statement is executed, a bit in c will be 1
whenever at least one of the corresponding bits in a or b is 1. In the above example, the value
of c will be 0000 0000 0000 1111, i.e., decimal 15 and is illustrated below.
Bitwise OR operator: a ¦ b
c = a ^ b;
make use of the bitwise XOR operator. After this statement is executed, a bit in c will be
I whenever the corresponding bits in a and b differ. So, in the above example, the value of c will
be 0000 0000 0000 1010 which, in decimal is 10 and is illustrated below.
Left shift operator: The left bit-shift operator, << is a binary operator. For example
consider the statement
c = a << 3;
The value in the integer a is shifted to the left by three bit positions. The result is assigned
to the integer c. Since the value of a is 0000 0000 0000 1101 the value of c after the execution
of the above statement is 0000 0000 1010 1000 (140 in decimal) and is illustrated below:
Left-Shift <<
drop off <— 0000 0000 0000 1101 <— insert 0’s
The three left-most bits drop off due to the left shift (i.e., they are not present in the
result). Three zeros are inserted in the right. The effect of shifting a variable to the left by one
bit position is to multiply it by 2. In the above example, a is shifted left by 3 positions, which is
equivalent to 3 multiplying a by 2*2*2*, i.e., 2. Since the initial value of a is 13, the value
assigned to c is 13*8=140.
Right shift operator: The right bit-shift operator is also a binary operator. For example,
consider:
c = a >> 2;
The value of a is shifted to the right by 2 positions. Since the value of a is 0000 0000
0000 1101, the value of c after the execution of the above statement is 0000 0000 0000 0011
(3 in decimal) and is illustrated below:
Right-Shift >>
insert 0’s —> 0000 0000 0000 1101 —> drop off
The 2 right-most bits drop off (are not present in the result), and zeros are inserted in the
left effect of shifting a variable to the right by one bit position is to perform integer division by 2
(i.e., divide by 2 and truncated the result). Hence, shifting to the right by 2 bit position has the
effect of integer division by 2*2*=4. Since the initial value of a is 13, shifting to the right by 2 bit
positions yields the value 3 ( the result of dividing 13 by 4 and truncating the result).
Shifting negative number: Note that zeros are not always inserted in the left, as shown in
the above example. If the number is negative to begin with then 1 is inserted in the left for every
bit shifted to the right. For example, if we assign a negative number, say -3 to a with the
statement:
a = -3;
Then the binary representation of a would be the two’s complement of the magnitude. To
find the 2’s complement of 3, take the binary representation of 3, complement it bitwise, and
add 1 to the result. The binary representation of 3 is: 0000 0000 0000 0011
Complementing bitwise (i.e, taking each bit and inverting it, making it 0 if it is 1 and vice-
versa), we get: 1111 1111 1111 1100
66
c = a >> 2;
will shift the value of a by 2 bit positions to the right and insert two 1’s in the left. So, at
end of this operation, the value of c will be:
This is a number which is in 2’s complement form again. To see the magnitude of this
negative number, take 2’s complement again (2’s complement of a 2’s complement is the
original number itself), resulting in
In the case of unsigned integers, the bit inserted on the left is always 0. Note that the
value of the bit inserted on the left varies with the sign only in the case of a right shift. In case
of a left shift, the bit on the right is always 0.
The bitwise complement operator (~) is a unary operator. It gives the value got by
complementing each bit of the operand. To illustrate its usefulness, consider a situation where
it is required to clear the least significant a can use the & operator to bitwise AND the integer
with a constant having only the least significant four bits initialized to zero.
i = i & 0xfff0;
But this method assumes that the size of an integer is 16 bits. If an integer is of 32 bits,
the above method clears the most significant sixteen bits also. Another way is to use the right
and left shift operators and the fact that a left shift always shifts in zeros to the right. The
statement below shifts the integer 4 bits to the right, and shifts it back 4 bits to the left.
i = (i>>4) << 4;
67
This method though portable, involves two shifts. It can be done more efficiently using
the ~ operator, as follows:
i = i & ~ 0xf;
The integer constant 0xf has only its significant four bits set. When the bitwise complement
(~) operator is applied to it, an integer that has all bits set except the least four significant bits,
is obtained. Applying the bitwise AND now gives the desired result. Expressions such as above,
where the variable being assigned to and the variable being operated on, are the same, permit
an easier method. For example, the assignment expression i = i & ~ 0xf above can be written
as:
i & = ~0xf;
The operator &= performs the bitwise AND operation on the operand on its left.
To illustrate the bitwise operators, a complete sample program is given below. This program
reads an integer and prints the value of a specified bit in the integer. The bits are numbered
from 0, starting from the right. For example, to find the value of the second bit of an integer i,
it is necessary to shift i to the right by two bits, and take the least significant digit.
#include <stdio.h>
void main ( )
int bit;
The statement,
first shifts i to the right by n bits and then masks (clears) all bits of i except the least
significant bit, giving us the value of the bit which we wanted. Parentheses are not required in
the above statement, since the operator >> has a greater precedence than & (i.e., in an
expression, if both >> and & are present, the >> operator is executed first). Since this fact is
not so obvious, it is always better to use parentheses in such situation, for the sake of readability.
The statement a += 5; will add the number 5 to the value of a. Similarly, a+=b-c will
evaluate b-c first, and adds the result to the value of a. The other assignment operators are:
-= /= *=
¦= &= ^=
These have obvious meanings. They evaluate the expression on their right, and use the
result to perform the corresponding operation on the variable on the left. Apart from the above
assignment operators, bit-shift assignment operators also exist. They are:
>>= <<=
a <<= 5;
The increment and decrement operators are very useful in C language. They are
extensively used in for and while loops. The syntax of the operators is given below:
The operator ++ adds 1 to the operand and — subtracts 1 from the operand. These
operators manifest in two forms: prefix and postfix. For example, the ++ operator can be used
in two ways:
These are two different expressions. The first expression immediately increments the
value of m by 1. For example, the statements,
int t, m = 1;
t = ++m;
will print,
prefix operator: t = 2, m = 2
The expression ++m will cause the value of m to be incremented first, and then this value
is assigned to t, resulting in both having the same value. On the other hand, the statement,
int t, m = 1;
t = m++;
will output
The expression m++ will first evaluate the value of m (which is 1), resulting in 1 being
assigned to t and then the value of m being incremented to 2.
The conditional operator consists of two symbols: the mark (?) and the colon (:). This is
the only operator in C that three operands. The syntax of the operator is given below:
Let us examine the ternary operator through an example. This program reads two integers
and displays the value of the larger of the two. If they are equal, then naturally either of them
will be printed.
#include <stdio.h>
void main ( )
{ int i, j, larger;
larger = i>j ? i: j;
larger = i>j ? i : j;
It has three components; the expression i>j before the question mark, and the variable i
and j after it, one on each side of the ‘:’. We shall first see a sample run of the above program,
and then analyses what the conditional operator does.
——
First, the expression before? (which is i > j) is evaluated. In the above case, the expression
is false.
Since the expression before? is false, the whole expression involving the conditional
operates to the expression following the colon (:). In this case, this is just the variable j.
as before, the expression before? (which is i>j) is evaluated. The expression is true,
since i is 5 and j is -1.
since the expression before? Is true, the whole expression involving the conditional
operators evaluates to the expression before the colon (:) In this case, this is the variable
i
9) Comma Operator
Consider the following statement that makes use of the comma operator:
i = (j = 3, j + 2);
The right hand side consists of two expressions separated by comma. The first expression
is j=3 and the second is j+2. These expression are evaluated from left to fight. That is, first the
value 3 is assigned to j and then the expression j+2 is evaluated, giving 5. The value of the
entire comma-separated expression is the value of the right-most expression. In the above
example, the value assigned to i would be 5.
72
The operator size of gives the size of the data type or the variable in terms of bytes
occupied in the memory, as illustrated earlier. Another operator is the member selection operator
(. and ->) which is used with structures and unions. Pointer operators, *and & are explained in
detail in later chapters.
d = a + b * c;
In the above expression, b is multiplied by c first. The result is added to a and the sum is
assigned to d. Since multiplication is done before addition, the multiplication operator has a
higher precedence than the additional operator. In order to override the precedence, braces
can be used. For example, the statement,
d = (a + b) * c;
would add a to b first, multiply the result by c and assign the product to d. Associativity of
an operator can be left-to-right or right-to-left. For example, in the expression.
d = a - b -c;
The first (left-most) minus is evaluated first. The variable b is subtracted from a. Then the
second minus is evaluated, causing c to be subtracted from the result. Thus, in the case of
many minus operators appearing in an expression without braces, the operators are evaluated
starting from the left-most operator and proceed rightward. The minus operator thus associates
from left to right. On the other hand, the equality operator associates from right to left. For
example, in the statement,
d = a = c;
the second (right-most) equality operator is evaluated first. The variable c is assigned to
a. The expression a = c evaluates to the value of a after the assignment has taken place. Then
this value is assigned to d, when the left-most equality operator is executed.
73
All the operators have been listed here for the purpose of completeness. Many of the
operators pertain to scop and pointers, and hence you may not be familiar with them. These
will be explained in a later lessons. The operators are divided into 16 categories. The first
category has the highest precedence; second category (unary operators) takes second
precedence, and so on down to the comma operator, which has the lowest precedence. The
operators within each category have equal precedence. The unary, and assignment operators
associate right-to-left: all other operators associate left-to-right.
the two operands are ++a and __ a. It is left to the compiler as to which expression it
evaluates first. If it evaluates ++a first, sum will be equal to -1, otherwise it will be 1.
b) Each relational operator needs are operand for comparison of the values.