Search for notes by fellow students, in your own course and all over the country.

Browse our notes for titles which look like what you need, you can preview any of the notes via a sample of the contents. After you're happy these are the notes you're after simply pop them into your shopping cart.

My Basket

You have nothing in your shopping cart yet.

Title: MASTER OF COMPUTER APPLICATION (RGPV UNIVERSITY BHOPAL)
Description: rgpv 5th semester notes for mca students

Document Preview

Extracts from the notes are below, to see the PDF you'll receive please use the links above


Let Us C
Fifth Edition

Yashavant P
...


About the Author
Destiny drew Yashavant Kanetkar towards computers when the IT
industry was just making a beginning in India
...

Yashavant has a passion for writing and is an author of several
books in C, C++, VC++, C#,
...
He is a much sought after speaker on various
technology subjects and is a regular columnist for Express
Computers and Developer 2
...
His current affiliations include
being a Director of KICIT, a training company and DCube
Software Technologies, a software development company
...
NET Technical Contributor” award recently
...
com
...
During this journey I have met so many students,
developers, professors, publishers and authors who expressed their
opinions about Let Us C
...

In particular I am indebted to Manish Jain who had a faith in this
book idea, believed in my writing ability, whispered the words of
encouragement and made helpful suggestions from time to time
...

During this course people like Ajay Joshi, Amol Tambat, Ajay
Daga, Nandita Shastri, Mrunal Khandekar and Rahul Bedge
helped in writing programs, spotting bugs, drawing figures and
preparing index
...

Anup Das, my colleague has a lot of influence on this Fifth
Edition
...
He sincerely wanted this edition
to offer “C, in today’s perspective”
...

I thank Seema, my wife, for her friendship and for her
contributions in everything that I do in IT in ways more than she
could ever guess
...

And finally my heartfelt gratitude to the countless students who
made me look into every nook and cranny of C
...


v

Preface to the Fifth Edition
It is mid 2004
...
and moved on
...
At times I take
secret pleasure in seeing that a book that I have been part of, has
contributed in its own little way in shaping so many budding
careers that have made the “India” brand acceptable
...
So overwhelming has been the response to all the
previous editions of “Let Us C” that I have now decided that each
year I would come up with a new edition of it so that I can keep
the readers abreast with the way C is being used at that point in
time
...
In the first
phase he is a learner trying to understand the language elements
and their nuances
...
In my opinion,
even today there isn’t any learning environment that can beat
Turbo C/C++ for simplicity
...

Armed with the knowledge of language elements the C
programmer enters the second phase
...
I am pointing towards programs in
Windows and Linux world
...
I
would like to your attention the fact that if you want to program
Windows or Linux you need to have a very good grasp over the
programming model used by each of these OS
...
Once you understand these thoroughly rest is just a
vi

matter of time
...

In Linux programming the basic hurdle is in choosing the Linux
distribution, compiler, editor, shell, libraries, etc
...
They have been mentioned in Chapter 20 and Appendix H
...

In fourth edition of Let Us C there were chapters on ‘Disk Basics’,
‘VDU Basics’, ‘Graphics’, ‘Mouse Programming’, ‘C and
Assembly’
...
Modern
counterparts of all of these have been covered in Chapters 16 to
21
...
kicit
...

Also, all the programs present in the book are available in source
code form at www
...
com/books/letusc/sourcecode
...
If you wish to get solutions for the Exercises in the
book they are available in another book titled ‘Let Us C
Solutions’
...
So if you feel that I
could have done certain job better than what I have, or you have
any suggestions about what you would like to see in the next
edition, please drop a line to letuscsuggestions@kicit
...

All the best and happy programming!

vii

Contents
1
...
The Decision Control Structure

49

Decisions! Decisions!
The if Statement
The Real Thing
Multiple Statements within if
The if-else Statement

50
51
55
56
58

viii

Nested if-elses
Forms of if
Use of Logical Operators
The else if Clause
The ! Operator
Hierarchy of Operators Revisited
A Word of Caution
The Conditional Operators
Summary
Exercise
3
...
The Case Control Structure
Decisions Using switch
The Tips and Traps
switch Versus if-else Ladder
The goto Keyword
Summary
Exercise

ix

61
62
64
66
72
73
73
76
77
78

97
98
99
101
105
107
114
115
116
118
120
121
124
124

135
136
140
144
145
148
149

5
...
Data Types Revisited

158
165
166
171
172
173
174
175
178
178
179
186
189
189
194
197
201
201

213

Integers, long and short
Integers, signed and unsigned
Chars, signed and unsigned
Floats and Doubles
A Few More Issues…
Storage Classes in C
Automatic Storage Class
Register Storage Class
Static Storage Class
External Storage Class
Which to Use When
Summary
Exercise

x

214
216
217
219
221
223
224
226
227
230
233
234
235

7
...
Arrays

242
244
248
252
253
255
258
260
260
261
263
264

269

What are Arrays
A Simple Program Using Array
More on Arrays
Array Initialization
Bounds Checking
Passing Array Elements to a Function
Pointers and Arrays
Passing an Entire Array to a Function
The Real Thing
Two Dimensional Arrays
Initializing a 2-Dimensional Array
Memory Map of a 2-Dimensional Array
Pointers and 2-Dimensional Arrays
Pointer to an Array
Passing 2-D array to a Function
Array of Pointers
Three Dimensional Array
Summary

xi

270
272
275
275
276
277
279
286
287
289
290
291
292
295
297
300
302
304

Exercise

304

9
...
Structures

328
329
334
335
337
339
342
343
344
347
351
352
353
354

363

Why Use Structures
Declaring a Structure
Accessing Structure Elements
How Structure Elements are Stored
Array of Structures
Additional Features of Structures
Uses of Structures
Summary
Exercise
11
...
File Input/Output

404
405
409
409

415

Data Organization
File Operations
Opening a File
Reading from a File
Trouble in Opening a File
Closing the File
Counting Characters, Tabs, Spaces, …
A File-copy Program
Writing to a File
File Opening Modes
String (line) I/O in Files
The Awkward Newline
Record I/O in Files
Text Files and Binary Files
Record I/O Revisited
Database Management
Low Level Disk I/O
A Low Level File-copy Program
I/O Under Windows
Summary
Exercise
13
...
Operations On Bits

481

Bitwise Operators
One’s Complement Operator
Right Shift Operator
Left Shift Operator
Bitwise AND Operator
Bitwise OR Operator
Bitwise XOR Operator
The showbits( ) Function
Summary
Exercise
15
...
C Under Windows

535

Which Windows…
Integers
The Use of typedef
Pointers in the 32-bit World
Memory Management
Device Access
DOS Programming Model
Windows Programming Model
Event Driven Model
Windows Programming, a Closer Look
The First Windows Program
Hungarian Notation
Summary
Exercise
17
...
Graphics Under Windows
Graphics as of Now
Device Independent Drawing

xv

562
563
566
567
569
570
572
575
575
576
579
580
580

Hello Windows
Drawing Shapes
Types of Pens
Types of Brushes
Code and Resources
Freehand Drawing, the Paintbrush Style
Capturing the Mouse
Device Context, a Closer Look
Displaying a Bitmap
Animation at Work
WM_CREATE and OnCreate( )
WM_TIMER and OnTimer( )
A Few More Points…
Windows, the Endless World…
Summary
Exercise
19
...
C Under Linux

649

What is Linux
C Programming Under Linux
The ‘Hello Linux’ Program
Processes
Parent and Child Processes
More Processes
Zombies and Orphans
One Interesting Fact
Summary
Exercise
21
...
h File
Appendix G – Boot Parameters
Appendix H – Linux Installation
Index

687
691
701
713
719
725
729
735
739

xvii

1

Getting Started
• What is C
• Getting Started with C
The C Character Set
Constants, Variables and Keywords
Types of C Constants
Rules for Constructing Integer Constants
Rules for Constructing Real Constants
Rules for Constructing Character Constants
Types of C Variables
Rules for Constructing Variable Names
C Keywords
• The First C Program
• Compilation and Execution
• Receiving Input
• C Instructions
Type Declaration Instruction
Arithmetic Instruction
Integer and Float Conversions
Hierarchy of Operations
Associativity Of Operators
• Control Instruction in C
• Summary
• Exercise

1

2

Let Us C

B

efore we can begin to write serious programs in C, it would
be interesting to find out what really is C, how it came into
existence and how does it compare with other computer
languages
...

Four important aspects of any language are the way it stores data,
the way it operates upon this data, how it accomplishes input and
output and how it lets you control the sequence of execution of
instructions in a program
...


What is C
C is a programming language developed at AT & T’s Bell
Laboratories of USA in 1972
...
In the late seventies C began to
replace the more familiar languages of that time like PL/I,
ALGOL, etc
...
It wasn’t made the ‘official’ Bell
Labs language
...
Ritchie seems to have been
rather surprised that so many programmers preferred C to older
languages like FORTRAN or PL/I, or the newer ones like Pascal
and APL
...

Possibly why C seems so popular is because it is reliable, simple
and easy to use
...

An opinion that is often heard today is – “C has been already
superceded by languages like C++, C# and Java, so why bother to

Chapter 1: Getting Started

3

learn C today”
...
There
are several reasons for this:
(a) I believe that nobody can learn C++ or Java directly
...
do deal with apart from
knowing the actual language elements
...
Hence one should first learn all the language
elements very thoroughly using C language before migrating
to C++, C# or Java
...

(b) C++, C# or Java make use of a principle called Object
Oriented Programming (OOP) to organize the program
...
But even
while using this organizing principle you would still need a
good hold over the language elements of C and the basic
programming skills
...

(d) Major parts of popular operating systems like Windows,
UNIX, Linux is still written in C
...
Moreover, if one is to extend the operating system to
work with new devices one needs to write device driver
programs
...


4

Let Us C

(e) Mobile devices like cellular phones and palmtops are
becoming increasingly popular
...
This smartness comes
from a microprocessor, an operating system and a program
embedded in this devices
...

No wonder that such programs are written in C
...

(f) You must have seen several professional 3D computer games
where the user navigates some object, like say a spaceship and
fires bullets at the invaders
...
Needless to say, such games won't become popular if
they takes a long time to move the spaceship or to fire a
bullet
...
This is where C language
scores over other languages
...

(g) At times one is required to very closely interact with the
hardware devices
...

I hope that these are very convincing reasons why one should
adopt C as the first and the very important step in your quest for
learning programming languages
...
However, there is

5

Chapter 1: Getting Started

a close analogy between learning English language and learning C
language
...

Learning C is similar and easier
...
A group of instructions
would be combined later on to form a program
...
1
...
1

The C Character Set
A character denotes any alphabet, digit or special symbol used to
represent information
...
2 shows the valid alphabets,
numbers and special symbols allowed in C
...
, Y, Z
a, b, ……, y, z

Digits

0, 1, 2, 3, 4, 5, 6, 7, 8, 9

Special symbols

~‘!@# %^&*()_-+=|\{}
[]:; "'<>,
...
2

Constants, Variables and Keywords
The alphabets, numbers and special symbols when properly
combined form constants, variables and keywords
...
A constant is an entity that
doesn’t change whereas a variable is an entity that may change
...
The results of
these calculations are stored in computers memory
...

The calculated values are stored in these memory cells
...
Since the value
stored in each location may change the names given to these
locations are called variable names
...

Here 3 is stored in a memory location and a name x is given to it
...
This would overwrite the earlier value 3, since a memory
location can hold only one value at a time
...
3
...
3
Since the location whose name is x can hold different values at
different times x is known as a variable
...


Types of C Constants
C constants can be divided into two major categories:
(a) Primary Constants
(b) Secondary Constants
These constants are further categorized as shown in Figure 1
...


8

Let Us C

C Constants

Primary Constants

Secondary Constants

Integer Constant

Array

Real Constant

Pointer

Character Constant

Structure
Union
Enum, etc
...
4
At this stage we would restrict our discussion to only Primary
Constants, namely, Integer, Real and Character constants
...
For constructing these
different types of constants certain rules have been laid down
...

It must not have a decimal point
...

If no sign precedes an integer constant it is assumed to be
positive
...

(f) The allowable range for integer constants is -32768 to 32767
...
For a 16-bit compiler like Turbo C or Turbo C++ the

vipin
Chapter 1: Getting Started

9

range is –32768 to 32767
...
Question like what exactly do you mean by a 16bit or a 32-bit compiler, what range of an Integer constant has to
do with the type of compiler and such questions are discussed in
detail in Chapter 16
...

Ex
...
The real
constants could be written in two forms—Fractional form and
Exponential form
...

It must have a decimal point
...

Default sign is positive
...

Ex
...
34
426
...
76
-48
...
It
however doesn’t restrict us in any way from using exponential
form of representation for other real constants
...
The part appearing before ‘e’ is called
mantissa, whereas the part following ‘e’ is called exponent
...

(b) The mantissa part may have a positive or negative sign
...

(d) The exponent must have at least one digit, which must be a

positive or negative integer
...

(e) Range of real constants expressed in exponential form is
-3
...
4e38
...
: +3
...
1e8
-0
...
2e-5

Rules for Constructing Character Constants
(a) A character constant is a single alphabet, a single digit or a

single special symbol enclosed within single inverted
commas
...

For example, ’A’ is a valid character constant whereas ‘A’ is
not
...

Ex
...
Variable names are names given to
locations in memory
...
In any language, the types of variables that it
can support depend on the types of constants that it can handle
...
For example, an integer variable can hold only an
integer constant, a real variable can hold only a real constant and a
character variable can hold only a character constant
...

However, for constructing variable names of all types the same set
of rules apply
...


Rules for Constructing Variable Names
(a) A variable name is any combination of 1 to 31 alphabets,

digits or underscores
...
Still, it would be
safer to stick to the rule of 31 characters
...

(b) The first character in the variable name must be an alphabet or
underscore
...

(d) No special symbol other than an underscore (as in gross_sal)
can be used in a variable name
...
: si_int
m_hra
pop_e_89

These rules remain same for all the types of primary and secondary
variables
...
how is C able to
differentiate between these variables? This is a rather simple

12

Let Us C

matter
...
This type
declaration is done at the beginning of the program
...
: int si, m_hra ;
float bassal ;
char code ;

Since, the maximum allowable length of a variable name is 31
characters, an enormous number of variable names can be
constructed using the above-mentioned rules
...

Thus, if we want to calculate simple interest, it is always advisable
to construct meaningful variable names like prin, roi, noy to
represent Principle, Rate of interest and Number of years rather
than using the variables a, b, c
...

The keywords cannot be used as variable names because if we do
so we are trying to assign a new meaning to the keyword, which is
not allowed by the computer
...

However, it would be safer not to mix up the variable names and
the keywords
...

There are only 32 keywords available in C
...
5 gives a list
of these keywords for your ready reference
...


13

Chapter 1: Getting Started

auto

double

int

struct

break

else

long

switch

case

enum

register

typedef

char

extern

return

union

const

float

short

unsigned

continue

for

signed

void

default

goto

sizeof

volatile

do

if

static

while

Figure 1
...
) provide
their own keywords apart from the ones mentioned above
...
Though it has
been suggested by the ANSI committee that every such compiler
specific keyword should be preceded by two underscores (as in
__asm ), not every vendor follows this rule
...
However, instead of this, we would write our first C
program now
...

Before we begin with our first C program do remember the
following rules that are applicable to all C programs:
(a) Each instruction in a C program is written as a separate

statement
...


14

Let Us C

(b) The statements in a program must appear in the same order in

which we wish them to be executed; unless of course the logic
of the problem demands a deliberate ‘jump’ or transfer of
control to a statement, which is out of sequence
...
However, no blank spaces are
allowed within a variable, constant or keyword
...

(e) C has no specific rules for the position at which a statement is

to be written
...

(f)

Every C statement must end with a ;
...


Let us now write down our first C program
...

/* Calculation of simple interest */
/* Author gekay Date: 25/05/2004 */
main( )
{
int p, n ;
float r, si ;
p = 1000 ;
n=3;
r = 8
...



Comment about the program should be enclosed within /* */
...




Though comments are not necessary, it is a good practice to
begin a program with a comment indicating the purpose of the
program, its author and the date on which the program was
written
...
For example, a comment can be written before the
statement, after the statement or within the statement as shown
below:
/* formula */ si = p * n * r / 100 ;
si = p * n * r / 100 ; /* formula */
si = p * n * r / /* formula */ 100 ;



Sometimes it is not so obvious as to what a particular
statement in a program accomplishes
...
For example:
/* formula for simple interest */
si = p * n * r / 100 ;



Often programmers seem to ignore writing of comments
...


16

Let Us C



Although a lot of comments are probably not necessary in this
program, it is usually the case that programmers tend to use
too few comments rather than too many
...




The normal language rules do not apply to text written within
/*
...
This is because the comments are solely given
for the understanding of the programmer or the fellow
programmers and are completely ignored by the compiler
...
For example,
/* Cal of SI /* Author sam date 01/01/2002 */ */

is invalid
...



main( ) is a collective name given to a set of statements
...
All
statements that belong to main( ) are enclosed within a pair of
braces { } as shown below
...
Every function has
a pair of parentheses ( ) associated with it
...




Any variable used in the program must be declared before
using it
...
5 ;



In the statement,
si = p * n * r / 100 ;

* and / are the arithmetic operators
...
C is very rich in operators
...
Surprisingly there
is no operator for exponentiation
...



Once the value of si is calculated it needs to be displayed on
the screen
...
All output to screen
is achieved using readymade library functions
...
We have used it display on the screen the
value contained in si
...
These
characters are printed as they are when the printf( ) is
executed
...
%f", si ) ;
printf ( "Prin = %d \nRate = %f", p, r ) ;

The output of the last statement would look like this
...
5

What is ‘\n’ doing in this statement? It is called newline and it
takes the cursor to the next line
...
‘\n’ is one of the several Escape
Sequences available in C
...
Right now, all that we can say is ‘\n’ comes in

Chapter 1: Getting Started

19

handy when we want to format the output properly on
separate lines
...
An expression is nothing but
a valid combination of constants, variables and operators
...

The results of these expressions can be printed as shown
below:
printf ( "%d %d %d %d", 3, 3 + 2, c, a + b * c – d ) ;

Note that 3 and c also represent valid expressions
...
To type your C program you need
another program called Editor
...
To carry out this conversion we need
another program called Compiler
...

There are several such IDEs available in the market targeted
towards different operating systems
...
Note that Turbo C++, Microsoft C++ and Borland C++
software also contain a C compiler bundled with them
...
Once you have mastered the language
elements you can then switch over to more sophisticated compilers
like Visual C++ under Windows or gcc under Linux
...

Wherever there is a deviation I would point it out that time
...
The compiler (TC
...

(b) Select New from the File menu
...

(d) Save the program using F2 under a proper name (say
Program1
...

(e) Use Ctrl + F9 to compile and execute the program
...

Note that on compiling the program its machine language
equivalent is stored as an EXE file (Program1
...

This file is called an executable file
...
In fact the other machine need not even have a
compiler to be able to execute the file
...
To get rid of this error, perform the following
steps and then recompile the program
...
In the dialog box that pops up, select ‘CPP always’
in the ‘Use C++ Compiler’ options
...
Make sure that the default extension is ‘C’ rather than
‘CPP’
...
5
...
If we want to calculate
simple interest for some other set of values then we are required to
make the relevant change in the program, and again compile and
execute it
...
Moreover, if you distribute the
EXE file of this program to somebody he would not even be able
to make changes in the program
...

To make the program general the program itself should ask the
user to supply the values of p, n and r through the keyboard during
execution
...

This function is a counter-part of the printf( ) function
...
This is illustrated in the program shown below
...
Here we have not used any expression in printf( )
which means that using expressions in printf( ) is optional
...
& is an ‘Address of’ operator
...
When we say
&a, we are telling scanf( ) at which memory location should it
store the value supplied by the user from the keyboard
...

Note that a blank, a tab or a new line must separate the values
supplied to scanf( )
...
This is
shown below:
Ex
...
5

Ex
...

1000 5

15
...
: The three values separated by newline
...
5

So much for the tips
...

/* Just for fun
...
" ) ;
printf ( "You have just entered the number %d", num ) ;
}

C Instructions
Now that we have written a few programs let us look at the
instructions that we used in these programs
...


(b) Arithmetic instruction



To perform arithmetic
operations between constants and variables
...


Since, the elementary C programs would usually contain only the
type declaration and the arithmetic instructions; we would discuss
only these two instructions at this stage
...


24

Let Us C

Type Declaration Instruction
This instruction is used to declare the type of variables being used
in the program
...
The type declaration statement is
written at the beginning of main( ) function
...
: int bas ;
float rs, grosssal ;
char name, code ;

There are several subtle variations of the type declaration
instruction
...

int i = 10, j = 25 ;
float a = 1
...
99 + 2
...
44 ;
(b) The order in which we define the variables is sometimes

important sometimes not
...
5, b = a + 3
...
1, a = 1
...
This is because here we are trying to use a even before
defining it
...


Arithmetic Instruction
A C arithmetic instruction consists of a variable name on the left
hand side of = and variable names & constants on the right hand
side of =
...

Ex
...
0056 ;
deta = alpha * beta / gamma + 3
...

= is the assignment operator
...

3
...
0056 are real constants
...

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

A C arithmetic statement could be of three types
...

Ex
...

Ex
...
123 / 4
...
3442 ;
si = prin * anoy * roi / 100
...

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

It is very important to understand how the execution of an
arithmetic statement takes place
...
This value is then assigned to the variable on the
left-hand side
...
Let us take a closer look at
these statements
...

(a) C allows only one variable on left-hand side of =
...

(b) In addition to the division operator C also provides a modular
division operator
...
Thus the expression 10 / 2
yields 5, whereas, 10 % 2 yields 0
...
Also note that on
using % the sign of the remainder is always same as the sign
of the numerator
...

(c) An arithmetic instruction is often used for storing character
constants in character variables
...
ASCII values are used to represent any
character in memory
...

(d) Arithmetic operations can be performed on ints, floats and
chars
...
The ASCII values of ‘a’ and ‘b’ are 97 and 98,
and hence can definitely be added
...
It must be written
explicitly
...

a = c
...
b(xy)
b=c*d*b*(x*y)

usual arithmetic statement
C statement

(f) Unlike other high level languages, there is no operator for
performing exponentiation operation
...

a = 3 ** 2 ;
b=3^2;

If we want to do the exponentiation we can get it done this
way:
#include ...
It is being
used to raise 3 to the power of 2
...
h> is a
preprocessor directive
...
We would learn more about
standard library functions in Chapter 5 and about preprocessor
in Chapter 7
...
These are mentioned below
...

(a) An arithmetic operation between an integer and integer

always yields an integer result
...

(c) An operation between an integer and real always yields a real

result
...
Hence the result is real
...


Operation

Result

Operation

Result

5/2

2

2/5

0

5
...
5

2
...
4

5 / 2
...
5

2 / 5
...
4

5
...
0

2
...
0 / 5
...
4

Figure 1
...
In such a case the value of the expression is promoted or

30

Let Us C

demoted depending on the type of the variable on left-hand side of
=
...

int i ;
float b ;
i = 3
...
5) it cannot be stored in i since it is an int
...
Hence what gets stored in i is 3
...
Here, 30 is promoted to 30
...

Instead of a simple expression used in the above examples if a
complex expression occurs, still the same rules apply
...

float a, b, c ;
int s ;
s = a * b * c / 100 + 32 / 4 - 3 * 1
...
As we know, during evaluation of the expression
the ints would be promoted to floats and the result of the
expression would be a float
...

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

k = 2
...
0 / 9

0
...
0

0

a = 2 / 9
...
2222

k = 2
...
0

0

a = 2
...
0

0
...
0

k = 9
...
0 / 2

4
...
0

4

a = 9 / 2
...
5

k = 9
...
0

4

a = 9
...
0

4
...
7
Note that though the following statements give the same result, 0,
the results are obtained differently
...
0 / 9 ;

In the first statement, since both 2 and 9 are integers, the result is
an integer, i
...
0
...
In the second
statement 9 is promoted to 9
...

Division yields 0
...
However, this cannot be stored in k, k
being an int
...


Hierarchy of Operations
While executing an arithmetic statement, which has two or more
operators, we may have some problems as to how exactly does it
get executed
...
The priority or precedence in which the operations in

32

Let Us C

an arithmetic statement are performed is called the hierarchy of
operations
...
8
...
8
Now a few tips about usage of operators in general
...
11 is operative
...

(b) We must always remember to use pairs of parentheses
...
Best way to avoid this error is to type ( ) and
then type an expression inside it
...

Example 1
...
5
...
Similarly 5 / 8 evaluates to zero, since 5 and 8 are integer
constants and hence must return an integer value
...
2: Determine the hierarchy of operations and evaluate
the following expression:
kk = 3 / 2 * 4 + 3 / 8 + 3

Stepwise evaluation of this expression is shown below:
kk = 3 / 2 * 4 + 3 / 8 + 3
kk = 1 * 4 + 3 / 8 + 3
kk = 4 + 3 / 8 + 3
kk = 4 + 0 + 3
kk = 4 + 3
kk = 7

operation: /
operation: *
operation: /
operation: +
operation: +

Note that 3 / 8 gives zero, again for the same reason mentioned in
the previous example
...
And
mind you there are as many as 45 odd operators in C, and these
can affect the evaluation of an expression in subtle and unexpected
ways if we aren't careful
...
We have not

34

Let Us C

encountered many out of these 45 operators, so we won’t pursue
the subject of precedence any further here
...
So a full-fledged
list of all operators and their precedence is given in Appendix A
...

So far we have seen how the computer evaluates an arithmetic
statement written in C
...
C can handle any complex expression with ease
...
9
...
9

Associativity of Operators
When an expression contains two operators of equal priority the tie
between them is settled using the associativity of the operators
...

Left to Right associativity means that the left operand must be

35

Chapter 1: Getting Started

unambiguous
...
Similarly, in
case of Right to Left associativity the right operand must be
unambiguous
...

Consider the expression
a=3/2*5 ;
Here there is a tie between operators of same priority, that is
between / and *
...
But both enjoy Left to Right associativity
...
10 shows for
each operator which operand is unambiguous and which is not
...
10
Since both / and * have L to R associativity and only / has
unambiguous left operand (necessary condition for L to R
associativity) it is performed earlier
...
Figure 1
...


36

Let Us C

Operator Left

Right

Remark

=

a

b or b = Left
operand
is
3
unambiguous, Right is
not

=

b or a = b

3

Right
operand
is
unambiguous, Left is not

Figure 1
...

Consider yet another expression
z=a*b+c/d;

Here * and / enjoys same priority and same associativity (Left to
Right)
...
12 shows for each operator which operand is
unambiguous and which is not
...
12
Here since left operands for both operators are unambiguous
Compiler is free to perform * or / operation as per its convenience

Chapter 1: Getting Started

37

since no matter which is performed earlier the result would be
same
...


Control Instructions in C
As the name suggests the ‘Control Instructions’ enable us to
specify the order in which the various instructions in a program are
to be executed by the computer
...
There
are four types of control instructions in C
...

Decision and Case control instructions allow the computer to take
a decision as to which instruction is to be executed next
...
In the following chapters we are going to learn these
instructions in detail
...


Summary
(a) The three primary constants and variable types in C are
integer, float and character
...

(c) Do not use a keyword as a variable name
...

(e) Operators having equal precedence are evaluated using
associativity
...

(g) Input/output in C can be achieved using scanf( ) and printf( )
functions
...

over time
hELLO
Plot # 3

basic-hra
422
mindovermatter
queue
...
562 * 150 ;
(b) name = ‘Ajay’ ;
(c) varchar = ‘3’ ;
(d) 3
...
5a + b ) ( d + e ) ;
(f) m_inst = rate of interest * amount in rs ;

Chapter 1: Getting Started

39

(g) si = principal * rateofinterest * numberofyears / 100 ;
(h) area = 3
...
14 * r ^ 2 * h ;
(j) k = ( (a * b ) + c ) ( 2
...


(a) g = big / 2 + big * 4 / big - big + abc / 3 ;
(abc = 2
...
2, assume on to be an int)
(c) s = qui * add / 4 - 6 / 2 + 2 / 3 * 6 / god ;
(qui = 4, add = 2, god = 2, assume s to be an int)
(d) s = 1 / 3 * a / 4 - 6 / 2 + 2 / 3 * 6 / g ;
(a = 4, g = 3, assume s to be an int)
[D] Fill the following table for the expressions given below and
then evaluate the result
...


40

Let Us C

Operator

Left

Right

Remark

/

10

5 or 5 / 2 Left
operand
is
/1
unambiguous, Right
is not


...



...


(a) g = 10 / 5 /2 / 1 ;
(b) b = 3 / 2 + 5 * 4 / 3 ;
(c) a = b = c = 3 + 4 ;

[E] Convert the following equations into corresponding C
statements
...
8 ( a + b ) 2 / c - 0
...
22 ( c + d )
g+v

(d)

A=

7
...
8 + 2b
( x + a ) (1 / y )

[F] What would be the output of the following programs:
(a) main( )
{

Chapter 1: Getting Started
int i = 2, j = 3, k, l ;
float a, b ;
k=i/j*j;
l=j/i*i;
a=i/j*j;
b=j/i*i;
printf( "%d %d %f %f", k, l, a, b ) ;
}
(b) main( )
{
int a, b ;
a = -3 - - 3 ;
b = -3 - - ( - 3 ) ;
printf ( "a = %d b = %d", a, b ) ;
}
(c)

main( )
{
float a = 5, b = 2 ;
int c ;
c=a%b;
printf ( "%d", c ) ;
}

(d) main( )
{
printf ( "nn \n\n nn\n" ) ;
printf ( "nn /n/n nn/n" ) ;
}
(e) main( )
{
int a, b ;
printf ( "Enter values of a and b" ) ;
scanf ( " %d %d ", &a, &b ) ;
printf ( "a = %d b = %d", a, b ) ;
}

41

42
(f)

Let Us C
main( )
{
int p, q ;
printf ( "Enter values of p and q" ) ;
scanf ( " %d %d ", p, q ) ;
printf ( "p = %d q =%d", p, q ) ;
}

[G] Pick up the correct alternative for each of the following
questions:

(a) C language has been developed by
(1) Ken Thompson
(2) Dennis Ritchie
(3) Peter Norton
(4) Martin Richards
(b) C can be used on
(1) Only MS-DOS operating system
(2) Only Linux operating system
(3) Only Windows operating system
(4) All the above
(c) C programs are converted into machine language with the
help of
(1) An Editor
(2) A compiler
(3) An operating system
(4) None of the above
(d) The real constant in C can be expressed in which of the
following forms
(1) Fractional form only
(2) Exponential form only
(3) ASCII form only

Chapter 1: Getting Started
(4) Both fractional and exponential forms
(e) A character variable can at a time store
(1) 1 character
(2) 8 characters
(3) 254 characters
(4) None of the above
(f) The statement char ch = ‘Z’ would store in ch
(1) The character Z
(2) ASCII value of Z
(3) Z along with the single inverted commas
(4) Both (1) and (2)
(g) Which of the following is NOT a character constant
(1) ‘Thank You’
(2) ‘Enter values of P, N, R’
(3) ‘23
...
7014e+38
(4) –1
...
56 ;
(2) con = 'T' * 'A' ;
(3) this = 'T' * 20 ;
(4) 3 + a = b ;

43

44

Let Us C

(k) Which of the following shows the correct hierarchy of
arithmetic operators in C
(1) **, * or /, + or (2) **, *, /, +, (3) **, /, *, +, (4) / or *, - or +
(l) In b = 6
...
6 / a
(2) a + 2
(3) 2 * n
(4) Depends upon compiler
(m) Which of the following is allowed in a C Arithmetic
instruction
(1) [ ]
(2) { }
(3) ( )
(4) None of the above
(n) Which of the following statements is false
(1) Each new C instruction has to be written on a separate
line
(2) Usually all C statements are entered in small case letters
(3) Blank spaces may be inserted between two words in a C
statement
(4) Blank spaces cannot be inserted within a variable name
(o) If a is an integer variable, a = 5 / 2 ; will return a value
(1) 2
...
14 + 2 ) * 3 / 5 ; evaluates to

Chapter 1: Getting Started
(1)
(2)
(3)
(4)

8
...
28
3
...
0?
(1) 0
(2) 0
...
His
dearness allowance is 40% of basic salary, and house rent
allowance is 20% of basic salary
...


Chapter 1: Getting Started

47

(b) The distance between two cities (in km
...
Write a program to convert and print this distance
in meters, feet, inches and centimeters
...
Assume that
the maximum marks that can be obtained by a student in each
subject is 100
...
Write a program to convert this temperature
into Centigrade degrees
...
Write a program to calculate the
area & perimeter of the rectangle, and the area &
circumference of the circle
...
Write a program to interchange the
contents of C and D
...

(Hint: Use the modulus operator ‘%’)
(h) If a five-digit number is input through the keyboard, write a
program to reverse the number
...

(j) In a town, the percentage of men is 52
...
If total percentage of literate men is 35 of
the total population, write a program to find the total number

48

Let Us C
of illiterate men and women if the population of the town is
80,000
...
If the amount to be withdrawn is input through the
keyboard in hundreds, find the total number of currency notes
of each denomination the cashier will have to give to the
withdrawer
...

(m) If a five-digit number is input through the keyboard, write a
program to print a new number by adding one to each of its
digits
...


2

The Decision
Control Structure
• Decisions! Decisions!
• The if Statement
The Real Thing
Multiple Statements within if
• The if-else Statement
Nested if-elses
Forms of if
• Use of Logical Operators
The else if Clause
The ! Operator
Hierarchy of Operators Revisited
• A Word of Caution
• The Conditional Operators
• Summary
• Exercise

49

50

Let Us C

W

e all need to alter our actions in the face of changing
circumstances
...
If the highway is busy I would take a diversion
...
If she says no, I
would look elsewhere
...
You can notice that all these decisions depend on some
condition being met
...
In fact this is what makes it worth
its salt
...
A
fourth, somewhat less important structure is the one that uses
conditional operators
...


Decisions! Decisions!
In the programs written in Chapter 1 we have used sequence
control structure in which the various steps are executed
sequentially, i
...
in the same order in which they appear in the
program
...
By default the instructions in a program
are executed sequentially
...
Many a times, we want a set of instructions to be
executed in one situation, and an entirely different set of
instructions to be executed in another situation
...
As mentioned earlier, a decision control instruction
can be implemented in C using:
(a) The if statement
(b) The if-else statement
(c) The conditional operators

Chapter 2: The Decision Control Structure

51

Now let us learn each of these and their variations in turn
...
The general form of if statement looks
like this:
if ( this condition is true )
execute this statement ;

The keyword if tells the compiler that what follows is a decision
control instruction
...
If the condition,
whatever it is, is true, then the statement is executed
...
But how do we express the condition itself
in C? And how do we evaluate its truth or falsity? As a general
rule, we express a condition using C’s ‘relational’ operators
...
Here’s how they look and how they are evaluated in
C
...
1

52

Let Us C

The relational operators should be familiar to you except for the
equality operator == and the inequality operator !=
...
Here is a simple program, which demonstrates the use
of if and the relational operators
...
If
you type some other number the program doesn’t do anything
...


Chapter 2: The Decision Control Structure

53

START
PRINT enter a num
less than 10
INPUT num

no

is
num > 10

yes

PRINT What an obedient
servant you are !

STOP

Figure 2
...
Study it carefully before
reading further
...

Example 2
...
If quantity
and price per item are input through the keyboard, write a program
to calculate the total expenses
...
3
/* Calculation of total expenses */
main( )
{
int qty, dis = 0 ;
float rate, tot ;
printf ( "Enter quantity and rate " ) ;
scanf ( "%d %f", &qty, &rate) ;
if ( qty > 1000 )
dis = 10 ;

Chapter 2: The Decision Control Structure

55

tot = ( qty * rate ) - ( qty * rate * dis / 100 ) ;
printf ( "Total expenses = Rs
...

Enter quantity and rate 1200 15
...
16740
...
50
Total expenses = Rs
...
000000

In the first run of the program, the condition evaluates to true, as
1200 (value of qty) is greater than 1000
...
Using this
new value total expenses are calculated and printed
...
Thus, dis, which is earlier set to 0,
remains 0, and hence the expression after the minus sign evaluates
to zero, thereby offering no discount
...


The Real Thing
We mentioned earlier that the general form of the if statement is as
follows
if ( condition )
statement ;

Truly speaking the general form is as follows:

56

Let Us C

if ( expression )
statement ;

Here the expression can be any valid expression including a
relational expression
...
For example all the following if statements are
valid
if ( 3 + 2 % 5 )
printf ( "This works" ) ;
if ( a = 10 )
printf ( "Even this works" ) ;
if ( -5 )
printf ( "Surprisingly even this works" ) ;

Note that in C a non-zero value is considered to be true, whereas a
0 is considered to be false
...
Hence the
printf( ) gets executed
...
Since 10 is non-zero, it is true hence again
printf( ) goes to work
...
So again
printf( ) goes to work
...
14 were
used it would be considered to be true
...

Issue is whether it is zero or non-zero
...

If such multiple statements are to be executed then they must be

Chapter 2: The Decision Control Structure

57

placed within a pair of braces as illustrated in the following
example
...
2: The current year and the year in which the
employee joined the organization are entered through the
keyboard
...
2500/is given to the employee
...

/* Calculation of bonus */
main( )
{
int bonus, cy, yoj, yr_of_ser ;
printf ( "Enter current year and year of joining " ) ;
scanf ( "%d %d", &cy, &yoj ) ;
yr_of_ser = cy - yoj ;
if ( yr_of_ser > 3 )
{
bonus = 2500 ;
printf ( "Bonus = Rs
...
If a
pair of braces is not used then the C compiler assumes that the
programmer wants only the immediately next statement after the if
to be executed on satisfaction of the condition
...


58

Let Us C

START
INPUT
cy, yoj

yr_of_ser = cy - yoj

no

yr_of_ser > 3

yes

bonus = 2500

PRINT
bonus

STOP

Figure 2
...
It does nothing when the expression evaluates to false
...
3: In a company an employee is paid as under:

Chapter 2: The Decision Control Structure

59

If his basic salary is less than Rs
...
If his salary is either equal to
or above Rs
...
500 and DA = 98% of basic
salary
...

/* Calculation of gross salary */
main( )
{
float bs, gs, da, hra ;
printf ( "Enter basic salary " ) ;
scanf ( "%f", &bs ) ;
if ( bs < 1500 )
{
hra = bs * 10 / 100 ;
da = bs * 90 / 100 ;
}
else
{
hra = 500 ;
da = bs * 98 / 100 ;
}
gs = bs + hra + da ;
printf ( "gross salary = Rs
...
5

STOP

Figure 2
...

(a) The group of statements after the if upto and not including the

else is called an ‘if block’
...

(b) Notice that the else is written exactly below the if
...
This formatting convention is

Chapter 2: The Decision Control Structure

61

followed throughout the book to enable you to understand the
working of the program better
...

(d) As with the if statement, the default scope of else is also the

statement immediately after the else
...


Nested if-elses
It is perfectly all right if we write an entire if-else construct within
either the body of the if statement or the body of an else statement
...
This is shown in the following
program
...
If the condition in the first if statement is false, then the
condition in the second if statement is checked
...

You can see in the program how each time a if-else construct is
nested within another if-else construct, it is also indented to add
clarity to the program
...

In the above program an if-else occurs within the else block of the
first if statement
...
There is no limit on how deeply the
ifs and the elses can be nested
...

These are to be read as ‘AND’ ‘OR’ and ‘NOT’ respectively
...
Most
obviously, two of them are composed of double symbols: || and
&&
...
These single symbols
also have a meaning
...

The first two operators, && and ||, allow two or more conditions
to be combined in an if statement
...
Consider the following example
...
4: The marks obtained by a student in 5 different
subjects are input through the keyboard
...

There are two ways in which we can write a program for this
example
...

/* Method – I */
main( )
{
int m1, m2, m3, m4, m5, per ;
printf ( "Enter marks in five subjects " ) ;
scanf ( "%d %d %d %d %d", &m1, &m2, &m3, &m4, &m5 ) ;
per = ( m1 + m2 + m3 + m4 + m5 ) / 5 ;

Chapter 2: The Decision Control Structure

65

if ( per >= 60 )
printf ( "First division ") ;
else
{
if ( per >= 50 )
printf ( "Second division" ) ;
else
{
if ( per >= 40 )
printf ( "Third division" ) ;
else
printf ( "Fail" ) ;
}
}
}

This is a straight forward program
...
This leads to three disadvantages:
(a) As the number of conditions go on increasing the level of

indentation also goes on increasing
...

(b) Care needs to be exercised to match the corresponding ifs and
elses
...

All these three problems can be eliminated by usage of ‘Logical
operators’
...

/* Method – II */
main( )
{
int m1, m2, m3, m4, m5, per ;
printf ( "Enter marks in five subjects " ) ;
scanf ( "%d %d %d %d %d", &m1, &m2, &m3, &m4, &m5 ) ;
per = ( m1 + m2 + m3 + m4 + m5 ) / 5 ;

66

Let Us C
if ( per >= 60 )
printf ( "First division" ) ;
if ( ( per >= 50 ) && ( per < 60 ) )
printf ( "Second division" ) ;
if ( ( per >= 40 ) && ( per < 50 ) )
printf ( "Third division" ) ;
if ( per < 40 )
printf ( "Fail" ) ;

}

As can be seen from the second if statement, the && operator is
used to combine two conditions
...
If one of the conditions
evaluate to false then the whole thing is treated as false
...

(b) In spite of using several conditions, the program doesn't creep
to the right
...
This effect becomes more pronounced as
the number of conditions go on increasing
...


The else if Clause
There is one more way in which we can write program for
Example 2
...
This involves usage of else if blocks as shown
below:

Chapter 2: The Decision Control Structure

67

/* else if ladder demo */
main( )
{
int m1, m2, m3, m4, m5, per ;
per = ( m1+ m2 + m3 + m4+ m5 ) / per ;
if ( per >= 60 )
printf ( "First division" ) ;
else if ( per >= 50 )
printf ( "Second division" ) ;
else if ( per >= 40 )
printf ( "Third division" ) ;
else
printf ( "fail" ) ;
}

You can note that this program reduces the indentation of the
statements
...

The last else goes to work only if all the conditions fail
...

Note that the else if clause is nothing different
...
This would be
evident if you look at the following code:
if ( i == 2 )
printf ( "With you…" ) ;
else
{
if ( j == 2 )
printf ( "…All the time" ) ;
}

if ( i == 2 )
printf ( "With you…" ) ;
else if ( j == 2 )
printf ( "…All the time " ) ;

Another place where logical operators are useful is when we want
to write programs for complicated logics that ultimately boil down

68

Let Us C

to only two answers
...
5: A company insures its drivers in the following
cases:




If the driver is married
...

If the driver is unmarried, female & above 25 years of age
...
If the marital status, sex
and age of the driver are the inputs, write a program to determine
whether the driver is to be insured or not
...
As
mentioned above, since these are the only two outcomes this
problem can be solved using logical operators
...

/* Insurance of driver - without using logical operators */
main( )
{
char sex, ms ;
int age ;
printf ( "Enter age, sex, marital status " ) ;
scanf ( "%d %c %c", &age, &sex, &ms ) ;
if ( ms == 'M' )
printf ( "Driver is insured" ) ;
else
{
if ( sex == 'M' )
{

Chapter 2: The Decision Control Structure

69

if ( age > 30 )
printf ( "Driver is insured" ) ;
else
printf ( "Driver is not insured" ) ;
}
else
{
if ( age > 25 )
printf ( "Driver is insured" ) ;
else
printf ( "Driver is not insured" ) ;
}
}
}

From the program it is evident that we are required to match
several ifs and elses and several pairs of braces
...
Let us now see how to avoid these
problems by using logical operators
...
If we list down
all those cases in which the driver is insured, then they would be:
(a) Driver is married
...

(c) Driver is an unmarried female above 25 years of age
...




For the second pair of parentheses to evaluate to true, each
condition in the parentheses separated by && must evaluate to
true
...




The last two of the above arguments apply to third pair of
parentheses as well
...

(b) When after testing several conditions the outcome is only one
of the two answers (This problem is often called yes/no
problem)
...
The
following program demonstrates it
...
6: Write a program to calculate the salary as per the
following table:

Gender

Years of Service

Qualifications

Salary

Male

>= 10

Post-Graduate

15000

>= 10

Graduate

10000

< 10

Post-Graduate

10000

< 10

Graduate

7000

>= 10

Post-Graduate

12000

>= 10

Graduate

9000

< 10

Post-Graduate

10000

< 10

Graduate

6000

Female

Figure 2
...
The
third logical operator is the NOT operator, written as !
...
For
example, if the expression evaluates to a non-zero value, then
applying ! operator to it results into a 0
...
The final result (after applying !) 0 or
1 is considered to be false or true respectively
...

! ( y < 10 )

This means “not y less than 10”
...
We can
express the same condition as ( y >= 10 )
...


Hierarchy of Operators Revisited
Since we have now added the logical operators to the list of
operators we know, it is time to review these operators and their
priorities
...
7 summarizes the operators we have seen so
far
...
(A full-fledged precedence table of operators is given
in Appendix A
...
7

A Word of Caution
What will be the output of the following program:

74

Let Us C

main( )
{
int i ;
printf ( "Enter value of i " ) ;
scanf ( "%d", &i ) ;
if ( i = 5 )
printf ( "You entered 5" ) ;
else
printf ( "You entered something other than 5" ) ;
}

And here is the output of two runs of this program
...
This is because we have
written the condition wrongly
...
As a result, the
condition gets reduced to if ( 5 ), irrespective of what you supply
as the value of i
...
Therefore, if ( 5 ) always
evaluates to true and hence the result
...
If the condition fails then straightaway the
printf( ) gets executed
...

Remember that the compiler would not point out this as an error,
since as far as the syntax is concerned nothing has gone wrong, but
the logic has certainly gone awry
...

The following figure summarizes the working of all the three
logical operators
...
8

76

Let Us C

The Conditional Operators
The conditional operators ? and : are sometimes called ternary
operators since they take three arguments
...
Their general form is,
expression 1 ? expression 2 : expression 3

What this expression says is: “if expression 1 is true (that is, if its
value is non-zero), then the value returned will be expression 2,
otherwise the value returned will be expression 3”
...

The equivalent if statement will be,
if ( x > 5 )
y=3;
else
y=4;
(b) char a ;
int y ;
scanf ( "%c", &a ) ;
y = ( a >= 65 && a <= 90 ? 1 : 0 ) ;

Here 1 would be assigned to y if a >=65 && a <=90 evaluates to
true, otherwise 0 would be assigned
...
This is illustrated in the
following examples:
Ex
...
:

char a = 'z' ;
printf ( "%c" , ( a >= 'a' ? a : '!' ) ) ;

(b) The conditional operators can be nested as shown below
...
The error can
be overcome by enclosing the statement in the : part within a
pair of parenthesis
...

Hence it reports an error
...
In practice rarely is this
the requirement
...


Summary
(a) There are three ways for taking decisions in a program
...

The default scope of the if statement is only the next
statement
...

An if block need not always be associated with an else block
...

If the outcome of an if-else ladder is only one of two answers
then the ladder should be replaced either with an else-if clause
or by logical operators
...

In C every test expression is evaluated in terms of zero and
non-zero values
...

Assignment statements used with conditional operators must
be enclosed within a pair of parenthesis
...
0 ;
if ( x == y )
printf ( "\nx and y are equal" ) ;
else
printf ( "\nx and y are not equal" ) ;
(f)

}
main( )
{
int x = 3, y, z ;
y = x = 10 ;
z = x < 10 ;
printf ( "\nx = %d y = %d z = %d", x, y, z ) ;
}

79

80

Let Us C

(g) main( )
{
int k = 35 ;
printf ( "\n%d %d %d", k == 35, k = 50, k > 40 ) ;
}
(h) main( )
{
int i = 65 ;
char j = ‘A’ ;
if ( i == j )
printf ( “C is WOW” ) ;
else
printf( "C is a headache" ) ;
}
(i)

main( )
{
int a = 5, b, c ;
b = a = 15 ;
c = a < 15 ;
printf ( "\na = %d b = %d c = %d", a, b, c ) ;
}

(j)

main( )
{
int x = 15 ;
printf ( "\n%d %d %d", x != 15, x = 20, x < 30 ) ;
}

[B] Point out the errors, if any, in the following programs:
(a) main( )
{
float a = 12
...
52 ;
if ( a = b )
printf ( "\na and b are equal" ) ;

Chapter 2: The Decision Control Structure
}
(b) main( )
{
int j = 10, k = 12 ;
if ( k >= j )
{
{
k=j;
j=k;
}
}
}
(c)

main( )
{
if ( 'X' < 'x' )
printf ( "\nascii value of X is smaller than that of x" ) ;
}

(d) main( )
{
int x = 10 ;
if ( x >= 2 ) then
printf ( "\n%d", x ) ;
}
(e) main( )
{
int x = 10 ;
if x >= 2
printf ( "\n%d", x ) ;
}
(f)

main( )
{
int x = 10, y = 15 ;
if ( x % 2 = y % 3 )

81

82

Let Us C
printf ( "\nCarpathians" ) ;
}

(g) main( )
{
int x = 30 , y = 40 ;
if ( x == y )
printf( "x is equal to y" ) ;
elseif ( x > y )
printf( "x is greater than y" ) ;
elseif ( x < y )
printf( "x is less than y" ) ;
}
(h) main( )
{
int x = 10 ;
if ( x >= 2 ) then
printf ( "\n%d", x ) ;
}
(i)

main( )
{
int a, b ;
scanf ( "%d %d",a, b ) ;
if ( a > b ) ;
printf ( "This is a game" ) ;
else
printf ( "You have to play it" ) ;
}

[C] Attempt the following:
(a) If cost price and selling price of an item is input through the

keyboard, write a program to determine whether the seller has
made profit or incurred loss
...


Chapter 2: The Decision Control Structure

83

(b) Any integer is input through the keyboard
...

(c) Any year is input through the keyboard
...

(Hint: Use the % (modulus) operator)
(d) According to the Gregorian calendar, it was Monday on the

date 01/01/1900
...

(e) A five-digit number is entered through the keyboard
...

(f)

If the ages of Ram, Shyam and Ajay are input through the
keyboard, write a program to determine the youngest of the
three
...
A triangle is valid if the sum of all the three angles
is equal to 180 degrees
...

(i)

Given the length and breadth of a rectangle, write a program to
find whether the area of the rectangle is greater than its
perimeter
...


(j)

Given three points (x1, y1), (x2, y2) and (x3, y3), write a
program to check if all the three points fall on one straight line
...


(Hint: Use sqrt( ) and pow( ) functions)
(l)

Given a point (x, y), write a program to find out if it lies on the
x-axis, y-axis or at the origin, viz
...


Logical Operators
If a = 10, b = 12, c = 0, find the values of the expressions in
the following table:
Expression

Value

a != 6 && b > 5
a == 9 || b < 3
! ( a < 10 )
! ( a > 5 && c )
5 && c != 8 || !c

1

[D] What would be the output of the following programs:
(a) main( )
{
int i = 4, z = 12 ;
if ( i = 5 || z > 50 )
printf ( "\nDean of students affairs" ) ;
else
printf ( "\nDosa" ) ;
}
(b) main( )
{
int i = 4, z = 12 ;

Chapter 2: The Decision Control Structure
if ( i = 5 && z > 5 )
printf ( "\nLet us C" ) ;
else
printf ( "\nWish C was free !" ) ;
}
(c)

main( )
{
int i = 4, j = -1, k = 0, w, x, y, z ;
w = i || j || k ;
x = i && j && k ;
y = i || j && k ;
z = i && j || k ;
printf ( "\nw = %d x = %d y = %d z = %d", w, x, y, z ) ;
}

(d) main( )
{
int i = 4, j = -1, k = 0, y, z ;
y = i + 5 && j + 1 || k + 2 ;
z = i + 5 || j + 1 && k + 2 ;
printf ( "\ny = %d z = %d", y, z ) ;
}
(e) main( )
{
int i = -3, j = 3 ;
if ( !i + !j * 1 )
printf ( "\nMassaro" ) ;
else
printf ( "\nBennarivo" ) ;
}
(f)

main( )
{
int a = 40 ;
if ( a > 40 && a < 45 )
printf ( "a is greater than 40 and less than 45" ) ;

85

86

Let Us C
else
printf ( "%d", a ) ;
}

(g) main( )
{
int p = 8, q = 20 ;
if ( p == 5 && q > 5 )
printf ( "\nWhy not C" ) ;
else
printf ( "\nDefinitely C !" ) ;
}
(h) main( )
{
int i = -1, j = 1, k ,l ;
k = i && j ;
l = i || j ;
printf ( "%d %d", I, j ) ;
}
(i)

main( )
{
int x = 20 , y = 40 , z = 45 ;
if ( x > y && x > z )
printf( "x is big" ) ;
else if ( y > x && y > z )
printf( "y is big" ) ;
else if ( z > x && z > y )
printf( "z is big" ) ;
}

(j)

main( )
{
int i = -1, j = 1, k ,l ;
k = !i && j ;
l = !i || j ;
printf ( "%d %d", i, j ) ;

Chapter 2: The Decision Control Structure
}
(k)

main( )
{
int j = 4, k ;
k = !5 && j ;
printf ( "\nk = %d", k ) ;
}

[E] Point out the errors, if any, in the following programs:
(a) /* This program
/* is an example of
/* using Logical operators */
main( )
{
int i = 2, j = 5 ;
if ( i == 2 && j == 5 )
printf ( "\nSatisfied at last" ) ;
}
(b) main( )
{
int code, flag ;
if ( code == 1 & flag == 0 )
printf ( "\nThe eagle has landed" ) ;
}
(c)

main( )
{
char spy = 'a', password = 'z' ;
if ( spy == 'a' or password == 'z' )
printf ( "\nAll the birds are safe in the nest" ) ;
}

(d) main( )
{

87

88

Let Us C
int i = 10, j = 20 ;
if ( i = 5 ) && if ( j = 10 )
printf ( "\nHave a nice day" ) ;
}

(a) main( )
{
int x = 10 , y = 20;
if ( x >= 2 and y <=50 )
printf ( "\n%d", x ) ;
}
(b) main( )
{
int a, b ;
if ( a == 1 & b == 0 )
printf ( "\nGod is Great" ) ;
}
(c)

main( )
{
int x = 2;
if ( x == 2 && x != 0 ) ;
{
printf ( "\nHi" ) ;
printf( "\nHello" ) ;
}
else
printf( "Bye" ) ;
}

(d) main( )
{
int i = 10, j = 10 ;
if ( i && j == 10)
printf ( "\nHave a nice day" ) ;
}

Chapter 2: The Decision Control Structure

89

[F] Attempt the following:
(a) Any year is entered through the keyboard, write a program to

determine whether the year is leap or not
...

(b) Any character is entered through the keyboard, write a

program to determine whether the character entered is a
capital letter, a small case letter, a digit or a special symbol
...

Characters

ASCII Values

A–Z

65 – 90

a–z

97 – 122

0–9

48 – 57

special symbols

0 - 47, 58 - 64, 91 - 96, 123 - 127

(c) An Insurance company follows following rules to calculate

premium
...
4 per thousand and his policy
amount cannot exceed Rs
...

(2) If a person satisfies all the above conditions except that
the sex is female then the premium is Rs
...
1 lakh
...
6 per thousand and his policy
cannot exceed Rs
...

(4) In all other cases the person is not insured
...


(d) A certain grade of steel is graded according to the following

conditions:
(i) Hardness must be greater than 50
(ii) Carbon content must be less than 0
...

(e) A library charges a fine for every book returned late
...
If you return the book after 30
days your membership will be cancelled
...


Chapter 2: The Decision Control Structure
(f)

91

If the three sides of a triangle are entered through the
keyboard, write a program to check whether the triangle is
valid or not
...


(g) If the three sides of a triangle are entered through the

keyboard, write a program to check whether the triangle is
isosceles, equilateral, scalene or right angled triangle
...
If
the time taken by the worker is between 2 – 3 hours, then the
worker is said to be highly efficient
...
If the time taken is between 4 – 5 hours, the
worker is given training to improve his speed, and if the time
taken by the worker is more than 5 hours, then the worker has
to leave the company
...

(i)

A university has the following rules for a student to qualify
for a degree with A as the main subject and B as the
subsidiary subject:
(a) He should get 55 percent or more in A and 45 percent or
more in B
...
However, he should get at least 45 percent in
A
...

(d) In all other cases he is declared to have failed
...


92
(j)

Let Us C

The policy followed by a company to process customer orders
is given by the following rules:
(a) If a customer order is less than or equal to that in stock
and has credit is OK, supply has requirement
...
Send him
intimation
...
Intimate to him data the
balance will be shipped
...


Conditional operators
[G] What would be the output of the following programs:
(a) main( )
{
int i = -4, j, num ;
j = ( num < 0 ? 0 : num * num ) ;
printf ( "\n%d", j ) ;
}
(b) main( )
{
int k, num = 30 ;
k = ( num > 5 ? ( num <= 10 ? 100 : 200 ) : 500 ) ;
printf ( "\n%d", num ) ;
}
(c)

main( )
{
int j = 4 ;
( !j != 1 ? printf ( "\nWelcome") : printf ( "\nGood Bye") ) ;

Chapter 2: The Decision Control Structure

93

}
[H] Point out the errors, if any, in the following programs:
(a) main( )
{
int tag = 0, code = 1 ;
if ( tag == 0 )
( code > 1 ? printf ( "\nHello" ) ? printf ( "\nHi" ) ) ;
else
printf ( "\nHello Hi !!" ) ;
}
(b) main( )
{
int ji = 65 ;
printf ( "\nji >= 65 ? %d : %c", ji ) ;
}
(c)

main( )
{
int i = 10, j ;
i >= 5 ? ( j = 10 ) : ( j = 15 ) ;
printf ( "\n%d %d", i, j ) ;
}

(d) main( )
{
int a = 5 , b = 6 ;
( a == b ? printf( "%d",a) ) ;
}
(e) main( )
{
int n = 9 ;
( n == 9 ? printf( "You are correct" ) ; : printf( "You are wrong" ) ;) ;
}

94
(f)

Let Us C
main( )
{
int kk = 65 ,ll ;
ll = ( kk == 65 : printf ( "\n kk is equal to 65" ) : printf ( "\n kk is not
equal to 65" ) ) ;
printf( "%d", ll ) ;
}

(g) main( )
{
int x = 10, y = 20 ;
x == 20 && y != 10 ? printf( "True" ) : printf( "False" ) ;
}
[I] Rewrite the following programs using conditional operators
...

(2) Whether a character entered through the keyboard is a
special symbol or not
...

(c) Write a program to find the greatest of the three numbers

entered through the keyboard using conditional operators
...
In the first one,
the calculations were carried out in a fixed order, while in
the second, an appropriate set of instructions were executed
depending upon the outcome of the condition being tested (or a
logical decision being taken)
...
Almost always, if something is worth doing, it’s
worth doing more than once
...
Programming is the same; we frequently need
to perform an action over and over, often with variations in the
details each time
...


Loops
The versatility of the computer lies in its ability to perform a set of
instructions repeatedly
...
This repetitive operation is done
through a loop control instruction
...
They are:
(a) Using a for statement
(b) Using a while statement
(c) Using a do-while statement
Each of these methods is discussed in the following pages
...
Perhaps you want to calculate gross
salaries of ten different persons, or you want to convert
temperatures from centigrade to fahrenheit for 15 different cities
...
Let us look at a
simple example, which uses a while loop
...

START

count = 1

is
count <= 3

No

Yes
STOP
INPUT
p, n, r

si = p * n * r / 100
PRINT
si
count = count + 1

Figure 3
...
%f", si ) ;
count = count + 1 ;
}
}

And here are a few sample runs
...
5
Simple interest = Rs
...
000000
Enter values of p, n and r 2000 5 13
...
1350
...
5
Simple interest = Rs
...
500000

The program executes all statements after the while 3 times
...
These statements
form what is called the ‘body’ of the while loop
...
So long as this condition
remains true all statements within the body of the while loop keep
getting executed repeatedly
...
The variable count is
many a times called either a ‘loop counter’ or an ‘index variable’
...


101

Chapter 3: The Loop Control Structure

START

initialise

False

test
True

STOP

body of loop

increment

Figure 3
...



The statements within the while loop would keep on getting
executed till the condition being tested remains true
...

In place of the condition there can be any other valid
expression
...



The condition being tested may use relational or logical
operators as shown in the following examples:
while ( i <= 10 )
while ( i >= 10 && j <= 15 )
while ( j > 10 && ( b < 15 || c < 20 ) )



The statements within the loop may be a single line or a block
of statements
...
For
example,
while ( i <= 10 )
i=i+1;

is same as
while ( i <= 10 )
{
i=i+1;
}



As a rule the while must test a condition that will eventually
become false, otherwise the loop would be executed forever,
indefinitely
...

The correct form would be as under:
main( )
{
int i = 1 ;
while ( i <= 10 )
{
printf ( "%d\n", i ) ;
i=i+1;
}
}



Instead of incrementing a loop counter, we can even decrement
it and still manage to get the body of the loop executed
repeatedly
...
It
can even be a float
...
0 ;
while ( a <= 10
...
" ) ;
printf ( "
...
1 ;

104

Let Us C
}

}



Even floating point loop counters can be decremented
...

What do you think would be the output of the following
program?
main( )
{
int i = 1 ;
while ( i <= 32767 )
{
printf ( "%d\n", i ) ;
i=i+1;
}
}

No, it doesn’t print numbers from 1 to 32767
...
To begin with, it prints out numbers from 1 to
32767
...
This
process goes on indefinitely
...
The reason is, we have carelessly given a ; after the
while
...

while ( i <= 10 )
;
{
printf ( "%d\n", i ) ;
i=i+1;
}

Since the value of i is not getting incremented the control
would keep rotating within the loop, eternally
...
In fact we can put a pair of braces around any
individual statement or set of statements without affecting the
execution of the program
...
To illustrate their usage let us consider a problem wherein
numbers from 1 to 10 are to be printed on the screen
...
Similarly, to
reduce the value of a variable by 1 a decrement operator -- is
also available
...

(c)

main( )
{
int i = 1 ;
while ( i <= 10 )
{
printf ( "%d\n", i ) ;
i += 1 ;
}
}

Note that += is a compound assignment operator
...
Similarly, j = j + 10 can also
be written as j += 10
...

(d) main( )
{
int i = 0 ;
while ( i++ < 10 )

Chapter 3: The Loop Control Structure

107

printf ( "%d\n", i ) ;
}

In the statement while ( i++ < 10 ), firstly the comparison of
value of i with 10 is performed, and then the incrementation
of i takes place
...
When the control reaches printf( ), i has already
been incremented, hence i must be initialized to 0
...
Since the incrementation of i happens before its
usage, here the ++ operator is called a pre-incrementation
operator
...
The for allows us to specify three things about
a loop in a single line:
(a) Setting a loop counter to an initial value
...

(c) Increasing the value of loop counter each time the program
segment within the loop has been executed
...
Compare
this program with the one, which we wrote using while
...


109

Chapter 3: The Loop Control Structure

START

count INPUT
=1
bs

count = count + 1

is
count <= 3

No

Yes
INPUT
p, n, r

si = p * n * r / 100

PRINT
si

Figure 3
...
%f\n", si ) ;
}
}

STOP

110

Let Us C

If this program is compared with the one written using while, it
can be seen that the three steps—initialization, testing and
incrementation—required for the loop construct have now been
incorporated in the for statement
...




Now the condition count <= 3 is tested
...




Upon reaching the closing brace of for, control is sent back to
the for statement, where the value of count gets incremented
by 1
...




If the value of count is still within the range 1 to 3, the
statements within the braces of for are executed again
...




When count reaches the value 4 the control exits from the loop
and is transferred to the statement (if any) immediately after
the body of for
...


111

Chapter 3: The Loop Control Structure

START

initialise

test

False

True
body of loop

STOP

increment

Figure 3
...
Thus the following for loops are perfectly ok
...
This time we would use a for loop instead of a
while loop
...
Instead of i = i + 1,
the statements i++ or i += 1 can also be used
...
As with the while, the
default scope of for is the immediately next statement after
for
...
Note that inspite of this the
semicolon after the condition is necessary
...

(d) main( )
{
int i = 1 ;
for ( ; i <= 10 ; )
{
printf ( "%d\n", i ) ;
i=i+1;
}
}

Here, neither the initialisation, nor the incrementation is done
in the for statement, but still the two semicolons are
necessary
...
Since the ++ operator
comes after i firstly comparison is done, followed by
incrementation
...

(f)

main( )
{
int i ;
for ( i = 0 ; ++i <= 10 ; )
printf ( "%d\n", i ) ;
}

114

Let Us C

Here, both, the comparison and the incrementation is done
through the same statement, ++i <= 10
...
Note
that it is necessary to initialize i to 0
...
To understand how nested loops work, look at the
program given below:
/* Demonstration of nested loops */
main( )
{
int r, c, sum ;
for ( r = 1 ; r <= 3 ; r++ ) /* outer loop */
{
for ( c = 1 ; c <= 2 ; c++ ) /* inner loop */
{
sum = r + c ;
printf ( "r = %d c = %d sum = %d\n", r, c, sum ) ;
}
}
}

When you run this program you will get the following output:
r = 1 c = 1 sum = 2
r = 1 c = 2 sum = 3
r = 2 c = 1 sum = 3
r = 2 c = 2 sum = 4
r = 3 c = 1 sum = 4
r = 3 c = 2 sum = 5

Here, for each value of r the inner loop is cycled through twice,
with the variable c taking values from 1 to 2
...

As you can see, the body of the outer for loop is indented, and the
body of the inner for loop is further indented
...

Instead of using two statements, one to calculate sum and another
to print it out, we can compact this into one single statement by
saying:
printf ( "r = %d c = %d sum = %d\n", r, c, r + c ) ;

The way for loops have been nested here, similarly, two while
loops can also be nested
...


Multiple Initialisations in the for Loop
The initialisation expression of the for loop can contain more than
one statement separated by a comma
...
e
...
However, only one expression
is allowed in the test expression
...

Use of multiple statements in the initialisation expression also
demonstrates why semicolons are used to separate the three
expressions in the for loop
...


116

Let Us C

The Odd Loop
The loops that we have used so far executed the statements within
them a finite number of times
...
This
situation can be programmed as shown below:
/* Execution of a loop an unknown number of times */
main( )
{
char another ;
int num ;
do
{
printf ( "Enter a number " ) ;
scanf ( "%d", &num ) ;
printf ( "square of %d is %d", num, num * num ) ;
printf ( "\nWant to enter another number y/n " ) ;
scanf ( " %c", &another ) ;
} while ( another == 'y' ) ;
}

And here is the sample output
...
The moment he answers n, the loop
terminates, since the condition ( another == 'y' ) fails
...


Chapter 3: The Loop Control Structure

117

Though it is simpler to program such a requirement using a dowhile loop, the same functionality if required, can also be
accomplished using for and while loops as shown below:
/* odd loop using a for loop */
main( )
{
char another = 'y' ;
int num ;
for ( ; another == 'y' ; )
{
printf ( "Enter a number " ) ;
scanf ( "%d", &num ) ;
printf ( "square of %d is %d", num, num * num ) ;
printf ( "\nWant to enter another number y/n " ) ;
scanf ( " %c", &another ) ;
}
}
/* odd loop using a while loop */
main( )
{
char another = 'y' ;
int num ;
while ( another == 'y' )
{
printf ( "Enter a number " ) ;
scanf ( "%d", &num ) ;
printf ( "square of %d is %d", num, num * num ) ;
printf ( "\nWant to enter another number y/n " ) ;
scanf ( " %c", &another ) ;
}
}

118

Let Us C

The break Statement
We often come across situations where we want to jump out of a
loop instantly, without waiting to get back to the conditional test
...
When break is
encountered inside any loop, control automatically passes to the
first statement after the loop
...
As an example, let’s consider the following example
...
A prime number is one, which is divisible only by 1
or itself
...

If remainder of any of these divisions is zero, the number is not a
prime
...
Following program implements this logic
...
e
...
Why does
the program require the if statement after the while loop at all?
Well, there are two ways the control could have reached outside
the while loop:
(a) It jumped out because the number proved to be not a prime
...

When the loop terminates in the second case, it means that there
was no number between 2 to num - 1 that could exactly divide
num
...
If this is true, the program
should print out the message “Prime number”
...
Consider the following program, which
illustrates this fact
...


The continue Statement
In some programming situations we want to take the control to the
beginning of the loop, bypassing the statements inside the loop,
which have not yet been executed
...
When continue is encountered inside any loop,
control automatically passes to the beginning of the loop
...
As an example, let's
consider the following program
...

12
21

Chapter 3: The Loop Control Structure

121

Note that when the value of i equals that of j, the continue
statement takes the control to the for loop (inner) bypassing rest of
the statements pending execution in the for loop (inner)
...
This difference is the place where the condition is
tested
...
As against this, the do-while
tests the condition after having executed the statements within the
loop
...
5 would clarify the execution of do-while loop still
further
...
5
This means that do-while would execute its statements at least
once, even if the condition fails for the first time
...
This difference is brought about more clearly by
the following program
...
Let's now write the same program using a
do-while loop
...

There are some occasions when we want to execute a loop at least
once no matter what
...
A break takes you out of the do-while
bypassing the conditional test
...


124

Let Us C

Summary
(a) The three type of loops available in C are for, while, and dowhile
...

(c) A continue statement skips the execution of the statements
after it and takes the control to the beginning of the loop
...

(e) The ++ operator increments the operand by 1, whereas, the -operator decrements it by 1
...
They modify the value of the operand to the left of
them
...
1 ;
while ( x == 1
...
1 ;
}
}

(m) main( )
{
while ( '1' < '2' )
printf ( "\nIn while loop" ) ;
}
(n) main( )
{
char x ;
for ( x = 0 ; x <= 255 ; x++ )
printf ( "\nAscii value %d Character %c", x, x ) ;
}
(o) main( )
{
int x = 4, y = 0, z ;
while ( x >= 0 )
{
x-- ;
y++ ;
if ( x == y )

127

128

Let Us C
continue ;
else
printf ( “\n%d %d”, x, y ) ;
}

}
(p) main( )
{
int x = 4, y = 0, z ;
while ( x >= 0 )
{
if ( x == y )
break ;
else
printf ( “\n%d %d”, x, y ) ;
x-- ;
y++ ;
}
}
[B] Attempt the following:

(a) Write a program to calculate overtime pay of 10 employees
...
12
...
Assume that employees do not
work for fractional part of an hour
...

(c) Two numbers are entered through the keyboard
...

(d) Write a program to print all the ASCII values and their
equivalent characters using a while loop
...


Chapter 3: The Loop Control Structure

129

(e) Write a program to print out all Armstrong numbers between
1 and 500
...
For example, 153 = ( 1 * 1 * 1 ) + ( 5 * 5
*5)+(3*3*3)
(f) Write a program for a matchstick game being played between
the computer and a user
...
Rules for the game are as follows:





There are 21 matchsticks
...

After the person picks, the computer does its
picking
...


(g) Write a program to enter the numbers till the user wants and
at the end it should display the count of positive, negative and
zeros entered
...

(i) Write a program to find the range of a set of numbers
...


for, break, continue, do-while
[C] What would be the output of the following programs:
(a) main( )
{
int i = 0 ;
for ( ; i ; )

130

Let Us C
printf ( "\nHere is some mail for you" ) ;

}
(b) main( )
{
int i ;
for ( i = 1 ; i <= 5 ; printf ( "\n%d", i ) ) ;
i++ ;
}
(c)

main( )
{
int i = 1, j = 1 ;
for ( ; ; )
{
if ( i > 5 )
break ;
else
j += i ;
printf ( "\n%d", j ) ;
i += j ;
}
}

(d) main( )
{
int i ;
for ( i = 1 ; i <= 5 ; printf ( "\n%c", 65 ) ) ;
i++ ;
}
[D] Answer the following:
(a) The three parts of the loop expression in the for loop are:

the i____________ expression
the t____________ expression
the i____________ expression

Chapter 3: The Loop Control Structure

131

(b) An expression contains relational operators, assignment

operators, and arithmetic operators
...

2
...

4
...

2
...

4
...

2
...

4
...

2
...

4
...

1
...
for ( ; ; ) ;

132

Let Us C

3
...
int y, x = 0 ;
do
{
y=x;
} while ( x == 0 ) ;

(g) Which of the following statement is used to take the control to

the beginning of the loop?
1
...

3
...


exit
break
continue
None of the above

[E] Attempt the following:
(a) Write a program to print all prime numbers from 1 to 300
...


The smiling face has an ASCII value 1
...

(e) According to a study, the approximate level of intelligence of

a person can be calculated using the following formula:
i = 2 + ( y + 0
...
5 to 12
...
5
...
The ASCII value for heart is 3 and that of
diamond is 4
...
The table should get displayed in
the following form
...


1000 per year while it lasts
...
6000 and
will have a salvage of Rs
...
If 12
percent per annum can be earned on alternate investments
what would be the minimum life of the machine to make it a
more attractive investment compared to alternative
investment?
(l)

When interest compounds q times per year at an annual rate of
r % for n years, the principle p compounds to an amount a as per
the following formula
a = p ( 1 + r / q ) nq

Write a program to read 10 sets of p, r, n & q and calculate
the corresponding as
...


x −1 1 ⎛ x −1 ⎞ 1 ⎛ x −1⎞ 1 ⎛ x −1⎞
+ ⎜
⎟+ ⎜
⎟+ ⎜
⎟ +
...


4

The Case Control
Structure
• Decisions Using switch
The Tips and Traps
• switch Versus if-else Ladder
• The goto Keyword
• Summary
• Exercise

135

136

Let Us C

I

n real life we are often faced with situations where we are
required to make a choice between a number of alternatives
rather than only one or two
...
Serious C programming is same; the choice we
are asked to make is more complicated than merely selecting
between two alternatives
...
This control instruction is in fact the topic
of this chapter
...


Decisions Using switch
The control statement that allows us to make a decision from the
number of choices is called a switch, or more correctly a switchcase-default, since these three keywords go together to make up
the control statement
...
It could be an integer
constant like 1, 2 or 3, or an expression that evaluates to an

Chapter 4: The Case Control Structure

137

integer
...
Each constant in each case must be different from all the
others
...

What happens when we run a program containing a switch? First,
the integer expression following the keyword switch is evaluated
...
When a match is
found, the program executes the statements following that case,
and all subsequent case and default statements as well
...
A few examples
will show how this control structure works
...
The program prints
case 2 and 3 and the default case
...
We said the switch
executes the case where a match is found and all the subsequent
cases and the default as well
...

The following example shows how this is done
...

main( )
{
int i = 2 ;
switch ( i )
{
case 1 :
printf ( "I am in case 1 \n" ) ;
break ;
case 2 :
printf ( "I am in case 2 \n" ) ;
break ;
case 3 :
printf ( "I am in case 3 \n" ) ;
break ;
default :
printf ( "I am in default \n" ) ;
}
}

The output of this program would be:
I am in case 2

Chapter 4: The Case Control Structure

139

The operation of switch is shown below in the form of a flowchart
for a better understanding
...
1

140

Let Us C

The Tips and Traps
A few useful tips about the usage of switch and a few pitfalls to be
avoided:
(a) The earlier program that used switch may give you the wrong
impression that you can use only cases arranged in ascending
order, 1, 2, 3 and default
...
Here is an example of scrambled case order:
main( )
{
int i = 22 ;
switch ( i )
{
case 121 :
printf ( "I am in case 121 \n" ) ;
break ;
case 7 :
printf ( "I am in case 7 \n" ) ;
break ;
case 22 :
printf ( "I am in case 22 \n" ) ;
break ;
default :
printf ( "I am in default \n" ) ;
}
}

The output of this program would be:
I am in case 22

(b) You are also allowed to use char values in case and switch as
shown in the following program:
main( )

Chapter 4: The Case Control Structure

141

{
char c = 'x' ;
switch ( c )
{
case 'v' :
printf ( "I am in case v \n" ) ;
break ;
case 'a' :
printf ( "I am in case a \n" ) ;
break ;
case 'x' :
printf ( "I am in case x \n" ) ;
break ;
default :
printf ( "I am in default \n" ) ;
}
}

The output of this program would be:
I am in case x

In fact here when we use ‘v’, ‘a’, ‘x’ they are actually
replaced by the ASCII values (118, 97, 120) of these character
constants
...
How this can be done is shown in the
following example
...
That is why if an
alphabet a is entered the case ‘a’ is satisfied and since there
are no statements to be executed in this case the control
automatically reaches the next case i
...
case ‘A’ and executes
all the statements in this case
...

(e) Every statement in a switch must belong to some case or the
other
...
However, the statement would never get
executed
...


Chapter 4: The Case Control Structure

143

main( )
{
int i, j ;
printf ( "Enter value of i" ) ;
scanf ( "%d”, &i ) ;
switch ( i )
{
printf ( "Hello" ) ;
case 1 :
j = 10 ;
break ;
case 2 :
j = 20 ;
break ;
}
}

(f) If we have no default case, then the program simply falls
through the entire switch and continues with the next
instruction (if any,) that follows the closing brace of switch
...
Yes, because it
offers a better way of writing programs as compared to if, and
no because in certain situations we are left with no choice but
to use if
...
Even a float is not allowed
...

(h) We can check the value of any expression in a switch
...

switch ( i + j * k )
switch ( 23 + 45 % 4 * k )
switch ( a < 4 && b > 7 )

Expressions can also be used in cases provided they are
constant expressions
...

(i) The break statement when used in a switch takes the control
outside the switch
...

(j) In principle, a switch may occur within another, but in
practice it is rarely done
...

(k) The switch statement is very useful while writing menu
driven programs
...


switch Versus if-else Ladder
There are some things that you simply cannot do with a switch
...
Thus the
following switch is illegal:

Chapter 4: The Case Control Structure

145

switch ( a )
{
case 3 :

...

}

(a), (b) and (c) above may lead you to believe that these are
obvious disadvantages with a switch, especially since there
weren’t any such limitations with if-else
...
How come? This is because the compiler generates a jump
table for a switch during compilation
...
As against this, if-elses are slower because they are
evaluated at execution time
...
Also, a switch with 2 cases
would work slower than if-else ladder
...
As against this, in an if-else ladder 10
conditions would be evaluated at execution time, which makes it
slow
...

If on the other hand the conditions in the if-else were simple and
less in number then if-else would work out faster than the lookup
mechanism of a switch
...
Thus, you as a programmer
should take a decision which of the two should be used when
...

There is seldom a legitimate reason for using goto, and its use is

146

Let Us C

one of the reasons that programs become unreliable, unreadable,
and hard to debug
...

In a difficult programming situation it seems so easy to use a goto
to take the control where you want
...
These constructs are far more logical and easy
to understand
...
They
obscure the flow of control
...
You
can always get the job done without them
...
This is the first
and last time that we are going to use goto in this book
...

main( )
{
int goals ;
printf ( "Enter the number of goals scored against India" ) ;
scanf ( "%d", &goals ) ;
if ( goals <= 5 )
goto sos ;
else
{
printf ( "About time soccer players learnt C\n" ) ;
printf ( "and said goodbye! adieu! to soccer" ) ;
exit( ) ; /* terminates program execution */
}
sos :
printf ( "To err is human!" ) ;

Chapter 4: The Case Control Structure

147

}

And here are two sample runs of the program
...



If the condition is satisfied the goto statement transfers control
to the label ‘sos’, causing printf( ) following sos to be
executed
...




The exit( ) function is a standard library function which
terminates the execution of the program
...



The only programming situation in favour of using goto is
when we want to take the control out of the loop that is
contained in several other loops
...


148

Let Us C

main( )
{
int i, j, k ;
for ( i = 1 ; i <= 3 ; i++ )
{
for ( j = 1 ; j <= 3 ; j++ )
{
for ( k = 1 ; k <= 3 ; k++ )
{
if ( i == 3 && j == 3 && k == 3 )
goto out ;
else
printf ( "%d %d %d\n", i, j, k ) ;
}
}
}
out :
printf ( "Out of the loop at last!" ) ;
}

Go through the program carefully and find out how it works
...


Summary
(a) When we need to choose one among number of alternatives, a
switch statement is used
...

(c) The case keyword is followed by an integer or a character
constant
...

(e) The usage of the goto keyword should be avoided as it usually
violets the normal flow of execution
...
0 ;

Let Us C

Chapter 4: The Case Control Structure
switch ( k = j + 1 )
{
case 3 :
printf ( "\nTrapped" ) ;
break ;
default :
printf ( "\nCaught!" ) ;
}
}
(f)

main( )
{
int ch = 'a' + 'b' ;
switch ( ch )
{
case 'a' :
case 'b' :
printf ( "\nYou entered b" ) ;
case 'A' :
printf ( "\na as in ashar" ) ;
case 'b' + 'a' :
printf ( "\nYou entered a and b" ) ;
}
}

(g) main( )
{
int i = 1 ;
switch ( i - 2 )
{
case -1 :
printf ( "\nFeeding fish" ) ;
case 0 :
printf ( "\nWeeding grass" ) ;
case 1 :
printf ( "\nmending roof" ) ;
default :
printf ( "\nJust to survive" ) ;

151

152

Let Us C
}

}
[B] Point out the errors, if any, in the following programs:
(a) main( )
{
int suite = 1 ;
switch ( suite ) ;
{
case 0 ;
printf ( "\nClub" ) ;
case 1 ;
printf ( "\nDiamond" ) ;
}
}
(b) main( )
{
int temp ;
scanf ( "%d", &temp ) ;
switch ( temp )
{
case ( temp <= 20 ) :
printf ( "\nOoooooohhhh! Damn cool!" ) ;
case ( temp > 20 && temp <= 30 ) :
printf ( "\nRain rain here again!" ) ;
case ( temp > 30 && temp <= 40 ) :
printf ( "\nWish I am on Everest" ) ;
default :
printf ( "\nGood old nagpur weather" ) ;
}
}
(c)

main( )
{
float a = 3
...
5 :
printf ( "\nThe art of C" ) ;
break ;
case 1
...
5 :
printf ( "\nSee through C" ) ;
break ;
case 3
...

2
...

4
...

Prime or not
Odd or even
Exit

154

Let Us C

Make use of switch statement
...
Factorial" ) ;
printf ( "\n2
...
Odd/Even" ) ;
printf ( "\n4
...

This is necessary since the menu must keep reappearing on the
screen once an item is selected and an appropriate action taken
...
The user should enter the class obtained by the
student and the number of subjects he has failed in
...

If the number of subjects he failed in is less than or equal
to 3 then the grace is of 5 marks per subject
...
If the number of subjects he failed in is less than or
equal to 2 then the grace is of 4 marks per subject
...
If the number of subjects he failed in is equal to 1
then the grace is of 5 marks per subject

156

Let Us C

5

Functions &
Pointers
• What is a Function
Why Use Functions
• Passing Values between Functions
• Scope Rule of Functions
• Calling Convention
• One Dicey Issue
• Advanced Features of Functions
Function Declaration and Prototypes
Call by Value and Call by Reference
An Introduction to Pointers
Pointer Notation
Back to Function Calls
Conclusions
Recursion
• Adding Functions to the Library
• Summary
• Exercise

157

158

Let Us C

K

nowingly or unknowingly we rely on so many persons for
so many things
...
He has to rely
on others
...
A computer program (except for the
simplest one) finds itself in a similar situation
...
Instead, it requests other program like
entities—called ‘functions’ in C—to get its tasks done
...
We will look at a variety of
features of these functions, starting with the simplest one and then
working towards those that demonstrate the power of C functions
...
Every C program can be thought of as
a collection of these functions
...
Sometimes the interaction with this person is very simple;
sometimes it’s complex
...
When
you want it to be done, you go to the service station and say, “It’s
time, do it now”
...
You don’t need to be told when the job is
done
...

Let us now look at a simple C function that operates in much the
same way as the mechanic
...


Chapter 5: Functions & Pointers

159

main( )
{
message( ) ;
printf ( "\nCry, and you stop the monotony!" ) ;
}
message( )
{
printf ( "\nSmile, and the world smiles with you
...

Smile, and the world smiles with you
...
What do we mean when we say that main( )
‘calls’ the function message( )? We mean that the control passes to
the function message( )
...
When the message( ) function runs out of
statements to execute, the control returns to main( ), which comes
to life again and begins executing its code at the exact point where
it left off
...

If you have grasped the concept of ‘calling’ a function you are
prepared for a call to more than one function
...




If a program contains only one function, it must be main( )
...




There is no limit on the number of functions that might be
present in a C program
...


Chapter 5: Functions & Pointers


161

After each function has done its thing, control returns to
main( )
...


As we have noted earlier the program execution always begins
with main( )
...
No precedence, no priorities, nobody is nobody’s
boss
...
No? Well, let’s illustrate with an
example
...


162

Let Us C

I am in main
I am in italy
I am in brazil
I am in argentina
I am back in italy
I am finally back in main

Here, main( ) calls other functions, which in turn call still other
functions
...
Since the compiler always begins the program
execution with main( ), every function in a program must be
called directly or indirectly by main( )
...

Let us now summarize what we have learnt so far
...

(b) A function gets called when the function name is followed by
a semicolon
...
For example,
argentina( )
{
statement 1 ;
statement 2 ;
statement 3 ;
}

Chapter 5: Functions & Pointers

163

(d) Any function can be called from any other function
...
For example,
main( )
{
message( ) ;
}
message( )
{
printf ( "\nCan't imagine life without C" ) ;
main( ) ;
}

(e) A function can be called any number of times
...
For example,
main( )
{
message1( ) ;
message2( ) ;
}
message2( )
{
printf ( "\nBut the butter was bitter" ) ;

164

Let Us C

}
message1( )
{
printf ( "\nMary bought some butter" ) ;
}

Here, even though message1( ) is getting called before
message2( ), still, message1( ) has been defined after
message2( )
...
This makes the
program easier to understand
...
Such a process is called ‘recursion’
...

(h) A function can be called from other function, but a function
cannot be defined in another function
...

main( )
{
printf ( "\nI am in main" ) ;
argentina( )
{
printf ( "\nI am in argentina" ) ;
}
}

(i) There are basically two types of functions:
Library functions Ex
...

User-defined functions Ex
...

As the name suggests, library functions are nothing but
commonly required functions grouped together and stored in

Chapter 5: Functions & Pointers

165

what is called a Library
...
Almost always a compiler comes with a library of
standard functions
...


Why Use Functions
Why write separate functions at all? Why not squeeze the entire
logic into one function, main( )? Two reasons:
(a) Writing functions avoids rewriting the same code over and

over
...
If later in the program you
want to calculate the area of a different triangle, you won’t
like it if you are required to write the same instructions all
over again
...
This section of code is nothing but a
function
...
If the operation of a program can
be divided into separate activities, and each activity placed in
a different function, then each could be written and checked
more or less independently
...

What is the moral of the story? Don’t try to cram the entire logic in
one function
...
Instead, break
a program into small units and write functions for each of these
isolated subdivisions
...
What is important is that these functions perform
some logically isolated task
...

We call them and they do what they are designed to do
...
It would be nice to have a little more
control over what functions do, in the same way it would be nice
to be able to tell the mechanic, “Also change the engine oil, I am
going for an outing”
...

The mechanism used to convey information to the function is the
‘argument’
...
The arguments are sometimes also called ‘parameters’
...
In this program, in main( ) we
receive the values of a, b and c through the keyboard and then
output the sum of a, b and c
...
If sum is to be
calculated in calsum( ) and values of a, b and c are received in
main( ), then we must pass on these values to calsum( ), and once
calsum( ) calculates the sum we must return it from calsum( )
back to main( )
...

Enter any three numbers 10 20 30
Sum = 60

There are a number of things to note about this program:
(a) In this program, from the function main( ) the values of a, b
and c are passed on to the function calsum( ), by making a
call to the function calsum( ) and mentioning a, b and c in the
parentheses:
sum = calsum ( a, b, c ) ;

In the calsum( ) function these values get collected in three
variables x, y and z:
calsum ( x, y, z )
int x, y, z ;

(b) The variables a, b and c are called ‘actual arguments’,
whereas the variables x, y and z are called ‘formal
arguments’
...
However, the type, order and number of
the actual and formal arguments must always be same
...
But the
compiler would still treat them as different variables since
they are in different functions
...

The one that we have used in our program is known as
Kernighan and Ritchie (or just K & R) method
...

(d) In the earlier programs the moment closing brace ( } ) of the
called function was encountered the control returned to the
calling function
...

This approach is fine if the called function is not going to
return any meaningful value to the calling function
...
Therefore, it is necessary to use the return statement
...

(2) It returns the value present in the parentheses after
return, to th3e calling program
...


Chapter 5: Functions & Pointers

169

(e) There is no restriction on the number of return statements
that may be present in a function
...

The following program illustrates these facts
...

(f) Whenever the control returns from a function some value is
definitely returned
...
For example,
sum = calsum ( a, b, c ) ;

(g) All the following are valid return statements
...
34 ) ;
return ;

170

Let Us C

In the last statement a garbage value is returned to the calling
function since we are not returning any specific value
...

(h) If we want that a called function should not return any value,
in that case, we must mention so by using the keyword void
as shown below
...
" ) ;
printf ( "\nTails you lose" ) ;
}

(i) A function can return only one value at a time
...

return ( a, b ) ;
return ( x, 12 ) ;

There is a way to get around this limitation, which would be
discussed later in this chapter when we learn pointers
...
For example,
main( )
{
int a = 30 ;
fun ( a ) ;
printf ( "\n%d", a ) ;
}
fun ( int b )
{
b = 60 ;

Chapter 5: Functions & Pointers

171

printf ( "\n%d", b ) ;
}

The output of the above program would be:
60
30

Thus, even though the value of b is changed in fun( ), the
value of a in main( ) remains unchanged
...


Scope Rule of Functions
Look at the following program
main( )
{
int i = 20 ;
display ( i ) ;
}
display ( int j )
{
int k = 35 ;
printf ( "\n%d", j ) ;
printf ( "\n%d", k ) ;
}

In this program is it necessary to pass the value of the variable i to
the function display( )? Will it not become automatically available
to the function display( )? No
...
The presence

172

Let Us C

of i is known only to the function main( ) and not to any other
function
...
That is why to
make the value of i available to display( ) we have to explicitly
pass it to display( )
...
In general we can say that the scope of a variable is
local to the function in which it is defined
...
There are
two possibilities here:
(a) Arguments might be passed from left to right
...

C language follows the second order
...
However, in some function
call the order of passing arguments becomes an important
consideration
...

This however is not the case
...
This is
because C’s calling convention is from right to left
...
Then result of ++a is passed
...
Finally, latest value of a, i
...
3, is passed
...
Once printf( ) collects them it
prints them in the order in which we have asked it to get them
printed (and not the order in which they were passed)
...


One Dicey Issue
Consider the following function calls:
#include ...
Whenever we
call the library functions we must write their prototype before
making the call
...
But since we don’t define the library functions (we
merely call them) we may not know the prototypes of library
functions
...
h’ files is also provided
...
But why multiple files? Because the library
functions are divided into different groups and one file is provided
for each group
...
h’, prototypes of all
mathematical functions are provided in the file ‘math
...

On compilation of the above code the compiler reports all errors
due to the mismatch between parameters in function call and their
corresponding prototypes declared in the file ‘conio
...
You can
even open this file and look at the prototypes
...
h>
int i = 10, j = 20 ;
printf ( "%d %d %d ", i, j ) ;
printf ( "%d", i, j ) ;

The above functions get successfully compiled even though there
is a mismatch in the format specifiers and the variables in the list
...
), and even
with the mismatch above the call still matches with the prototype
of printf( ) present in ‘stdio
...
At run-time when the first printf( )
is executed, since there is no variable matching with the last
specifier %d, a garbage integer gets printed
...


Advanced Features of Functions
With a sound basis of the preliminaries of C functions, let us now
get into their intricacies
...

(a) Function Declaration and Prototypes
(b) Calling functions by value or by reference
(c) Recursion

Let us understand these features one by one
...
More specifically,
whenever a call is made to a function, the compiler assumes that
this function would return a value of the type int
...
Suppose we want to find out square of a number
using a function
...

Enter any number 3
Square of 3 is 9
...
5
Square of 1
...
000000
Enter any number 2
...
5 is 6
...
But square of 1
...
Neither is 6 a square of 2
...
This happened because any C
function, by default, always returns an integer value
...
5 as
2
...
25 is to be returned to
main( )
...
How
do we overcome this? The following program segment illustrates
how to make square( ) capable of returning a float value
...

Enter any number 1
...
5 is 2
...
5
Square of 2
...
250000

Chapter 5: Functions & Pointers

177

Now the expected answers i
...
2
...
25 are obtained
...
What it means is square( ) is a function that
receives a float and returns a float
...

There is a possibility that we may call square( ) from several other
functions other than main( )
...
No, in
such a case we would make only one declaration outside all the
functions at the beginning of the program
...
In some programming situations we want that a called
function should not return any value
...
This is illustrated in the following
program
...
" ) ;
printf ( "\nwho eat nuggets of information
...
" ) ;
printf ( "\nwhen you least expect
...
Therefore, it would just flash the four
messages about viruses and return the control back to the main( )
function
...
But, if you
observe carefully, whenever we called a function and passed
something to it we have always passed the ‘values’ of variables to
the called function
...

By this what we mean is, on calling a function we are passing
values of variables to it
...
So instead of passing the value of a variable, can we not
pass the location number (also called address) of the variable to a
function? If we were able to do so it would become a ‘call by
reference’
...
First we must equip ourselves with
knowledge of how to make a ‘call by reference’
...
So let us first acquire the basics of pointers after
which we would take up this topic once again
...
Other languages have pointers but
few use them so frequently as C does
...


Chapter 5: Functions & Pointers

179

The difficulty beginners have with pointers has much to do with
C’s pointer terminology than the actual concept
...

It is hard to get a grip on pointers just by listening to programmer’s
jargon
...
The first thing we
want to do is explain the rationale of C’s pointer notation
...

(b) Associate the name i with this memory location
...


We may represent i’s location in memory by the following
memory map
...
1

location number

180

Let Us C

We see that the computer has selected memory location 65524 as
the place to store the value 3
...
The
important point is, i’s address in memory is a number
...
‘&’ used in this
statement is C’s ‘address of’ operator
...
Since 65524 represents an address, there is no question of a
sign being associated with it
...
We
have been using the ‘&’ operator all the time in the scanf( )
statement
...
It gives the value stored at a particular address
...

Observe carefully the output of the following program:

181

Chapter 5: Functions & Pointers
main( )
{
int i = 3 ;
printf ( "\nAddress of i = %u", &i ) ;
printf ( "\nValue of i = %d", i ) ;
printf ( "\nValue of i = %d", *( &i ) ) ;
}

The output of the above program would be:
Address of i = 65524
Value of i = 3
Value of i = 3

Note that printing the value of *( &i ) is same as printing the value
of i
...
This address
can be collected in a variable, by saying,
j = &i ;

But remember that j is not an ordinary variable like any other
integer variable
...
Since j is a variable the compiler must
provide it space in the memory
...


i

j

3

65524

65524

Figure 5
...

But wait, we can’t use j in a program without declaring it
...
In other words j points to an integer
...
It stands for ‘value at address’
...

Here is a program that demonstrates the relationships we have
been discussing
...
This program
summarizes everything that we have discussed so far
...
Everything we say about C
pointers from here onwards will depend on your understanding
these expressions thoroughly
...
e
...
Remember that, addresses
(location nos
...
Now we can put these two
facts together and say—pointers are variables that contain
addresses, and since addresses are always whole numbers, pointers
would always contain whole numbers
...
What it means is, s is going to contain the
address of a floating-point value
...
Or in other
words, the value at address stored in ch is going to be a char
...
Pointer, we know
is a variable that contains address of another variable
...
Thus, we now have a
pointer that contains another pointer’s address
...

main( )
{
int i = 3, *j, **k ;
j = &i ;
k = &j ;
printf ( "\nAddress of i = %u", &i ) ;
printf ( "\nAddress of i = %u", j ) ;
printf ( "\nAddress of i = %u", *k ) ;
printf ( "\nAddress of j = %u", &j ) ;
printf ( "\nAddress of j = %u", k ) ;
printf ( "\nAddress of k = %u", &k ) ;
printf ( "\nValue of j = %u", j ) ;
printf ( "\nValue of k = %u", k ) ;
printf ( "\nValue of i = %d", i ) ;
printf ( "\nValue of i = %d", * ( &i ) ) ;
printf ( "\nValue of i = %d", *j ) ;
printf ( "\nValue of i = %d", **k ) ;
}

The output of the above program would be:
Address of i = 65524
Address of i = 65524
Address of i = 65524
Address of j = 65522
Address of j = 65522
Address of k = 65520
Value of j = 65524
Value of k = 65522

185

Chapter 5: Functions & Pointers
Value of i
Value of i
Value of i
Value of i

=3
=3
=3
=3

Figure 5
...

Remember that when you run this program the addresses that get
printed might turn out to be something different than the ones
shown in the figure
...


i

j

k

3

65524

65522

65524

65522

65520

Figure 5
...
We
can extend the above program still further by creating a pointer to
a pointer to an integer pointer
...
There is no limit on how far can we go on
extending this definition
...
And that point of comprehension is usually a
pointer to a pointer
...
But just in case
...
Arguments can
generally be passed to functions in one of the two ways:
(a) sending the values of the arguments
(b) sending the addresses of the arguments

In the first method the ‘value’ of each of the actual arguments in
the calling function is copied into corresponding formal arguments
of the called function
...
The following
program illustrates the ‘Call by Value’
...

In the second method (call by reference) the addresses of actual
arguments in the calling function are copied into formal arguments
of the called function
...
The following program illustrates this
fact
...


188

Let Us C

Usually in C programming we make a call by value
...
But if
desired, it can always be achieved through a call by reference
...
This is shown in the program given below
...
14 * r * r ;
*p = 2 * 3
...

Enter radius of a circle 5
Area = 78
...
400000

Here, we are making a mixed call, in the sense, we are passing the
value of radius but, addresses of area and perimeter
...
That is why when the control
returns from the function areaperi( ) we are able to output the
values of area and perimeter
...


Conclusions
From the programs that we discussed here we can draw the
following conclusions:
(a) If we want that the value of an actual argument should not get
changed in the function being called, pass the actual argument
by value
...

(c) If a function is to be made to return more than one value at a
time then return these values indirectly by using a call by
reference
...
A function
is called ‘recursive’ if a statement within the body of a function
calls the same function
...

Let us now see a simple example of recursion
...
As we know, the

190

Let Us C

factorial of a number is the product of all the integers between 1
and that number
...
This can
also be expressed as 4! = 4 * 3! where ‘!’ stands for factorial
...
Hence
this can be programmed using recursion
...

main( )
{
int a, fact ;
printf ( "\nEnter any number " ) ;
scanf ( "%d", &a ) ;
fact = factorial ( a ) ;
printf ( "Factorial value = %d", fact ) ;
}
factorial ( int x )
{
int f = 1, i ;
for ( i = x ; i >= 1 ; i-- )
f=f*i;
return ( f ) ;
}

And here is the output
...
Recursive factorial function can be
understood only if you are thorough with the above logic
...

main( )
{
int a, fact ;
printf ( "\nEnter any number " ) ;
scanf ( "%d", &a ) ;
fact = rec ( a ) ;
printf ( "Factorial value = %d", fact ) ;
}
rec ( int x )
{
int f ;
if ( x == 1 )
return ( 1 ) ;
else
f = x * rec ( x - 1 ) ;
return ( f ) ;
}

And here is the output for four runs of the program
Enter any number 1
Factorial value = 1
Enter any number 2
Factorial value = 2
Enter any number 3

192

Let Us C

Factorial value = 6
Enter any number 5
Factorial value = 120

Let us understand this recursive factorial function thoroughly
...
The value of a (i
...
1) is copied
into x
...

When the number entered through scanf( ) is 2, the ( x == 1 ) test
fails, so we reach the statement,
f = x * rec ( x - 1 ) ;

And here is where we meet recursion
...
Since
the current value of x is 2, it is same as saying that we must
calculate the value (2 * rec ( 1 ))
...

Thus the statement,
x * rec ( x - 1 ) ;

evaluates to 2, which is stored in the variable f, and is returned to
main( ), where it is duly printed as
Factorial value = 2

Now perhaps you can see what would happen if the value of a is 3,
4, 5 and so on
...
But
before sending the computed value, rec( ) calls rec( ) and waits for
a value to be returned
...
We speak of this series
of calls to rec( ) as being different invocations of rec( )
...
These
recursive invocations end finally when the last invocation gets an
argument value of 1, which the preceding invocation of rec( ) now
uses to calculate its own f value and so on up the ladder
...
I hope
you agree that it’s difficult to visualize how the control flows from
one function call to another
...
4 would make
things a bit clearer
...
Using
Figure 5
...
Go through the figure carefully
...
From
here, since x is not equal to 1, the if block is skipped and rec( ) is
called again with the argument ( x – 1 ), i
...
2
...
Since x is still not equal to 1, rec( ) is called yet another time,
with argument (2 - 1)
...

Similarly, each rec( ) evaluates its f from the returned value, and
finally 6 is returned to main( )
...
4
...
These have been shown in the figure just to

194

Let Us C

help you keep track of how the control flows during successive
recursive calls
...
4
Recursion may seem strange and complicated at first glance, but it
is often the most direct way to code an algorithm, and once you are
familiar with recursion, the clearest way of doing so
...
For
example, if you are to store five numbers then we can store them
in five different variables, an array, a linked list, a binary tree, etc
...
The compiler uses one such data structure called stack
for implementing normal as well as recursive function calls
...
This means
that the last item to get stored on the stack (often called Push
operation) is the first one to get out of it (often called as Pop
operation)
...
Now let us see how the stack works in case of the
following program
...
Following this the address of the statement printf( ) is
pushed on the stack and the control is transferred to fun( )
...
In fun( ) the values of
a and b that were pushed on the stack are referred as i and j
...
When
value of sum is returned sum is popped up from the stack
...
Using this address the control returns
to the printf( ) statement in main( )
...

How the values are being pushed and popped even though we
didn’t write any code to do so? Simple—the compiler on

196

Let Us C

encountering the function call would generate code to push
parameters and the address
...
Figure
5
...


Copy of a
Copy of b
Empty stack

sum
Address

Address of
printf( )
Copy of a

5
2
When call to
fun( ) is met

Copy of b

xxxx
5
2
Before transfering
control to fun( )

7
xxxx

xxxx

i

5

5

j

2

2

After control
reaches fun( )

On returning control
While returning
from fun( )
control from fun( )

Figure 5
...

When it is done this way it is known as ‘CDecl Calling
Convention’
...
The calling
convention also decides whether the parameters being passed to
the function are pushed on the stack in left-to-right or right-to-left
order
...
Thus during the call to fun( ) firstly value of b is pushed to
the stack, followed by the value of a
...
Whenever we make a
recursive call the parameters and the return address gets pushed on
the stack
...
Thus during every recursive function call we
are working with a fresh set of parameters
...
If you
don’t do this and you call the function, you will fall in an
indefinite loop, and the stack will keep on getting filled with
parameters and the return address each time there is a call
...
This is a very common
error while writing recursive functions
...


Adding Functions to the Library
Most of the times we either use the functions present in the
standard library or we define our own functions and use them
...
It makes sense in doing so as the functions that are to
be added to the library are first compiled and then added
...

Let us now see how to add user-defined functions to the library
...
For example, Turbo C/C++

198

Let Us C

compilers provide a utility called ‘tlib
...
Let
us use this utility to add a function factorial( ) to the library
...
c’
...
c’ file using Alt F9
...
obj’ would get created containing the compiled code in
machine language
...
lib + c:\fact
...
lib’ is a library filename, + is a switch, which
means we want to add new function to library and ‘c:\fact
...
obj’ file
...
h’
...

(e) To use the function present inside the library, create a
program as shown below:
#include "c:\\fact
...

If we wish we can delete the existing functions present in the
library using the minus ( - ) switch
...
Let’s see how to do this
...
As their names suggest, factorial( ) calculates and
returns the factorial value of the integer passed to it, prime( )
reports whether the number passed to it is a prime number or not
and fibonacci( ) prints the first n terms of the Fibonacci series,
where n is the number passed to it
...
Note that these steps are
specific to Turbo C/C++ compiler and would vary for other
compilers
...
c’
...

(b) Create a file ‘myfuncs
...

From the dialog that pops us select the option ‘Library’
...


200

Let Us C

(d) Compile the program using Alt F9
...
lib’
...
The library now stands created
...
Here is how it can be done
...
c’ and type the following code in it
...
h"
main( )
{
int f, result ;
f = factorial ( 5 ) ;
result = prime ( 13 ) ;
fibonacci ( 6 ) ;
printf ( "\n%d %d", f, result ) ;
}

Note that the file ‘myfuncs
...
c’
...
h’
mention the appropriate path
...

On doing so a dialog would pop up
...
prj’ and select OK
...
On doing so a file
dialog would appear
...
c’ and then select
‘Add’
...
lib’ in the same manner
...

(d) Compile and execute the project using Ctrl F9
...

(b) Function declaration specifies what is the return type of the
function and the types of parameters it accepts
...

(d) Variables declared in a function are not available to other
functions in a program
...

(e) Pointers are variables which hold addresses of other variables
...

(g) Pointers can be used to make a function return more than one
value simultaneously
...

(i) Adding too many functions and calling them frequently may
slow down the program execution
...
5 ;
char ch = 'C' ;
printit ( a, ch ) ;
}
printit ( a, ch )
{
printf ( "\n%f %c", a, ch ) ;
}

(d) main( )
{
message( ) ;

203

204

Let Us C

message( ) ;
}
message( ) ;
{
printf ( "\nPraise worthy and C worthy are synonyms" ) ;
}
(e) main( )
{
let_us_c( )
{
printf ( "\nC is a Cimple minded language !" ) ;
printf ( "\nOthers are of course no match !" ) ;
}
}
(f)

main( )
{
message( message ( ) ) ;
}
void message( )
{
printf ( "\nPraise worthy and C worthy are synonyms" ) ;
}

[C] Answer the following:

(a) Is this a correctly written function:
sqr ( a ) ;
int a ;
{
return ( a * a ) ;
}

(b) State whether the following statements are True or False:

Chapter 5: Functions & Pointers

205

1
...

2
...

3
...

4
...

5
...

6
...

7
...

8
...

9
...

10
...

[D] Answer the following:

(a) Write a function to calculate the factorial value of any integer
entered through the keyboard
...


206

Let Us C

(c) Write a general-purpose function to convert any given year
into its roman equivalent
...
Write a function to
determine whether the year is a leap year or not
...
Write a
function to obtain the prime factors of this number
...


Function Prototypes, Call by Value/Reference, Pointers
[E] What would be the output of the following programs:
(a) main( )
{
float area ;
int radius = 1 ;
area = circle ( radius ) ;
printf ( "\n%f", area ) ;
}
circle ( int r )

Chapter 5: Functions & Pointers

207

{
float a ;
a = 3
...

(b) Write a function that receives 5 integers and returns the sum,
average and standard deviation of these numbers
...

(c) Write a function that receives marks received by a student in 3
subjects and returns the average and percentage of these
marks
...

[G] What would be the output of the following programs:
(a) main( )
{
int i = 5, j = 2 ;

208

Let Us C
junk ( i, j ) ;
printf ( "\n%d %d", i, j ) ;

}
junk ( int i, int j )
{
i=i*i;
j=j*j;
}
(b) main( )
{
int i = 5, j = 2 ;
junk ( &i, &j ) ;
printf ( "\n%d %d", i, j ) ;
}
junk ( int *i, int *j )
{
*i = *i * *i ;
*j = *j * *j ;
}
(c)

main( )
{
int i = 4, j = 2 ;
junk ( &i, j ) ;
printf ( "\n%d %d", i, j ) ;
}
junk ( int *i, int j )
{
*i = *i * *i ;
j=j*j;
}

(d) main( )
{
float a = 13
...
Modify the
function suitably to obtain the prime factors recursively
...
In a Fibonacci sequence the sum of two
successive terms gives the third term
...

(d) A positive integer is entered through the keyboard, write a
function to find the binary equivalent of this number using
recursion
...

(f) Write a C function to evaluate the series

sin( x) = x − ( x 3 / 3!) + ( x 5 / 5!) − ( x 7 / 7!) + L

212

Let Us C

to five significant digits
...
In other words if x = 5, y = 8, z = 10 after
circular shift y = 5, z = 8, x =10 after circular shift y = 5, z = 8
and x = 10
...

(h) Write a function to find the binary equivalent of a given
decimal integer and display it
...
Use these functions to develop a function
which returns a value 1 if the point (x, y) lines inside the
triangle ABC, otherwise a value 0
...


6

Data Types
Revisited







Integers, long and short
Integers, signed and unsigned
Chars, signed and unsigned
Floats and Doubles
A Few More Issues…
Storage Classes in C
Automatic Storage Class
Register Storage Class
Static Storage Class
External Storage Class
Which to Use When
• Summary
• Exercise

213

214

Let Us C

s seen in the first chapter the primary data types could be of
three varieties—char, int, and float
...
Fact is, the C programmers aren’t really deprived
...
In fact, the
number of data types that can be derived in C, is in principle,
unlimited
...


A

Not only this, the primary data types themselves could be of
several types
...
Or an int could be a short int or a long int
...

To fully define a variable one needs to mention not only its type
but also its storage class
...


Integers, long and short
We had seen earlier that the range of an Integer constant depends
upon the compiler
...
For a 32-bit compiler the range
would be –2147483648 to +2147483647
...
As against this, a 32-bit
compiler like VC++ generates machine language code that is
targeted towards a 32-bit microprocessor like Intel Pentium
...
It would run successfully but
at that time the 32-bit processor would work as if it were a 16-bit
processor
...
If this
backward compatibility support is not provided the 16-bit program

215

Chapter 6: Data Types Revisited

would not run on it
...

Remember that out of the two/four bytes used to store an integer,
the highest bit (16th/32nd bit) is used to store the sign of the integer
...

C offers a variation of the integer data type that provides what are
called short and long integer values
...
Though not a rule, short and long integers
would usually occupy two and four bytes respectively
...
1 shows the sizes of different integers based upon the OS
used
...
1
long variables which hold long integers are declared using the
keyword long, as in,

216

Let Us C

long int i ;
long int abc ;

long integers cause the program to run a bit slower, but the range
of values that we can use is expanded tremendously
...
More than this you should not need unless you are
taking a world census
...
short integer variables are declared as,
short int j ;
short int height ;

C allows the abbreviation of short int to short and of long int to
long
...

Sometimes we come across situations where the constant is small
enough to be an int, but still we want to give it as much storage as
a long
...


Integers, signed and unsigned
Sometimes, we know in advance that the value stored in a given
integer variable will always be positive—when it is being used to

Chapter 6: Data Types Revisited

217

only count things, for example
...
Thus, declaring an integer as unsigned almost
doubles the size of the largest possible value that it can otherwise
take
...
Note that an unsigned integer still occupies
two bytes
...
By default a short int is a signed short int and
a long int is a signed long int
...
To begin
with it might appear strange as to how a char can have a sign
...
e
...
And if 65’s binary can be stored,
then -54’s binary can also be stored (in a signed char)
...
Let us now see a program that illustrates this range:
main( )
{
char ch = 291 ;
printf ( "\n%d %c", ch, ch ) ;
}

What output do you expect from this program? Possibly, 291 and
the character corresponding to it
...
Surprised? The
reason is that ch has been defined as a char, and a char cannot
take a value bigger than +127
...
This value in our case happens to be
35, hence 35 and its corresponding character #, gets printed out
...

main( )
{
char ch ;
for ( ch = 0 ; ch <= 255 ; ch++ )
printf ( "\n%d %c", ch, ch ) ;
}

This program should output ASCII values and their corresponding
characters
...
The reason is that
ch has been defined as a char, and a char cannot take values
bigger than +127
...
-128 is less than 255 hence
the condition is still satisfied
...
-2, -1, 0, +1, +2,
...

Thus the value of ch would keep oscillating between -128 to +127,
thereby ensuring that the loop never gets terminated
...
Thus the only
alternative is to declare ch as an int
...
The program is definitely less elegant, but workable all the
same
...
4e38
to +3
...
If this is insufficient then C offers a double data type
that occupies 8 bytes in memory and has a range from -1
...
7e308
...
7e4932 to +1
...
A long
double occupies 10 bytes in memory
...


220

Let Us C

Let us now write a program that puts to use all the data types that
we have learnt in this chapter
...
Note
the format specifiers used to input and output these data types
...
2
...
4e38 to +3
...
7e308 to +1
...
7e4932 to +1
...
Sizes in this figure are for 16-bit compiler
...
2

A Few More Issues…
Having seen all the variations of the primary types let us take a
look at some more related issues
...

This is even true in case of chars and floats
...

For example, the result of 22
...
0 would be reported more

222

Let Us C

accurately by VC++ compiler as compared to TC/TC++
compilers
...
Since these
microprocessors do not offer floating point support, TC/TC++
performs all float operations using a software piece called
Floating Point Emulator
...
Also, this emulator
becomes part of the EXE file, thereby increasing its size
...

(b) If you look at ranges of chars and ints there seems to be one
extra number on the negative side
...
For
example, let us see how -128 is stored
...
A 1’s compliment is obtained by changing all 0s
to 1s and 1s to 0s
...
e
...
A 2’s compliment is obtained by
adding 1 to the 1’s compliment
...
This is an 8-bit number and it can be easily
accommodated in a char
...
However +127 can be
stored as its binary 01111111 turns out to be a 8-bit number
...
e
...
This is
because from the 9-bit binary of +128, 010000000, only the
right-most 8 bits get stored
...
Thus the value
of the number becomes -128 since it is indeed the binary
of -128, as can be understood from (b) above
...
In general, if we exceed the range from
positive side we end up on the negative side
...
If we exceed the range from negative side we end up
on positive side
...
To fully define a variable one
needs to mention not only its ‘type’ but also its ‘storage class’
...

We have not mentioned storage classes yet, though we have
written several programs in C
...
If we don’t specify the
storage class of a variable in its declaration, the compiler will
assume a storage class depending on the context in which the
variable is used
...

From C compiler’s point of view, a variable name identifies some
physical location within the computer where the string of bits
representing the variable’s value is stored
...
It is the variable’s storage class that
determines in which of these two locations the value is stored
...

(b) What will be the initial value of the variable, if initial value is
not specifically assigned
...
e
...

(c) What is the scope of the variable; i
...
in which functions the
value of the variable would be available
...
e
...


224

Let Us C

There are four storage classes in C:
(a)
(b)
(c)
(d)

Automatic storage class
Register storage class
Static storage class
External storage class

Let us examine these storage classes one by one
...

An unpredictable value, which is often
called a garbage value
...

− Till the control remains within the block
in which the variable is defined
...

main( )
{
auto int i, j ;
printf ( "\n%d %d", i, j ) ;
}

The output of the above program could be
...
When you run
this program you may get different values, since garbage values

Chapter 6: Data Types Revisited

225

are unpredictable
...
Note that the keyword for this storage class is
auto, and not automatic
...

main( )
{
auto int i = 1 ;
{
{
{
printf ( "\n%d ", i ) ;
}
printf ( "%d ", i ) ;
}
printf ( "%d", i ) ;
}
}

The output of the above program is:
111

This is because, all printf( ) statements occur within the outermost
block (a block is all statements enclosed within a pair of braces) in
which i has been defined
...
The moment the control comes out of
the block in which the variable is defined, the variable and its
value is irretrievably lost
...

main( )
{
auto int i = 1 ;
{

226

Let Us C
auto int i = 2 ;
{
auto int i = 3 ;
printf ( "\n%d ", i ) ;
}
printf ( "%d ", i ) ;

}
printf ( "%d", i ) ;
}

The output of the above program would be:
321

Note that the Compiler treats the three i’s as totally different
variables, since they are defined in different blocks
...
Similarly, when the control comes out of the next
innermost block, the third printf( ) refers to the i with value 1
...


Register Storage Class
The features of a variable defined to be of register storage class
are as under:
Storage
Default initial value
Scope

-

Life

-

-

CPU registers
...

Local to the block in which the variable
is defined
...


Chapter 6: Data Types Revisited

227

A value stored in a CPU register can always be accessed faster
than the one that is stored in memory
...
A good example of frequently used variables is
loop counters
...

main( )
{
register int i ;
for ( i = 1 ; i <= 10 ; i++ )
printf ( "\n%d", i ) ;
}

Here, even though we have declared the storage class of i as
register, we cannot say for sure that the value of i would be stored
in a CPU register
...
What
happens in such an event
...

Not every type of variable can be stored in a CPU register
...
However, if you use the register storage class
for a float or a double variable you won’t get any error messages
...


Static Storage Class
The features of a variable defined to have a static storage class are
as under:
Storage
Default initial value




Memory
...


228

Let Us C


Scope

Local to the block in which the variable
is defined
...


Life

Compare the two programs and their output given in Figure 6
...

main( )
{
increment( ) ;
increment( ) ;
increment( ) ;
}

main( )
{
increment( ) ;
increment( ) ;
increment( ) ;
}

increment( )
increment( )
{
{
auto int i = 1 ;
static int i = 1 ;
printf ( "%d\n", i ) ;
printf ( "%d\n", i ) ;
i=i+1;
i=i+1;
}
}
The output of the above programs would be:
1
1
1

1
2
3

Figure 6
...
The function increment( ) gets called from main( )
thrice
...
The only
difference in the two programs is that one uses an auto storage
class for variable i, whereas the other uses static storage class
...
The difference between them is that static
variables don’t disappear when the function is no longer active
...
If the control comes back to the same function
again the static variables have the same values they had last time
around
...
When the function
terminates, i vanishes and its new value of 2 is lost
...

On the other hand, if i is static, it is initialized to 1 only once
...
During the first call to increment( ), i is
incremented to 2
...
The next
time increment( ) is called, i is not re-initialized to 1; on the
contrary its old value 2 is still available
...
e
...

When increment( ) is called the third time, the current value of i
(i
...
3) gets printed and once again i is incremented
...

Consider one more program
...
Thus j becomes pointer to k
...
This correctly prints out 35
...
This time printf( ) prints a garbage value
...
We then accessed
this value using its address that was collected in j
...
If we want
to get the correct value each time then we must declare k as static
...

All this having been said, a word of advice—avoid using static
variables unless you really need them
...


External Storage Class
The features of a variable whose storage class has been defined as
external are as follows:
Storage
Default initial value
Scope
Life






Memory
...

Global
...


Chapter 6: Data Types Revisited

231

External variables differ from those we have already discussed in
that their scope is global, not local
...
Here is an example to illustrate this fact
...

Look at the following program
...
Since both of them have
been defined outside all the functions both enjoy external storage
class
...
When we declare a variable no space is reserved for it,
whereas, when we define it space gets reserved for it in memory
...
There was no need to declare x since its
definition is done before its usage
...

Another small issue—what will be the output of the following
program?
int x = 10 ;
main( )
{
int x = 20 ;
printf ( "\n%d", x ) ;

Chapter 6: Data Types Revisited

233

display( ) ;
}
display( )
{
printf ( "\n%d", x ) ;
}

Here x is defined at two places, once outside main( ) and once
inside it
...
Hence the
printf( ) outputs 20
...
Hence this time the value of
the global x, i
...
10 gets printed
...
For all practical purposes it will be treated as an
extern variable
...
This means that the variable
would not be available to any function that is defined in a file other
than the file in which the variable is defined
...
We can make a few ground
rules for usage of different storage classes in different
programming situations with a view to:
(a) economise the memory space consumed by the variables
(b) improve the speed of execution of the program
The rules are as under:

234

Let Us C



Use static storage class only if you want the value of a
variable to persist between different function calls
...
Reason is, there are very
few CPU registers at our disposal and many of them might be
busy doing something else
...
A typical application of register storage class
is loop counters, which get used a number of times in a
program
...
This would
avoid unnecessary passing of these variables as arguments
when making a function call
...




If you don’t have any of the express needs mentioned above,
then use the auto storage class
...


Summary
(a) We can use different variations of the primary data types,
namely signed and unsigned char, long and short int, float,
double and long double
...

(b) The maximum value a variable can hold depends upon the
number of bytes it occupies in memory
...
We can declare a
variable as unsigned to accommodate greater value without
increasing the bytes occupied
...


Exercise
[A] What would be the output of the following programs:
(a) main( )
{
int i ;
for ( i = 0 ; i <= 50000 ; i++ )
printf ( "\n%d", i ) ;
}
(b) main( )
{
float a = 13
...
5 ;
printf ( "\n%f %lf", a, b ) ;
}
(c)

int i = 0 ;
main( )
{
printf ( "\nmain's i = %d", i ) ;
i++ ;
val( ) ;
printf ( "\nmain's i = %d", i ) ;
val( ) ;
}
val( )
{
i = 100 ;
printf ( "\nval's i = %d", i ) ;
i++ ;
}

236
(d) main( )
{
int x, y, s = 2 ;
s *= 3 ;
y=f(s);
x=g(s);
printf ( "\n%d %d %d", s, y, x ) ;
}
int t = 8 ;
f ( int a )
{
a += -5 ;
t -= 4 ;
return ( a + t ) ;
}
g ( int a )
{
a=1;
t += a ;
return ( a + t ) ;
}
(e) main( )
{
static int count = 5 ;
printf ( "\ncount = %d", count-- ) ;
if ( count != 0 )
main( ) ;
}
(f)

main( )
{
int i, j ;
for ( i = 1 ; i < 5 ; i++ )
{
j=g(i);
printf ( "\n%d", j ) ;
}

Let Us C

Chapter 6: Data Types Revisited
}
g ( int x )
{
static int v = 1 ;
int b = 3 ;
v += x ;
return ( v + x + b ) ;
}
(g) float x = 4
...
0 ;
y=f(x);
printf ( "\n%f %f", x, y ) ;
}
float f ( float a )
{
a += 1
...
5 ;
return ( a + x ) ;
}
(h) main( )
{
func( ) ;
func( ) ;
}
func( )
{
auto int i = 0 ;
register int j = 0 ;
static int k = 0 ;
i++ ; j++ ; k++ ;
printf ( "\n %d % d %d", i, j, k ) ;
}

237

238
(i)

Let Us C

int x = 10 ;
main( )
{
int x = 20 ;
{
int x = 30 ;
printf ( "\n%d", x ) ;
}
printf ("\n%d", x ) ;
}

[B] Point out the errors, if any, in the following programs:
(a) main( )
{
long num ;
num = 2 ;
printf ( "\n%ld", num ) ;
}
(b) main( )
{
char ch = 200 ;
printf ( "\n%d", ch ) ;
}
(c)

main( )
{
unsigned a = 25 ;
long unsigned b = 25l ;
printf ( "\n%lu %u", a, b ) ;
}

(d) main( )
{
long float a = 25
...
345 ;
float *b ;
b = &a ;
printf ( "\n%f %u", a, b ) ;
}
(f)

static int y ;
main( )
{
static int z ;
printf ("%d %d", y, z ) ;
}

[C] State whether the following statements are True or False:

(a) Storage for a register storage class variable is allocated
each time the control reaches the block in which it is
present
...

(c) The value of an automatic storage class variable persists
between various function invocations
...

(e) The register storage class variables cannot hold float
values
...


240

Let Us C

(g) If the variable x is defined as extern and a variable x is
also defined as a local variable of some function, then the
global variable gets preference over the local variable
...

(i) The life of static variable is till the control remains within
the block in which it is defined
...

(k) The address of register variable is not accessible
...
Go through it and find out why is it necessary to
declare the storage class of the variable sum as static
...
It is a
program that processes our source program before it is
passed to the compiler
...
We can certainly write C programs
without knowing anything about the preprocessor or its facilities
...
This chapter explores the preprocessor
directives and discusses the pros and cons of using them in
programs
...
Figure 7
...
You
can observe from the figure that our program passes through
several processors before it is ready to be executed
...
2
...
C then the
expanded source code gets stored in a file PR1
...
When this
expanded source code is compiled the object code gets stored in
PR1
...
When this object code is linked with the object code of
library functions the resultant executable code gets stored in
PR1
...

The preprocessor offers several features called preprocessor
directives
...
The directives can be placed anywhere in a program but
are most often placed at the beginning of a program, before the
first function definition
...
C)
Preprocessor
Expanded source code (PR1
...
OBJ)
Linker
Executable code (PR1
...
1
Processor

Input

Output

Editor

Program typed from
keyboard

C source code containing
program and preprocessor
commands

Preprocessor

C source code file

Source code file with the
preprocessing commands
properly sorted out

Compiler

Source code file with
preprocessing commands
sorted out

Relocatable object code

Linker

Relocatable object code
and the standard C
library functions

Executable code in
machine language

Figure 7
...


Macro Expansion
Have a look at the following program
...
What purpose does it serve? During preprocessing, the
preprocessor replaces every occurrence of UPPER in the program
with 25
...

#define PI 3
...
25 ;
float area ;
area = PI * r * r ;
printf ( "\nArea of circle = %f", area ) ;
}

Chapter 7: The C Preprocessor

245

UPPER and PI in the above programs are often called ‘macro
templates’, whereas, 25 and 3
...

When we compile the program, before the source code passes to
the compiler it is examined by the C preprocessor for any macro
definitions
...
Only after this procedure has been completed is the
program handed over to the compiler
...
This makes it easy for programmers to pick out all the
macro templates when reading through the program
...
A space between # and define is optional
...

And now a million dollar question
...
1415 in
our program? Probably, we have made the program easier to read
...
1415 is such a common constant that it is easily
recognizable, there are many instances where a constant doesn’t
reveal its purpose so readily
...
But which would you find easier to
understand in the middle of your program “\x1B[2J” or
“CLEARSCREEN”? Thus, we would use the macro definition
#define CLEARSCREEN "\x1B[2J"

Then wherever CLEARSCREEN appears in the program it would
automatically be replaced by “\x1B[2J” before compilation begins
...
Suppose a constant like 3
...
This value may have to be
changed some day to 3
...
Ordinarily, you would need to go
through the program and manually change each occurrence of the
constant
...
141592

Beyond this the change will be made automatically to all
occurrences of PI before the beginning of compilation
...
This convenience may not matter
for small programs shown above, but with large programs macro
definitions are almost indispensable
...
A variable could also
have provided a meaningful name for a constant and permitted one
change to effect many occurrences of the constant
...
Then, why not use it? For three
reasons it’s a bad idea
...

Secondly, using a variable for what is really a constant encourages
sloppy thinking and makes the program more difficult to
understand: if something never changes, it is hard to imagine it as
a variable
...
So it’s
no longer a constant that you think it is
...
This directive is used extensively by C
programmers, as you will see in many programs in this book
...

A #define directive is many a times used to define operators as
shown below
...
" ) ;
else
printf ( "\nIn front of the maintenance man" ) ;
}

A #define directive could be used even to replace a condition, as
shown below
...
This is shown below
...
as yet !" ) ;
}

Macros with Arguments
The macros that we have used so far are called simple macros
...
Here is an
example that illustrates this fact
...
14 * x * x )
main( )
{
float r1 = 6
...
5, a ;
a = AREA ( r1 ) ;
printf ( "\nArea of circle = %f", a ) ;
a = AREA ( r2 ) ;
printf ( "\nArea of circle = %f", a ) ;
}

Here’s the output of the program
...
656250
Area of circle = 19
...
14 * x * x )
...
The x in the macro template
AREA(x) is an argument that matches the x in the macro
expansion ( 3
...
The statement AREA(r1) in the
program causes the variable r1 to be substituted for x
...
14 * r1 * r1 )

After the above source code has passed through the preprocessor,
what the compiler gets to work on will be this:
main( )
{
float r1 = 6
...
5, a ;
a = 3
...
14 *r2 * r2 ;
printf ( "Area of circle = %f", a ) ;
}

Here is another example of macros with arguments:
#define ISDIGIT(y) ( y >= 48 && y <= 57 )
main( )
{
char ch ;
printf ( "Enter any digit " ) ;
scanf ( "%c", &ch ) ;
if ( ISDIGIT ( ch ) )
printf ( "\nYou entered a digit" ) ;
else
printf ( "\nIllegal input" ) ;

250

Let Us C

}

Here are some important points to remember while writing macros
with arguments:
(a) Be careful not to leave a blank between the macro template
and its argument while defining the macro
...
14 * x * x )
If we were to write AREA (x) instead of AREA(x), the (x)
would become a part of macro expansion, which we certainly
don’t want
...
14 * r1 * r1 )

which won’t run
...

(b) The entire macro expansion should be enclosed within
parentheses
...

#define SQUARE(n) n * n
main( )
{
int j ;
j = 64 / SQUARE ( 4 ) ;
printf ( "j = %d", j ) ;
}

The output of the above program would be:
j = 64

whereas, what we expected was j = 4
...

(c) Macros can be split into multiple lines, with a ‘\’ (back slash)
present at the end of each line
...

#define HLINE for ( i = 0 ; i < 79 ; i++ ) \
printf ( "%c", 196 ) ;
#define VLINE( X, Y ) {\
gotoxy ( X, Y ) ; \
printf ( "%c", 179 ) ; \
}
main( )
{
int i, y ;
clrscr( ) ;
gotoxy ( 1, 12 ) ;
HLINE
for ( y = 1 ; y < 25 ; y++ )
VLINE ( 39, y ) ;
}

This program draws a vertical and a horizontal line in the
center of the screen
...
If your source code is present in
the file PR1
...
I
...
c

Here CPP stands for C PreProcessor
...
I
...

Note that the file PR1
...
The procedure for generating expanded source code
for compilers other than Turbo C/C++ might be a little
different
...
As we know, even a function can be written to calculate the
area of the circle
...
Then what is the difference between
the two?
In a macro call the preprocessor replaces the macro template with
its macro expansion, in a stupid, unthinking, literal way
...

This brings us to a question: when is it best to use macros with
arguments and when is it better to use a function? Usually macros
make the program run faster but increase the program size,
whereas functions make the program smaller and compact
...
On the other hand, if a function
is used, then even if it is called from hundred different places in

Chapter 7: The C Preprocessor

253

the program, it would take the same amount of space in the
program
...

This gets avoided with macros since they have already been
expanded and placed in the source code before compilation
...
On the other hand, if we have a
fairly large macro and it is used fairly often, perhaps we ought to
replace it with a function
...
This directive causes one file to be included in
another
...
Of course this
presumes that the file being included is existing
...
It is a good programming practice to keep different
sections of a large program separate
...

(b) There are some functions and some macro definitions that we
need almost in all programs that we write
...

It is common for the files that are to be included to have a
...
This extension stands for ‘header file’, possibly because
it contains statements which when included go to the head of your
program
...

For example prototypes of all mathematics related functions are
stored in the header file ‘math
...
h’, and
so on
...
These
are:
#include "filename"
#include

The meaning of each of these forms is given below:
#include "goto
...
c
in the current directory as well as the
specified list of directories as mentioned in
the include search path that might have been
set up
...
c>

This command would look for the file goto
...


The include search path is nothing but a list of directories that
would be searched for the file being included
...
If you
are using Turbo C/C++ compiler then the search path can be set up
by selecting ‘Directories’ from the ‘Options’ menu
...
In this dialog box against ‘Include
Directories’ we can specify the search path
...
Both relative
and absolute paths are valid
...
\dir\incfiles’ is a valid
path
...

Where would #ifdef be useful? When would you like to compile
only a part of your program? In three cases:
(a) To “comment out” obsolete lines of code
...

This involves rewriting some part of source code to the
client’s satisfaction and deleting the old code
...


256

Let Us C

Now you would definitely not like to retype the deleted code
again
...
But we might have already
written a comment in the code that we are about to “comment
out”
...

Obviously, this solution won’t work since we can’t nest
comments in C
...

main( )
{
#ifdef OKAY
statement 1 ;
statement 2 ; /* detects virus */
statement 3 ;
statement 4 ; /* specific to stone virus */
#endif
statement 5 ;
statement 6 ;
statement 7 ;
}

Here, statements 1, 2, 3 and 4 would get compiled only if the
macro OKAY has been defined, and we have purposefully
omitted the definition of the macro OKAY
...

(b) A more sophisticated use of #ifdef has to do with making the
programs portable, i
...
to make them work on two totally
different computers
...
You can do so by
isolating the lines of code that must be different for each
machine by marking them off with #ifdef
...
This is
because the macro INTEL has not been defined
...

If you want to run your program on a Motorola PC, just add a
statement at the top saying,
#define INTEL

Sometimes, instead of #ifdef the #ifndef directive is used
...
The above example if written using
#ifndef, would look like this:
main( )
{
#ifndef INTEL
code suitable for a Intel PC
#else
code suitable for a Motorola PC

258

Let Us C
#endif
code common to both the computers

}

(c) Suppose a function myfunc( ) is defined in a file ‘myfile
...
h’
...
h’ and ‘myfile1
...

This is because the same file ‘myfile
...

To avoid this we can write following code in the header file
...
h */
#ifndef __myfile_h
#define __myfile_h
myfunc( )
{
/* some code */
}
#endif

First time the file ‘myfile
...
If it has not been then it gets defined and the rest of the
code gets included
...
Note that there is nothing special about
__myfile_h
...


#if and #elif Directives
The #if directive can be used to test whether an expression
evaluates to a nonzero value or not
...


Chapter 7: The C Preprocessor

259

A simple example of #if directive is shown below:
main( )
{
#if TEST <= 5
statement 1 ;
statement 2 ;
statement 3 ;
#else
statement 4 ;
statement 5 ;
statement 6 ;
#endif
}

If the expression, TEST <= 5 evaluates to true then statements 1, 2
and 3 are compiled otherwise statements 4, 5 and 6 are compiled
...

If we so desire we can have nested conditional compilation
directives
...

#if ADAPTER == VGA
code for video graphics array
#else
#if ADAPTER == SVGA
code for super video graphics array
#else
code for extended graphics adapter
#endif
#endif

The above program segment can be made more compact by using
another conditional compilation directive called #elif
...


260

Let Us C

Observe that by using the #elif directives the number of #endifs
used in the program get reduced
...
They are:
(a) #undef
(b) #pragma

#undef Directive
On some occasions it may be desirable to cause a defined name to
become ‘undefined’
...
In order to undefine a macro that has been earlier
#defined, the directive,
#undef macro template

can be used
...
All subsequent #ifdef PENTIUM statements would
evaluate to false
...


Chapter 7: The C Preprocessor

261

#pragma Directive
This directive is another special-purpose directive that you can use
to turn on or off certain features
...
There are certain pragmas available with Microsoft C
compiler that deal with formatting source listings and placing
comments in the object file generated by the compiler
...
Some of these pragmas are
discussed below
...
Their usage is as follows:
void fun1( ) ;
void fun2( ) ;
#pragma startup fun1
#pragma exit fun2
main( )
{
printf ( "\nInside maim" ) ;
}
void fun1( )
{
printf ( "\nInside fun1" ) ;
}
void fun2( )
{
printf ( "\nInside fun2" ) ;
}

262

Let Us C

And here is the output of the program
...
If we want two functions to get
executed at startup then their pragmas should be defined in
the reverse order in which you want to get them called
...
Usage of this
pragma is shown below
...
These are:
(a) Though promised, f1( ) doesn’t return a value
...

(c) The control can never reach x++ in f3( )
...
However, this does not happen
since we have suppressed the warnings using the #pragma
directives
...
Though it is a bad
practice to suppress warnings, at times it becomes useful to
suppress them
...
At such times you may suppress the warnings
...


Summary
(a) The preprocessor directives enable the programmer to write
programs that are easy to develop, read, modify and transport
to a different computer system
...

(c) The directives like #undef and #pragma are also useful
although they are seldom used
...

2
...

4
...
A macro must always be written in capital letters
...
A macro should always be accomodated in a single line
...
After preprocessing when the program is sent for
compilation the macros are removed from the expanded
source code
...
Macros with arguments are not allowed
...
Nested macros are allowed
...
In a macro call the control is passed to the macro
...
h"
#include ...

2
...

4
...

2
...

4
...

2
...

4
...

2
...

4
...
To test whether a character entered is a small case letter or
not
...
To test whether a character entered is a upper case letter or
not
...
To test whether a character is an alphabet or not
...

4
...

(b) Write macro definitions with arguments for calculation of
area and perimeter of a triangle, a square and a circle
...
h”
...

(c) Write down macro definitions for the following:
1
...

3
...


To find arithmetic mean of two numbers
...

To convert a uppercase alphabet to lowercase
...


(d) Write macro definitions with arguments for calculation of
Simple Interest and Amount
...
h”
...


268

Let Us C

8

Arrays
• What are Arrays
A Simple Program Using Array
• More on Arrays
Array Initialisation
Bounds Checking
Passing Array Elements to a Function
• Pointers and Arrays
Passing an Entire Array to a Function
The Real Thing
• Two Dimensional Arrays
Initialising a 2-Dimensional Array
Memory Map of a 2-Dimensional Array
Pointers and 2-Dimensional Arrays
Pointer to an Array
Passing 2-D Array to a Function
• Array of Pointers
• Three-Dimensional Array
• Summary
• Exercise

269

270

T

Let Us C
he C language provides a capability that enables the user to
design a set of similar data types, called array
...


We should note that, in many C books and courses arrays and
pointers are taught separately
...
This is because pointers and arrays are so
closely related that discussing arrays without discussing pointers
would make the discussion incomplete and wanting
...
Hence it is all too relevant
to study them together rather than as isolated topics
...
Why so?
Because when a value 10 is assigned to x, the earlier value of x,
i
...
5, is lost
...
However, there are situations in which we
would want to store more than one value at a time in a single
variable
...
In such a case we
have two options to store these marks in memory:

Chapter 8: Arrays

271

(a) Construct 100 variables to store percentage marks obtained by
100 different students, i
...
each variable containing one
student’s marks
...

Obviously, the second alternative is better
...
Moreover, there are certain logics
that cannot be dealt with, without the use of an array
...
These similar quantities could be
percentage marks of 100 students, or salaries of 300 employees, or
ages of 50 employees
...
Each member in the group is referred to by its
position in the group
...

per = { 48, 88, 34, 23, 96 }

If we want to refer to the second number of the group, the usual
notation used is per2
...
However, in C, the fourth number is referred as
per[3]
...
Thus, in this example per[3] refers to 23 and
per[4] refers to 96
...
Here per is the subscripted variable
(array), whereas i is its subscript
...
These similar
elements could be all ints, or all floats, or all chars, etc
...
Remember that all elements of

272

Let Us C

any given array must be of the same type
...
e
...


A Simple Program Using Array
Let us try to write a program to find average marks obtained by a
class of 30 students in a test
...

Array Declaration
To begin with, like other variables an array needs to be declared so
that the compiler will know what kind of an array and how large
an array we want
...
The [30] however is new
...
This number is often
called the ‘dimension’ of the array
...

Accessing Elements of an Array
Once an array is declared, let us see how individual elements in the
array can be referred
...
This number specifies the
element’s position in the array
...
Thus, marks[2] is not the second
element of the array, but the third
...

This variable can take different values and hence can refer to the
different elements in the array in turn
...

Entering Data into an Array
Here is the section of code that places data into an array:
for ( i = 0 ; i <= 29 ; i++ )
{
printf ( "\nEnter marks " ) ;
scanf ( "%d", &marks[i] ) ;
}

The for loop causes the process of asking for and receiving a
student’s marks from the user to be repeated 30 times
...
This process will be repeated until i

274

Let Us C

becomes 29
...

In scanf( ) function, we have used the “address of” operator (&) on
the element marks[i] of the array, just as we have used it earlier
on other variables (&rate, for example)
...

Reading Data from an Array
The balance of the program reads the data back out of the array
and uses it to calculate the average
...
When all
the marks have been added up, the result is divided by 30, the
number of students, to get the average
...

(b) The first element in the array is numbered 0, so the last
element is 1 less than the size of the array
...

(d) Before using an array its type and dimension must be
declared
...
This is a very important point
which we would discuss in more detail later on
...
This is
because of the convenience with which arrays lend themselves to
programming
...


Array Initialisation
So far we have used arrays that did not have any values in them to
begin with
...
Let us now see how to initialize an array while
declaring it
...

int num[6] = { 2, 4, 12, 5, 45, 5 } ;
int n[ ] = { 2, 4, 12, 5, 45, 5 } ;
float press[ ] = { 12
...
2 -23
...
3 } ;

Note the following points carefully:
(a) Till the array elements are not given any specific values, they
are supposed to contain garbage values
...

Array Elements in Memory
Consider the following array declaration:
int arr[8] ;

What happens in memory when we make this declaration? 16
bytes get immediately reserved in memory, 2 bytes each for the 8
integers (under Windows/Linux the array would occupy 32 bytes

276

Let Us C

as each integer would occupy 4 bytes)
...
This so happens because the storage class of this array is
assumed to be auto
...
Whatever be the initial values, all the array elements would
always be present in contiguous memory locations
...
1
...
1

Bounds Checking
In C there is no check to see if the subscript used for an array
exceeds the size of the array
...

This will lead to unpredictable results, to say the least, and there
will be no error message to warn you that you are going beyond
the array size
...
Thus,
the following program may turn out to be suicidal
...


Passing Array Elements to a Function
Array elements can be passed to a function by calling the function
by value, or by reference
...
These two calls
are illustrated below:
/* Demonstration of call by value */
main( )
{
int i ;
int marks[ ] = { 55, 65, 75, 56, 78, 78, 90 } ;
for ( i = 0 ; i <= 6 ; i++ )
display ( marks[i] ) ;
}
display ( int m )
{
printf ( "%d ", m ) ;
}

And here’s the output
...

Note that since at a time only one element is being passed, this
element is collected in an ordinary integer variable m, in the
function display( )
...


278

Let Us C

/* Demonstration of call by reference */
main( )
{
int i ;
int marks[ ] = { 55, 65, 75, 56, 78, 78, 90 } ;
for ( i = 0 ; i <= 6 ; i++ )
disp ( &marks[i] ) ;
}
disp ( int *n )
{
printf ( "%d ", *n ) ;
}

And here’s the output
...
Hence, the variable in which this address is
collected (n) is declared as a pointer variable
...

Read the following program carefully
...
The
program is only partly complete
...
Try your hand at it
...
Consider the following
example:
main( )
{
int i = 3, *x ;
float j = 1
...


280

Let Us C

Value of i = 3
Value of j = 1
...
65526 is original value in
x plus 2, 65524 is original value in y plus 4, and 65520 is original
value in z plus 1
...

That is why, when the integer pointer x is incremented, it points to
an address two locations after the current location, since an int is
always 2 bytes long (under Windows/Linux since int is 4 bytes
long, new value of x would be 65528)
...
This is a very important result
and can be effectively used while passing the entire array to a
function
...
Thus, the following operations
can be performed on a pointer:
(a) Addition of a number to a pointer
...
For example,

Chapter 8: Arrays

281

int i = 4, *j, *k ;
j = &i ;
j=j-2;
j=j-5;
k=j-6;

(c) Subtraction of one pointer from another
...
The
resulting value indicates the number of bytes separating the
corresponding array elements
...

main( )
{
int arr[ ] = { 10, 20, 30, 45, 67, 56, 74 } ;
int *i, *j ;
i = &arr[1] ;
j = &arr[5] ;
printf ( "%d %d", j - i, *j - *i ) ;
}

Here i and j have been declared as integer pointers holding
addresses of first and fifth element of the array respectively
...
The expression j - i would print a value
4 and not 8
...
What would be the result of the
expression *j - *i? 36, since *j and *i return the values
present at addresses contained in the pointers j and i
...
Such comparisons can
be useful when both pointer variables point to elements of the
same array
...
Moreover, a pointer variable can be compared with
zero (usually expressed as NULL)
...

main( )
{
int arr[ ] = { 10, 20, 36, 72, 45, 36 } ;
int *j, *k ;
j = &arr [ 4 ] ;
k = ( arr + 4 ) ;
if ( j == k )
printf ( "The two pointers point to the same location" ) ;
else
printf ( "The two pointers do not point to the same location" ) ;
}

A word of caution! Do not attempt the following operations on
pointers
...

(a) Addition of two pointers
(b) Multiplication of a pointer with a constant
(c) Division of a pointer with a constant
Now we will try to correlate the following two facts, which we
have learnt above:
(a) Array elements are always stored in contiguous memory
locations
...


283

Chapter 8: Arrays

Suppose we have an array num[ ] = { 24, 34, 12, 44, 56, 17 }
...


24

34

65512

65514

12

65516

44

56

17

65518

65520

65522

Figure 8
...

main( )
{
int num[ ] = { 24, 34, 12, 44, 56, 17 } ;
int i ;
for ( i = 0 ; i <= 5 ; i++ )
{
printf ( "\nelement no
...
0 address = 65512
element no
...
2 address = 65516
element no
...
4 address = 65520
element no
...
When you run this program, you may get different
addresses, but what is certain is that each subsequent address
would be 2 bytes (4 bytes under Windows/Linux) greater than its
immediate predecessor
...

main( )
{
int num[ ] = { 24, 34, 12, 44, 56, 17 } ;
int i ;
for ( i = 0 ; i <= 5 ; i++ )
{
printf ( "\naddress = %u ", &num[i] ) ;
printf ( "element = %d", num[i] ) ;
}
}

The output of this program would be:
address = 65512 element = 24
address = 65514 element = 34
address = 65516 element = 12
address = 65518 element = 44
address = 65520 element = 56
address = 65522 element = 17

This method of accessing array elements by using subscripted
variables is already known to us
...

main( )
{
int num[ ] = { 24, 34, 12, 44, 56, 17 } ;

Chapter 8: Arrays

285

int i, *j ;
j = &num[0] ; /* assign address of zeroth element */
for ( i = 0 ; i <= 5 ; i++ )
{
printf ( "\naddress = %u ", j ) ;
printf ( "element = %d", *j ) ;
j++ ; /* increment pointer to point to next location */
}
}

The output of this program would be:
address = 65512 element = 24
address = 65514 element = 34
address = 65516 element = 12
address = 65518 element = 44
address = 65520 element = 56
address = 65522 element = 17

In this program, to begin with we have collected the base address
of the array (address of the 0th element) in the variable j using the
statement,
j = &num[0] ; /* assigns address 65512 to j */

When we are inside the loop for the first time, j contains the
address 65512, and the value at this address is 24
...
65514)
...
65514 contains the
second element of the array, therefore when the printf( )

286

Let Us C

statements are executed for the second time they print out the
second element of the array and its address (i
...
34 and 65514)
...

Obviously, a question arises as to which of the above two methods
should be used when? Accessing array elements by pointers is
always faster than accessing them by subscripts
...

Instead, it would be easier to access the elements using a subscript
if there is no fixed logic in accessing the elements
...


Passing an Entire Array to a Function
In the previous section we saw two programs—one in which we
passed individual elements of an array to a function, and another in
which we passed addresses of individual elements to a function
...
Consider the following example:
/* Demonstration of passing an entire array to a function */
main( )
{
int num[ ] = { 24, 34, 12, 44, 56, 17 } ;
dislpay ( &num[0], 6 ) ;
}
display ( int *j, int n )
{

287

Chapter 8: Arrays
int i ;
for ( i = 0 ; i <= n - 1 ; i++ )
{
printf ( "\nelement = %d", *j ) ;
j++ ; /* increment pointer to point to next element */
}
}

Here, the display( ) function is used to print out the array
elements
...
The for loop is same as the one
used in the earlier program to access the array elements using
pointers
...
It is also necessary to pass the total number of elements
in the array, otherwise the display( ) function would not know
when to terminate the for loop
...
Thus, the following two
function calls are same:
display ( &num[0], 6 ) ;
display ( num, 6 ) ;

The Real Thing
If you have grasped the concept of storage of array elements in
memory and the arithmetic of pointers, here is some real food for
thought
...


24

34

12

44

56

17

65512

65514

65516

65518

65520

65522

Figure 8
...
Thus, by saying *num we would be able to refer to
the zeroth element of the array, that is, 24
...

Similarly, by saying *( num + 1 ) we can refer the first element of
the array, that is, 34
...
When we say, num[i], the C compiler internally
converts it to *( num + i )
...

/* Accessing array elements in different ways */
main( )
{
int num[ ] = { 24, 34, 12, 44, 56, 17 } ;
int i ;
for ( i = 0 ; i <= 5 ; i++ )
{
printf ( "\naddress = %u ", &num[i] ) ;
printf ( "element = %d %d ", num[i], *( num + i ) ) ;
printf ( "%d %d", *( i + num ), i[num] ) ;
}
}

The output of this program would be:

Chapter 8: Arrays

289

address = 65512 element = 24 24 24 24
address = 65514 element = 34 34 34 34
address = 65516 element = 12 12 12 12
address = 65518 element = 44 44 44 44
address = 65520 element = 56 56 56 56
address = 65522 element = 17 17 17 17

Two Dimensional Arrays
So far we have explored arrays with only one dimension
...
The twodimensional array is also called a matrix
...

main( )
{
int stud[4][2] ;
int i, j ;
for ( i = 0 ; i <= 3 ; i++ )
{
printf ( "\n Enter roll no
...
and marks, whereas, in
second part through another for loop we print out these values
...
The second
subscript tells which of the two columns are we talking about—the
zeroth column which contains the roll no
...
Remember the counting of rows and
columns begin with zero
...


col
...
0

col
...
1

row no
...
1

1212

33

row no
...
3

1312

78

Figure 8
...
The above arrangement highlights the fact that a twodimensional array is nothing but a collection of a number of onedimensional arrays placed one below the other
...
However, you can access the array
elements columnwise as well
...


Initialising a 2-Dimensional Array
How do we initialize a two-dimensional array? As simple as this
...

int stud[4][2] = { 1234, 56, 1212, 33, 1434, 80, 1312, 78 } ;

of course with a corresponding loss in readability
...

Thus the declarations,
int arr[2][3] = { 12, 34, 23, 45, 56, 45 } ;
int arr[ ][3] = { 12, 34, 23, 45, 56, 45 } ;

are perfectly acceptable,
whereas,
int arr[2][ ] = { 12, 34, 23, 45, 56, 45 } ;
int arr[ ][ ] = { 12, 34, 23, 45, 56, 45 } ;

would never work
...
in one
column and the marks in the other
...
4 is only conceptually
true
...

In memory whether it is a one-dimensional or a two-dimensional
array the array elements are stored in one continuous chain
...
5
We can easily refer to the marks obtained by the third student
using the subscript notation as shown below:
printf ( "Marks of third student = %d", stud[2][1] ) ;

Can we not refer the same element using pointer notation, the way
we did in one-dimensional arrays? Answer is yes
...
So, read on
...
More specifically, each row of a
two-dimensional array can be thought of as a one-dimensional
array
...

Thus, the declaration,
int s[5][2] ;

Chapter 8: Arrays

293

can be thought of as setting up an array of 5 elements, each of
which is a one-dimensional array containing 2 integers
...

Similarly, if we can imagine s to be a one-dimensional array then
we can refer to its zeroth element as s[0], the next element as s[1]
and so on
...
This fact can be demonstrated by the
following program
...

Address of 0 th 1-D array = 65508
Address of 1 th 1-D array = 65512
Address of 2 th 1-D array = 65516
Address of 3 th 1-D array = 65520

Let’s figure out how the program works
...
Each one-dimensional array occupies 4 bytes (two
bytes for each integer)
...
Hence

294

Let Us C

each one-dimensional arrays starts 4 bytes further along than the
last one, as can be seen in the memory map of the array shown
below
...
6
We know that the expressions s[0] and s[1] would yield the
addresses of the zeroth and first one-dimensional array
respectively
...
6 these addresses turn out to be 65508
and 65512
...

What remains is to be able to refer to individual elements of a onedimensional array
...
We know (from the above program) that s[2] would
give the address 65516, the address of the second one-dimensional
array
...
Or
( s[2] + 1 ) would give the address 65518
...
But, we have already studied while learning
one-dimensional arrays that num[i] is same as *( num + i )
...
Thus, all the
following expressions refer to the same element,
s[2][1]
* ( s[2] + 1 )
*(*(s+2)+1)

Chapter 8: Arrays

295

Using these concepts the following program prints out each
element of a two-dimensional array using pointer notation
...

1234
1212
1434
1312

56
33
80
78

Pointer to an Array
If we can have a pointer to an integer, a pointer to a float, a pointer
to a char, then can we not have a pointer to an array? We certainly
can
...


296

Let Us C

/* Usage of pointer to an array */
main( )
{
int s[5][2] = {
{ 1234, 56 },
{ 1212, 33 },
{ 1434, 80 },
{ 1312, 78 }
};
int ( *p )[2] ;
int i, j, *pint ;
for ( i = 0 ; i <= 3 ; i++ )
{
p = &s[i] ;
pint = p ;
printf ( "\n" ) ;
for ( j = 0 ; j <= 1 ; j++ )
printf ( "%d ", *( pint + j ) ) ;
}
}

And here is the output
...
Note that the
parentheses in the declaration of p are necessary
...
Array of pointers is
covered in a later section in this chapter
...
Thus
first time through this loop p would contain the address of the
zeroth 1-D array
...
Lastly, in the inner for loop using the pointer pint we

Chapter 8: Arrays

297

have printed the individual elements of the 1-D array to which p is
pointing
...
Is there any situation where we can appreciate its usage
better? The entity pointer to an array is immensely useful when we
need to pass a 2-D array to a function
...


Passing 2-D Array to a Function
There are three ways in which we can pass a 2-D array to a
function
...

/* Three ways of accessing a 2-D array */
main( )
{
int a[3][4] = {
1, 2, 3, 4,
5, 6, 7, 8,
9, 0, 1, 6
};
clrscr( ) ;
display ( a, 3, 4 ) ;
show ( a, 3, 4 ) ;
print ( a, 3, 4 ) ;
}
display ( int *q, int row, int col )
{
int i, j ;
for ( i = 0 ; i < row ; i++ )
{
for ( j = 0 ; j < col ; j++ )
printf ( "%d ", * ( q + i * col + j ) ) ;

298

Let Us C

printf ( "\n" ) ;
}
printf ("\n" ) ;
}
show ( int ( *q )[4], int row, int col )
{
int i, j ;
int *p ;
for ( i = 0 ; i < row ; i++ )
{
p=q+i;
for ( j = 0 ; j < col ; j++ )
printf ( "%d ", * ( p + j ) ) ;
printf ( "\n" ) ;
}
printf ( "\n" ) ;
}
print ( int q[ ][4], int row, int col )
{
int i, j ;
for ( i = 0 ; i < row ; i++ )
{
for ( j = 0 ; j < col ; j++ )
printf ( "%d ", q[i][j] ) ;
printf ( "\n" ) ;
}
printf ( "\n" ) ;
}

And here is the output…
1234
5678

299

Chapter 8: Arrays
9016
1234
5678
9016
1234
5678
9016

In the display( ) function we have collected the base address of the
2-D array being passed to it in an ordinary int pointer
...
Suppose i is
equal to 2 and j is equal to 3, then we wish to reach the element
a[2][3]
...
Refer Figure 8
...


1

2

3

4

5

6

7

8

9

0

1

6

65502 …04 …06 …08 …10 …12 …14 …16 …18 …20 …22 …24

Figure 8
...

This turns out to be * (65502 + 11 )
...
Value at this
address is 6
...
A more general
formula for accessing each array element would be:
* ( base address + row no
...
of columns + column no
...
e
...
7)
...
Next time through the loop when i takes a
value 1, the expression q + i fetches the address of the first 1-D
array
...
This
address is once again assigned to p, and using it all elements of the
next 1-D array are accessed
...
The only advantage is that we can now use the more
familiar expression q[i][j] to access array elements
...


Array of Pointers
The way there can be an array of ints or an array of floats,
similarly there can be an array of pointers
...
The addresses present in the array of
pointers can be addresses of isolated variables or addresses of
array elements or any other addresses
...
I think a
program would clarify the concept
...
8 shows the contents and the arrangement of the array of
pointers in memory
...
The for loop in the program
picks up the addresses present in arr and prints the values present
at these addresses
...
8
An array of pointers can even contain the addresses of other
arrays
...

main( )
{
static int a[ ] = { 0, 1, 2, 3, 4 } ;

302

Let Us C

int *p[ ] = { a, a + 1, a + 2, a + 3, a + 4 } ;
printf ( "\n%u %u %d", p, *p, * ( *p ) ) ;
}

I would leave it for you to figure out the output of this program
...
This is because, in practice, one rarely uses this
array
...
The outer array has three elements, each of which is a

303

Chapter 8: Arrays

two-dimensional array of four one-dimensional arrays, each of
which contains two integers
...
Then four such onedimensional arrays are placed one below the other to give a twodimensional array containing four rows
...
In the
array declaration note how the commas have been given
...
9 would possibly help you in visualising the situation better
...
9
Again remember that the arrangement shown above is only
conceptually true
...
10
...
10

65494

65510

304

Let Us C

How would you refer to the array element 1 in the above array?
The first subscript should be [2], since the element is in third twodimensional array; the second subscript should be [3] since the
element is in fourth row of the two-dimensional array; and the
third subscript should be [1] since the element is in second position
in the one-dimensional array
...
It may be noted here that
the counting of array elements even for a 3-D array begins with
zero
...
For example, the following two expressions refer to
the same element in the 3-D array:
arr[2][3][1]
*( *( *( arr + 2 ) + 3 ) + 1 )

Summary
(a) An array is similar to an ordinary variable except that it can
store multiple elements of similar type
...

(c) The array variable acts as a pointer to the zeroth element of
the array
...

(d) On incrementing a pointer it points to the next location of its
type
...

(f) Only limited arithmetic can be done on pointers
...

2
...

4
...

2
...

4
...
The array int num[26] has twenty-six elements
...
The expression num[1] designates the first element in the
array
3
...

4
...

[D] Attempt the following:

(a) Twenty-five numbers are entered from the keyboard into an
array
...
Write a program to find if the number to
be searched is present in the array and if it is present, display
the number of times it appears in the array
...
Write a program to find out how many of them are
positive, how many are negative, how many are even and how
many odd
...
(Refer Figure 8
...
11 (a)

309

Chapter 8: Arrays

Bubble Sort
Iteration 1

Iteration 2

0 44

33

33

33

0

33

0 33

0 33

1 33

44

44

44

1

44

1 44

1 22

2 55

55

55

22

2

22

2 22

2 44

3 22

22

22

55

3

11

3 11

3 11

11

4

55

4 55

4 55

4 11

11

11

Iteration 3

Iteration 4
Result

0 33

0 22

0

22

0 11

1 22

1 33

1

11

1 22

2 11

2 11

2

33

2 33

3 44

3 44

3

44

3 44

4 55

4 55

4

55

4 55

Figure 8
...
11 (c)

Result

310

Let Us C

(d) Implement the following procedure to generate prime
numbers from 1 to 100 into a program
...

step 1
step 2
step 3
step 4
step 5

Fill an array num[100] with numbers from 1 to 100
Starting with the second entry in the array, set all its
multiples to zero
...

Repeat step 3 till you have set up the multiples of
all the non-zero elements to zero
At the conclusion of step 4, all the non-zero entries
left in the array would be prime numbers, so print
out these numbers
...
24, 1
...
5, 5
...
5 } ;
float *j ;
j=a;
j=j+4;
printf ( "\n%d %d %d", j, *j, a[4] ) ;
}
(e) main( )
{
float a[ ] = { 13
...
5, 1
...
4, 3
...

2
...

4
...

2
...

4
...

2
...

4
...

2
...

4
...

2
...

4
...

2
...

4
...

(b) Which of the following is the correct way of declaring a float
pointer:
5
...

7
...


float ptr ;
float *ptr ;
*float ptr ;
None of the above

(c) Add the missing statement for the following program to print
35
...

10
...

12
...

(b) If an array arr contains n elements, then write a program to
check if arr[0] = arr[n-1], arr[1] = arr[n-2] and so on
...

(d) Write a program which performs the following tasks:





initialize an integer array of 10 elements in main( )
pass the entire array to a function modify( )
in modify( ) multiply each element of array by 3
return the control to main( ) and print the new array
elements in main( )

(e) The screen is divided into 25 rows and 80 columns
...
Each character displayed on the screen
occupies two bytes in VDU memory
...

For example, the ASCII value of the character present on
zeroth row and zeroth column on the screen is stored at

317

Chapter 8: Arrays

location number 0xB8000000
...
Similarly ASCII value of character in row 0, col 1 will be at
location 0xB8000000 + 2, and its colour at 0xB8000000 + 3
...

The procedure should stop the moment the user hits a key
from the keyboard
...

(For monochrome adapter, use 0xB0000000 instead of
0xB8000000)
...

(c) Write a program to obtain transpose of a 4 x 4 matrix
...

(d) Very often in fairs we come across a puzzle that contains 15
numbered square pieces mounted on a frame
...
A possible
arrangement of these pieces is shown below:

1

4

15

7

8

10

2

11

14

3

6

13

12

9

5

Figure 8
...

Implement the following procedure through a program:

320

Let Us C

Draw the boxes as shown above
...
Allow the user to hit any of the arrow keys (up,
down, left, or right)
...
Similarly, if down arrow key is hit, then
13 should move down and blank should replace the original
position of 13
...

The user would continue hitting the arrow keys till the
numbers aren’t arranged in ascending order
...
The user who
manages it in minimum number of moves is the one who
wins
...
Arrow keys are special keys which
are identified by their ‘scan codes’
...
It would return the scan code of the
arrow key being hit
...
We are going to deal with it later
...
h"
getkey( )
{
union REGS i, o ;

321

Chapter 8: Arrays
while ( !kbhit( ) )
;
i
...
ah = 0 ;
int86 ( 22, &i, &o ) ;
return ( o
...
ah ) ;
}

(e) Those readers who are from an Engineering/Science
background may try writing programs for following problems
...

Write a program to multiply any two 3 x 3 matrices
...

Write a program to obtain the determinant value of a 5 x
5 matrix
...

……
...

*pj = j + 5;
j = *pj + 5 ;
pj = pj ;
*pi = i + j

Each integer quantity occupies 2 bytes of memory
...
Match the value
represented by left hand side quantities with the right
...

2
...

4
...

b
...

d
...

6
...

8
...

10
...

f
...

h
...

j
...

l
...

2
...

4
...

6
...

8
...

10
...

9
b
...

4
d
...

2
f
...

14
h
...

1
j
...

5
l
...

6
(h) Match the following with reference to the following program
segment:
struct
{
int x, y;
} s[ ] = { 10, 20, 15, 25, 8, 75, 6, 2 };
int *i ;
i=s;

323

Chapter 8: Arrays
1
...

3
...

5
...

7
...

9
...


*( i + 3 )
s[i[7]]
...
y
i[i[1]-i[2]]
i[s[3]
...
y + 10
( *(s + *( i + 1) / *i ) )
...

b
...

d
...

f
...

h
...

j
...

l
...

2
...

4
...

6
...

8
...

10
...

b
...

d
...

f
...

h
...

j
...

l
...

(k) Write a program to find if a square matrix is symmetric
...
The norm is
defined as the square root of the sum of squares of all
elements in the matrix
...
Thus, if p[0] = 15, p[1]= 30, p[2] = 28,
p[3]= 19 and p[4] = 61 then after the shift p[0] = 28, p[1] =
19, p[2] = 61, p[3] = 15 and p[4] = 30
...

(n) A 6 x 6 matrix is entered through the keyboard and stored in a
2-dimensional array mat[7][7]
...

(o) For the following set of sample data, compute the standard
deviation and the mean
...

(p) The area of a triangle can be computed by the sine law when 2
sides of the triangle and the angle between them are known
...


a

b

angle

1
2
3

137
...
2
149
...
9
92
...
93

0
...
89
1
...
0
155
...
7

100
...
95
120
...
00
1
...
75

(q) For the following set of n data points (x, y), compute the
correlation coefficient r, given by
r=

∑ xy − ∑ x∑ y
[n∑ x − ( ∑ x ) ] [n∑ y − ( ∑ y )
2

x
34
...
87
41
...
23
40
...
29
53
...
14
49
...
71
55
...
43
100
...
43
97
...
32
98
...
07
97
...
59
94
...
65

(r) For the following set of point given by (x, y) fit a straight line
given by
y = a + bx

where,
__

__

a = y − bx
b=
x
3
...
5

326
4
...
5
6
...
5
8
...
0
9
...
5
10
...
0
3
...
0
6
...
5
9
...
5
12
...
0

(s) The X and Y coordinates of 10 different points are entered
through the keyboard
...


9

Puppetting On
Strings











What are Strings
More about Strings
Pointers and Strings
Standard Library String Functions
strlen( )
strcpy( )
strcat( )
strcmp( )
Two-Dimensional Array of Characters
Array of Pointers to Strings
Limitation of Array of Pointers to Strings
Solution
Summary
Exercise

327

328

Let Us C

n the last chapter you learnt how to define arrays of differing
sizes and dimensions, how to initialize arrays, how to pass
arrays to a function, etc
...
And strings, the ways to manipulate them,
and how pointers are related to strings are going to be the topics of
discussion in this chapter
...

Character arrays are many a time also called strings
...
Character arrays or strings
are used by programming languages to manipulate text such as
words and sentences
...
For example,
char name[ ] = { 'H', 'A', 'E', 'S', 'L', 'E', 'R', '\0' } ;

Each character in the array occupies one byte of memory and the
last character is always ‘\0’
...
‘\0’ is called
null character
...
ASCII value of
‘\0’ is 0, whereas ASCII value of ‘0’ is 48
...
1 shows the
way a character array is stored in memory
...

The terminating null (‘\0’) is important, because it is the only way
the functions that work with a string can know where the string
ends
...


329

Chapter 9: Puppetting On Strings

H

A

E

S

L

E

R

\0

65518 65519 65520 65521 65522 65523 65524 65525

Figure 9
...
For example, the
string used above can also be initialized as,
char name[ ] = "HAESLER" ;

Note that, in this declaration ‘\0’ is not necessary
...


More about Strings
In what way are character arrays different than numeric arrays?
Can elements in a character array be accessed in the same way as
the elements of a numeric array? Do I need to take any special care
of ‘\0’? Why numeric arrays don’t end with a ‘\0’? Declaring
strings is okay, but how do I manipulate them? Questions galore!!
Well, let us settle some of these issues right away with the help of
sample programs
...

Klinsman

No big deal
...
Can we write
the while loop without using the final value 7? We can; because
we know that each character array always ends with a ‘\0’
...

main( )
{
char name[ ] = "Klinsman" ;
int i = 0 ;
while ( name[i] != `\0' )
{
printf ( "%c", name[i] ) ;
i++ ;
}
}

And here is the output
...
Here is another version of the
same program; this one uses a pointer to access the array elements
...

This base address is stored in the variable ptr using,
ptr = name ;

Once the base address is obtained in ptr, *ptr would yield the
value at this address, which gets printed promptly through,
printf ( "%c", *ptr ) ;

Then, ptr is incremented to point to the next character in the
string
...
This process is
carried out till ptr doesn’t point to the last character in the string,
that is, ‘\0’
...
Thus, all the
following notations refer to the same element:
name[i]
*( name + i )
*( i + name )
i[name]

332

Let Us C

Even though there are so many ways (as shown above) to refer to
the elements of a character array, rarely is any one of them used
...
Note that printf( ) doesn’t print the
‘\0’
...
The same specification can be used to receive a string from
the keyboard, as shown below
...

Enter your name Debashish
Hello Debashish!

Note that the declaration char name[25] sets aside 25 bytes under
the array name[ ], whereas the scanf( ) function fills in the
characters typed at keyboard into this array until the enter key is
hit
...
Naturally,
we should pass the base address of the array to the scanf( )
function
...
This is because the C compiler doesn’t
perform bounds checking on character arrays
...

(b) scanf( ) is not capable of receiving multi-word strings
...
The way to get around this limitation is by
using the function gets( )
...

main( )
{
char name[25] ;
printf ( "Enter your full name " ) ;
gets ( name ) ;
puts ( "Hello!" ) ;
puts ( name ) ;
}

And here is the output
...
Also, on
displaying a string, unlike printf( ), puts( ) places the cursor
on the next line
...

If we are prepared to take the trouble we can make scanf( )
accept multi-word strings by writing it in this manner:
char name[25] ;
printf ( "Enter your full name " ) ;
scanf ( "%[^\n]s", name ) ;

Though workable this is the best of the ways to call a
function, you would agree
...
We may either store it in a
string or we may ask the C compiler to store it at some location in
memory and assign the address of the string in a char pointer
...
For
example, we cannot assign a string to another, whereas, we can
assign a char pointer to another char pointer
...

main( )
{
char str1[ ] = "Hello" ;
char str2[10] ;
char *s = "Good Morning" ;
char *q ;

Chapter 9: Puppetting On Strings

335

str2 = str1 ; /* error */
q = s ; /* works */
}

Also, once a string has been defined it cannot be initialized to
another set of characters
...

main( )
{
char str1[ ] = "Hello" ;
char *p = "Hello" ;
str1 = "Bye" ; /* error */
p = "Bye" ; /* works */
}

Standard Library String Functions
With every C compiler a large set of useful string handling library
functions are provided
...
2 lists the more commonly used
functions along with their purpose
...
2
Out of the above list we shall discuss the functions strlen( ),
strcpy( ), strcat( ) and strcmp( ), since these are the most
commonly used functions
...
Let us study these functions
one by one
...

Its usage is illustrated in the following program
...

string = Bamboozled length = 10
string = Humpty Dumpty length = 13

Note that in the first call to the function strlen( ), we are passing
the base address of the string, and the function in turn returns the
length of the string
...
Even in the second call,
len2 = strlen ( "Humpty Dumpty" ) ;

what gets passed to strlen( ) is the address of the string and not the
string itself
...

/* A look-alike of the function strlen( ) */
main( )
{
char arr[ ] = "Bamboozled" ;
int len1, len2 ;
len1 = xstrlen ( arr ) ;
len2 = xstrlen ( "Humpty Dumpty" ) ;
printf ( "\nstring = %s length = %d", arr, len1 ) ;
printf ( "\nstring = %s length = %d", "Humpty Dumpty", len2 ) ;
}

338

Let Us C

xstrlen ( char *s )
{
int length = 0 ;
while ( *s != '\0' )
{
length++ ;
s++ ;
}
return ( length ) ;
}

The output would be
...
All that it does is keep
counting the characters till the end of string is not met
...


strcpy( )
This function copies the contents of one string into another
...
Here is an example of strcpy( ) in action
...

source string = Sayonara
target string = Sayonara

On supplying the base addresses, strcpy( ) goes on copying the
characters in source string into the target string till it doesn't
encounter the end of source string (‘\0’)
...
Thus, a string gets copied into another,
piece-meal, character by character
...

Let us now attempt to mimic strcpy( ), via our own string copy
function, which we will call xstrcpy( )
...

source string = Sayonara
target string = Sayonara

Note that having copied the entire source string into the target
string, it is necessary to place a ‘\0’ into the target string, to mark
its end
...
So what is the need of the
const qualifier?
What would happen if we add the following lines beyond the last
statement of xstrcpy( )?
...
Can we not
ensure that the source string doesn’t change even accidentally in
xstrcpy( )? We can, by changing the definition as follows:
void xstrcpy ( char *t, const char *s )
{
while ( *s != '\0' )
{

Chapter 9: Puppetting On Strings

341

*t = *s ;
s++ ;
t++ ;
}
*t = '\0' ;
}

By declaring char *s as const we are declaring that the source
string should remain constant (should not change)
...
It also reminds
anybody reading the program listing that the variable is not
intended to change
...
The following code
fragment would help you to fix your ideas about const further
...
The following program shows how this can be
done
...
14 ;
printf ( "\nEnter radius of circle " ) ;
scanf ( "%f", &r ) ;
a = pi * r * r ;
printf ( "\nArea of circle = %f", a ) ;
}

strcat( )
This function concatenates the source string at the end of the target
string
...
Here is an example of
strcat( ) at work
...

source string = Folks!
target string = HelloFolks!

Chapter 9: Puppetting On Strings

343

Note that the target string has been made big enough to hold the
final string
...


strcmp( )
This is a function which compares two strings to find out whether
they are same or different
...
If the two strings are identical,
strcmp( ) returns a value zero
...
Here is a program which puts strcmp( ) in
action
...

0 4 -32

In the first call to strcmp( ), the two strings are identical—“Jerry”
and “Jerry”—and the value returned by strcmp( ) is zero
...
In
the third call to strcmp( ) “Jerry” doesn’t match with “Jerry boy”,
because the null character at the end of “Jerry” doesn’t match the
blank in “Jerry boy”
...
e
...

The exact value of mismatch will rarely concern us
...
If it is, a negative value is returned; if it
isn’t, a positive value is returned
...
Try to implement this procedure into a function
xstrcmp( )
...
Let’s now look at a similar entity, but one dealing
with characters
...

When you do so, it checks your name against a master list to see if
you are worthy of entry to the palace
...

#define FOUND 1
#define NOTFOUND 0
main( )
{
char masterlist[6][10] = {
"akshay",
"parag",
"raman",
"srinivas",
"gopal",
"rajesh"
};
int i, flag, a ;
char yourname[10] ;

Chapter 9: Puppetting On Strings

345

printf ( "\nEnter your name " ) ;
scanf ( "%s", yourname ) ;
flag = NOTFOUND ;
for ( i = 0 ; i <= 5 ; i++ )
{
a = strcmp ( &masterlist[i][0], yourname ) ;
if ( a == 0 )
{
printf ( "Welcome, you can enter the palace" ) ;
flag = FOUND ;
break ;
}
}
if ( flag == NOTFOUND )
printf ( "Sorry, you are a trespasser" ) ;
}

And here is the output for two sample runs of this program
...
The order of the subscripts in the array declaration is
important
...

Instead of initializing names, had these names been supplied from
the keyboard, the program segment would have looked like this
...
As seen in
the last section, if the two strings match, strcmp( ) would return a
value 0, otherwise it would return a non-zero value
...
To begin with, we set flag to
NOTFOUND
...
When the control reaches beyond the for loop, if
flag is still set to NOTFOUND, it means none of the names in the
masterlist[ ][ ] matched with the one supplied from the keyboard
...
3
...
The arrangement as you can
appreciate is similar to that of a two-dimensional numeric array
...
3

\0

a
\0

s

\0
65513
(last location)

Chapter 9: Puppetting On Strings

347

Here, 65454, 65464, 65474, etc
...
As seen from the above pattern some of the
names do not occupy all the bytes reserved for them
...
Thus, 3 bytes go waste
...
In fact, more the
number of names, more would be the wastage
...
by using what is called an ‘array of
pointers’, which is our next topic of discussion
...

Therefore, if we construct an array of pointers it would contain a
number of addresses
...

char *names[ ] = {
"akshay",
"parag",
"raman",
"srinivas",
"gopal",
"rajesh"
};

In this declaration names[ ] is an array of pointers
...
That is, base address of “akshay” is
stored in names[0], base address of “parag” is stored in names[1]
and so on
...
4
...
4
In the two-dimensional array of characters, the strings occupied 60
bytes
...
A substantial saving, you
would agree
...
Thus, one reason to store strings in an array of pointers
is to make a more efficient use of available memory
...
This is shown by
the following programs
...
The purpose of both the programs is
very simple
...

/* Exchange names using 2-D array of characters */
main( )
{
char names[ ][10] = {

Chapter 9: Puppetting On Strings

349

"akshay",
"parag",
"raman",
"srinivas",
"gopal",
"rajesh"
};
int i ;
char t ;
printf ( "\nOriginal: %s %s", &names[2][0], &names[3][0] ) ;
for ( i = 0 ; i <= 9 ; i++ )
{
t = names[2][i] ;
names[2][i] = names[3][i] ;
names[3][i] = t ;
}
printf ( "\nNew: %s %s", &names[2][0], &names[3][0] ) ;
}

And here is the output
...
In effect, 10
exchanges are needed to interchange two names
...
Here is the program
...

Original: raman srinivas
New: srinivas raman

The output is same as the earlier program
...

Thus, by effecting just one exchange we are able to interchange
names
...

Thus, from the point of view of efficient memory usage and ease
of programming, an array of pointers to strings definitely scores
over a two-dimensional character array
...


Chapter 9: Puppetting On Strings

351

Limitation of Array of Pointers to Strings
When we are using a two-dimensional array of characters we are
at liberty to either initialize the strings where we are declaring the
array, or receive the strings using scanf( ) function
...
Thus, the
following program would never work out
...
And it would be definitely
wrong to send these garbage values to scanf( ) as the addresses
where it should keep the strings received from the keyboard
...

#include "alloc
...

Then we have found out its length using strlen( ) and allocated
space for making a copy of this name
...
This
function requires the number of bytes to be allocated and returns
the base address of the chunk of memory that it allocates
...

Hence it has been converted into char * using a feature called
typecasting
...
The
prototype of this function has been declared in the file ‘alloc
...

Hence we have #included this file
...
Moreover, there is no way to increase or
decrease the array size during execution of the program
...


Chapter 9: Puppetting On Strings

353

Unlike this, using malloc( ) we can allocate memory dynamically,
during execution
...

Once we have allocated the memory using malloc( ) we have
copied the name received through the keyboard into this allocated
space and finally stored the address of the allocated chunk in the
appropriate element of names[ ], the array of pointers to strings
...


Summary
(a) A string is nothing but an array of characters terminated by
‘\0’
...

(c) Though scanf( ) can be used to receive multi-word strings,
gets( ) can do the same job in a cleaner way
...

(e) Strings can be operated upon using several standard library
functions like strlen( ), strcpy( ), strcat( ) and strcmp( )
which can manipulate strings
...

(f) Though in principle a 2-D array can be used to handle several
strings, in practice an array of pointers to strings is preferred
since it takes less space and is efficient in processing strings
...


Exercise
Simple strings

354

Let Us C

[A] What would be the output of the following programs:

(a) main( )
{
char c[2] = "A" ;
printf ( "\n%c", c[0] ) ;
printf ( "\n%s", c ) ;
}
(b) main( )
{
char s[ ] = "Get organised! learn C!!" ;
printf ( "\n%s", &s[2] ) ;
printf ( "\n%s", s ) ;
printf ( "\n%s", &s ) ;
printf ( "\n%c", s[2] ) ;
}
(c) main( )
{
char s[ ] = "No two viruses work similarly" ;
int i = 0 ;
while ( s[i] != 0 )
{
printf ( "\n%c %c", s[i], *( s + i ) ) ;
printf ( "\n%c %c", i[s], *( i + s ) ) ;
i++ ;
}
}
(d) main( )
{
char s[ ] = "Churchgate: no church no gate" ;
char t[25] ;
char *ss, *tt ;
ss = s ;
while ( *ss != '\0' )
*ss++ = *tt++ ;

Chapter 9: Puppetting On Strings

355

printf ( "\n%s", t ) ;
}

(e) main( )
{
char str1[ ] = { ‘H’, ‘e’, ‘l’, ‘l’, ‘o’ } ;
char str2[ ] = "Hello" ;
printf ( "\n%s", str1 ) ;
printf ( "\n%s", str2 ) ;
}

(f) main( )
{
printf ( 5 + "Good Morning " ) ;
}
(g) main( )
{
printf ( "%c", "abcdefgh"[4] ) ;
}
(h) main( )
{
printf ( "\n%d%d", sizeof ( ‘3’ ), sizeof ( "3" ), sizeof ( 3 ) ) ;
}
[B] Point out the errors, if any, in the following programs:

(a) main( )
{
char *str1 = "United" ;
char *str2 = "Front" ;
char *str3 ;
str3 = strcat ( str1, str2 ) ;
printf ( "\n%s", str3 ) ;
}
(b) main( )
{

356

Let Us C
int arr[ ] = { ‘A’, ‘B’, ‘C’, ‘D’ } ;
int i ;
for ( i = 0 ; i <= 3 ; i++ )
printf ( "\n%d", arr[i] ) ;

}

(c) main( )
{
char arr[8] = "Rhombus" ;
int i ;
for ( i = 0 ; i <= 7 ; i++ )
printf ( "\n%d", *arr ) ;
arr++ ;
}
[C] Fill in the blanks:

(a) "A" is a ___________ while ’A’ is a ____________
...

(c) The array char name[10] can consist of a maximum of
______ characters
...

[D] Attempt the following:

(a) Which is more appropriate for reading in a multi-word string?
gets( )

printf( )

scanf( )

puts( )

(b) If the string "Alice in wonder land" is fed to the following
scanf( ) statement, what will be the contents of the arrays
str1, str2, str3 and str4?
scanf ( "%s%s%s%s%s", str1, str2, str3, str4 ) ;

357

Chapter 9: Puppetting On Strings

(c) Write a program that converts all lowercase characters in a
given string to its equivalent uppercase character
...
For example, if the sting is "Working with
strings is fun", then if from position 4, 4 characters are to be
extracted then the program should return string as "king"
...

(e) Write a program that converts a string like "124" to an integer
124
...
For example, if the input is
Grim

return

to the

planet

of

apes!!

the output should be
Grim return to the planet of apes!!

Two-dimensional array, Array of pointers to strings
[E] Answer the following:

(a) How many bytes in memory would be occupied by the
following array of pointers to strings? How many bytes would
be required to store the same strings, if they are stored in a
two-dimensional character array?
char *mess[ ] = {
"Hammer and tongs",
"Tooth and nail",

358

Let Us C
"Spit and polish",
"You and C"
};

(b) Can an array of pointers to strings be used to collect strings
from the keyboard? If not, why not?
[F] Attempt the following:

(a) Write a program that uses an array of pointers to strings str[ ]
...
If str1 is found, then
replace it with str2
...
",
"Move a mountain",
"Level a building",
"Erase the past",
"Make a million",
"
...

(b) Write a program to sort a set of names stored in an array in
alphabetical order
...
",
"But to really mess things up
...
Call this function for reversing each
string stored in s
...


September 2004
Mon

Tue

6
13
20
27

7
14
21
28

Wed
1
8
15
22
29

Thu
2
9
16
23
30

Fri
3
10
17
24

Sat
4
11
18
25

Sun
5
12
19
26

Note that according to the Gregorian calendar 01/01/1900 was
Monday
...

(e) Modify the above program suitably so that once the calendar
for a particular month and year has been displayed on the

360

Let Us C

screen, then using arrow keys the user must be able to change
the calendar in the following manner:
Up arrow key
Down arrow key
Right arrow key
Left arrow key

: Next year, same month
: Previous year, same month
: Same year, next month
: Same year, previous month

If the escape key is hit then the procedure should stop
...

(f) A factory has 3 division and stocks 4 categories of products
...
There are three independent
suppliers of products to the factory:
(a) Design a data format to represent each transaction
...

(c) If the cost per item is also given write a program to
calculate the total inventory values
...
Using an array
simulate a dequeue of characters and the operations retrieve
left, retrieve right, insert left, insert right
...

Two pointers (namely, left and right) are needed in this
simulation
...
Assume
that the sentence is not more than 80 characters long
...


Chapter 9: Puppetting On Strings

361

(j) Write a program that takes a set of names of individuals and
abbreviates the first, middle and other names except the last
name by their first letter
...
For example, in the
sentence
“Pleases read this application and give me gratuity”
such occurrences are ea, ea, ui
...
Same thing is true about
C language
...
In
fact when we handle real world data, we don’t usually deal with
little atoms of information by themselves—things like integers,
characters and such
...
As you can see all this data is dissimilar, for
example author is a string, whereas number of pages is an integer
...
A structure gathers together, different atoms of
information that comprise a given entity
...


Why Use Structures
We have seen earlier how ordinary variables can hold one piece of
information and how arrays can hold a number of pieces of
information of the same data type
...
But quite often we deal with
entities that are collection of dissimilar data types
...
You
might want to store its name (a string), its price (a float) and
number of pages in it (an int)
...

(b) Use a structure variable
...
For the sake of
programming convenience assume that the names of books would

Chapter 10: Structures

365

be single character long
...

main( )
{
char name[3] ;
float price[3] ;
int pages[3], i ;
printf ( "\nEnter names, prices and no
...

Enter names, prices and no
...
00 354
C 256
...
70 512
And this is what you entered
A 100
...
500000 682
F 233
...
But as you must have realized, it is an unwieldy
approach that obscures the fact that you are dealing with a group
of characteristics related to a single entity—the book
...
For example, we
would be required to use a number of arrays, if we also decide to
store name of the publisher, date of purchase of book, etc
...

A structure contains a number of data types grouped together
...
The
following example illustrates the use of this data type
...
of pages of 3 books\n" ) ;
scanf ( "%c %f %d", &b1
...
price, &b1
...
name, &b2
...
pages ) ;
scanf ( "%c %f %d", &b3
...
price, &b3
...
name, b1
...
pages ) ;
printf ( "\n%c %f %d", b2
...
price, b2
...
name, b3
...
pages ) ;
}

And here is the output
...
of pages of 3 books
A 100
...
50 682
F 233
...
000000 354
C 256
...
700000 512

This program demonstrates two fundamental aspects of structures:
(a) declaration of a structure
(b) accessing of structure elements
Let us now look at these concepts one by one
...
Each
variable of this data type will consist of a character variable called
name, a float variable called price and an integer variable called
pages
...


...
For example the
variables b1, b2, b3 can be declared to be of the type struct book,
as,
struct book b1, b2, b3 ;

This statement sets aside space in memory
...
These
bytes are always in adjacent memory locations
...

For example,
struct book
{
char name ;
float price ;
int pages ;
};
struct book b1, b2, b3 ;

is same as
...

struct

Chapter 10: Structures

369

{
char name ;
float price ;
int pages ;
} b1, b2, b3 ;

Like primary variables and arrays, structure variables can also be
initialized where they are declared
...

struct book
{
char name[10] ;
float price ;
int pages ;
};
struct book b1 = { "Basic", 130
...
80, 800 } ;

Note the following points while declaring a structure type:
(a) The closing brace in the structure type declaration must be
followed by a semicolon
...
All
a structure declaration does is, it defines the ‘form’ of the
structure
...

In very large programs they are usually put in a separate
header file, and the file is included (using the preprocessor
directive #include) in whichever program we want to use this
structure type
...

In arrays we can access individual elements of an array using a
subscript
...
They use a dot (
...
So to refer to pages of the structure defined in our
sample program we have to use,
b1
...
price

Note that before the dot there must always be a structure variable
and after the dot there must always be a structure element
...
The following program would
illustrate this:
/* Memory map of structure elements */
main( )
{
struct book
{
char name ;
float price ;
int pages ;
};
struct book b1 = { 'B', 130
...
name ) ;

371

Chapter 10: Structures
printf ( "\nAddress of price = %u", &b1
...
pages ) ;
}

Here is the output of the program
...
1
...
name

b1
...
pages

‘B’

130
...
1

Array of Structures
Our sample program showing usage of structure is rather simple
minded
...
But that’s all we intended to do
anyway
...

In our sample program, to store data of 100 books we would be
required to use 100 different structure variables from b1 to b100,
which is definitely not very convenient
...
Following program shows how to
use an array of structures
...
name, &b[i]
...
pages ) ;
}
for ( i = 0 ; i <= 99 ; i++ )
printf ( "\n%c %f %d", b[i]
...
price, b[i]
...

struct book b[100] ;

Chapter 10: Structures

373

This provides space in memory for 100 structures of the type
struct book
...
For
example, we refer to zeroth book’s price as b[0]
...

Similarly, we refer first book’s pages as b[1]
...

(c) It should be appreciated what careful thought Dennis Ritchie
has put into C language
...
But
even using structures programming convenience could not be
achieved, because a lot of variables (b1 to b100 for storing
data about hundred books) needed to be handled
...
Hats off to the genius!
(d) In an array of structures all elements of the array are stored in
adjacent memory locations
...
In our example,
b[0]’s name, price and pages in memory would be
immediately followed by b[1]’s name, price and pages, and
so on
...
What
causes this error to occur? When parsing our source file, if the
compiler encounters a reference to the address of a float, it
sets a flag to have the linker link in the floating-point
emulator
...
There are some cases in which the
reference to the float is a bit obscure and the compiler does
not detect the need for the emulator
...

How can we force the formats to be linked? That’s where the
linkfloat( ) function comes in
...
There is no need
to call this function, just define it anywhere in your program
...
We would highlight these intricacies
with suitable examples:
(a) The values of a structure variable can be assigned to another
structure variable of the same type using the assignment
operator
...
Obviously, programmers prefer assignment to
piece-meal copying
...

main( )
{
struct employee
{
char name[10] ;
int age ;
float salary ;
};
struct employee e1 = { "Sanjay", 30, 5500
...
name, e1
...
age = e1
...
salary = e1
...
name, e1
...
salary ) ;
printf ( "\n%s %d %f", e2
...
age, e2
...
name, e3
...
salary ) ;
}

The output of the program would be
...
500000
Sanjay 30 5500
...
500000

Ability to copy the contents of all structure elements of one
variable into the corresponding elements of another structure
variable is rather surprising, since C does not allow assigning
the contents of one array to another just by equating the two
...

This copying of all structure elements at one go has been
possible only because the structure elements are stored in
contiguous memory locations
...
And who knows, had this been so, structures would
not have become popular at all
...
Using
this facility complex data types can be created
...

main( )
{
struct address

376

Let Us C
{
char phone[15] ;
char city[25] ;
int pin ;
};
struct emp
{
char name[25] ;
struct address a ;
};
struct emp e = { "jeru", "531046", "nagpur", 10 };
printf ( "\nname = %s phone = %s", e
...
a
...
a
...
a
...

name = jeru phone = 531046
city = nagpur pin = 10

Notice the method used to access the element of a structure
that is part of another structure
...
a
...
a
...
We
can nest a structure within a structure, within another
structure, which is in still another structure and so on
...
Such
construction however gives rise to variable names that can be
surprisingly self descriptive, for example:
maruti
...
bolt
...
qty

Chapter 10: Structures

377

This clearly signifies that we are referring to the quantity of
large sized bolts that fit on an engine of a maruti car
...
We may either pass individual structure
elements or the entire structure variable at one go
...

/* Passing individual structure elements */
main( )
{
struct book
{
char name[25] ;
char author[25] ;
int callno ;
};
struct book b1 = { "Let us C", "YPK", 101 } ;
display ( b1
...
author, b1
...

Let us C YPK 101

Observe that in the declaration of the structure, name and
author have been declared as arrays
...
name, b1
...
callno ) ;

378

Let Us C

we are passing the base addresses of the arrays name and
author, but the value stored in callno
...

It can be immediately realized that to pass individual elements
would become more tedious as the number of structure
elements go on increasing
...
This method is shown in the
following program
...
name, b
...
callno ) ;
}

And here is the output
...
We cannot say,
struct book b1 ;

because the data type struct book is not known to the
function display( )
...

(d) The way we can have a pointer pointing to an int, or a pointer
pointing to a char, similarly we can have a pointer pointing to
a struct
...

Let us look at a program that demonstrates the usage of a
structure pointer
...
name, b1
...
callno ) ;
printf ( "\n%s %s %d", ptr->name, ptr->author, ptr->callno ) ;
}

The first printf( ) is as usual
...
We can’t use ptr
...
callno because ptr is
not a structure variable but a pointer to a structure, and the dot

380

Let Us C

operator requires a structure variable on its left
...
Remember that on the left hand side of
the ‘
...
The arrangement
of the structure variable and pointer to structure in memory is
shown in the Figure 10
...


b1
...
author

b1
...
2
Can we not pass the address of a structure variable to a
function? We can
...

/* Passing address of a structure variable */
struct book
{
char name[25] ;
char author[25] ;
int callno ;
};
main( )
{
struct book b1 = { "Let us C", "YPK", 101 } ;
display ( &b1 ) ;

Chapter 10: Structures

381

}
display ( struct book *b )
{
printf ( "\n%s %s %d", b->name, b->author, b->callno ) ;
}

And here is the output
...

Also, the structure struct book should be declared outside
main( ) such that this data type is available to display( ) while
declaring pointer to the structure
...
a, &e
...
s ) ;

If we execute this program using TC/TC++ compiler we get
the addresses as:
65518 65520 65521

As expected, in memory the char begins immediately after
the int and float begins immediately after the char
...
In fact there is a hole of
three bytes after the char
...
VC++ is a 32-bit compiler targeted to generate code for a
32-bit microprocessor
...
Hence the VC++ compiler aligns
every element of a structure at an address that is multiple of
four
...

However, some programs need to exercise precise control
over the memory areas where data is placed
...
For this the
byte arrangement of the structure elements must match the
arrangement of various fields in the boot sector of the disk
...
This directive specifies packing alignment for
structure members
...
Turbo C/C++
compiler doesn’t support this feature, VC++ compiler does
...

#pragma pack(1)
struct emp
{
int a ;
char ch ;
float s ;
};

Chapter 10: Structures

383

#pragma pack( )
struct emp e ;
printf ( "%u %u %u", &e
...
ch, &e
...
That is, to maintain
data about employees in an organization, books in a library, items
in a store, financial accounting transactions in a company etc
...
They can be used for a variety of purposes like:
(a)
(b)
(c)
(d)
(e)
(f)
(g)
(h)
(i)
(j)
(k)
(l)

Changing the size of the cursor
Clearing the contents of the screen
Placing the cursor at an appropriate position on screen
Drawing any graphics shape on the screen
Receiving a key from the keyboard
Checking the memory size of the computer
Finding out the list of equipment attached to the computer
Formatting a floppy
Hiding a file from the directory
Displaying the directory of a disk
Sending the output to printer
Interacting with the mouse

And that is certainly a very impressive list! At least impressive
enough to make you realize how important a data type a structure
is and to be thorough with it if you intend to program any of the

384

Let Us C

above applications
...


Summary
(a) A structure is usually used when we wish to store dissimilar
data together
...
) operator
...

(d) All elements of one structure variable can be assigned to
another structure variable using the assignment (=) operator
...

(f) It is possible to create an array of structures
...
num = 1 ;
strcpy ( m
...
mess2, "Everything looks like a nail" ) ;
/* assume that the strucure is located at address 1004 */
printf ( "\n%u %u %u", &m
...
mess1, m
...
num, m2
...
mess2 ) ;
}

[B] Point out the errors, if any, in the following programs:
(a) main( )
{
struct employee
{
char name[25] ;
int age ;
float bs ;
};
struct employee e ;
strcpy ( e
...
name, age ) ;
}
(b) main( )
{
struct
{
char name[25] ;

385

386

Let Us C
char language[10] ;
};
struct employee e = { "Hacker", "C" } ;
printf ( "\n%s %d", e
...
language ) ;

}
(c)

struct virus
{
char signature[25] ;
char status[20] ;
int size ;
} v[2] = {
"Yankee Doodle", "Deadly", 1813,
"Dark Avenger", "Killer", 1795
};
main( )
{
int i ;
for ( i = 0 ; i <=1 ; i++ )
printf ( "\n%s %s", v
...
status ) ;
}

(d) struct s
{
char ch ;
int i ;
float a ;
};
main( )
{
struct s var = { 'C', 100, 12
...
ch, v
...
a ) ;
}
(e) struct s
{
int i ;
struct s *p ;
};
main( )
{
struct s var1, var2 ;
var1
...
i = 200 ;
var1
...
p = &var1 ;
printf ( "\n%d %d", var1
...
p -> i ) ;
}
[C] Answer the following:

(a) Ten floats are to be stored in memory
...
engine
...

2
...

4
...
All structure elements are stored in contiguous memory
locations
...
An array should be used to store dissimilar elements, and
a structure to store similar elements
...
In an array of structures, not only are all structures stored
in contiguous memory locations, but the elements of
individual structures are also stored in contiguous
locations
...
tt
...
( *tt )
...
time
...
tt -> seconds
[D] Attempt the following:

(a) Create a structure to specify data on students given below:
Roll number, Name, Department, Course, Year of joining
Assume that there are not more than 450 students in the
collage
...

(b) Write a function to print the data of a student whose roll
number is given
...
The
data to be stored is: Account number, Name, Balance in
account
...

(a) Write a function to print the Account number and name
of each customer with balance below Rs
...

(b) If a customer request for withdrawal or deposit, it is
given in the form:
Acct
...

(c) An automobile company has serial number for engine parts
starting from AA0 to FF9
...

(a) Specify a structure to store information corresponding to
a part
...

(d) A record contains name of cricketer, his age, number of test
matches that he has played and the average runs that he has
scored in each test match
...
Use the qusort( ) standard library function
...
Write a program to
create an array of the structure and enter some data into it
...
Display the names of
those employees whose tenure is 3 or more than 3 years
according to the given current date
...
The menu options should be:

390
1
...

3
...

5
...

7
...

(g) Write a program that compares two given dates
...
If the dates are equal then display
message as "Equal" otherwise "Unequal"
...
While the elements of an array
occupy contiguous memory locations, those of a linked list
are not constrained to be stored in adjacent location
...
The
order of the elements is maintained by explicit links between
them
...
e
...

Write a program to build a linked list by adding new nodes at
the beginning, at the end or in the middle of the linked list
...

(i) A stack is a data structure in which addition of new element
or deletion of existing element always takes place at the same

Chapter 10: Structures

391

end
...
This situation
can be compared to a stack of plates in a cafeteria where every
new plate taken off the stack is also from the ‘top’ of the
stack
...
For example, recursion, keeping track of function calls,
evaluation of expressions, etc
...

(j) Unlike a stack, in a queue the addition of new element takes
place at the end (called ‘rear’ of queue) whereas deletion takes
place at the other end (called ‘front’ of queue)
...


392

Let Us C

11

Console
Input/Output
• Types of I/O
• Console I/O Functions
Formatted Console I/O Functions
sprintf( ) and sscanf( ) Functions
Unformatted Console I/O Functions
• Summary
• Exercise

393

394

Let Us C

A

s mentioned in the first chapter, Dennis Ritchie wanted C
to remain compact
...
Thus, C simply has no
provision for receiving data from any of the input devices (like say
keyboard, disk, etc
...
Then how do we manage I/O, and how is it
that we were we able to use printf( ) and scanf( ) if C has nothing
to offer for I/O? This is what we intend to explore in this chapter
...
There is not much use writing a
program that spends all its time telling itself a secret
...
It’s a simple matter for a
system programmer to write a few small programs that would link
the C compiler for particular Operating system’s I/O facilities
...
They write several
standard I/O functions and put them in libraries
...
Whichever C compiler you are
using it’s almost certain that you have access to a library of I/O
functions
...
Thus, the way one OS displays output
on screen may be different than the way another OS does it
...
Similarly, the printf( ) function for a Unixbased compiler has been written keeping in mind the way Unix
outputs characters to screen
...
We
should just use printf( ) and it would take care of the rest of the

Chapter 11: Console Input/Output

395

details that are OS dependent
...

There are numerous library functions available for I/O
...


(b)

File I/O functions

- Functions to perform I/O
operations on a floppy disk or
hard disk
...

File I/O functions would be discussed in Chapter 12
...
Console
I/O functions can be further classified into two categories—
formatted and unformatted console I/O functions
...
For example, if values of
average marks and percentage marks are to be displayed on the
screen, then the details like where this output would appear on the
screen, how many spaces would be present between the two
values, the number of places after the decimal points, etc
...
The functions available
under each of these two categories are shown in Figure 11
...
Now
let us discuss these console I/O functions in detail
...
1

Formatted Console I/O Functions
As can be seen from Figure 11
...

These functions allow us to supply the input in a fixed format and
let us obtain the output in the specified form
...

We have talked a lot about printf( ), used it regularly, but without
having introduced it formally
...
Its
general form looks like this
...
2 ;
printf ( "Average = %d\nPercentage = %f", avg, per ) ;
}

The output of the program would be
...
200000

How does printf( ) function interpret the contents of the format
string
...
So
long as it doesn’t come across either a % or a \ it continues to
dump the characters that it encounters, on to the screen
...
The moment it
comes across a conversion specification in the format string it
picks up the first variable in the list of variables and prints its value
in the specified format
...
Similarly, when
an escape sequence is met it takes the appropriate action
...
This process continues till the end of format string
is not reached
...

They tell printf( ) to print the value of avg as a decimal integer
and the value of per as a float
...


398

Let Us C

Data type
Integer

Format specifier
short signed

%d or %I

short unsigned

%lu

unsigned hexadecimal

%x

unsigned octal

%o

float

%f

double

%lf

signed character

%c

unsigned character

Character

%ld

long unsigned

Real

%u

long singed

%c

String

%s

Figure 11
...

Specifier

Description

dd

Digits specifying field width


...
3

Chapter 11: Console Input/Output

399

Now a short explanation about these optional format specifiers
...
For example, %10d
says, “print the variable as a decimal integer in a field of 10
columns”
...
If we include the minus sign in format specifier (as in
%-10d), this means left justification is desired and the value will
be padded with blanks on the right
...

main( )
{
int weight = 63 ;
printf ( "\nweight is %d kg", weight ) ;
printf ( "\nweight is %2d kg", weight ) ;
printf ( "\nweight is %4d kg", weight ) ;
printf ( "\nweight is %6d kg", weight ) ;
printf ( "\nweight is %-6d kg", weight ) ;
}

The output of the program would look like this
...

main( )
{
printf ( "\n%f %f %f", 5
...
5, 133
...
0, 1200
...
3 ) ;
}

And here is the output
...
000000 13
...
900000
305
...
900000 3005
...
A better way
would be something like this
...
1f %10
...
1f", 5
...
5, 133
...
1f %10
...
1f", 305
...
9, 3005
...

01234567890123456789012345678901
5
...
5
133
...
0
1200
...
3

The format specifiers could be used even while displaying a string
of characters
...

012345678901234567890123456789012345678901234567890
Sandy
Malya
AjayKumar
Gurubaxani

The format specifier %20s reserves 20 columns for printing a
string and then prints the string in these 20 columns with right
justification
...
Obviously, the format %-20s would have left justified
the string
...
The newline character is an ‘escape sequence’, so called
because the backslash symbol (\) is considered as an ‘escape’
character—it causes an escape from the normal interpretation of a
string, so that the next character is recognized as one having a
special meaning
...
A \t moves the cursor to the next tab stop
...
In other words, the
screen is divided into 10 zones of 8 columns each
...
For
example, if cursor is positioned in column 5, then printing a tab
takes it to column 8
...

1
2
3
4
01234567890123456789012345678901234567890
You
must
be
crazy
to
hate
this
book

The \n character causes a new line to begin following ‘crazy’
...
Figure 11
...


Esc
...


Purpose

Esc
...


Purpose

\n

New line

\t

Tab

\b

Backspace

\r

Carriage return

\f

Form feed

\a

Alert

\’

Single quote

\”

Double quote

\\

Backslash

Figure 11
...
\b moves the cursor one position to the left of its
current position
...
\a alerts the user by sounding the
speaker inside the computer
...

Characters that are ordinarily used as delimiters
...
Thus, the statement,
printf ( "He said, \"Let's do it!\"" ) ;

Chapter 11: Console Input/Output

403

will print
...
This is not true at all
...

Sometimes the result is nonsensical, as in case when we ask it to
print a string using %d
...
Sometimes the result is disastrous and the entire program
blows up
...

main( )
{
char ch = 'z' ;
int i = 125 ;
float a = 12
...

z 122 -9362831782501783000000000000000000000000000
...
000000
} 125 -9362831782501783000000000000000000000000000
...
550000 0

I would leave it to you to analyze the results by yourselves
...

Let us now turn our attention to scanf( )
...

The general form of scanf( ) statement is as follows:
scanf ( "format string", list of addresses of variables ) ;

For example:
scanf ( "%d %f %c", &c, &a, &ch ) ;

Note that we are sending addresses of variables (addresses are
obtained by using ‘&’ the ‘address of’ operator) to scanf( )
function
...
The values that are supplied through the keyboard must
be separated by either blank(s), tab(s), or newline(s)
...

All the format specifications that we learnt in printf( ) function are
applicable to scanf( ) function as well
...
Instead of sending the output to
the screen as printf( ) does, this function writes the output to an
array of characters
...

main( )
{

Chapter 11: Console Input/Output

405

int i = 10 ;
char ch = 'A' ;
float a = 3
...
Since the string str is present in memory what is written
into str using sprintf( ) doesn’t get displayed on the screen
...
In
our program this was achieved by the second printf( ) statement
...
It allows us
to read characters from a string and to convert and store them in C
variables according to specified formats
...

You may find it convenient to read in strings from a file and then
extract values from a string by using sscanf( )
...


Unformatted Console I/O Functions
There are several standard library functions available under this
category—those that can deal with a single character and those
that can deal with a string of characters
...

So far for input we have consistently used the scanf( ) function
...
you need to hit the Enter key before the function can

406

Let Us C

digest what you have typed
...
getch( ) and getche( ) are two
functions which serve this purpose
...
The ‘e’ in getche( )
function means it echoes (displays) the character that you typed to
the screen
...
getchar( ) works
similarly and echo’s the character that you typed on the screen, but
unfortunately requires Enter key to be typed following the
character that you typed
...
Here is a sample program that illustrates the use of these
functions
...

Press any key to continue
Type any character B
Type any character W
Continue Y/N Y

Chapter 11: Console Input/Output

407

putch( ) and putchar( ) form the other side of the coin
...
As far as the working of putch( )
putchar( ) and fputchar( ) is concerned it’s exactly same
...

main( )
{
char ch = 'A' ;
putch ( ch ) ;
putchar ( ch ) ;
fputchar ( ch ) ;
putch ( 'Z' ) ;
putchar ( 'Z' ) ;
fputchar ( 'Z' ) ;
}

And here is the output
...


gets( ) and puts( )
gets( ) receives a string from the keyboard
...

main( )
{
char name[50] ;
printf ( "\nEnter name " ) ;
scanf ( "%s", name ) ;
printf ( "%s", name ) ;

408

Let Us C

}

And here is the output
...
The result
is that there is no way (at least not without a lot of trouble on the
programmer’s part) to enter a multi-word string into a single
variable (name in this case) using scanf( )
...
As said earlier, it gets a string
from the keyboard
...
Thus,
spaces and tabs are perfectly acceptable as part of the input string
...

The puts( ) function works exactly opposite to gets( ) function
...

Here is a program which illustrates the usage of these functions:
main( )
{
char footballer[40] ;
puts ( "Enter name" ) ;
gets ( footballer ) ; /* sends base address of array */
puts ( "Happy footballing!" ) ;
puts ( footballer ) ;
}

Following is the sample output:
Enter name

Chapter 11: Console Input/Output

409

Jonty Rhodes
Happy footballing!
Jonty Rhodes

Why did we use two puts( ) functions to print “Happy
footballing!” and “Jonty Rhodes”? Because, unlike printf( ),
puts( ) can output only one string at a time
...
Similarly,
unlike scanf( ), gets( ) can be used to read only one string at a
time
...

(b) All I/O in C is done using standard library functions
...

(d) The formatted console I/O functions can force the user to
receive the input in a fixed format and display the output in a
fixed format
...

(f) Unformatted console I/O functions work faster since they do
not have the overheads of formatting the input or output
...
5367 ;
char str[ ] = "Life is like that" ;
printf ( "\n%4d\t%3
...
2f\n%s", 12, 3
...
34174 ;
char name[10] = "Shweta" ;
sprintf ( buffer, "%d %lf %s", no, val, name ) ;
printf ( "\n%s", buffer ) ;
sscanf ( buffer, "%4d %2
...

2
...

4
...

2
...

4
...

2
...

4
...
scanf( )
2
...

2
...

4
...

2
...

4
...

(b) Write down a function getint( ), which would receive a
numeric string from the keyboard, convert it to an integer
number and return the integer to the calling function
...

This is because if the data is large, only a limited amount
of it can be stored in memory and only a limited amount
of it can be displayed on the screen
...
Memory is volatile
and its contents would be lost once the program is terminated
...
Obviously both these operations would be
tedious
...
This medium is usually a ‘file’ on the disk
...


Data Organization
Before we start doing file input/output let us first find out how data
is organized on the disk
...
How this binary data is stored on the disk varies from one
OS to another
...
It is the compiler
vendor’s responsibility to correctly implement these library
functions by taking the help of OS
...
1
...
1

C Library
functions

OS

Disk

Chapter 12: File Input/Output

417

File Operations
There are different operations that can be carried out on a file
...
We will first list the program and show what it does,
and then dissect it line by line
...
*/
# include "stdio
...
C", "r" ) ;
while ( 1 )
{
ch = fgetc ( fp ) ;
if ( ch == EOF )
break ;
printf ( "%c", ch ) ;
}
fclose ( fp ) ;
}

418

Let Us C

On execution of this program it displays the contents of the file
‘PR1
...
Let us now understand how it does the
same
...
To open the file we have called the function
fopen( )
...
C” in ‘read’ mode, which tells
the C compiler that we would be reading the contents of the file
...
In fact fopen( ) performs three
important tasks when you open the file in “r” mode:
(a) Firstly it searches on the disk the file to be opened
...

(c) It sets up a character pointer that points to the first character
of the buffer
...
Every time we read something from a disk, it
takes some time for the disk drive to position the read/write head
correctly
...
If this were to be done for every character we read
from the disk, it would take a long time to complete the reading
operation
...
It would be more
sensible to read the contents of the file into the buffer while
opening the file and then read the file character by character from
the buffer rather than from the disk
...
2
...
C
Memory
40
DISK
Buffer
fp
40

Figure 12
...

Instead of writing characters in the file on the disk one character at
a time it would be more efficient to write characters in a buffer and
then finally transfer the contents from the buffer to the disk
...
has to be maintained
...
fopen( ) returns the address of
this structure, which we have collected in the structure pointer
called fp
...
h”
(standing for standard input/output header file)
...


Reading from a File
Once the file has been opened for reading using fopen( ), as we
have seen, the file’s contents are brought into buffer (partly or
wholly) and a pointer is set up that points to the first character in
the buffer
...
2)
...
This has been used in our program as,
ch = fgetc ( fp ) ;

fgetc( ) reads the character from the current pointer position,
advances the pointer position so that it now points to the next
character, and returns the character that is read, which we collected
in the variable ch
...

We have used the function fgetc( ) within an indefinite while loop
...
When shall we
break out
...
But what is end
of file? A special character, whose ASCII value is 26, signifies end
of file
...

While reading from the file, when fgetc( ) encounters this special
character, instead of returning the character that it has read, it
returns the macro EOF
...
h”
...


Chapter 12: File Input/Output

421

In our program we go on reading each character from the file till
end of file is not met
...
Once out of the loop, we close the file
...
While opening the
file in “r” mode, this may happen because the file being opened
may not be present on the disk at all
...
Similarly, while opening the file for
writing, fopen( ) may fail due to a number of reasons, like, disk
space may be insufficient to open a new file, or the disk may be
write protected or the disk is damaged and so on
...
If the file
opening fails due to any of the several reasons mentioned above,
the fopen( ) function returns a value NULL (defined in “stdio
...
Here is how this can be handled in a
program
...
h"
main( )
{
FILE *fp ;
fp = fopen ( "PR1
...

This is done using the function fclose( ) through the statement,
fclose ( fp ) ;

Once we close the file we can no longer read from it using getc( )
unless we reopen the file
...
On closing the file the buffer
associated with the file is removed from memory
...
Suppose we
open a file with an intention to write characters into it
...
When we attempt to
write characters into this file using fputc( ) the characters would
get written to the buffer
...

(b) At the end of file a character with ASCII value 26 would get
written
...

You can imagine a possibility when the buffer may become full
before we close the file
...
All this buffer
management is done for us by the library functions
...
Let us write a program that will read a
file and count how many characters, spaces, tabs and newlines are
present in it
...
h"
main( )
{
FILE *fp ;
char ch ;
int nol = 0, not = 0, nob = 0, noc = 0 ;
fp = fopen ( "PR1
...

Number of characters = 125
Number of blanks = 25
Number of tabs = 13
Number of lines = 22

The above statistics are true for a file “PR1
...
You may give any other filename and obtain different results
...

In this program too we have opened the file for reading and then
read it character by character
...


A File-copy Program
We have already used the function fgetc( ) which reads characters
from a file
...
As a practical use of these character I/O
functions we can copy the contents of one file into another, as
demonstrated in the following program
...

#include "stdio
...
c", "r" ) ;
if ( fs == NULL )
{
puts ( "Cannot open source file" ) ;
exit( ) ;

Chapter 12: File Input/Output

425

}
ft = fopen ( "pr2
...
What is
new is only the function fputc( )
...


Writing to a File
The fputc( ) function is similar to the putch( ) function, in the
sense that both output characters
...

Which file? The file signified by ft
...


426

Let Us C

Note that our sample file-copy program is capable of copying only
text files
...
EXE or
...


File Opening Modes
In our first program on disk I/O we have opened the file in read
(“r”) mode
...
Following is a list of all possible modes in
which a file can be opened
...

"r"

Searches file
...
If the file cannot be opened fopen( )
returns NULL
...


"w"

Searches file
...

If the file doesn’t exist, a new file is created
...

Operations possible – writing to the file
...
If the file is opened successfully fopen( )
loads it into memory and sets up a pointer that points to the
last character in it
...
Returns NULL, if unable to open file
...


"r+"

Searches file
...
Returns NULL, if unable to open the file
...

"w+"

Searches file
...

If the file doesn’t exist a new file is created
...

Operations possible - writing new contents, reading them
back and modifying existing contents of the file
...
If the file is opened successfully fopen( )
loads it into memory and sets up a pointer which points to
the first character in it
...
Returns NULL, if unable to open file
...
Cannot modify existing
contents
...
However,
in some situations the usage of functions that read or write entire
strings might turn out to be more efficient
...
Here is a program
that writes strings to a file using the function fputs( )
...
h"
main( )
{
FILE *fp ;
char s[80] ;

428

Let Us C

fp = fopen ( "POEM
...

Enter a few lines of text:
Shining and bright, they are forever,
so true about diamonds,
more so of memories,
especially yours !

Note that each string is terminated by hitting enter
...

This creates a string of zero length, which the program recognizes
as the signal to close the file and exit
...
Since
fputs( ) does not automatically add a newline character to the end
of the string, we must do this explicitly to make it easier to read
the string back from the file
...


Chapter 12: File Input/Output

429

/* Reads strings from the file and displays them on screen */
#include "stdio
...
TXT", "r" ) ;
if ( fp == NULL )
{
puts ( "Cannot open file" ) ;
exit( ) ;
}
while ( fgets ( s, 79, fp ) != NULL )
printf ( "%s" , s ) ;
fclose ( fp ) ;
}

And here is the output
...
The first is the address
where the string is stored, and the second is the maximum length
of the string
...
The third argument, as
usual, is the pointer to the structure FILE
...


430

Let Us C

The Awkward Newline
We had earlier written a program that counts the total number of
characters present in a file
...
TXT”), it would give us the character count as 101
...

This discrepancy occurs because when we attempt to write a “\n”
to the file using fputs( ), fputs( ) converts the \n to \r\n
combination
...

If we read the same line back using fgets( ) the reverse conversion
happens
...
Hence the OS counts \r and \n as separate
characters
...


Record I/O in Files
So far we have dealt with reading and writing only characters and
strings
...

Following program illustrates the use of structures for writing
records of employees
...
h"
main( )
{
FILE *fp ;
char another = 'Y' ;
struct emp
{
char name[40] ;
int age ;
float bs ;
};
struct emp e ;
fp = fopen ( "EMPLOYEE
...
name, &e
...
bs ) ;
fprintf ( fp, "%s %d %f\n", e
...
age, e
...

Enter name, age and basic salary: Sunil 34 1250
...
50
Add another record (Y/N) Y
Enter name, age and basic salary: Rahul 34 1400
...
The user can input as many records as he desires
...

The key to this program is the function fprintf( ), which writes the
values in the structure variable to the file
...
As in printf( ), we can format the data in a variety of
ways, by using fprintf( )
...

Perhaps you are wondering what for have we used the function
fflush( )
...
After
supplying data for one employee, we would hit the enter key
...

So when it’s time to supply Y or N for the question ‘Another
employee (Y/N)’, getch( ) will read the enter key from the buffer
thinking that user has entered the enter key
...
It is designed to remove or ‘flush
out’ any data remaining in the buffer
...
Here we have used
‘stdin’, which means buffer related with standard input
device—keyboard
...
Here is how it can be done
...
h"
main( )
{
FILE *fp ;
struct emp
{
char name[40] ;
int age ;
float bs ;
};
struct emp e ;
fp = fopen ( "EMPLOYEE
...
name, &e
...
bs ) != EOF )
printf ( "\n%s %d %f", e
...
age, e
...

Sunil 34 1250
...
500000
Rahul 34 1400
...
Some of them would not work correctly on binary files
...
In actuality the ASCII codes of these
characters are stored in text files
...
C
...
This
collection might be a compiled version of a C program (say
PR1
...
A very easy way to find out whether a file is a
text file or a binary file is to open that file in Turbo C/C++
...

As mentioned while explaining the file-copy program, the program
cannot copy binary files successfully
...

#include "stdio
...
exe", "rb" ) ;
if ( fs == NULL )
{
puts ( "Cannot open source file" ) ;
exit( ) ;
}
ft = fopen ( "newpr1
...
Note that here we have opened the source and target files in
“rb” and “wb” modes respectively
...

From the programming angle there are three main areas where text
and binary mode files are different
...


436

Let Us C

Text versus Binary Mode: Newlines
We have already seen that, in text mode, a newline character is
converted into the carriage return-linefeed combination before
being written to the disk
...
However, if a file is opened in binary
mode, as opposed to text mode, these conversions will not take
place
...
In text mode, a special character, whose
ASCII value is 26, is inserted after the last character in the file to
mark the end of file
...

As against this, there is no such special character present in the
binary mode files to mark the end of file
...

There is a moral to be derived from the end of file marker of text
mode files
...
If this number is detected while we are reading
the file by opening it in text mode, reading would be terminated
prematurely at that point
...
See to it that the file that
has been written in text mode is read back only in text mode
...


Chapter 12: File Input/Output

437

Text versus Binary Mode: Storage of Numbers
The only function that is available for storing numbers in a disk
file is the fprintf( ) function
...
Text and
characters are stored one character per byte, as we would expect
...

Numbers are stored as strings of characters
...
Similarly, the floating-point number 1234
...
Thus, numbers with more digits would
require more disk space
...
The solution is
to open the file in binary mode and use those functions (fread( )
and fwrite( ) which are discussed later) which store the numbers in
binary format
...


Record I/O Revisited
The record I/O program that we did in an earlier section has two
disadvantages:
(a) The numbers (basic salary) would occupy more number of
bytes, since the file has been opened in text mode
...

(b) If the number of fields in the structure increase (say, by
adding address, house rent allowance etc
...

Let us now see a more efficient way of reading/writing records
(structures)
...
We will write two programs, first one would write
records to the file and the second would read these records from
the file and display them on the screen
...
h"
main( )
{
FILE *fp ;
char another = 'Y' ;
struct emp
{
char name[40] ;
int age ;
float bs ;
};
struct emp e ;
fp = fopen ( "EMP
...
name, &e
...
bs ) ;
fwrite ( &e, sizeof ( e ), 1, fp ) ;
printf ( "Add another record (Y/N) " ) ;

Chapter 12: File Input/Output

439

fflush ( stdin ) ;
another = getche( ) ;
}
fclose ( fp ) ;
}

And here is the output
...
50
Add another record (Y/N) Y
Enter name, age and basic salary: Ranjan 21 1300
...
70
Add another record (Y/N) N

Most of this program is similar to the one that we wrote earlier,
which used fprintf( ) instead of fwrite( )
...
DAT” has now been opened in binary mode
...
Then, the following statement
writes the structure to the file:
fwrite ( &e, sizeof ( e ), 1, fp ) ;

Here, the first argument is the address of the structure to be written
to the disk
...
Instead
of counting the bytes occupied by the structure ourselves, we let
the program do it for us by using the sizeof( ) operator
...
This keeps
the program unchanged in event of change in the elements of the
structure
...
In this case, we want to write only one
structure at a time
...

The last argument is the pointer to the file we want to write to
...

/* Reads records from binary file and displays them on VDU */
#include "stdio
...
DAT", "rb" ) ;
if ( fp == NULL )
{
puts ( "Cannot open file" ) ;
exit( ) ;
}
while ( fread ( &e, sizeof ( e ), 1, fp ) == 1 )
printf ( "\n%s %d %f", e
...
age, e
...
The format of fread( ) is same as
that of fwrite( )
...
Ordinarily, this should correspond to the third
argument, the number of records we asked for
...
If
we have reached the end of file, since fread( ) cannot read
anything, it returns a 0
...

As you can now appreciate, any database management application
in C must make use of fread( ) and fwrite( ) functions, since they
store numbers more efficiently, and make writing/reading of
structures quite easy
...


Database Management
So far we have learnt record I/O in bits and pieces
...

I have attempted to do this in the following menu driven program
...

Following comments would help you in understanding the
program easily:


Addition of records must always take place at the end of
existing records in the file, much in the same way you would
add new records in a register manually
...
Naturally, records should be listed from first record to
last record
...
Instead of asking the record

442

Let Us C

number to be modified, it would be more meaningful to ask for
the name of the employee whose record is to be modified
...



In deleting records, except for the record to be deleted, rest of
the records must first be written to a temporary file, then the
original file must be deleted, and the temporary file must be
renamed back to original
...
It is imperative that the file
should be opened in binary mode
...




clrscr( ) function clears the contents of the screen and
gotoxy( ) places the cursor at appropriate position on the
screen
...


Given below is the complete listing of the program
...
h"
main( )
{
FILE *fp, *ft ;
char another, choice ;
struct emp
{
char name[40] ;
int age ;
float bs ;
};

Chapter 12: File Input/Output
struct emp e ;
char empname[40] ;
long int recsize ;
fp = fopen ( "EMP
...
DAT", "wb+" ) ;
if ( fp == NULL )
{
puts ( "Cannot open file" ) ;
exit( ) ;
}
}
recsize = sizeof ( e ) ;
while ( 1 )
{
clrscr( ) ;
gotoxy ( 30, 10 ) ;
printf ( "1
...
List Records" ) ;
gotoxy ( 30, 14 ) ;
printf ( "3
...
Delete Records" ) ;
gotoxy ( 30, 18 ) ;
printf ( "0
...
" ) ;
scanf ( "%s %d %f", e
...
age, &e
...
name, e
...
bs ) ;
break ;
case '3' :
another = 'Y' ;
while ( another == 'Y' )
{
printf ( "\nEnter name of employee to modify " ) ;
scanf ( "%s", empname ) ;
rewind ( fp ) ;
while ( fread ( &e, recsize, 1, fp ) == 1 )

Chapter 12: File Input/Output

445

{
if ( strcmp ( e
...
name, &e
...
bs ) ;
fseek ( fp, - recsize, SEEK_CUR ) ;
fwrite ( &e, recsize, 1, fp ) ;
break ;
}
}
printf ( "\nModify another Record (Y/N) " ) ;
fflush ( stdin ) ;
another = getche( ) ;
}
break ;
case '4' :
another = 'Y' ;
while ( another == 'Y' )
{
printf ( "\nEnter name of employee to delete " ) ;
scanf ( "%s", empname ) ;
ft = fopen ( "TEMP
...
name, empname ) != 0 )
fwrite ( &e, recsize, 1, ft ) ;
}
fclose ( fp ) ;
fclose ( ft ) ;

446

Let Us C
remove ( "EMP
...
DAT", "EMP
...
DAT", "rb+" ) ;
printf ( "Delete another Record (Y/N) " ) ;
fflush ( stdin ) ;
another = getche( ) ;
}
break ;
case '0' :
fclose ( fp ) ;
exit( ) ;
}

}
}

To understand how this program works, you need to be familiar
with the concept of pointers
...
On opening a file a pointer is set up which points to the
first record in the file
...

On using the functions fread( ) or fwrite( ), the pointer moves to
the beginning of the next record
...
Note that the pointer movement is of utmost
importance since fread( ) always reads that record where the
pointer is currently placed
...

The rewind( ) function places the pointer to the beginning of the
file, irrespective of where it is present right now
...
In the program above, to move the pointer to the previous
record from its current position, we used the function,

Chapter 12: File Input/Output

447

fseek ( fp, -recsize, SEEK_CUR ) ;

Here, -recsize moves the pointer back by recsize bytes from the
current position
...
h”
...

fseek ( fp, 0, SEEK_END ) ;

In fact -recsize or 0 are just the offsets that tell the compiler by
how many bytes should the pointer be moved from a particular
position
...
All these act as a reference from which the pointer
should be offset
...

If we wish to know where the pointer is positioned right now, we
can use the function ftell( )
...
The value
returned by ftell( ) can be used in subsequent calls to fseek( )
...


Low Level Disk I/O
In low level disk I/O, data cannot be written as individual
characters, or as strings or as formatted data
...


448

Let Us C

Writing a buffer full of data resembles the fwrite( ) function
...
Thus, the buffer in the low level I/O
functions is very much a part of the program, rather than being
invisible as in high level disk I/O functions
...

(b) Since there are fewer layers of routines to go through, low
level I/O functions operate faster than their high level
counterparts
...


A Low Level File-copy Program
Earlier we had written a program to copy the contents of one file to
another
...
Each character that was read was written
into the target file using fputc( )
...
While
doing so the chunk would be read into the buffer and would be
written to the file from the buffer
...
This is what is low-level about this program
...

/* File-copy program which copies text,
...
exe files */
#include "fcntl
...
h" /* if present in sys directory use

Chapter 12: File Input/Output
"c:tc\\include\\sys\\types
...
h" /* if present in sys directory use
"c:\\tc\\include\\sys\\stat
...
The size of this buffer is important for efficient operation
...


Opening a File
We have opened two files in our program, one is the source file
from which we read the information, and the other is the target file
into which we write the information read from the source file
...
This is done using the statement,
inhandle = open ( source, O_RDONLY | O_BINARY ) ;

We open the file for the same reason as we did earlier—to
establish communication with operating system about the file
...
The possible file opening modes
are given below:
O_APPEND

- Opens a file for appending

Chapter 12: File Input/Output
O_CREAT
O_RDONLY
O_RDWR
O_WRONLY
O_BINARY
O_TEXT

451

- Creates a new file for writing (has no effect
if file already exists)
- Creates a new file for reading only
- Creates a file for both reading and writing
- Creates a file for writing only
- Creates a file in binary mode
- Creates a file in text mode

These ‘O-flags’ are defined in the file “fcntl
...
So this file must
be included in the program while usng low level disk I/O
...
h” is not necessary for low level disk I/O
...
Chapter 14 discusses bitwise
operators in detail
...
And finally, since we want to open the file in
binary mode we have used O_BINARY
...
This argument is called ‘permission argument’
...
h” and “stat
...
h”
...
This
is a number assigned to a particular file, which is used thereafter to
refer to the file
...


Interaction between Buffer and File
The following statement reads the file or as much of it as will fit
into the buffer:
bytes = read ( inhandle, buffer, 512 ) ;

The read( ) function takes three arguments
...

The read( ) function returns the number of bytes actually read
...
In our
program we have assigned this number to the variable bytes
...
The read( ) function returns the number
of bytes actually read
...
This
value will be equal to the buffer size (512 bytes) until the end of
file, when the buffer will only be partially full
...


Chapter 12: File Input/Output

453

Note that when large buffers are used they must be made global
variables otherwise stack overflow occurs
...

Windows permits several applications to use the same screen
simultaneously
...
To avoid such situations
Windows has completely abandoned console I/O functions
...
The details of this mechanism are discussed in
Chapter 17
...


Summary
(a) File I/O can be performed on a character by character basis, a
line by line basis, a record by record basis or a chunk by
chunk basis
...

(c) File I/O is done using a buffer to improve the efficiency
...

(e) Library functions convert \n to \r\n or vice versa while
writing/reading to/from a file
...

This can be avoided using functions fread( ) and fwrite( )
...


Exercise
[A] Point out the errors, if any, in the following programs:
(a) #include "stdio
...
txt", fp ) ;
if ( fp == NULL )
printf ( "Unable to open file…" ) ;
}
openfile ( char *fn, FILE **f )
{
*f = fopen ( fn, "r" ) ;
}
(b) #include "stdio
...
C" ,"r") ;
if ( fp == null )
{
puts ( "Cannot open file" ) ;
exit( ) ;
}
while ( ( c = getc ( fp ) ) != EOF )
putch ( c ) ;
fclose ( fp ) ;

Chapter 12: File Input/Output
}
(c)

main( )
{
char fname[ ] = "c:\\students
...
" ) ;
}

(d) main( )
{
FILE *fp ;
char str[80] ;
fp = fopen ( "TRY
...
h"
{
unsigned char ;
FILE *fp ;
fp = fopen ( "trial", "r" ) ;
while ( ( ch = getc ( fp ) ) != EOF )
printf ( "%c", ch ) ;
fclose ( fp ) ;
}
(f)

main( )
{
FILE *fp ;
char name[25] ;
int age ;
fp = fopen ( "YOURS", "r" ) ;

455

456

Let Us C
while ( fscanf ( fp, "%s %d", name, &age ) != NULL )
fclose ( fp ) ;

}
(g) main( )
{
FILE *fp ;
char names[20] ;
int i ;
fp = fopen ( "students
...
c", "r" ) ;
for ( i = 0 ; i <= 10 ; i++ )
fwrite ( name, sizeof ( name ), 1, fp ) ;
close ( fp ) ;
}
(i)

#include "fcntl
...
c" , "r" ) ;
if ( fp == -1 )
puts ( "cannot open file" ) ;
else
close ( fp ) ;

Chapter 12: File Input/Output

457

}
(j)

main( )
{
int fp ;
fp = fopen ( "students
...

2
...

4
...
h
stdio
...
h
stdio
...

2
...

4
...
The disadvantage of High Level Disk I/O functions is that
the programmer has to manage the buffers
...
If a file is opened for reading it is necessary that the file
must exist
...
If a file opened for writing already exists its contents
would be overwritten
...
For opening a file in append mode it is necessary that the
file should exist
...
The disk is searched for existence of the file
...
The file is brought into memory
...
A pointer is set up which points to the first character in the
file
...
All the above
...

(g) While using the statement,
fp = fopen ( "myfile
...
c’ does not exist on the disk
‘myfile
...
c", "wb" ) ;
what happens if,




‘myfile
...

‘myfile
...
To store these marks in a file
‘marks
...

(b) Write a program to find the size of a text file without
traversing it character by character
...

(d) Suppose a file contains student’s records with each record
containing name and age of a student
...

(e) Write a program to copy one file to another
...

(f) Write a program that merges lines alternately from two files
and writes the results to new file
...

(g) Write a program to display the contents of a text file on the
screen
...
Display the name of
the file whose contents are being displayed, and the page
numbers in the zeroth row
...
’ in 24th
row
...

(h) Write a program to encrypt/decrypt a file using:

460

Let Us C

(1) An offset cipher: In an offset cipher each character from
the source file is offset with a fixed value and then
written to the target file
...

(2) A substitution cipher: In this each character read from the
source file is substituted by a corresponding
predetermined character and this character is written to
the target file
...

(i) In the file ‘CUSTOMER
...
DAT’ there are several
records with the following structure:
struct trans
{
int accno ,
char trans_type ;

Chapter 12: File Input/Output

461

float amount ;
};

The parameter trans_type contains D/W indicating deposit or
withdrawal of amount
...
DAT’ file, i
...
if the trans_type is ‘D’ then
update the balance of ‘CUSTOMER
...
Similarly, if
trans_type is ‘W’ then subtract the amount from balance
...
e
...
Should
remain in the account
...

(k) A hospital keeps a file of blood donors in which each record
has the format:
Name: 20 Columns
Address: 40 Columns

462

Let Us C

Age: 2 Columns
Blood Type: 1 Column (Type 1, 2, 3 or 4)
Write a program to read the file and print a list of all blood
donors whose age is below 25 and blood is type 2
...
Make a provision to display
the nth name in the list (n is data to be read) and to display all
names starting with S
...
and
name of the student
...
A Transaction file
contains the roll numbers and an appropriate code to add or
delete a student
...
Assume that the
Master file and the Transaction file are arranged in ascending
order by roll numbers
...

(n) In a small firm employee numbers are given in serial
numerical order, that is 1, 2, 3, etc
...

If more employees join, append their data to the file
...

If some employee’s gross salary increases, retrieve the
record and update the salary
...

(o) Given a text file, write a program to create another text file
deleting the words “a”, “the”, “an” and replacing each one of
them with a blank space
...
DAT with the
following record structure:
struct employee {
int empno ;
char name[30] ;
int basic, grade ;
};

Every employee has a unique empno and there are supposed
to be no gaps between employee numbers
...
It is intended to check whether there are
missing employee numbers
...

(q) Write a program to carry out the following:




To read a text file “TRIAL
...

Count and display the number of words contained in the
file
...


Assume that the end of a word may be a space, comma or a
full-stop followed by one or more spaces or a newline
character
...
Also
give the total number of words in the list
...

(s) Write a program to carry out the following:
(a) Read a text file ‘INPUT
...

(t) Write a C program to read a large text file ‘NOTES
...


13

More Issues In
Input/Output





Using argc and argv
Detecting Errors in Reading/Writing
Standard I/O Devices
I/O Redirection
Redirecting the Output
Redirecting the Input
Both Ways at Once
• Summary
• Exercise

465

466

Let Us C

I

n Chapters 11 and 12 we saw how Console I/O and File I/O are
done in C
...
These issues help in
making the I/O operations more elegant
...
This program can be improved in two ways:
(a) There should be no need to compile the program every time to
use the file-copy utility
...

(b) Instead of the program prompting us to enter the source and
target filenames, we must be able to supply them at command
prompt, in the form:
filecopy PR1
...
C

where, PR1
...
C is the target
filename
...
In MS-DOS, the executable file
(the one which can be executed at command prompt and has an
extension
...
In VC++ compiler under Windows
same can be done by using F7 to compile the program
...

The second improvement is possible by passing the source
filename and target filename to the function main( )
...
h"
main ( int argc, char *argv[ ] )
{
FILE *fs, *ft ;
char ch ;
if ( argc != 3 )
{
puts ( "Improper number of arguments" ) ;
exit( ) ;
}
fs = fopen ( argv[1], "r" ) ;
if ( fs == NULL )
{
puts ( "Cannot open source file" ) ;
exit( ) ;
}
ft = fopen ( argv[2], "w" ) ;
if ( ft == NULL )
{
puts ( "Cannot open target file" ) ;
fclose ( fs ) ;
exit( ) ;
}
while ( 1 )
{
ch = fgetc ( fs ) ;
if ( ch == EOF )
break ;
else
fputc ( ch, ft ) ;
}

467

468

Let Us C

fclose ( fs ) ;
fclose ( ft ) ;
}

The arguments that we pass on to main( ) at the command prompt
are called command line arguments
...
Out of
these, argv is an array of pointers to strings and argc is an int
whose value is equal to the number of strings to which argv
points
...
More precisely, the strings at the
command line are stored in memory and address of the first string
is stored in argv[0], address of the second string is stored in
argv[1] and so on
...
For example, in our sample
program, if at the command prompt we give,
filecopy PR1
...
C

then,
argc would contain 3
argv[0] would contain base address of the string “filecopy”
argv[1] would contain base address of the string “PR1
...
C”

Whenever we pass arguments to main( ), it is a good habit to
check whether the correct number of arguments have been passed
on to main( ) or not
...
This
program is better than the earlier file-copy program on two counts:
(a) There is no need to recompile the program every time we
want to use this utility
...

(b) We are able to pass source file name and target file name to
main( ), and utilize them in main( )
...
the while loop that we have used in our
program can be written in a more compact form, as shown below:
while ( ( ch = fgetc ( fs ) ) != EOF )
fputc ( ch, ft ) ;

This avoids the usage of an indefinite loop and a break statement
to come out of this loop
...
Remember that it is necessary to put the expression
ch = fgetc ( fs )

within a pair of parentheses, so that first the character read is
assigned to variable ch and then it is compared with EOF
...
It is shown
below:
while ( !feof ( fs ) )
{
ch = fgetc ( fs ) ;
fputc ( ch, ft ) ;
}

Here, feof( ) is a macro which returns a 0 if end of file is not
reached
...
When the end of file is reached feof( ) returns a non-zero

470

Let Us C

value, ! makes it 0 and since now the condition evaluates to false
the while loop gets terminated
...

fs = fopen ( "PR1
...
Naturally there must be a
provision to test whether our attempt to read/write was successful
or not
...
It returns a
zero if the read/write is successful and a non-zero value in case of
a failure
...

#include "stdio
...
The moment the error occurs
ferror( ) returns a non-zero value and the if block gets executed
...
Thus in the above program the perror( )
function can be used as shown below
...
In our program we have just displayed the
filename in place of the error message
...
Most OSs also predefine pointers for three standard files
...
These standard file
pointers are shown in Figure 13
...
1
Thus the statement ch = fgetc ( stdin ) would read a character
from the keyboard rather than from a file
...

Note that under MS-DOS two more standard file pointers are
available—stdprn and stdaux
...
The following
program shows how to use the standard file pointers
...

/* Prints file contents on printer */
#include "stdio
...
txt", "r" ) ;
if ( fp == NULL )
{
printf ( "Cannot open file" ) ;
exit( ) ;
}
while ( ( ch = fgetc ( fp ) ) != EOF )
fputc ( ch, stdprn ) ;
fclose ( fp ) ;
}

The statement fputc ( ch, stdprn ) writes a character read from the
file to the printer
...
Standard files and their
use in redirection have been dealt with in more details in the next
section
...
h”
...


I/O Redirection
Most operating systems incorporate a powerful feature that allows
a program to read and write files, even when such a capability has
not been incorporated in the program
...

Normally a C program receives its input from the standard input
device, which is assumed to be the keyboard, and sends its output
to the standard output device, which is assumed to be the VDU
...
Redirection
permits us to change these assumptions
...
This is
often a more convenient and flexible approach than providing a
separate function in the program to write to the disk or printer
...

To use redirection facility is to execute the program from the
command prompt, inserting the redirection symbols at appropriate
places
...


Redirecting the Output
Let’s see how we can redirect the output of a program, from the
screen to a file
...
c */
#include "stdio
...
EXE
...
The Ctrl-Z character is often
called end of file character
...
EXE
perhaps I had a wicked childhood,
perhaps I had a miserable youth,
but somewhere in my wicked miserable past,
there must have been a moment of truth ^Z
C>

Now let’s see what happens when we invoke this program from in
a different way, using redirection:
C>UTIL
...
TXT
C>

Here we are causing the output to be redirected to the file
POEM
...
Can we prove that this the output has indeed gone to
the file POEM
...
TXT
perhaps I had a wicked childhood,
perhaps I had a miserable youth,
but somewhere in my wicked miserable past,
there must have been a moment of truth
C>

There’s the result of our typing sitting in the file
...

Note that the data to be redirected to a file doesn’t need to be typed
by a user at the keyboard; the program itself can generate it
...

As an example consider the following program for generating the
ASCII table on screen:

476

Let Us C

/* File name: ascii
...
EXE > TABLE
...
This can be a useful capability any
time you want to capture the output in a file, rather than displaying
it on the screen
...
One of
these names in PRN, which stands for the printer
...
For example, if you
invoke the “ascii
...
EXE > PRN

the ASCII table will be printed on the printer
...
Let
us now see how this can be done
...
Suppose we use a file called NEWPOEM
...
TXT
...
EXE < NEWPOEM
...
Using redirection we’ve made our program UTIL
...


Both Ways at Once
Redirection of input and output can be used together; the input for
a program can come from a file via redirection, at the same time its
output can be redirected to a file
...

The following command demonstrates this process
...
TXT > POETRY
...
TXT and instead of sending the output to the screen it
would redirect it to the file POETRY
...

Similarly to send the contents of the file NEWPOEM
...
TXT > PRN

While using such multiple redirections don’t try to send output to
the same file from which you are receiving input
...
So by the time we
manage to receive the input from a file it is already erased
...
Thus, redirection is used to
establish a relationship between a program and a file
...

This is called ‘piping’, and is done using the operator ‘|’, called
pipe
...


Summary
(a) We can pass parameters to a program at command line using
the concept of ‘command line arguments’
...

(c) We can use the standard file pointer stdin to take input from
standard input device such as keyboard
...

(e) We can use the standard file pointers stdprn and stdaux to
interact with printer and auxiliary devices respectively
...

(g) The operators < and > are called redirection operators
...

Print a file on the printer
...


Chapter 13: More Issues In Input/Output


479

Display the contents of an existing file
...
h"
main( )
{
char ch, str[10] ;
while ( ( ch = getc ( stdin ) ) != -1 )
putc ( ch, stdout ) ;
}

(b) State True or False:
1
...

2
...

3
...

4
...

(c) Point out the errors, if any, in the following program
main ( int ac, char ( * ) av[ ] )
{
printf ( "\n%d", ac ) ;
printf ( "\n%s", av[0] ) ;
}
[B] Attempt the following:

(a) Write a program to carry out the following:
(a) Read a text file provided at command prompt
(b) Print each word in reverse order
For example if the file contains
INDIA IS MY COUNTRY

Output should be

480

Let Us C

AIDNI SI YM YRTNUOC

(b) Write a program using command line arguments to search for
a word in a file and replace it with the specified word
...

C> change
(c) Write a program that can be used at command prompt as a
calculating utility
...

C> calc
Where, n and m are two integer operands
...
If arithmetic
operator is supplied, the output should be the result of the
operation
...


14

Operations On
Bits
• Bitwise Operators
One’s Complement Operator
Right Shift Operator
Left Shift Operator
Bitwise AND Operator
Bitwise OR Operator
Bitwise XOR Operator
• The showbits( ) Function
• Summary
• Exercise

481

482

Let Us C

S

o far we have dealt with characters, integers, floats and their
variations
...
However, we haven’t attempted
to look within these data types to see how they are constructed out
of individual bits, and how these bits can be manipulated
...
This is because, the programming languages
are byte oriented, whereas hardware tends to be bit oriented
...
So let us take apart the byte
...


Bitwise Operators
One of C’s powerful features is a set of bit manipulation operators
...
The various Bitwise Operators available
in C are shown in Figure 14
...


Operator

Meaning

~
>>
<<
&
|
^

One’s complement
Right shift
Left shift
Bitwise AND
Bitwise OR
Bitwise XOR(Exclusive OR)

Figure 14
...
Before moving on to the details of the operators, let

483

Chapter 14: Operations On Bits

us first take a look at the bit numbering scheme in integers and
characters
...
2
Throughout this discussion of bitwise operators we are going to
use a function called showbits( ), but we are not going to show
you the details of the function immediately
...

We begin with a plain-jane example with showbits( ) in action
...

Decimal 0 is same as binary 0000000000000000
Decimal 1 is same as binary 0000000000000001
Decimal 2 is same as binary 0000000000000010
Decimal 3 is same as binary 0000000000000011
Decimal 4 is same as binary 0000000000000100
Decimal 5 is same as binary 0000000000000101

Let us now explore the various bitwise operators one by one
...
For
example one’s complement of 1010 is 0101
...
Note that here when we talk of a
number we are talking of binary equivalent of the number
...
One’s complement of
65 therefore would be, 1111 1111 1011 1110
...
Following program shows
one’s complement operator in action
...

Decimal 0 is same as binary 0000000000000000
One’s complement of 0 is 1111111111111111
Decimal 1 is same as binary 0000000000000001
One’s complement of 1 is 1111111111111110
Decimal 2 is same as binary 0000000000000010
One’s complement of 2 is 1111111111111101
Decimal 3 is same as binary 0000000000000011
One’s complement of 3 is 1111111111111100

In real-world situations where could the one’s complement
operator be useful? Since it changes the original number beyond
recognition, one potential place where it can be effectively used is
in development of a file encryption utility as shown below:
/* File encryption utility */
#include "stdio
...
C", "r" ) ; /* normal file */
ft = fopen ( "TARGET
...


Right Shift Operator
The right shift operator is represented by >>
...
It shifts each bit in its left operand to the right
...
e
...

Thus, ch >> 3 would shift all bits in ch three places to the right
...

For example, if the variable ch contains the bit pattern 11010111,
then, ch >> 1 would give 01101011 and ch >> 2 would give
00110101
...
These blanks must be filled somehow
...
The following program demonstrates the effect
of right shift operator
...

Decimal 5225 is same as binary 0001010001101001
5225 right shift 0 gives 0001010001101001
5225 right shift 1 gives 0000101000110100
5225 right shift 2 gives 0000010100011010
5225 right shift 3 gives 0000001010001101
5225 right shift 4 gives 0000000101000110
5225 right shift 5 gives 0000000010100011

Note that if the operand is a multiple of 2 then shifting the operand
one bit to right is same as dividing it by 2 and ignoring the
remainder
...


488

Let Us C

A Word of Caution
In the explanation a >> b if b is negative the result is
unpredictable
...
On some computer right shifting a would result in extending
the sign bit
...
Without sign extension, the
operation a >> 4 would be 0000111111111111
...
Thus the sign bit 1 continues to get
extended
...
The following program should
clarify my point
...

Decimal 5225 is same as binary 0001010001101001

489

Chapter 14: Operations On Bits
5225 left shift 0 gives 0001010001101001
5225 left shift 1 gives 0010100011010010
5225 left shift 2 gives 0101000110100100
5225 left shift 3 gives 1010001101001000
5225 left shift 4 gives 0100011010010000

Having acquainted ourselves with the left shift and right shift
operators, let us now find out the practical utility of these
operators
...

Similarly, a 2-byte entry is made of the time of creation or
modification of the file
...
The bitwise distribution of year,
month and date in the 2-byte entry is shown in Figure 14
...


15 14 13 12 11 10 9

8

7

4

3

2

1

0

Y

M

M M M D
month

D

D

D

D

Y

Y

Y Y Y
year

Y

6

5

day

Figure 14
...
This
binary value is placed in the date field in the directory entry of the
file as shown below
...
4
Just to verify this bit distribution, let us take the bits representing
the month,
month = 0011
=1*2+1*1
=3

Similarly, the year and the day can also be verified
...
How does this integer to date
conversion take place? Obviously, using left shift and right shift
operators
...
4 depicting the bit pattern of the
2- byte date field, we see that the year, month and day exist as a
bunch of bits in contiguous locations
...

For example, to get year as a separate entity from the two bytes
entry we right shift the entry by 9 to get the year
...


491

Chapter 14: Operations On Bits

15 14 13 12 11 10
0

0

0

1

0

1

9
0

8
0

year

7
0

6
1

5
1

4
0

3

2

1

0

1

0

0

1

month

day

Right shifting by 9 gives
15 14 13 12 11 10
0

0

0

0

0

0

9
0

8
0

7
0

6
0

5
0

4
0

3

2

1

0

1

0

1

0

year

Figure 14
...


492

Let Us C

15 14 13 12 11 10
0

9

8

0

0
year

0

1

1

6

5

4

3

2

1

0

1

1

0

1

0

0

1

month

Left shifting by 7 gives,
15 14 13 12 11 10
0

7

0

9 8

1

month

6

5

4

3

2

1

0

1

0

0

0

1

0

1

0

9 8 7
0 0 0

6
0

5
0

4
0

3
0

2
0

1
1

0
1

0

0

7

day

day

Right shifting by 12 gives,
15 14 13 12 11 10
0 0 0 0 0 0

month

Figure 14
...
Left shifting by 11 gives
0100100000000000
...

This entire logic can be put into a program as shown below:
/* Decoding date field in directory entry using bitwise operators */
main( )
{
unsigned int d = 9, m = 3, y = 1990, year, month, day, date ;
date = ( y - 1980 ) * 512 + m * 32 + d ;
printf ( "\nDate = %u", date ) ;

Chapter 14: Operations On Bits

493

year = 1980 + ( date >> 9 ) ;
month = ( (date << 7 ) >> 12 ) ;
day = ( (date << 11 ) >> 11 ) ;
printf ( "\nYear = %u ", year ) ;
printf ( "Month = %u ", month ) ;
printf ( "Day = %u", day ) ;
}

And here is the output
...
Remember it is different than
&&, the logical AND operator
...
While operating upon these two operands they are
compared on a bit-by-bit basis
...
The second operand is often
called an AND mask
...
The rules that decide the value of the resultant
bit are shown below:

First bit

Second bit

First bit & Second bit

0

0

0

0

1

0

1

0

0

1

1

1

Figure 14
...
8
...
8
The example given below shows more clearly what happens while
ANDing one operand with another
...
8 are applied to each pair of bits one by one
...
9
Work through the Truth Table and confirm that the result obtained
is really correct
...

Probably, the best use of the AND operator is to check whether a
particular bit of an operand is ON or OFF
...

Suppose, from the bit pattern 10101101 of an operand, we want to
check whether bit number 3 is ON (1) or OFF (0)
...
This operand can
be represented bitwise as 00001000
...
e the value of the
second operand
...
Had it been OFF, the bit number 3 in the
resulting bit pattern would have evaluated to 0 and the complete
bit pattern would have been 00000000
...
If the
bit is ON (1), the resulting value turns out to be a non-zero value
which is equal to the value of second operand, and if the bit is OFF
(0) the result is zero as seen above
...

/* To test whether a bit in a number is ON or OFF */
main( )
{

496

Let Us C

int i = 65, j ;
printf ( "\nvalue of i = %d", i ) ;
j = i & 32 ;
if ( j == 0 )
printf ( "\nand its fifth bit is off" ) ;
else
printf ( "\nand its fifth bit is on" ) ;
j = i & 64 ;
if ( j == 0 )
printf ( "\nwhereas its sixth bit is off" ) ;
else
printf ( "\nwhereas its sixth bit is on" ) ;
}

And here is the output
...
The status of a file is governed by the value of individual bits
in this attribute byte
...
The meaning of each bit in
the attribute byte is shown in Figure 14
...


Chapter 14: Operations On Bits

Bit numbers
7

6

5

4

3

2


...



...



...



...



...



...



...



...



...



...


497

Meaning
1

0


...


1

Read only


...


Hidden


...



...


1


...



...


1


...



...


Sub-directory entry


...



...



...


Archive bit


...



...



...



...



...



...



...


Unused

Figure 14
...
A hidden file is one, which is never shown in the directory,
even though it exists on the disk
...

So, our first operand in this case becomes the attribute byte of the
file in question, whereas the second operand is the 1 * 21 = 2, as
discussed earlier
...

The second, and equally important use of the AND operator is in
changing the status of the bit, or more precisely to switch OFF a
particular bit
...
On
applying this mask, we get,
00000111
11111101
-------------00000101

Original bit pattern
AND mask
Resulting bit pattern

Here in the AND mask we keep the value of all other bits as 1
except the one which is to be switched OFF (which is purposefully
kept as 0)
...
At the same time the value 1
provided in all the other bits of the AND mask (second operand)
keeps the bit values of the other bits in the first operand unaltered
...

(b) It is used to turn OFF a particular bit in a number
...
The rules that govern the value of the resulting bit
obtained after ORing of two bits is shown in the truth table below
...
11

0

1

1

499

Chapter 14: Operations On Bits

Using the Truth table confirm the result obtained on ORing the
two operands as shown below
...

Let us consider the bit pattern 11000011
...
Note
that all the other bits in the mask are set to 0 and only the bit,
which we want to set ON in the resulting value is set to 1
...
The OR operator returns 1, when any one
of the two bits or both the bits are 1, whereas XOR returns 1 only
if one of the two bits is 1
...


^

0

1

0

0

1

1

1

0

Figure 14
...
A number
XORed with another number twice gives the original number
...


500

Let Us C

main( )
{
int b = 50 ;
b = b ^ 12 ;
printf ( "\n%d", b ) ; /* this will print 62 */
b = b ^ 12 ;
printf ( "\n%d", b ) ; /* this will print 50 */
}

The showbits( ) Function
We have used this function quite often in this chapter
...
The function is given below followed by
a brief explanation
...
If the bit is OFF we print a 0 otherwise we print a 1
...
If the variable n’s most significant bit is 0, then k
would contain a value 0, otherwise it would contain a non-zero
value
...

On the second go-around of the loop, the value of i is decremented
and hence the value of andmask changes, which will now be
0100000000000000
...
The same operation is
repeated for all bits in the number
...

(b) The bitwise operators include operators like one’s
complement, right-shift, left-shift, bitwise AND, OR, and
XOR
...

(d) The right-shift and left-shift operators are useful in
eliminating bits from a number—either from the left or from
the right
...

(f) The bitwise OR operator is used to turn on a particular bit
...


Exercise
[A] Answer the following:

(a) The information about colors is to be stored in bits of a char
variable called color
...
e
...
Write a program that asks the user to enter
a number and based on this number it reports which colors in
the rainbow does the number represents
...
The various parameters considered in the
survey were, the economic status (upper, middle, and lower
class) the languages readers prefer (English, Hindi, Regional
language) and category of paper (daily, supplement, tabloid)
...

The bit-wise information to be stored in an integer is given
below:
Bit Number

Information

0
1
2
3
4
5
6
7
8

Upper class
Middle class
Lower class
English
Hindi
Regional Language
Daily
Supplement
Tabloid

At the end give the statistical data for number of persons who
read English daily, number of upper class people who read
tabloid and number of regional language readers
...

The information regarding the games won by a particular
college is stored in bit numbers 0, 1, 2, 3, 4, 5, 6, 7 and 8
respectively of an integer variable called game
...
If a number is entered through the
keyboard, then write a program to find out whether the
college won the Champion of the Champions trophy or not,
along with the names of the games won by the college
...
), a
feline (cat, lynx, jaguar, etc
...
) or a marsupial (koala, wombat, etc
...
Bit number 4 of the variable
type stores the information about whether the animal is
Carnivore or Herbivore
...
Also
determine whether the animal is a canine, feline, cetacean or a
marsupial
...

Distribution of different bits which account for hours, minutes
and seconds is given below
...


504

Let Us C

15 14 13 12 11 10 9

8

7

6

5

4

3

2

H H H H H M M M M M M S

S

S

1

0

S S

Figure 14
...
If bit number 0 is on then it indicates Ist
year student, bit number 1 to 3 stores IInd year, IIIrd year and
IVth year student respectively
...
Rest of the
bits store room number
...

The contents of array are,
int data[ ] = { 273, 548, 786, 1096 } ;

(g) What will be the output of the following program:
main( )
{
int i = 32, j = 65, k, l, m, n, o, p ;
k = i | 35 ; l = ~k ; m = i & j ;
n = j ^ 32 ; o = j << 2 ; p = i >> 5 ;
printf ( "\nk = %d l = %d m = %d", k, l, m ) ;
printf ( "\nn = %d o = %d p = %d", n, o, p ) ;
}

16

C Under Windows












Which Windows…
Integers
The Use of typedef
Pointers in the 32-bit World
Memory Management
Device Access
DOS Programming Model
Windows Programming Model
Event Driven Model
Windows Programming, a Closer Look
The First Windows Program
Hungarian Notation
Summary
Exercise

535

536

Let Us C

S

o far we have learnt every single keyword, operator and
instruction available in C
...
We did all this
learning by compiling our programs using a 16-bit compiler like
Turbo C/C++
...
To
make a beginning one has to take a very important decision—
should we attempt to build programs that are targeted towards 16bit environments like MS-DOS or 32-bit environments like
Windows/Linux
...
That raises a very
important question—is it futile to learn C programming using 16bit compiler like Turbo C/C++? Absolutely not! The typical 32-bit
environment offers so many features that the beginner is likely to
feel lost
...

Now that the C fundamentals are out of the way and you are
confident about the language features it is time for us to delve into
the modern 32-bit operating environments
...
More and more software is being created for 32-bit
environments like Windows and Linux
...
Chapters 20
& 21 are devoted to exploring C under Linux
...

But the truth is much farther than that
...
So many are the differences that
Microsoft categorizes the different versions under two major
heads—Consumer Windows and Windows NT Family
...

Consumer Windows was targeted towards the home or small office
users, whereas NT family was targeted towards business users
...

Hence in this book we would concentrate only on NT Family
Windows
...

Before we start writing C programs under Windows let us first see
some of the changes that have happened under Windows
environment
...
As
against this, under 32-bit environment an integer is of 4 bytes
...
Thus there is no
difference between an int and a long int
...
In such as case it
would be more sensible to use a short int since it is only 2 bytes
long
...
new datatypes that have been
added in C under Windows compiler? Not at all
...

A typical C under Windows program would contain several such
typedefs
...
These are:
(a) A typical Windows program is required to perform several
complex tasks
...
Naturally a program that carries out so many
tasks would be very big in size
...
This can be overcome by
suitably typedefining the integer as shown above
...
This
can be done using a structure
...
This can be avoided by using typedef as
shown below:
struct rect
{
int top ;
int left ;
int right ;
int bottom ;
};
typedef struct rect RECT ;
typedef struct rect* PRECT ;

Chapter 16: C Under Windows

539

RECT r ;
PRECT pr ;

What have we achieved out of this? It makes user-defined
data types like structures look, act and behave similar to
standard data types like integers, floats, etc
...
Some of these could be as
follows:
typedef int COL ;
typedef int COLOR ;
typedef int COLOUR ;
typedef int COLORREF ;

To avoid this chaos Microsoft has done several typedefs for
commonly required entities in Windows programming
...
These header files are provided as
part of 32-bit compiler like Visual C++
...
If we were to run another program we were
required to terminate the first one before launching the second
...
Since only one program could
run at any given time entire resources of the machine like memory
and hardware devices were accessible to this program
...
Hence it is known as a multi-tasking
environment
...
To prevent this,
Windows does not permit any application direct access to any
machine resource
...
This had a direct bearing on
the way the application programs are created
...
So we would restrict our discussion about the
new mechanisms that have been introduced in Windows to topics
that are related, to C programming
...


Memory Management
Since users have become more demanding, modern day
applications have to contend with these demands and provide
several features in them
...
The maximum
allowable memory—1 MB—that was used in 16-bit environment
was just too small for this
...
Since Windows runs on 32-bit
microprocessors each CPU register is 32-bit long
...

Thus a 32-bit address can be stored in these registers
...
As a result, we can access 4 GB of memory locations using
32-bit registers
...


Chapter 16: C Under Windows

541

However, if we decide to install 4 GB memory it would cost a lot
...
Be aware that this balance memory is simulated as and
when the need to do so arises
...

Note that programs cannot execute straight-away from hard disk
...
Suppose there are multiple programs already in
memory and a new program starts executing
...
This operation is often called page-out operation
...

When that part of the program that was paged out is needed it is
brought back into memory (called page-in operation) and some
other programs (or their parts) are paged out
...
A few more facts that you must note
about paging are as follows:
(a) Part of the program that is currently executing might also be
paged out to the disk
...

Now imagine how the paging operations would affect our
programming
...
If this page gets paged out and is later paged in
to a different physical location then the pointer would obviously
have a wrong address
...
It always holds
a virtual address of that location
...
It is a number,
which contains three parts
...
This is shown in Figure 16
...


Page Dir
...
1
The CR3 register holds the physical location of Page Directory
Table
...
The value present at this index is
the starting address of the Page Table
...
The value
present at this index is the starting address of the physical page in
memory
...

Note that the CR3 register is not accessible from an application
...

Also, as the paging activity is going on the OS would suitably keep
updating the values in the two tables
...
Hence no program is permitted a direct access to any of
the devices
...
There is a
standard way in which an application can communicate with the
device driver
...
This standard way of communication
is discussed in detail in Chapter 17
...
In this model programs are executed from
top to bottom in an orderly fashion
...
However, the path remains fairly predictable
...
If you assume some input data you can easily walk
through the program from beginning to end
...
The operating
system simply loads and executes the program and then waits for it
to finish
...
For other
operations like generating graphics, carrying out serial
communication, etc
...

Unfortunately the DOS functions and the BIOS functions do not
have any names
...
This is a messy affair since the
programmer has to remember interrupt numbers for calling
different functions
...
This lead to lot of difficulties
since different functions use different registers for communication
...
But the library doesn’t have a parallel function for every
DOS/BIOS function
...

At times the programs are needed to directly interact with the
hardware
...

Figure 16
...


545

Chapter 16: C Under Windows

main( )
{
fun( ) ;
}
fun( )
{


}

On execution
transfer control
to program
Interrupt
& CPU
Registers
Interrupt
& CPU
Registers

DOS OS

DOS
Functions

BIOS
Function

Hardware
Sequentially Executing
DOS program

Figure 16
...
These have been
listed below:

No True Reuse
The library functions that are called from each program become
part of the executable file (
...
Thus the same
functions get replicated in several EXE files, thereby wasting
precious disk space
...

For example, successful DOS-based software like Lotus 1-2-3,
Foxpro, Wordstar offered different types of menus
...
As the look and feel of all
DOS based programs is different, the user takes a lot of time in
learning how to interact with the program

Messy Calling Mechanism
It is difficult to remember interrupt numbers and the registers that
are to be used for communication with DOS/BIOS functions
...


Hardware Dependency
DOS programs are always required to bother about the details of
the hardware on which they are running
...
Hence DOS programmers are under the
constant fear that if the hardware on which the programs are
running changes then the program may crash
...
Not only does this
make the program lengthy, the programmer has to understand a lot
of technical details of the hardware
...


Windows Programming Model
From the perspective of the user the shift from MS-DOS to
Windows OS involves switching over to a Graphical User
Interface from the typical Text Interface that MS-DOS offers
...
Mastering this new GUI
environment and getting comfortable with the multitasking feature
is at the most a matter of a week or so
...


Better Calling Mechanism
Instead of calling functions using Interrupt numbers and registers
Windows provides functions within itself which can be called
using names
...
There are literally hundreds of

548

Let Us C

API functions available
...


True Reuse
A C under Windows program calls several API functions during
course of its execution
...
To avoid this, the API functions are stored in
special files that have an extension
...

DLL stands for Dynamic Link Libraries
...
The functions present in DLLs
can be linked during execution
...
Since linking is
done dynamically the functions do not become part of the
executable file
...
It is also possible to create your own DLLs
...

(b) Breaking an application into component parts to provide a
way to easily upgrade application’s components
...
Figure 16
...


Chapter 16: C Under Windows

DLL

Description

USER32
...


GDI32
...
DLL

549

Contains functions to handle memory
management, threading, etc
...
3

Consistent Look and Feel
Consistent look and feel means that each program offers a
consistent and similar user interface
...
Every
program occupies a window—a rectangular area on the screen
...
Most program functions are
initiated through the program’s menu
...

Some menu items invoke dialog boxes, into which the user enters
additional information
...
It opens a file
...

Once you know how to use one Windows program, you’re in a
good position to easily learn another
...
Most Windows programs have both a keyboard interface
and a mouse interface
...


550

Let Us C

From the programmer’s perspective, the consistent user interface
results from using the Windows API functions for constructing
menus and dialog boxes
...


Hardware Independent Programming
As we saw earlier a Windows program can always call Windows
API functions
...
What is new in Windows is that the OS can also communicate
with application
...

Suppose we have written a program that contains a menu item,
which on selection is supposed to display a string “Hello World”
in the window
...
On executing this program it will
perform the initializations and then wait for the user input
...
This key-press or mouse-click is known as an
‘event’
...
The device driver would now inform
Windows about it
...
This notification is known as a
‘message’
...

When the application receives the message it communicates back
with the OS by calling a Windows API function to display the
string “Hello World” in the window
...
Thus there is a two-way
communication between the OS and the application
...
4
...
4
Suppose the keyboard and the mouse are now replaced with a new
keyboard and mouse
...
This is because at no time does the application carry out any
direct communication with the devices
...
Similarly, if
the screen or the graphics card is replaced no change would be
required in the program
...


Event Driven Model
When a user interacts with a Windows program a lot of events
occur
...
Since the order in which the user would
interact with the user-interface elements of the program cannot be
predicted the order of occurrence of events, and hence the order of
messages, also becomes unpredictable
...
Hence
this programming model is called ‘Event Driven Programming
Model’
...
Your
job is to anticipate what users are likely to do with your
application’s user interface objects and have a function waiting,
ready to execute at the appropriate time
...


Windows Programming, a Closer Look
There can be hundreds of ways in which the user may interact with
an application
...
For example, events occur when we create a
window, when the window’s contents are to be drawn, etc
...

Thus literally hundreds of messages may be sent to an application
thereby creating a chaos
...

Order is brought to this chaos by putting all the messages that
reach the application into a ‘Queue’
...

In fact the OS maintains several such queues
...
This queue is known as
‘System Message Queue’
...
Such queues are called ‘Application Message
Queues’
...

When we click a mouse and an event occurs the device driver
posts a message into the System Message Queue
...
Next it posts a message into the

553

Chapter 16: C Under Windows

Application Message Queue of the application in which the mouse
was clicked
...
5
...


Msg
...

Queue

Other
Mess

Application1

Application1
Msg
...
Queue

Application2

Figure 16
...
Here we go…

554

Let Us C

The First Windows Program
To keep things simple we would begin with a program that merely
displays a “Hello” message in a message box
...
h>
int _stdcall WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdline, int nCmdShow )
{
MessageBox ( 0, “Hello!”, “Title”, 0 ) ;
return ( 0 ) ;
}

Naturally a question would come to your mind—how do I create
and run this program and what output does it produce
...
Here it is…

Figure 16
...
0’
...

(b) From the File | New menu, select ‘Win32 Application’, and
give a project name, say, ‘sample1’
...

(c) From the File | New menu, select ‘C++ Source File’, and give
a suitable file name, say, ‘sample1’
...

(d) The ‘Win32 Application-Step 1 of 1’ window will appear
...


Chapter 16: C Under Windows

555

(e) A ‘New Project Information’ dialog will appear
...

(f) Again select ‘File | New | C++ Source File’
...
c’
...

(g) Type the program in the ‘sample1
...

(h) Save this file using ‘Save’ option from the File menu
...
exe’
...
exe’ from the Build menu
...
The way every C under
DOS program begins its execution with main( ), every C under
Windows program begins its execution with WinMain( )
...
A
typical WinMain( ) looks like this:
int __stdcall WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow )

Note the __stdcall before WinMain( )
...
Calling Conventions
indicate two things:
(a) The order (left to right or right to left) in which the arguments
are pushed onto the stack when a function call is made
...


Out of the different calling conventions available most commonly
used conventions are __cdecl and __stdcall
...
In
__cdecl the stack is cleaned up by the calling function, whereas in
case of __stdcall the stack is cleaned up by the called function
...
If not mentioned,
__cdecl calling convention is assumed by the compiler
...
The first is an
unsigned int and the second is a pointer to a char
...
h’
...
hInstance,
hPrevInstance, lpszCmdLine and nCmdShow are simple
variable names
...
Let us now understand the meaning of these
parameters as well as the rest of the program
...
Windows creates this ID number when the
application starts
...

A handle is simply a 32-bit number that refers to an entity
...

The actual value of the handle is unimportant to your
programs, but the Windows module that gives your program
the handle knows how to use it to refer to an entity
...

hPrevInstance: This parameter is a remnant of earlier
versions of Windows and is no longer significant
...
It is being persisted with only to
ensure backward compatibility
...
This is similar to the argv, argc parameters passed
to main( ) in a DOS program
...
This integer tells the program whether the window
that it creates should appear minimized, as an icon, normal, or
maximized when it is displayed for the first time
...




Returning 0 from WinMain( ) indicates success, whereas,
returning a nonzero value indicates failure
...
The command line arguments can be
supplied to the program by executing it from Start | Run as
shown in Figure 16
...


Figure 16
...
7 that ‘myapp
...
The parameter lpszCmdline points to the string
“abc ijk xyz”
...


558

Let Us C

Hungarian Notation
Hungarian Notation is a variable-naming convention so called in
the honor of the legendary Microsoft programmer Charles
Simonyi
...
For example, the sz prefix in szCmdLine stands for
‘string terminated by zero’; the prefix h in hInstance stands for
‘handle’; the prefix n in nCmdShow stands for int
...
Though
basically this notation is a good idea nowadays its usage is
discouraged
...
For example, suppose the 16-bit code used 2-byte
and 4-byte integer variables called wParam and lParam, where w
indicated a 16-bit integer (word) and a 32-bit integer (long)
respectively
...
You would agree that if we follow
the Hungarian notation then we would have to make a whole lot of
changes in the variable names when we port the code to a 32-bit or
a 64-bit environment
...


Summary
(a) Under Windows an integer is four bytes long
...

(b) Under Windows a pointer is four bytes long
...

(d) DOS uses a Sequential Programming Model, whereas,
Windows uses an Event Driven Programming Model
...


Chapter 16: C Under Windows

559

(f) Windows does not permit direct access to memory or
hardware devices
...

(h) Under Windows there is two-way communication between the
program and the OS
...

(j) Windows maintains an application message queue per running
application
...

(l) Commonly used calling conventions are __cdecl and
__stdcall
...


Exercise
[A] State True or False:

(a) MS-DOS uses a procedural programming model
...

(c) API functions under Windows do not have names
...

(e) Windows uses a 4 GB virtual memory space
...

(g) Under Windows the address stored in a pointer is a virtual
address and not a physical address
...


560

Let Us C

[B] Answer the following:

(a) Why is Event-driven Programming Model better than the
Sequential Programming Model?
(b) What is the meaning of different parts of the address stored in
a pointer under Windows environment?
(c) Why Windows does not permit direct access to hardware?
(d) What is the difference between an event and a message?
(e) Why Windows maintains a different message queue for each
application?
(f) In which different situations messages get posted into an
application message queue?
[C] Attempt the following:

(a) Write a program that prints the value of hInstance in a
message box
...

(c) Write a program that receives a number as a command line
argument and prints its factorial value in a message box
...


17

Windows
Programming





The Role of a Message Box
Here comes the window…
More Windows
A Real-World Window
Creation and Displaying of Window
Interaction with Window
Reacting to Messages
• Program Instances
• Summary
• Exercise

561

562

Let Us C

E

event driven programming requires a change in mind set
...

However this change would be bolstered by writing event
driven programs
...
I am
hopeful that by the time you reach the end of this chapter you
would be so comfortable with it as if you have been using it all
your life
...
We do this to
ascertain whether we are getting the results as per our
expectations
...
Under Windows screen is a
shared resource
...
You
would not be able to make out which output is of what application
...
That’s where a message box enters the scene
...
It can be dismissed either by clicking the
‘close button’ in its title bar or by clicking the OK button present
in it
...
Some of these are given below
MessageBox ( 0, “Are you sure”, “Caption”, MB_YESNO ) ;
MessageBox ( 0, “Print to the Printer”, “Caption”, MB_YESNO CANCEL) ;
MessageBox ( 0, “icon is all about style”, “Caption”, MB_OK |
MB_ICONINFORMATION ) ;

You can put the above statements within WinMain( ) and see the
results for yourself
...
What if we want to draw a free hand
drawing or display an image, etc
...
This would

Chapter 17: Windows Programming

563

not be possible
...
The next section discusses how this can be done
...
These are
shown in Figure 17
...


Caption
Bar

Minimize
Box
Close
Butt
on

Icon

Menu
Vertical
Scrol

Client
Area

Horizontal Scroll

Figure 17
...
For example, a
window may not contain the minimize box, the maximize box, the
scroll bars and the menu
...
Here is the program…
#include ...
2
Let us now understand the program
...

All these properties taken together are known as ‘window class’
...
Windows insists that a
window class should be registered with it before we attempt to
create windows of that type
...
Each of these windows
would enjoy the same properties that have been registered through
the window class
...

Some of these are BUTTON, EDIT, LISTBOX, etc
...


Chapter 17: Windows Programming

565

To actually create a window we need to call the API function
CreateWindow( )
...
The second parameter indicates the
text that is going to appear on the button surface
...

WS_OVERLAPPEDWINDOW is a commonly used style
...
The next three
parameters specify the handles to the parent window, the menu and
the application instance respectively
...

We can easily devote a section of this book to CreateWindow( )
and its parameters
...
Nobody is supposed
to remember all the parameters, their meaning and their order
...
This help is
available as part of VC++ 6
...
It is also available on the
net at http://www
...
microsoft
...

Note that CreateWindow( ) merely creates the window in
memory
...
This can be done
using the ShowWindow( ) API function
...
Our program uses this
handle to refer to the window while calling ShowWindow( )
...
If the
value of this parameter is SW_SHOWNORMAL we get a normal
sized window, if it is SW_SHOWMINIMIZED we get a
minimized window and if it is SW_SHOWMINIMIZED we get a
maximized window
...
This variable contains SW_SHOWNORMAL by
default
...


566

Let Us C

The WS_OVERLAPPEDWINDOW style is a collection of the
following styles:
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME |
WS_MINIMIZEBOX | WS_MAXIMIZEBOX

As you can make out from these macros they essentially control
the look and feel of the window being created
...
h’ header file
...
2
...
This is because
on doing so execution of WinMain( ) comes to an end and
moreover we have made no provision to interact with the window
...
You would observe that no sooner does the window appear
it disappears
...


More Windows
Now that we know how to create a window let us create several
windows on the screen
...

#include ...
3
Note that each window created in this program is assigned a
different handle
...


A Real-World Window
Suppose we wish to create a window and draw a few shapes in it
...
Hence we would have to create our own window class,
register it with Windows OS and then create a window on the basis
of it
...
Here is
the program…
#include ...
h"
void OnDestroy ( HWND ) ;
int __stdcall WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdline, int nCmdShow )
{
MSG m ;
/* perform application initialization */
InitInstance ( hInstance, nCmdShow, "title" ) ;
/* message loop */
while ( GetMessage ( &m, 0, 0, 0 ) )
DispatchMessage ( &m ) ;
return 0 ;
}
LRESULT CALLBACK WndProc ( HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam )
{
switch ( message )
{
case WM_DESTROY :
OnDestroy ( hWnd ) ;
break ;
default :
return DefWindowProc ( hWnd, message, wParam, lParam ) ;
}
return 0 ;
}

Chapter 17: Windows Programming

569

void OnDestroy ( HWND hWnd )
{
PostQuitMessage ( 0 ) ;
}

On execution of this program the window shown in Figure 17
...
We can use minimize and the maximize
button it its title bar to minimize and maximize the window
...
Finally, we can
close the window by clicking on the close window button in the
title bar
...
4
Let us now try to understand this program step by step
...
These steps are:
(a)
(b)
(c)
(d)

Creation of a window class
...

Creation of a window based on the registered class
...


Creation of a window class involves setting up of elements of a
structure called WNDCLASSEX
...
They govern the properties of the window
...
Since all the
4 steps mentioned above would be required in almost every
program in this chapter I have written this code in a user-defined
function called InitInstance( ) in the file ‘helper
...

Though writing code in a header file goes against the convention I
have still done so to achieve simplicity
...
h’ file is available in Appendix F
...
kicit
...
h
As expected WinMain( ) starts off by calling the function
InitInstance( ) present in ‘helper
...
This file has been
#included at the beginning of the program
...

Once the window has been created and displayed let us see how
we can interact with it
...
a suitable
message is posted into the message queue of our application
...

A message contains a message id and some other additional
information about the message
...
Since it is difficult
to memorize the message ids they have been suitably #defined in
‘windows
...
The message id and the additional information are
stored in a structure called MSG
...
The first
parameter passed to this function is the address of the MSG
structure variable
...
Don’t bother about the other parameters right now
...
This is done by calling the DispatchMessage( ) API
function
...
These are as
follows:
(a) From the MSG structure that we pass to it,
DisplayMessage( ) extracts the handle of the window for
which this message is meant for
...

(c) From the window class structure it obtains the address of a
function called WndProc( ) (short for window procedure)
...

(d) Using this address it calls the function WndProc( )
...
Hence
calls to GetMesage( ) and DispatchMessage( ) have been made in
a while loop in WinMain( )
...
Now the control comes
out of the loop and WinMain( ) comes to an end
...
This function is shown below:
LRESULT CALLBACK WndProc ( HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam )

This function always receives four parameters
...
The second parameter is the message id, whereas, the
third and fourth parameters contain additional information about
the message
...
CALLBACK is a typedef of __stdcall
...
h’
...

In the WndProc( ) function we have checked the message id using
a switch
...
This message is posted to the message
queue when the user clicks on the ‘Close Window’ button in the
title bar
...
This function posts a WM_QUIT
message into the message queue
...

For all messages other than WM_DESTROY the control lands in
the default clause of switch
...
This function does the default

Chapter 17: Windows Programming

573

processing of the message that we have decided not to tackle
...
For
example on double clicking the title bar DefWindowProc( )
maximizes the window
...
Since we have not
handled this message the DefWindowProc( ) function gets called
to tackle this message
...
As discussed earlier, in WndProc( ) we have
made the provision to terminate the application on encountering
WM_DESTROY
...
I would urge you to go through the
above explanation till the time you are absolutely sure that you
have understood every detail of it
...
For your
convenience I have given a flowchart of the entire working in
Figure 17
...


574

Let Us C

START Execution
Call InitInstance( )

Fill WNDCLASSEX structure to define window class
Call RegisterCallEx( ) to register the window class with OS
Call CreateWindow( ) to create window in memory
Call ShowWindow( ) to display window on screen

Pick message from message queue – GetMessage( )
Is
the message
WM_QUIT

Yes

STOP

No
Process the message – DispatchMessage( )

Call Window Procedure

Is the message
WM_DESTROY

Yes Post WM_QUIT –
PostQuitMessage( )

No
Do default processing of
message – DefWindowProc( )

Figure 17
...
This is handy for cutting and pasting between two copies of
Notepad or when running more than one terminal session with a
terminal emulator program
...

Windows performs an interesting memory optimization trick
...
For example, if you get three instances of Notepad
running, there will only be one copy of Notepad’s code in
memory
...
The
difference between handling of the code and the data is logical, as
each instance of Notepad might edit a different file, so the data
must be unique to each instance
...


Summary
(a) A message box can be displayed by calling the
MessageBox( ) API function
...

(c) Appearance of a message box can be customized
...

(e) The window that is created in memory is displayed using the
ShowWindow( ) API function
...

(g) The header file ‘Windows
...


576

Let Us C

(h) When the user clicks in a window, or moves mouse pointer on
the window, messages are generated and posted in the
application message queue
...

(j) The GetMessage( )-DispatchMessage( ) loop breaks when
GetMessage( ) encounters the WM_QUIT message
...


Exercise
[A] State True or False:

(a) MessageBox( ) is an API function
...

(c) The CreateWindow( ) function creates and displays the
window on the screen
...

(e) Every window has to be created using pre-registered window
class
...

(g) We can use the pre-defined window classes but cannot create
our own
...

(i) To be able to interact with a window it is necessary to
implement the message loop
...


Chapter 17: Windows Programming

577

(b) Run any Windows based program and see whether you can
identify all the elements of the application window
...

(e) Explain the need of RegisterClassEx( ) function
...

(h) Try to display a window with different combinations of
window styles and observer the results
...
Otherwise people would have
still been using the character oriented interfaces of MS-DOS
or Unix
...
Once you get a hang of how to
draw inside a window it would open up immense possibilities that
you never thought were possible
...
Today we are living in a world of 1024 x
768 resolution offering 16
...
Graphical menus,
icons, colored cursors, bitmaps, wave files and animations are the
order of the day
...
Moreover, with the whole lot of Windows API functions to
support graphics activity there is so much that can be achieved in a
graphics program under Windows
...


Device Independent Drawing
Windows allow programmers to write programs to display text or
graphics on the screen without concern over the specifics of the
video hardware
...

The key to this ‘device independence’ is Windows’ use of a
‘device context’
...


Chapter 18: Graphics Under Windows

581

During the original design of Windows, one of the goals was to
provide ‘device independence’
...

Windows takes care of the hardware, allowing the programmer to
concentrate on the program itself
...

Windows programs do not send data directly to the screen or
printer
...
However, it does not know how it would be
sent there, neither does it need to bother to know this
...
This standard way uses an entity called
Device Context, or simply a DC
...
For example, a screen DC is associated
with a screen, a printer DC is associated with a printer, etc
...

Similarly, any drawing done using the printer DC is directed to the
printer
...

A windows program obtains a handle (ID value) for the screen or
printer’s DC
...
The advantage of using the
DC is that the graphics and text commands that we send using the
DC are always the same, regardless of where the physical output is
showing up
...
The GDI is a program file called
GDI32
...
The

582

Let Us C

Windows environment loads GDI32
...
Windows also loads a ‘device driver’
program if the hardware conversions are not part of GDI32
...

Common examples are VGA
...
SYS for the HP LaserJet printer
...

Thus GDI provides all the basic drawing functionality for
Windows; the device context represents the device providing a
layer of abstraction that insulates your applications from the
trouble of drawing directly to the hardware
...


Hello Windows
We would begin our tryst with graphics programming under
windows by displaying a message “Hello Windows” in different
fonts
...
First take a look at
the program given below before we set out to understand it
...
h>
# include "helper
...
lfFaceName, fonts[ i ] ) ; /* copy font name */
f
...
lfItalic = 1 ; /* italic */
hfont = CreateFontIndirect ( &f ) ;
holdfont = SelectObject ( hdc, hfont ) ;
SetTextColor ( hdc, RGB ( 0, 0, 255 ) ) ;
TextOut ( hdc, 10, 70 * i, "Hello Windows", 13 ) ;
SelectObject ( hdc, holdfont ) ;
DeleteObject ( hfont ) ;
}
EndPaint ( hWnd, &ps ) ;
}

On execution of this program the window shown in Figure 18
...


Figure 18
...
This message is generated whenever the client area of the
window needs to be redrawn
...

(b) When the window is minimized and then maximized
...

(d) When the size of the window changes on stretching its
boundaries
...

Would a WM_PAINT message be generated when the cursor is
dragged in the window? No
...

When the switch-case structure inside WndProc( ) finds that the
message ID passed to WndProc( ) is WM_PAINT, it calls the
function OnPaint( )
...
This function obtains a handle to the
device context
...
Lastly it removes WM_PAINT from the
message queue
...

Inside the loop we have displayed “Hello Windows” in three
different fonts
...
This structure is used to indicate the font
properties like font name, font height, italic or normal, etc
...
The properties that we have not setup in the loop are all
initialized to 0
...


586

Let Us C

This function loads the relevant font file
...

CreateFontIndirect( ) returns the handle to the font created in
memory
...
This function returns the
handle to the existing font in the DC, which is preserved in
holdfont variable
...
The RGB( ) macro uses the red, green and blue
component values to generate a 32-bit color value
...
To TextOut( )
we have to pass the handle to the DC, position where the text is to
be displayed, the text to be displayed and its length
...
Hence before
associating another font with it we have deleted the existing font
using the DeleteObject( ) API function
...
If not released we would be wasting precious memory,
because the device context structure would remain in memory but
we would not be able access it
...
This function permits finer control over the way the text
is displayed
...


Drawing Shapes
If text is so near can graphics be far behind? Now that we know
how to draw text in a window let us now create a simple program
that displays different shapes in a window
...
The rest of
the program is same as in the previous section
...


Chapter 18: Graphics Under Windows

587

void OnPaint ( HWND hWnd )
{
HDC hdc ;
PAINTSTRUCT ps ;
HBRUSH hbr ;
HGDIOBJ holdbr ;
POINT pt[5] = { 250, 150, 250, 300, 300, 350, 400, 300, 320, 190 } ;
hdc = BeginPaint ( hWnd, &ps ) ;
hbr = CreateSolidBrush ( RGB ( 255, 0, 0 ) ) ;
holdbr = SelectObject ( hdc, hbr ) ;
MoveToEx ( hdc, 10, 10, NULL ) ;
LineTo ( hdc, 200, 10 ) ;
Rectangle ( hdc, 10, 20, 200, 100 ) ;
RoundRect ( hdc, 10, 120, 200, 220, 20, 20 ) ;
Ellipse ( hdc, 10, 240, 200, 340 ) ;
Pie ( hdc, 250, 10, 350, 110, 350, 110, 350, 10 ) ;
Polygon ( hdc, pt, 5 ) ;
SelectObject ( hdc, holdbr ) ;
DeleteObject ( hbr ) ;
EndPaint ( hWnd, &ps ) ;
}

On execution of this program the window shown in Figure 18
...


588

Let Us C

Figure 18
...
The DC contains a default
pen and brush
...
In this program we have used the
default pen and a blue colored solid brush for drawing the shapes
...
For creating a solid colored brush we need
to call the CreateSolidBrush( ) API function
...
The
function returns the handle of the brush which we have preserved

Chapter 18: Graphics Under Windows

589

in the hbr variable
...

The handle of the default brush in DC is collected in the holdbr
variable
...
For drawing the line we have used MoveToEx( ) and
LineTo( ) API functions
...

The RoundRect( ) function draws a rectangle with rounded
corners
...

Likewise, x2, y2 represent coordinates of the bottom right corner
of the rectangle
...

Note that rectangle and the rounded rectangle are drawn from x1,
y1 up to x2-1, y2-1
...

The Pie( ) function draws a pie-shaped wedge by drawing an
elliptical arc whose center and two endpoints are joined by lines
...
In Pie( x1, y1, x2, y2, x3, y3, x4,
y4 ), x1, y1 and x2, y2 specify the x and y-coordinates of the upper
left corner and bottom right corner respectively, of the bounding
rectangle
...

In Polygon ( lpPoints, nCount ), lpPoints points to an array of
points that specifies the vertices of the polygon
...
nCount specifies the number of
vertices stored in the array
...


590

Let Us C

Once we are through with drawing the shapes the old brush is
selected back in the DC and then the brush created by us is deleted
using DeleteObject( ) function
...
We can create pens of different style, color
and thickness to do our drawing
...

void OnPaint ( HWND hWnd )
{
HDC hdc ;
PAINTSTRUCT ps ;
HPEN hpen ;
HGDIOBJ holdpen ;
hdc = BeginPaint ( hWnd, &ps ) ;
hpen = CreatePen ( PS_DASH, 1, RGB ( 255, 0, 0 ) ) ;
holdpen = SelectObject ( hdc, hpen ) ;
MoveToEx ( hdc, 10, 10, NULL ) ;
LineTo ( hdc, 500, 10 ) ;
SelectObject ( hdc, holdpen ) ;
DeleteObject ( hpen ) ;
hpen = CreatePen ( PS_DOT, 1, RGB ( 255, 0, 0 ) ) ;
holdpen = SelectObject ( hdc, hpen ) ;
MoveToEx ( hdc, 10, 60, NULL ) ;
LineTo ( hdc, 500, 60 ) ;
SelectObject ( hdc, holdpen ) ;
DeleteObject ( hpen ) ;

Chapter 18: Graphics Under Windows

591

hpen = CreatePen ( PS_DASHDOT, 1, RGB ( 255, 0, 0 ) ) ;
holdpen = SelectObject ( hdc, hpen ) ;
MoveToEx ( hdc, 10, 110, NULL ) ;
LineTo ( hdc, 500, 110 ) ;
SelectObject ( hdc, holdpen ) ;
DeleteObject ( hpen ) ;
hpen = CreatePen ( PS_DASHDOTDOT, 1, RGB ( 255, 0, 0 ) ) ;
holdpen = SelectObject ( hdc, hpen ) ;
MoveToEx ( hdc, 10, 160, NULL ) ;
LineTo ( hdc, 500, 160 ) ;
SelectObject ( hdc, holdpen ) ;
DeleteObject ( hpen ) ;
hpen = CreatePen ( PS_SOLID, 10, RGB ( 255, 0, 0 ) ) ;
holdpen = SelectObject ( hdc, hpen ) ;
MoveToEx ( hdc, 10, 210, NULL ) ;
LineTo ( hdc, 500, 210 ) ;
SelectObject ( hdc, holdpen ) ;
DeleteObject ( hpen ) ;
EndPaint ( hWnd, &ps ) ;
}

On execution of this program the window shown in Figure 18
...


592

Let Us C

Figure 18
...

This function needs three parameters—pen style, pen thickness
and pen color
...

have been defined in ‘windows
...

Note that for pen styles other than PS_SOLID the pen thickness
has to be 1 pixel
...
These are—solid brush, hatch
brush and pattern brush
...

Here is the OnPaint( ) handler which achieves this
...
4
appears
...
4
In the OnPaint( ) handler we have drawn three rectangles—first
using a solid brush, second using a hatched brush and third using a
pattern brush
...
We simply have to make calls to CreateSolidBrush( )
and CreateHatchBrush( ) respectively
...
There are several other styles
defined in ‘windows
...

For creating a pattern brush we need to first create a bitmap
(pattern)
...
You can use any other bitmap file present
on your hard disk
...
When the compile such a program we usually
want these resources to become a part of our EXE file
...
To be able to
use a resource (bitmap file in our case) it is not enough to just copy
it in the project directory
...

(a) From the ‘Insert’ menu option of VC++ 6
...


Chapter 18: Graphics Under Windows

595

(b) From the dialog that pops up select ‘bitmap’ followed by the
import button
...
bmp file
...
rc)
...
h’ also gets created
...
rc’ file to the project using the Project | Add
to Project | Files option
...
The id is #defined in the file ‘resource
...
Somewhere
information has to be stored linking the id with the actual
...
This is done in the ‘Script1
...
We need to
include the ‘resource
...

To create the pattern brush we first need to load the bitmap in
memory
...
The first parameter passed to this function is the handle
to the instance of the program
...
We have passed this hInst to LoadBitmap( )
...

This string is created from the resource id using the
MAKEINTRESOURCE macro
...
This handle is then passed to the
CreatePatternBrush( ) function
...

Note that if the size of the bitmap is bigger than the rectangle
being drawn then the bitmap is suitably clipped
...

While doing the clean up firstly the brush is deleted followed by
the bitmap
...
Static data
is that portion of the program which is not executed as machine
instructions and which does not change as the program executes
...

The designers of Windows wisely decided that static data should
be handled separately from the program code
...
By
separating static data from the program code the creators of
Windows were able to use a standard C/C++ compiler to create the
code portion of the finished Windows program, and they only had
to write a ‘Resource compiler’ to create the resources that
Windows programs use
...
It also means that a programmer
can work on a program’s logic, while a designer works on how the
program looks
...
It provides a facility to draw a freehand drawing
using mouse
...
We can indicate
where the freehand drawing begins by clicking the left mouse
button
...
This drawing should continue till we do not release
the left mouse button
...
For free hand
drawing we need to tackle three mouse messages—
WM_LBUTTONDOWN
for
left
button
click,
WM_MOUSEMOVE
for
mouse
movement
and
WM_LBUTTONUP for releasing the left mouse button
...
The

Chapter 18: Graphics Under Windows

597

WndProc( ) function and the message handlers that perform this
task are given below
int x1, y1, x2, y2 ;
LRESULT CALLBACK WndProc ( HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam )
{
switch ( message )
{
case WM_DESTROY :
OnDestroy ( hWnd ) ;
break ;
case WM_LBUTTONDOWN :
OnLButtonDown ( hWnd, LOWORD ( lParam ),
HIWORD ( lParam ) ) ;
break ;
case WM_LBUTTONUP :
OnLButtonUp( ) ;
break ;
case WM_MOUSEMOVE :
OnMouseMove ( hWnd, wParam, LOWORD ( lParam ),
HIWORD ( lParam ) ) ;
break ;
default:
return DefWindowProc ( hWnd, message, wParam, lParam ) ;
}
return 0 ;
}
void OnLButtonDown ( HWND hWnd, int x, int y )
{
SetCapture ( hWnd ) ;
x1 = x ;

598

Let Us C

y1 = y ;
}
void OnMouseMove ( HWND hWnd, int flags, int x, int y )
{
HDC hdc ;
if ( flags == MK_LBUTTON ) /* is left mouse button depressed */
{
hdc = GetDC ( hWnd ) ;
x2 = x ;
y2 = y ;
MoveToEx ( hdc, x1, y1, NULL ) ;
LineTo ( hdc, x2, y2 ) ;
ReleaseDC ( hWnd, hdc ) ;
x1 = x2 ;
y1 = y2 ;
}
}
void OnLButtonUp( )
{
ReleaseCapture( ) ;
}

On execution of this program the window shown in Figure 18
...
We can now click the left mouse button with mouse
pointer placed anywhere in the window
...
The freehand drawing
would continue till we do not release the left mouse button
...
5
It appears that for drawing the freehand we should simply receive
the mouse coordinates as it is moved and then highlight the pixels
at these coordinates using the SetPixel( ) API function
...
This is
because usually the mouse is dragged pretty fast whereas the
mouse move messages won’t arrive so fast
...
This is what has been done in our program
...


600

Let Us C

Let us now discuss each mouse handler
...
While doing so,
we have passed the mouse coordinates where the click occurred
...
In
lParam the low order 16 bits contain the current x - coordinate of
the mouse whereas the high order 16 bits contain the y coordinate
...

In OnLButtonDown( ) we have preserved the starting point of
freehand in global variables x1 and y1
...
If it stands depressed then the
flags variable contains MK_LBUTTON
...

A line is then drawn between x1, y1 and x2, y2 using the functions
MoveToEx( ) and LineTo( )
...
Hence the current values of
x2, y2 are stored in x1, y1
...
This is because we are carrying out the
drawing activity in reaction to a message other than WM_PAINT
...

You can try using BeginPaint( ) / EndPaint( ) in mouse handlers
and GetDC( ) / ReleaseDC( ) in OnPaint( )
...
So our window would not receive
any messages
...
The process of
doing this is known as mouse capturing
...
As a result, the program
continues to respond to mouse events during freehand drawing
even if the mouse is moved outside the client area
...


Device Context, a Closer Look
Now that we have written a few programs and are comfortable
with idea of selecting objects like font, pen and brush into the DC,
it is time for us to understand how Windows achieves the device
independent drawing using the concept of DC
...
A screen DC and its working is
shown in Figure 18
...


602

Let Us C

App1

App2

Screen DC
HPEN 200
HBRUSH 400
HBITMAP 600
HFONT 700

...


...


...

Other Info
Screen

Drawing Object

Drawing Object

O/P Device

Red
Pen

HFONT = 700

Blue
Brush

900

Arial

1000

Black Pen
200

White Brush
400

Mono
...
6
You can make following observations from Figure 18
...

It merely holds their handles
...

(c) Default objects like black pen, white brush, etc
...


Chapter 18: Graphics Under Windows

603

(d) The drawing objects that an application explicitly creates can
be shared within DCs of the same application, but is never
shared between different applications
...

In other words with one screen multiple DCs can exist
...
(Truly speaking the
request comes from GDI functions that our application calls)
...


Displaying a Bitmap
We are familiar with drawing normal shapes on screen using a
device context
...
This is because there might be color variations in the
screen on which the bitmap was created and the screen on which it
is being displayed
...
But
where in RAM—in the 1 x 1 pixel bitmap whose handle is present
in memory DC
...
Thus if we attempt to draw a line using a
memory DC it would end up on the 1 x 1 pixel bitmap
...
Hence
we need to expand the size and color capability of this bitmap
...
This
is shown in Figure 18
...


604

Let Us C

Default Memory DC
HPEN
HBRUSH
HBITMAP
HFONT

200
400
405
800

...


...


...

Other Info

Black Pen
200
New O/P Device

White Brush
400
Font
800

40000
190x220 24 –color
bitmap

Figure 18
...
We can make it visible by simply
copying the bitmap image (including what has been drawn on it) to
the screen DC by using the API function BitBlt( )
...
Here making
compatible means making certain adjustments in the contents of
the memory DC structure
...

Let us now take a look at the program that puts all these concepts
in action
...
Here is the code…
void OnPaint ( HWND hWnd )
{
HDC hdc ;
HBITMAP hbmp ;
HDC hmemdc ;
HGDIOBJ holdbmp ;
PAINTSTRUCT ps ;
hdc = BeginPaint ( hWnd, &ps ) ;
hbmp = LoadBitmap ( hInst, MAKEINTRESOURCE ( IDB_BITMAP1 ) ) ;
hmemdc = CreateCompatibleDC ( hdc ) ;
holdbmp = SelectObject ( hmemdc, hbmp ) ;
BitBlt ( hdc, 10, 20, 190, 220, hmemdc, 0, 0, SRCCOPY ) ;
EndPaint ( hWnd, &ps ) ;
SelectObject ( hmemdc, holdbmp ) ;
DeleteObject ( hbmp ) ;
DeleteDC ( hmemdc ) ;
}

On executing the program we get the window shown in Figure
18
...


606

Let Us C

Figure 18
...
Next we
have loaded the vulture bitmap image in memory by calling the
LoadBitmap( ) function
...
Then
we have created a memory device context and made its properties
compatible with that of the screen DC
...
Note that we have
passed the handle to the screen DC to this function
...
After this we have
selected the loaded bitmap into the memory DC
...
As a result of this the
vulture now appears in the window
...
These are as under:
hdc – Handle to target DC where the bitmap is to be blitted
10, 20 – Position where the bitmap is to be blitted
190, 220 – Width and height of bitmap being blitted
0, 0 – Top left corner of the source image
...

SRCCOPY – Specifies one of the raster-operation codes
...
SRCCOPY means that the pixel color of
source should be copied onto the destination pixel of the target
...
So having the ability to display a
bitmap in a window is fine, but if we can add movement and sound
to it then nothing like it
...

If we are to animate an object in the window we need to carry out
the following steps:
(a) Create an image that is to be animated as a resource
...

(c) Repeatedly display this prepared image at suitable places in
the window taking care that when the next image is displayed
the previous image is erased
...

Let us now write a program that on execution makes a red colored
ball move in the window
...
Note that the width and height of the redcolored ball is 22 pixels
...

HBITMAP hbmp ;
int x, y ;
HDC hmemdc ;
HGDIOBJ holdbmp ;
LRESULT CALLBACK WndProc ( HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam )
{
switch ( message )
{
case WM_DESTROY :
OnDestroy ( hWnd ) ;
break ;
case WM_CREATE :
OnCreate ( hWnd ) ;
break ;
case WM_TIMER :
OnTimer ( hWnd ) ;
break ;
default :
return DefWindowProc ( hWnd, message, wParam, lParam ) ;
}
return 0 ;
}
void OnCreate ( HWND hWnd )
{
RECT r ;
HDC hdc ;
hbmp = LoadBitmap ( hInst, MAKEINTRESOURCE ( IDB_BITMAP1 ) ) ;
hdc = GetDC ( hWnd ) ;

Chapter 18: Graphics Under Windows
hmemdc = CreateCompatibleDC ( hdc ) ;
holdbmp = SelectObject ( hmemdc, hbmp ) ;
ReleaseDC ( hWnd, hdc ) ;
srand ( time ( NULL ) ) ;
GetClientRect ( hWnd, &r ) ;
x = rand( ) % r
...
bottom - 22 ;
SetTimer ( hWnd, 1, 50, NULL ) ;
}
void OnDestroy ( HWND hWnd )
{
KillTimer ( hWnd, 1 ) ;
SelectObject ( hmemdc, holdbmp ) ;
DeleteDC ( hmemdc ) ;
DeleteObject ( hbmp ) ;
PostQuitMessage ( 0 ) ;
}
void OnTimer ( HWND hWnd )
{
HDC hdc ;
RECT r ;
const int wd = 22, ht = 22 ;
static int dx = 10, dy = 10 ;
hdc = GetDC ( hWnd ) ;
BitBlt ( hdc, x, y, wd, ht, hmemdc, 0, 0, WHITENESS ) ;
GetClientRect ( hWnd, &r ) ;
x += dx ;
if ( x < 0 )
{

609

610

Let Us C
x=0;
dx = 10 ;
PlaySound ("chord
...
right - wd ) )
{
x = r
...
wav", NULL, SND_FILENAME | SND_ASYNC ) ;
}
y += dy ;
if ( y < 0 )
{
y=0;
dy = 10 ;
PlaySound ("chord
...
bottom - ht ) )
{
y = r
...
wav", NULL, SND_FILENAME | SND_ASYNC );
}
BitBlt ( hdc, x, y, wd, ht, hmemdc, 0, 0, SRCCOPY ) ;
ReleaseDC ( hWnd, hdc ) ;
}

From the WndProc( ) function you can observe that we have
handled two new messages here—WM_CREATE and
WM_TIMER
...
Let us now understand
these handlers one by one

WM_CREATE and OnCreate( )

Chapter 18: Graphics Under Windows

611

The WM_CREATE message arrives whenever a new window is
created
...
In our program to make the ball move we
need to display it at different places at different times
...
However,
we need to load the image only once
...

You are already familiar with the steps involved in preparing the
image for blitting—loading the bitmap, creating a memory DC,
making it compatible with screen DC and selecting the bitmap in
the memory DC
...
We have also called the
SetTimer( ) function
...


WM_TIMER and OnTimer( )
If we are to perform an activity at regular intervals we have two
choices:
(a) Use a loop and monitor within the loop when is it time to
perform that activity
...
This mechanism when
used posts a WM_TIMER message at regular intervals to our
application
...
If the control is within the loop and a new message
arrives the message would not get processed unless the control
goes out of the loop
...
That is, whenever WM_TIMER arrives

612

Let Us C

that time its handler does the job that we want to get executed
periodically
...

All that we have done in the OnTimer( ) handler is erase the ball
from previous position and draw it at a new position
...
If so we
have played a sound file using the PlaySound( ) API function and
then changed the direction of the ball
...
Hence we need to pass the id of the
timer that we want to set up to the SetTimer( ) function
...

(b) For multiple timers Windows would post multiple
WM_TIMER messages
...

(c) For drawing as well as erasing the ball we have used the same
function—BitBlt( )
...
When we use this code the
color values of the source pixels get ignored
...

(d) The size of client area of the window can be obtained using
the GetClientRect( ) API function
...
To ensure this we
have generated its initial x, y coordinates using the standard
library function rand( )
...
To ensure that we do get true
random numbers, somehow we need to tie the random number
generation with time, as time of each execution of our
program would be different
...
We have further
passed this time to the srand( ) function
...
h’
...
h’
...
If first
parameter is filename then the second has to be NULL
...
SND_FILENAME indicates
that the first parameter is the filename, whereas
SND_ASYNC indicates that the sound should be played in
the background
...
lib’
...
On selection of this item a dialog pops
up
...
lib’ in the ‘Object / Library modules’ edit box
...
For this we have called the KillTimer( ) API function
passing to it the ID of the timer
...
In this chapter and in the

614

Let Us C

last two I have tried to catch the essence of Windows’ Event
Driven Programming model
...
Windows API is truly
an endless world
...
The programs
that we have written have merely scratched the surface
...
The intention of this chapter was to unveil
before you, to give you the first glimpse of what is possible under
Windows
...
Having made a sound beginning, rest is for you to explore
...
In Windows, the code once written
works on any video adapter
...
Instead, it draws to the logical display
surface using device context
...

(d) It is necessary to obtain the device context before drawing
text or graphics in the client area
...
The information
includes color of pen and brush, screen resolution, color
palettes, etc
...


Chapter 18: Graphics Under Windows

615

(f) If we don’t select any brush or pen into the device context
then the drawing drawn in the client area would be drawn
with the default pen (black pen) and default brush (white
brush)
...
RGB ( 0, 0, 0 ) gives black color,
whereas, RGB ( 255, 255, 255 ) gives white color
...


Exercise
[A] State True or False:

(a) Device independence means the same program is able to work
using different screens, keyboards and printers without
modifications to the program
...

(c) The API function EndPaint( ) is used to release the DC
...

(e) The pen thickness for the pen style other than PS_SOLID has
to be 1 pixel
...

(g) If we drag the mouse from (10, 10) to (110, 100), 100
WM_MOUSEMOVE messages would be posted into the
message queue
...

(i) With each DC a default monochrome bitmap of size 1 pixel x
1 pixel is associated
...

[B] Answer the following:
(a) What is meant by Device Independent Drawing and how it is
achieved?

616

Let Us C

(b) Explain the significance of WM_PAINT message
...

(e) What do you mean by capturing a mouse?
(f) Write down the steps that need to be carried out to animate an
object
...
If you click
the right mouse button the color of subsequent hellos should
change
...

(c) Write a program to gradient fill the entire client area with
shades of blue color
...
If the window is resized the boxes should also get
resized so that all the 64 boxes are visible at all times
...

(f) Write a program that displays different text in different colors
and fonts at different places after every 10 seconds
...

Mangling Keys
KeyLogger
Where is This Leading
Summary
Exercise

617

618

Let Us C

T

here are two types of Windows programmers those who are
happy in knowing the things the way they are under
Windows and those who wish to know why the things are
the way they are
...
They are the real power users of Windows
...
The focus here would be
restricted to mechanisms that are involved in interaction with the
hardware under the Windows world
...


Hardware Interaction
Primarily interaction with hardware suggests interaction with
peripheral devices
...
The interaction may also involve communicating
with chips present on the motherboard
...
During this interaction one or more
of the following activities may be performed:
(a) Reacting to events that occur because of user’s interaction
with the hardware
...

(b) Reacting to events that do not need explicit user’s interaction
...

(c) Explicit communication from a program without the
occurrence of an event
...


Chapter 19: Interaction With Hardware

619

Let us now see how this interaction is done under different
platforms
...
For different events there are different interrupts
...
IVT is present in memory
...
Depending upon which interrupt has occurred the
Microprocessor picks the address of the appropriate BIOS routine
from IVT and transfers execution control to it
...
Naturally, for different interrupts different
BIOS routines are called
...

Refer Figure 19
...


620

Let Us C

Key hit / Mouse click
generates an interrupt
Microprocessor
Microprocessor
looks up IVT

Address
of ISR1

Address
of ISR2

Suitable
ISR is
called

ISR1

ISR2

IVT

BIOS Routines

Figure 19
...
Once this is done whenever a hardware interrupt occurs our
routine’s address from IVT is picked up and the control is
transferred to our routine
...
This finer control may involve changing codes of keys
or handling hitting of multiple keys simultaneously
...
These are shown in Figure 19
...


Chapter 19: Interaction With Hardware

621

C Program

BIOS
Functions

DOS
Functions

Library
Functions

Direct
Interaction

Hardware

Figure 19
...

(a) Calling DOS Functions
To interact with the hardware a program can call DOS
functions
...
As a result, the programmer is not
required to know all the hardware details to be able to interact
with it
...

This is difficult since the programmer has to remember
interrupt service numbers for calling different DOS functions
...
This leads to lot of difficulties since
different functions use different registers for communication
...

(b) Calling BIOS Functions

622

Let Us C

DOS functions can carry out jobs like console I/O, file I/O,
printing, etc
...
the program has to
call another set of functions called ROM-BIOS functions
...
BIOS functions suffer
from the same difficulty as DOS functions—they do not have
names
...

(c) Calling Library Functions
We can call library functions which in turn can call
DOS/BIOS functions to carry out the interaction with
hardware
...
But the library doesn’t have a
parallel function for every DOS/BIOS function
...

(d) Directly interacting with the hardware
At times the programs are needed to directly interact with the
hardware
...
For example, while writing
good video games one is required to watch the status of
multiple keys simultaneously
...
At such times
we have to interact with the keyboard controller chip directly
...
Moreover, not every technical
detail about how the hardware from a particular manufacturer
works is well documented
...
As a reaction to this signal a
table called Interrupt Descriptor Table (IDT) is looked up and a
corresponding routine for the interrupt gets called
...
These routines are part of the Windows OS itself
...
This ISR interacts with the hardware
...
Every piece of hardware
works differently than the other
...
If this code is written in the kernel then the kernel would
have to be rewritten and recompiled every time a new hardware
comes into existence
...
Hence the
new code to interact with the device is written in a separate
program called device driver
...
This device driver is an extension
of the OS itself
...
Out of the several
components of Windows OS a component called kernel is tightly
integrated with the processor architecture
...
One of
goals of Windows NT family was to keep the other components of
OS and the device drivers portable across different microprocessor
architectures
...
So, had registration of the
device driver’s ISR in IDT been allowed, then the mechanism

624

Let Us C

would fail on processors which do not use IDT, thereby
compromising portability of device drivers
...
3 for understanding the interrupt handling
mechanism under Windows
...
3
If we are to gain finer control while reacting to interrupts we
would be required to write a device driver containing a new ISR to
do so
...
This is primarily
because under Windows every device is shared amongst multiple
applications running in memory
...
Instead it provides several API functions
to carry out the interaction
...
When we
call an API function to interact with a device, it in turn accesses
the device driver program for the device
...
There is a standard way
in which an application can communicate with the device driver
...
In the sections to follow we would see how to
communicate with the device driver to be able to interact with the
hardware
...
That is the beauty of the Windows
architecture
...
The API functions that we would need to
interact with this new device driver would remain same
...
4

C Program

Windows API

Device Driver

Hardware

Figure 19
...
We would illustrate this with the help of several
programs
...
Rather than the physical structure
of the floppy disk it is the way the stored information is laid out
and managed that concerns programmers most
...
Each floppy disk
consists of four logical parts—Boot Sector, File Allocation Table
(FAT), Directory and Data space
...
That is, how
many sides does it contain, how many tracks are there on each
side, how many sectors are there per track, how many bytes are
there per sector, etc
...
The Directory contains information about the files like
its attributes, name, size, etc
...
Figure
19
...
44 MB disk
...
5
With the logical structure of the floppy disk behind us let us now
write a program that reads the boot sector of a floppy disk and
displays its contents on the screen
...
A good
enough reason for us to add the capability to read a boot sector to
our knowledge! Here is the program…
# include ...
h>
# include ...
h>
# pragma pack ( 1 )
struct boot
{
BYTE jump [ 3 ] ;

628

Let Us C

char bsOemName [ 8 ] ;
WORD bytesperSector ;
BYTE sectorspercluster ;
WORD sectorsreservedarea ;
BYTE copiesFAT ;
WORD maxrootdirentries ;
WORD totalSectors ;
BYTE mediaDescriptor ;
WORD sectorsperFAT ;
WORD sectorsperTrack ;
WORD sides ;
WORD hiddenSectors ;
char reserve [ 480 ] ;
};
void ReadSector ( char*src, int ss, int num, void* buff ) ;
void main( )
{
struct boot b ;
ReadSector ( "\\\\
...
id ) ;
printf ( "Bytes per Sector: %d\n", b
...
spc ) ;
/* rest of the statements can be written by referring Figure 19
...
The Boot Parameters are useful while
performing read/write operations on the disk
...
6 shows
the break up of the boot parameters for a floppy disk
...
1

Bytes per sector

2

512

Sectors per cluster

1

1

Reserved sectors

2

1

Number of FAT copies

1

2

Max
...
Of sides

2

2

Hidden sectors

4

0

Huge sectors

4

0

BIOS drive number

1

0

Reserved sectors

1

0

Boot signature

1

41

Volume ID

4

349778522

Volume label

11

ICIT

File system type

8

FAT12

Figure 19
...
6 our program has
first created a structure called boot
...
Then
comes the surprise—there is no WinMain( ) in the program
...
This has been done only for the
sake of simplicity
...
If you wish
you can of course adapt this program to display the same contents
in a window
...
Only
difference is that it is built as a ‘Win32 Console Application’ using
VC++
...

To actually read the contents of boot sector of the floppy disk the
program makes a call to a user-defined function called
ReadSector( )
...

The first parameter passed to ReadSector( ) is a string that
indicates the storage device from where the reading has to take
place
...
In \\
...
’ for the machine name
...
’ means the same machine on which the program is executing
...
The second
parameter is the logical sector number
...
The third
parameter is the number of sectors that we wish to read
...
The last parameter is the address of a buffer/variable
that would collect the data that is read from the floppy
...
As a
result, the structure variable would be setup with the contents of
the boot sector data at the end of the function call
...
If you wish you can print the rest of the
contents as well
...
e
...
This function
begins by making a call to the CreateFile( ) API function as
shown below:
h = CreateFile ( src, GENERIC_READ,
FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0 ) ;

The CreateFile( ) API function is very versatile
...
The CreateFile( ) function opens the specified device as
a file
...
Reading
from this file means reading from the device
...
The first
parameter is the string specifying the device to be opened
...
By specifying the GENERIC_READ flag we have
indicated that we just wish to read from the file (device)
...
Since
floppy drive is a shared resource across all the running
applications we have specified the FILE_SHARE_READ flag
...
The
fourth parameter indicates security access for the file (device)
...
The fifth parameter specifies what action to take if

632

Let Us C

the file already exists
...

Since the floppy disk file was already opened by the OS a long
time back during the booting
...

Hence we have passed a 0 value for them
...

The device file mechanism allows us to read from the file (device)
by setting the file pointer using the SetFilePointer( ) API function
and then reading the file using the ReadFile( ) API function
...

The first parameter to SetFilePointer( ) is the handle of the device
file that we obtained by calling the CreateFile( ) function
...
This second parameter is relative to the third parameter
...

To actually read from the device file we have made a call to the
ReadFile( ) API function
...
The first parameter is the handle of the file (device), the
second parameter is the address of a buffer where the read contents
should be dumped
...
We have specified the value as 512 * num so as to
read num sectors
...
Lastly,
once our work with the device is over we should close the file
(device) using the CloseHandle( ) API function
...
Its name is WriteFile( )
...
The
parameters of WriteFile( ) are same as that of ReadFile( )
...
Given below is the code of WriteSector( ) function that
works exactly opposite to the ReadSector( ) function
...
We simply need to change the
string that specifies the device
...
\\a:", 0, 1, &b ) ; /* reading from 2nd floppy drive */
ReadSector ( "\\\\
...
\\c:", 0, 1, &b ) ; /* writing to a hard disk */
ReadSector ( "\\\\
...

(a) If we are to read from the second floppy drive we should
replace A: with B: while calling ReadSector( )
...
use the string with appropriate drive letter
...
\C: to \\
...


634

Let Us C

(c) To read from the CD-ROM just specify the drive letter of the
drive
...

(d) The hard disk is often divided into multiple partitions
...

are stored in a table on the disk
...
If we are to read the partition table contents
we can do so by using the string \\
...

(e) Using \\
...
Here 0 represents the first hard disk in
the system
...


Communication with Keyboard
Like mouse messages there also exist messages for keyboard
...

Of these, WM_KEYDOWN and WM_KEYUP are sent to an
application (which has the input focus) whenever the key is
pressed and released respectively
...
When we tackle WM_KEYDOWN or WM_KEYUP
we need to ourselves check the status of toggle keys like NumLock
and CapsLock and shift keys like Ctrl, Alt and Shift
...

What is mentioned above is the normal procedure followed by
most Windows applications
...

For example, suppose we are to perform one of the following jobs:
(a) Once you hit any key CapsLock should become on
...


Chapter 19: Interaction With Hardware

635

(b) If we hit a key once it should appear twice on the screen
...

Note that all these effects should work on a system-wide basis for
all Win32 applications
...
Let us understand these mechanisms one by
one
...
DLL file during execution
...
DLL file is a binary file
that cannot execute on its own
...


Windows Hooks
As the name suggests, the hook mechanism permits us to intercept
and alter the flow of messages in the OS before they reach the
application
...
The hooking mechanism involves writing a hook
procedure in a DLL file and registering this procedure with the
OS
...

For different messages there are different types of hooks
...
You can refer MSDN
for nearly a dozen more types of hooks
...


636

Let Us C

Before we proceed to write our own hook procedure let us
understand the normal working of the keyboard messages
...
7
...
queue by calling
keybd_event( )

System Msg
...
Queue

Application2
Msg
...
7
With reference to Figure 19
...

(b) The kernel routine calls the ISR of the keyboard device driver
...

(d) The ISR calls a OS function keybd_event( ) to post the key
code to the System Message Queue
...

Let us now see what needs to be done if we are to alter this
procedure
...
As a result, our hook procedure would receive the message
before it is dispatched to the appropriate Application Message
Queue
...

Let us now put all this theory into practice by writing a few
programs
...
This effect would come into being when the first key is hit
subsequent to the execution of our program
...

(b) An application EXE which loads the DLL in memory
...


638

Let Us C

/* hook
...
h>
static HHOOK hkb = NULL ;
HANDLE h ;
BOOL __stdcall DllMain ( HANDLE hModule, DWORD ul_reason_for_call,
LPVOID lpReserved )
{
h = hModule ;
return TRUE ;
}
BOOL __declspec ( dllexport ) installhook( )
{
hkb = SetWindowsHookEx ( WH_KEYBOARD,
( HOOKPROC ) KeyboardProc, ( HINSTANCE ) h, 0 ) ;
if ( hkb == NULL )
return FALSE ;
return TRUE ;
}
LRESULT __declspec ( dllexport ) __stdcall KeyboardProc ( int nCode,
WPARAM wParam, LPARAM lParam )
{
short int state ;
if ( nCode < 0 )
return CallNextHookEx ( hkb, nCode, wParam, lParam ) ;
if ( ( nCode == HC_ACTION ) &&
( ( DWORD ) lParam & 0x40000000 ) )
{
state = GetKeyState ( VK_CAPITAL ) ;
if ( (state & 1 )== 0) /* if off */

Chapter 19: Interaction With Hardware

639

{
keybd_event ( VK_CAPITAL , 0,
KEYEVENTF_EXTENDEDKEY, 0 ) ;
keybd_event ( VK_CAPITAL , 0,
KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0 ) ;
}
}
return CallNextHookEx ( hkb, nCode, wParam, lParam ) ;
}
BOOL __declspec ( dllexport ) removehook( )
{
return UnhookWindowsHookEx ( hkb ) ;
}

Follow the steps mentioned below to create this program:
(a) Select ‘File | New’ option to start a new project in VC++
...

(c) In the ‘Win32 Dynamic-link Library Step 1 of 1’ select “An
empty DLL project” and click on the ‘Finish’ button
...

(e) From the ‘File’ tab select ‘C++ source file’ and give the file
name as ‘hook
...
Type the code listed above in this file
...
DLL file
...
It has been
replaced by a function called DllMain( )
...
It gets called when the DLL is
loaded or unloaded
...
In this function we have merely stored the handle
to the DLL that has been loaded in memory into a global variable
h for later use
...
Our DLL contains three such
functions—installhook( ), removehook( ) and KeyboardProc( )
...

These functions would be called from the second program
...
The handlers
for messages WM_CREATE and WM_DESTROY are given
below:
/* capslocked
...
dll" ) ;
if ( h != NULL )
{
p = GetProcAddress ( h, "installhook" ) ;
( *p )( ) ; /* calls installhoook( ) function */
}
}
void OnDestroy ( HWND hWnd )
{
BOOL ( CALLBACK *p )( ) ;
p = GetProcAddress ( h, "removehook" ) ;
( *p )( ) ; /* calls removehoook( ) function */
FreeLibrary ( h ) ;
PostQuitMessage ( 0 ) ;
}

Chapter 19: Interaction With Hardware

641

As we know, the OnCreate( ) and OnDestroy( ) handlers would
be called when the WM_CREATE and WM_DESTROY
messages arrive respectively
...
To do this we have called the
LoadLibrary( ) API function
...
The returned address is
stored in p, where p is a pointer to the installhook( ) function
...

In the installhook( ) function we have called the API function
SetWindowsHookEx( ) to register our hook procedure with the
OS as shown below:
hkb = SetWindowsHookEx ( WH_KEYBOARD,
( HOOKPROC ) KeyboardProc, ( HINSTANCE ) h, 0 ) ;

Here the first parameter is the type of hook that we wish to
register, whereas the second parameter is the address of our hook
procedure KeyboardProc( )
...

From now on whenever a keyboard message is retrieved by the OS
from the System Message Queue the message is firstly passed to
our hook procedure, i
...
to KeyboardProc( ) function
...
To begin with we have checked whether nCode
parameter is less than 0
...
The MSDN documentation suggests that “if code
is less than zero, the hook procedure must pass the message to the
CallNextHookEx( ) function without further processing and
should return the value returned by CallNextHookEx( )”
...

These hook procedures always get called in an order that is

642

Let Us C

opposite to their order of installation
...

If the nCode parameter contains a value HC_ACTION it means
that the message that was just removed form the system message
queue was a keyboard message
...
If the
state of the key was ‘depressed’ (30th bit of lParam is 1) then we
have obtained the state of the CapsLock key by calling the
GetKeyState( ) API function
...

For this simulation we have called the function keybd_event( )
twice—first call is for pressing the CapsLock and second is for
releasing it
...
The parameter VK_CAPITAL represents the code
for the CapsLock key
...
But this time the CapsLock would be
on so we would end up passing control to the next hook procedure
through a call to CallNextHookEx( )
...
In this handler we have obtained the address of
the removehook( ) exported function and called it
...
Note
that to this function we have passed the handle to our hook
...

Hereafter the CapsLock would behave normally
...


Chapter 19: Interaction With Hardware

643

One last point about this program—the ‘hook
...


Did You Press It TTwwiiccee…
...
So how about tasting
the power some bit more
...

Here is the code for the hook procedure
...
If it does then we have
checked the present state of the key in question
...
However, this may lead to a
serious problem
...
Once again the conditions would become true and we
would post the same message again
...

This can be prevented by using a using a simple flag variable as
shown in the code
...
So also is the application program
...
That is,
convert an A to a B, B to C, C to D, etc
...
We simply have to increment the key code before
posting it into the system message queue
...
This can be achieved by simply
returning a non-zero value from the hook procedure (thus
bypassing the call to CallNextHookEx( ))
...

LRESULT __declspec ( dllexport ) __stdcall KeyboardProc ( int nCode,
WPARAM wParam, LPARAM lParam )
{
static BYTE key ;
static BOOL flag = FALSE ;

Chapter 19: Interaction With Hardware

645

if ( nCode < 0 )
return CallNextHookEx ( hkb, nCode, wParam, lParam ) ;
if ( ( nCode == HC_ACTION ) &&
( ( DWORD ) lParam & 0x80000000 ) == 0 )
{
if ( flag == FALSE )
{
key = wParam ;
key ++ ;
keybd_event ( key , 0, KEYEVENTF_EXTENDEDKEY, 0 ) ;
flag = TRUE ;
return 1 ;
}
else
{
if ( key == ( BYTE ) wParam )
flag = FALSE ;
}
}
return CallNextHookEx ( hkb, nCode, wParam, lParam ) ;
}

KeyLogger
There are several malicious programs that are floating on the net
that steal away your passwords
...
These programs make use of windows hooks to trap
every key that is pressed
...

However, such key logger programs deviate from the ones that we
developed in three fundamental ways:
(a) They do not pop any window on the screen; otherwise the
program’s presence would get detected
...

(c) The logged keys are secretly sent over the net to the malicious
users who write such programs
...


Where is This Leading
Even for a moment do not create an impression in you mind that
Windows Hooks are only for notorious activities
...
These activities
include:
(a) Multimedia keyboards have special key like Cut, Copy, Paste,
etc
...
On
pressing these keys these programs use the hook mechanism
to place the simulated keys in the system message queue
...
To manage these
actions a windows hook called Journal hook is used
...
This again can
be achieved using mouse and keyboard hook
...
But the above three I
believe would be ample to prove to you the constructive side of the
powerful mechanism called Windows Hooks
...

(2) When the program interacts with the hardware without any
user intervention
...
In Windows the
same thing is done by the device driver’s ISR
...
In Windows the
same thing can be done by using API functions
...

(e) Interaction with the any device can be done using API
functions like CreateFile( ), ReadFile( ), WriteFile( ) and
CloseHandle( )
...

(g) Windows provides a powerful mechanism called hooks that
can alter the flow of messages before they reach the
application
...

(i) Windows hooks can be put to many good uses
...

(b) Under Windows on occurrence of an interrupt the kernel
routine calls the appropriate device driver’s ISR
...


648

Let Us C

(d) Under Windows we can write device drivers to extend the OS
itself
...

(f) While reading a sector from the disk the CreateFile( )
function creates a file on the disk
...

(h) The ReadFile( ) and WriteFile( ) API functions can only
perform reading or writing from/to a disk file
...

(d) What is the standard way of communicating with a device
under Windows?
(e) Write a program to read the contents of Boot Sector of a 32bit FAT file system and print them on the screen
...

(f) Write a program that ensures that the key ‘A’ is completely
disabled across all applications
...


20

C Under Linux











What is Linux
C Programming Under Linux
The ‘Hello Linux’ Program
Processes
Parent and Child Processes
More Processes
Zombies and Orphans
One Interesting Fact
Summary
Exercise

649

650

Let Us C

T

oday the programming world is divided into two major
camps—the Windows world and the Linux world
...
How big and
committed is this community is one of the hottest debates that is
raging in all parts of the world
...

Before you decide to join the Windows or the Linux camp you
should first get familiar with both of them
...
This and the next one
would deal with Linux programming
...
I hope you
find the journey interesting and exciting
...
Its kernel was
written from scratch by Linus Torvalds with assistance from a
loosely-knit team of programmers across the world on Internet
...
Moreover,
unlike Windows or Unix, Linux is available completely free of
cost
...

Anybody is free to change it to suit his requirement, with a
precondition that the changed kernel can be distributed only in the
source code form
...
A common user may not want
the headaches of downloading the kernel, going through the
complicated compilation process, then downloading the
frameworks, programs and utilities
...
They distribute the
precompiled kernel, programs, utilities and frameworks on a
common media
...
Some of
the popular distributions are RedHat, SUSE, Caldera, Debian,
Mandrake, Slackware, etc
...
Which one is better
than the other is only a matter of taste
...

These days it also runs on Compaq Alpha AXP, Sun SPARC,
Motorola 68000 machines (like Atari ST and Amiga), MIPS,
PowerPC, ARM, Intel Itanium, SuperH, etc
...

Under Linux one is faced with simply too many choices of Linux
distributions, graphical shells and managers, editors, compilers,
linkers, debuggers, etc
...
0
Console Shell
- BASH
Graphical Shell
- KDE 3
...


C Programming Under Linux
How is C under Linux any different than C under DOS or C under
Windows? Well, it is same as well as different
...
The usage of standard library
functions is also same even though the implementation of each
might be different under different OS
...
The programmer however doesn’t
suffer because of this since he can continue to call printf( ) the
same way no matter how it is implemented
...
If we are to build programs that
utilize the features offered by the OS then things are bound to be
different across OSs
...
The architecture
of this program would be very closely tied with the OS under
which it is being built
...
are very closely
tied with the OS for which the program is being built
...
Hence naturally the program that achieves
the same task under different OS would have to be different
...
Here is the
source code
...
It begins with main( ) and uses printf( )
standard library function to produce its output
...
The steps for typing, compiling and
executing the program are discussed below
...
Though any
editor can be used to do so, we have preferred to use the editor
called ‘KWrite’
...
Note that
KWrite is a text editor and is a part of K Desktop environment
(KDE)
...

Once KDE is started select the following command from the
desktop panel to start KWrite:
K Menu | Accessories | More Accessories | KWrite
If you face any difficulty in starting the KWrite editor please refer
Appendix H
...
c’
...
c’ using the cd command
...
c

(d) On successful compilation gcc produces a file named ‘a
...

This file contains the machine code of the program which can
now be executed
...

#
...
out

(f) Now you should be able to see the output ‘Hello Linux’ on
the screen
...
We will begin with processes
...
Today the modern OSs like Windows and

654

Let Us C

Linux permit execution of several tasks simultaneously
...

In Linux each running task is known as a ‘process’
...
What
happens is that the microprocessor divides the execution time
equally among all the running processes
...
Once the
time-slice allocated for a process expires the operation that it is
currently executing is put on hold and the microprocessor now
directs its attention to the next process
...
The switching of processes
happens so fast that we get a false impression that the processor is
executing several processes simultaneously
...
This
scheduler program is fairly complex
...
This
includes current values of CPU registers, contents of System Stack
and Application Stack, etc
...
This process of shifting over from
one thread to another is often called a Context Switch
...

Kernel assigns each process running in memory a unique ID to
distinguish it from other running processes
...
It is very simple to print the PID of
a running process programmatically
...
When the execution of the program comes
to an end the process stands terminated
...
Hence the kernel assigns a new
ID to the process each time
...


Parent and Child Processes
As we know, our running program is a process
...
There is a parent-child relationship
between the two processes
...
This function splits the running
process into two processes, the existing one is known as parent and
the new process is known as child
...
h>
int main( )
{
printf ( "Before Forking\n" ) ;
fork( ) ;
printf ( "After Forking\n" ) ;
}

Here is the output of the program…
Before Forking
After Forking
After Forking

656

Let Us C

Watch the output of the program
...
In other words
fork( ) has managed to split our process into two
...
Since these jobs may
be inter-related we may not want to create two different programs
to perform them
...
Suppose we want
perform two jobs—copy contents of source file to target file and
display an animated GIF file indicating that the file copy is in
progress
...
Once the copying is over the playing of the GIF file
should be stopped
...
Also, they cannot
be performed one after another
...

At such times we would want to use fork( ) to create a child
process and then write the program in such a manner that file copy
is done by the parent and displaying of animated GIF file is done
by the child process
...
Note that the issue here is to show how to perform
two different but inter-related jobs simultaneously
...

# include ...
There onwards the
execution of the fork( ) function continues in both the processes
...
Hence control would come back from fork( )
twice, even though it is actually called only once
...
This can be exploited by our
program to segregate the code that we want to execute in the
parent process from the code that we want to execute in the child
process
...

In the parent process the ‘else block’ would get executed, whereas
in the child process the ‘if block’ would get executed
...
This program would use the
fork( ) call to create a child process
...
Here is the
program…
# include ...
As the name suggests, this
function returns the PID of the parent of the calling process
...
A lot of things that
follow use the fork( ) function
...

Note that even Linux internally uses fork( ) to create new child
processes
...
The father of all these processes is a
process called init
...


Chapter 19: Interaction With Hardware

659

# ps –A

Here the switch –A indicates that we want to list all the running
processes
...
For this first we should create a child process using
fork( ) and then from within the child process we should call an
exec function to execute the program on the disk as part of a child
process
...
For
example, execl( ) function permits us to pass a list of command
line arguments to the program to be executed
...

There also exist other variations like execle( ) and execvp( )
...

# include ...

This function accepts variable number of arguments
...
The remaining parameters describe the command line
arguments for the program to be executed
...
Thus in our
case the we have called upon the execl( ) function to execute the ls
program as shown below
ls -al /etc

As a result, all the contents of the /etc directory are listed on the
screen
...
This is because the exec family functions overwrite
the image of the calling process with the code and data of the
program that is to be executed
...

Hence the call to printf( ) did not materialize
...
This is
because a child would not get created and execl( ) would simply
overwrite the main process itself
...
Hence fork( ) and
execl( ) usually go hand in hand
...

But from where does the ps program get this information? Well,
Linux maintains a table containing information about all the
processes
...
Apart from other
information the process table contains an entry of ‘exit code’ of the
process
...
Even though the process comes to an end its entry
would remain in the process table until such time that the parent of
the terminated process queries the exit code
...

When we fork a new child process and the parent and the child
continue to execute there are two possibilities—either the child
process ends first or the parent process ends first
...

(a) Child terminates earlier than the parent
In this case till the time parent does not query the exit code of the
terminated child the entry of the child process would continue to
exist
...
Zombie means ghost, or in plain simple Hindi a ‘Bhoot’
...
This would
prevent a zombie
...
In such a case the
zombie child process is treated as an ‘Orphan’ process
...
Next, as a responsible parent init queries the
process table as a result of which the child process entry is
eliminated from the process table
...
When our parent process
terminates, the shell queries the process table
...
However, the child process
which is still running is left orphaned
...
Note that
in this case the child process does not become a zombie
...
However, as a good programming practice our
program should get the exit code of the terminated process and
thereby ensure a proper cleanup
...
Why is it important to get the exit
code of the terminated process
...
The following program
shows how this can be done
...
h>
# include ...

This loop ensures that the child does not terminate immediately
...
This function makes the parent process wait

Chapter 19: Interaction With Hardware

663

till the time the execution of the child process does not come to an
end
...

Once the child process, terminates the waitpid( ) function queries
its exit code and returns back to the parent
...

The first parameter of waitpid( ) function is the pid of the child
process for which the wait has to be performed
...
The third parameter is
used to specify some options to control the behavior of the wait
operation
...
Next we have made use of the WIFEXITED( ) macro
to test if the child process exited normally or not
...
Using this macro the parent suitably
prints a message to report the status (normal/abnormal)
termination of its child process
...

Then does it mean that the child process contains the data and code
below the fork( ) call
...
In actuality the code
never gets duplicated
...
As against this, some data is shared, some is not
...
However, if any of the processes (either
child or parent) attempt to change the value of a variable it is no
longer shared
...
This not only ensures data
integrity but also saves precious memory
...

(b) A Linux distribution consists of the kernel with source code
along with a large collection of applications, libraries, scripts,
etc
...

(d) Basic scheduling unit in Linux is a ‘Process’
...

(e) fork( ) library function can be used to create child processes
...

(g) execl( ) library function is used to execute another program
from within a running program,
...

(i) execl( ) and fork( ) usually go hand in hand
...

(k) kill command can be used to terminate a process
...

(m) An ‘Orphan’ is a child process whose parent has terminated
...

(o) A parent process can avoid creation of a Zombie and Orphan
processes using waitpid( ) function
...

(b) All distributions of Linux contain the same collection of
applications, libraries and installation scripts
...


Chapter 19: Interaction With Hardware

665

(d) execl( ) library function can be used to create a new child
process
...

(f) A family of fork( ) and exec( ) functions are available, each
doing basically the same job but with minor variations
...

(h) fork( ) overwrites the image (code and data) of the calling
process
...

(j) Every zombie process is essentially an orphan process
...

[B] Answer the following:

(a) If a program contains four calls to fork( ) one after the other
how many total processes would get created?
(b) What is the difference between a zombie process and an
orphan process?
(c) Write a program that prints the command line arguments that
it receives
...

Do you observe any change in the output of the program?
(f)

How does waitpid( ) prevent creation of Zombie or Orphan
processes?

666

Let Us C

21

More Linux
Programming









Communication using Signals
Handling Multiple Signals
Registering a Common Handler
Blocking Signals
Event driven programming
Where Do You Go From Here
Summary
Exercise

667

668

Let Us C

C

ommunication is the essence of all progress
...
In today’s world a
program that runs in isolation is of little use
...
In Chapters 16 and 17 we saw how a
Windows based program communicates with Windows
...


Communication using Signals
In the last chapter we used fork( ) and exec( ) library function to
create a child process and to execute a new program respectively
...
Thus the direction of communication was from the
program to the OS
...
Let
us now write a simple program that would help you experience the
signal mechanism
...
All that we have done here
is we have used an infinite while loop to print the message
"Program Running" on the screen
...
When we press Ctrl +
C the keyboard device driver informs the Linux kernel about
pressing of this special key combination
...
Since we have done nothing to
handle this signal the default signal handler gets called
...

Hence on pressing Ctrl + C the program gets terminated
...
Well,
it is simple
...

A unique number is associated with each signal
...
in the file ‘signal
...

Every process contains several ‘signal ID - function pointer’ pairs
indicating for which signal which function should be called
...
It is
precisely this default signal handler for SIGINT that got called
when we pressed Ctrl + C when the above program was executed
...

Let us know see how can we prevent the termination of our
program even after hitting Ctrl + C
...
h>
void sighandler ( int signum )
{
printf ( "SIGINT received
...
The first parameter

670

Let Us C

of this function specifies the ID of the signal that we wish to
register
...

This address has to be typecasted to a void * before passing it to
the signal( ) function
...
This function would display the
message ‘SIGINT received
...
Note that unlike the default handler, our
handler does not terminate the execution of our program
...
For this we need to open a new instance of command
prompt (terminal)
...
Next do a ps –a to obtain the list of
processes running at all the command prompts that we have
launched
...
out
...
out’
process by saying
# kill 3276

In my case the terminal on which I executed a
...
In your case the terminal name
and the process id might be a different number
...

Note that signals work asynchronously
...
Once the execution of the signal
handler is over the execution of the program is resumed from the
point where it left off when the signal was received
...
Here is the program to do this…
# include ...
h>
# include ...

The signal( ) function is called thrice to register a different handler
for each of the three signals
...

As in the previous program, here too, when we press Ctrl + C the
handler for the SIGINT i
...
inthandler( ) is called
...
This is because
when the kill command is used it sends the running program a
SIGTERM signal
...
Since we have handled this signal ourselves, the
handler for SIGTERM i
...
termhandler( ) gets called
...
Once the execution of termhandler( ) function is over
the program resumes its execution and continues to print ‘Program
Running’
...
Use the following command from the another terminal:
kill –SIGKILL 3276

As the command indicates, we are trying to send a SIGKILL
signal to our program
...

Most signals may be caught by the process, but there are a few
signals that the process cannot catch, and they cause the process to
terminate
...

The SIGKILL signal is an un-catchable signal that forcibly
terminates the execution of a process
...


Chapter 21: More Linux Programming

673

The SIGKILL signal is to be used as a last resort to terminate a
program that gets out of control
...
It first sends a
SIGTERM signal to all processes, waits for a while, thus giving a
‘grace period’ to all the running processes
...

That leaves only one question—when does a process receive the
SIGCONT signal? Let me try to answer this question
...
The process is stopped but is not terminated, i
...
it is
suspended
...

To resume the execution of the suspended process we can make
use of the fg (foreground) command
...


Registering a Common Handler
Instead of registering a separate handler for each signal we may
decide to handle all signals using a common signal handler
...
h>
# include ...
h>
void sighandler ( int signum )
{
switch ( signum )
{
case SIGINT :

674

Let Us C
printf ( "SIGINT Received\n" ) ;
break ;

case SIGTERM :
printf ( "SIGTERM Received\n" ) ;
break ;
case SIGCONT :
printf ( "SIGCONT Received\n" ) ;
break ;
}
}
int main( )
{
signal ( SIGINT, sighandler ) ;
signal ( SIGTERM, sighandler ) ;
signal ( SIGCONT, sighandler ) ;
while ( 1 )
printf ( "\rProgram running" ) ;
return 0 ;
}

In this program during each call to the signal( ) function we have
specified the address of a common signal handler named
sighandler( )
...
This does not
lead to a problem since the sighandler( ) we can figure out inside
the signal ID using the first parameter of the function
...

Note that we can easily afford to mix the two methods of
registering signals in a program
...
Registering a common handler makes sense if
we want to react to different signals in exactly the same way
...
In such a case we may decide
to block the signal
...
Note that if a signal
arrives when it is blocked it is simply queued into a signal queue
...
Thus blocking of signals
defers the delivery of signals to a process till the execution of
some critical/time-critical code is over
...
Let us now write a program to understand signal
blocking
...
h>
# include ...
h>
# include ...
Next we want to

Chapter 21: More Linux Programming

677

repeatedly accept strings in a buffer and display them on the screen
till the time the user does not enter an ‘n’ from the keyboard
...

However, a SIGCONT should be permitted
...

Once we are through with the loop we must unblock these signals
...

The first parameter of the sigprocmask( ) function specifies
whether we want to block/unblock a set of signals
...
The last
parameter can be either NULL or the address of sigset_t type
variable which would be set up with the existing set of signals
before blocking/unblocking signals
...
The sigemptyset( ) empties a sigset_t variable so that it
does not refer to any signals
...
We have used this
function to quickly initialize the sigset_t variable block to a known
empty state
...
This can be achieved using
the sigaddset( ) library function
...

After the loop we have also used an infinite while loop to print the
‘Program running’ message
...
Once the user enters ‘n’ from the
keyboard the execution comes out of the while loop and unblocks

678

Let Us C

the signals
...
So if we press Ctrl + C or use the kill
command when the execution of the loop that receives input is not
over these signals would be kept pending
...


Event Driven programming
Having understood the mechanism of signal processing let us now
see how signaling is used by Linux – based libraries to create
event driven GUI programs
...
We have
chosen the GTK library version 2
...

Here, GTK stands for Gimp’s Tool Kit
...
Given below is the first program that
uses this toolkit to create a window on the screen
...
c */
# include ...
c `pkg-config gtk+-2
...
c’ and then
linking it with the necessary libraries from GTK toolkit
...

Here is the output of the program…

Figure 21
...
Every window under
GTK is known as a widget
...

This function requires the addresses of the command line
arguments received in main( )
...
The only parameter this function takes is the
type of windows to be created
...
This call creates a window in memory and returns a
pointer to the widget object
...
We have collected this
pointer in a GtkWidget structure pointer called p
...
The first parameter of this
function is a pointer to the GtkWidget structure representing
the window for which the title has to be set
...

(d) Register a signal handler for the destroy signal
...
The
handler for the destroy signal should perform clean up
activities and then shutdown the application
...
We only need to associate this function with the destroy
signal
...
The first parameter of this function is the pointer to
the widget for which destroy signal handler has to be
registered
...
The third parameter is the address of the
signal handler routine
...

(e) Resize the window to the desired size using the
gtk_widget_set_size_request( ) function
...

(f) Display the window on the screen using the function
gtk_widget_show( )
...
This can be
accomplished using the gtk_main( ) function
...
c */
# include ...


Chapter 21: More Linux Programming

683

Figure 21
...
The only difference is that
in addition to the destroy signal we have registered a signal
handler for the expose_event using the g_signal_connect( )
function
...
By writing the code for drawing shapes in the
handler for this signal we are assured that the drawing would never
vanish if the windows is dragged outside the screen and then
brought back in, or some other window uncovers a portion of our
window which was previously overlapped, and so on
...

The way in Windows we have a device context, under Linux we
have a graphics context
...
This function returns a pointer to the
graphics context structure
...
Once we are
through with drawing we should release the graphics context using
the gdk_gc_unref( ) function
...
With that knowledge under your belt
you are now capable of exploring the vast world of Linux on your
own
...

Idea here was to raise the hood and show you what lies underneath
it
...
Good luck!

Summary
(a) Programs can communicate with the Linux OS using library
functions
...

(c) The interrupt signal (SIGINT) is sent by the kernel to our
program when we press Ctrl + C
...

(e) A process cannot handle an un-catchable signal
...


Chapter 21: More Linux Programming

685

(g) A process can block a signal or a set of signals using the
sigprocmask( ) function
...

(i) A SIGSTOP signal is generated when we press Ctrl + Z
...

(k) A suspended process can be resumed using the fg command
...

(m) In GTK, the g_signal_connect( ) function can be used to
connect a function with an event
...

(b) Blocked signals are ignored by a process
...

(d) Blocked signals are ignored once the signals are unblocked
...

(f) gtk_main( ) function makes uses of a loop to prevent the
termination of the program
...

(h) The sigprocmask( ) function can block as well as unblock
signals
...

(d) Write a program to handle the SIGINT and SIGTERM
signals
...
Run the
program and make use of Ctrl + C more than once
...
What are your observations?
(e) Write a program that blocks the SIGTERM signal during
execution of the SIGINT signal
...


Left to Right

Unary minus

-

Right to left

Increment/Decrement

++

One’s compliment

~

Right to left

Negation

!

Right to Left

--

Right to Left

Address of

&

Right to left

Value of address

*

Right to left

Type cast

( type )

Right to left

Size in bytes

sizeof

Right to left

Multiplication

*

Left to right

Division

/

Left to right

Modulus

%

Left to right

Addition

+

Left to right

Subtraction

-

Left to right

Left shift

<<

Left to right

Right shift

>>

Left to right

Less than

<

Left to right

Less than or equal to

<=

Left to right

Greater than

>

Left to right

Greater than or equal to

>=

Left to right

Equal to

==

Left to right

Not equal to

!=

Left to right

Continued…

689

Appendix A: Precedence Table
Continued…
Description

Operator

Associativity

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

Conditional

? :

Right to left

Assignment

=

Right to left

*=

Right to left

-=

&=

Right to left

^=

|=

Right to left

<<=

Figure A1
...
However, this book would be incomplete if it has
nothing to say about standard library functions
...
An excellent book dedicated totally to
standard library functions is Waite group’s, Turbo C Bible, written
by Nabjyoti Barkakti
...
The
functions have been classified into broad categories
...
Unhappily,
among their most enduring accomplishments are several
new techniques for wasting time
...
And one hears again and again about programs
that had to be rewritten all over again because the bugs present in
it could not be located
...
Bugs are C programmer's
birthright
...
No sure-shot way for
that
...
They are not arranged in any
particular order
...

For example,
int choice ;
scanf ( "%d", choice ) ;

Here, the & before the variable choice is missing
...
Safety is in
eliminating the blanks
...

What do you think will be the output of the following
program:
main( )
{
int i = 10 ;
while ( i = 10 )
{
printf ( "got to get out" ) ;
i++ ;
}
}

At first glance it appears the message will be printed once and
the control will come out of the loop since i becomes 11
...
This is because
the = used in the condition always assigns the value 10 to i,
and since i is non-zero the condition is satisfied and the body
of the loop is executed over and over again
...

Observe the following program
...
Cause is
the semicolon after while
...

[4] Omitting the break statement at the end of a case in a switch
statement
...

main( )
{
int ch = 1 ;
switch ( ch )
{
case 1 :
printf ( "\nGoodbye" ) ;
case 2 :
printf ( "\nLieutenant" ) ;
}
}

Here, since the break has not been given after the printf( ) in
case 1, the control runs into case 2 and executes the second
printf( ) as well
...
Especially, in cases when we are checking whether
the value of a variable equals a capital letter or a small case

Appendix C: Chasing The Bugs

705

letter
...

[5] Using continue in a switch
...
Remember that
continue works only with loops, never with a switch
...

yr = romanise ( year, 1000, 'm' ) ;

Here, three arguments in the order int, int and char are being
passed to romanise( )
...
A careless mismatch might give strange results
...

If we make the following function call,
area = area_circle ( 1
...
Note that unless otherwise mentioned
the compiler would assume that this function returns a value
of the type int
...


706

Let Us C

How do you recognize a C programmer? Ask him to write a
paragraph in English and watch whether he ends each
sentence with a semicolon
...
However, a semicolon at the end of a macro
definition might create a problem
...

#define SQR(x) x * x
main( )
{
int a ;
a = 25 / SQR ( 5 ) ;
printf ( "\n%d", a ) ;
}

In this example we expect the value of a to be 1, whereas it
turns out to be 25
...

#define ABS (a) ( a = 0 ? a : -a )

Here, the space between ABS and (a) makes the preprocessor
believe that you want to expand ABS into (a), which is
certainly not what you want
...

#define SUM ( a ) ( a + a )
main( )
{
int w, b = 5 ;
w = SUM( b++ ) ;
printf ( "\n%d", w ) ;
}

On preprocessing, the macro would be expanded to,
w = ( b++ ) + ( b++ ) ;

If you are wanting to first get sum of 5 and 5 and then
increment b to 6, that would not happen using the above
macro definition
...

In the statement
ch = 'z' ;

a single character is assigned to ch
...

Note that in the first case, the declaration of ch would be,
char ch ;

whereas in the second case it would be,
char *ch ;

[13] Forgetting the bounds of an array
...
Compiler would
not give a warning if our program exceeds the bounds
...

[14] Forgetting to reserve an extra location in a character array for the
null terminator
...


Appendix C: Chasing The Bugs

709

For example, the dimension of the array word[ ] should be 9
if a string “Jamboree” is to be stored in it
...

main( )
{
char ch ;
FILE *fp ;
fp = fopen ( "text
...
As a result, the
value that is assigned to ch will be the true/false result of the
test—1 if the value returned by getc( ) is not equal to EOF,
and 0 otherwise
...
while referring to a
structure element
...
only a structure
variable can occur, whereas on the left of the operator -> only
a pointer to a structure can occur
...

main( )

710

Let Us C

{
struct emp
{
char name[35] ;
int age ;
};
struct emp e = { "Dubhashi", 40 } ;
struct emp *ee ;
printf ( "\n%d", e
...

main( )
{
unsigned int *s ;
s = 0x413 ;
printf ( "\n%d", *s ) ;
}

Here, it is necessary to use the keyword far in the declaration
of variable s, since the address that we are storing in s (0x413)
is a address of location present in BIOS Data Area, which is
far away from the data segment
...

Under Windows every pointer is 4-byte pointer
...


Appendix C: Chasing The Bugs

711

main( )
{
char ch ;
for ( ch = 0 ; ch <= 255 ; ch++ )
printf ( "\n%c %d", ch, ch ) ;
}

Can you believe that this is an indefinite loop? Probably, a
closer look would confirm it
...
Hence, the moment ch tries to become 128 (through
ch++), the value of character range is exceeded, therefore the
first number from the negative side of the range, -128, gets
assigned to ch
...


712

Let Us C

C

Creating
Libraries

701

702

Let Us C

I

n Chapter 5 we saw how to add/delete functions to/from
existing libraries
...
Here we would assume that we wish to
create a library containing the functions factorial( ), prime( ) and
fibonacci( )
...
Here are the steps that need to
be carried out to create this library
...


(a) Define the functions factorial( ), prime( ) and fibonacci( ) in
a file, say ‘myfuncs
...
Do not define main( ) in this file
...
h’ and declare the prototypes of
factorial( ), prime( ) and fibonacci( ) in it as shown below:
int factorial ( int ) ;
int prime ( int ) ;
void fibonacci ( int ) ;

(c) From the Options menu select the menu-item ‘Application’
...

Select OK
...
This would create the
library file called ‘myfuncs
...

That’s it
...
Now we have to use the
functions defined in this library
...

(a) Create a file, say ‘sample
...

#include "myfuncs
...
h’ should be in the same directory
as the file ‘sample
...
If not, then while including ‘myfuncs
...

(b) Go to the ‘Project’ menu and select ‘Open Project…’ option
...
Give the name of the
project, say ‘sample
...

(c) From the ‘Project’ menu select ‘Add Item’
...
Select the file ‘sample
...
Also add the file ‘myfuncs
...

Finally select ‘Done’
...


704

Let Us C

D

Hexadecimal
Numbering
• Numbering Systems
• Relation Between Binary and Hex

713

714

Let Us C

W

hile working with computers we are often required to use
hexadecimal numbers
...
Before justifying this statement let us first discuss what
numbering systems are, why computers use binary numbering
system, how binary and hexadecimal numbering systems are
related and how to use hexadecimal numbering system in everyday
life
...
For example,
binary numbering system has base 2 and hexadecimal numbering
system has base 16, just the way decimal numbering system has
base 10
...
For example, in decimal numbering system, when we have
used digits from 0 to 9, we run out of digits
...


...
This seems perfectly natural
...
It is very easy to use other bases as well
...


...
In hex
notation, the ten digits 0 through 9 are used to represent the values
zero through nine, and the remaining six values, ten through
fifteen, are represented by symbols A to F
...
Here is how the counting in hex would look
like:
0
1

716

Let Us C

2
3
4
5
6
7
8
9
A
B
C
D
E
F last available digit
10 start using a new column
11

...


Many other numbering systems can also be imagined
...
From the base 12 system we retain our 12
hour system for time, the number of inches in a foot and so on
...

The hex numbers are built out of hex digits in much the same way
the decimal numbers are built out of decimal digits
...
In a binary system, there are only two digits 0
and 1
...


...
Thus, binary
numbering system corresponds nicely with the circuits in the
computer—0 means off, and 1 means on
...

Hex numbers are used primarily as shorthand for binary numbers
that the computers work with
...
1)
...

Suppose we want to represent a binary number 11000101 in a
short way
...


Hex

Binary

Hex

Binary

0

0000

8

1000

1

0001

9

1001

2

0010

A

1010

3

0011

B

1011

4

0100

C

1100

5

0101

D

1101

6

0110

E

1110

7

0111

F

1111

Figure D
...
Just look at Figure D
...
From it
find out the hex digits for the two four-bit sets (1100 and 0101)
...
Therefore, the binary number’s hex
equivalent is C5
...
In this
method neither multiplication nor addition is needed
...
Quick now, what’s binary 1100 in hex?
That’s right C
...
With a little
practice it is easy to translate even long numbers into hex
...

As it happens with many unfamiliar subjects, learning hexadecimal
requires a little practice
...
Soon you will be talking hexadecimal as
if you had known it all your life
...
Their values range from 0 to
255
...
of Characters

Capital letters

26

Small-case Letters

26

Digits

10

Special Symbols

32

Control Character

34

Graphics Character

128

Total

256

Figure E
...
Each
ASCII character has a unique appearance
...
Out of the 128 graphic
characters (Extended ASCII characters), there are characters that
are used for drawing single line and double line boxes in text
mode
...
2
...
2





190



╣185

206
202




╝188
╖183

210



╢182

215

216
212

187

186

197
192

203





179

195├

201 205

╔ ═ ╦

╛196



211



208



189

722

Let Us C

Value

Char

Value

Char

Value

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21





















§

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43












44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

!
"
#
$
%
&

(
)
*
+

Char
,

...
h File

725

726

Let Us C

LRESULT CALLBACK WndProc ( HWND, UINT, WPARAM, LPARAM ) ;
HINSTANCE hInst ; // current instance
/* FUNCTION: InitInstance ( HANDLE, int
PURPOSE: Saves instance handle and creates main window
COMMENTS: In this function, we save the instance handle in a global
variable and create and display the main program window
...
cbSize
= sizeof ( WNDCLASSEX ) ;
wcex
...
lpfnWndProc = ( WNDPROC ) WndProc ;
wcex
...
cbWndExtra
=0;
wcex
...
hIcon
= NULL ;
wcex
...
hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 ) ;
wcex
...
lpszClassName = classname ;
wcex
...
h
return FALSE ;
ShowWindow ( hWnd, nCmdShow ) ;
UpdateWindow ( hWnd ) ;
return TRUE ;
}

727

728

Let Us C

G

Boot Parameters

729

730

Let Us C

T

he disk drives in DOS and Windows are organized as zerobased drives
...
The hard
disk drive can be further partitioned into logical partitions
...
When a file/directory is
created on the disk, instead of allocating a sector for it, a group of
sectors is allocated
...
How many sectors together form one cluster depends
upon the capacity of the disk
...
Accordingly, we have
12-bit, 16-bit or 32-bit FAT
...
Since each entry in FAT represents a cluster number, the
maximum cluster number possible in a 12-bit FAT is 212 (4096)
...
Also, for a 32-bit FAT the maximum cluster number
is 228 (268435456
...

All FAT systems are not supported by all versions of DOS and
Windows
...
There are differences in the
organization of contents of Boot Sector, FAT and Directory in
FAT12/FAT16 system on one hand and FAT32 on the other
...
6 we saw the breakup of the contents of
the boot sector of a 12-bit FAT
...


731

Appendix G: Boot Parameters

Description

Length

Typical Values

Jump instruction

3

EB3C90

OEM name

8

MSWIN4
...
Root directory entries

2

512

Total sectors

2

0

Media descriptor

1

F8

Sectors per FAT

2

256

Sectors per track

2

63

No
...
1
Let us now take a look at the 32-bit FAT system’s boot sector
contents
...
2
...
1

Bytes per sector

2

512

Sectors per cluster

1

8

Reserved sectors

2

51

Number of FAT copies

1

2

Root directory entries

2

0

Total sectors

2

0

Media descriptor

1

F8

Sectors per FAT

2

0

Sectors per track

2

63

No
...
2
There are significant changes in the contents of the boo t sector of
a 32-bit FAT system
...
The first two
bytes contain the low word of the value, whereas, the next two
bytes contain the high word value
...
Hence the entry
‘Sectors per FAT’ for a disk with a 32-bit file system would
typically have a value 0
...

The boot sector of a 32-bit FAT system also has new entries like
‘Drive description flag’, ‘File system version’ ‘Starting cluster
number of the root directory’, ‘Sector number of the file system
information sector’, and the sector number of the ‘Backup boot
sector’
...
Bit 8 of this flag
indicates whether or not the information written to the active FAT
will be written to all copies of the FAT
...
These
bits are meaningful only if bit 8 is set
...

The entry ‘File system information sector’ contains a value
indicating the sector number where the file system information is
present
...
3
...
3
The entry ‘File information sector’ contains a value OFFFFh if
there is no such sector
...
Otherwise this
value is any non-zero value less than the reserved sector count
...
0
...
Follow the
steps mentioned below to carry out the installation
...

Insert the first CD in the drive and boot the system from it
...

Select the ‘Skip’ option in the "CD Found" dialog box
...

Click on the ‘Next’ button in the ‘Language selection’ screen
...

Click on the ‘Next’ button in the ‘Mouse Configuration’
screen
...

Click on the ‘Next’ button in the ‘Disk Partitioning Setup’
screen
...
Ignore any warnings generated by
clicking on the ‘OK’ button
...

Click on the ‘Next’ button in the ‘Network configuration’
screen
...

Click on the ‘Next’ button in the ‘additional language
support’ screen
...

Type a password for the root account in the ‘Set root
password’ screen and then click on the ‘Next’ button
...


Appendix H: Linux Installation

737

(s) In the ‘Package group selection’ screen make sure that you
select the following options—X window system, K desktop
environment, Development tools, GNOME software
development and then click on the ‘Next’ button
...

(v) Click on the ‘Next’ button in the ‘Monitor configuration’
screen
...

(x) Once the system restarts configure the system to boot from
Hard Disk
...
Once you
have logged in, to start typing the program use the following menu
options:
KMenu | Run Command

A dialog would now pop up
...
Now you can
type the program and save it
...

This can be done using the following menu option
...
You can launch another
instance of the command prompt by repeating the step mentioned
above
Title: MASTER OF COMPUTER APPLICATION (RGPV UNIVERSITY BHOPAL)
Description: rgpv 5th semester notes for mca students