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: Complete Guide To C Language
Description: Complete Guide To C language, With Exercises, Useful Referance Book to First Year Undergraduate to Last Year Graduate

Document Preview

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


Complete
Guide To C
Contents
1
...

Getting Started 1
What is C 2
Getting Started with C 4
The C Character Set 5
Constants, Variables and Keywords 6
Types of C Constants 7
Rules for Constructing Integer Constants 8
Rules for Constructing Real Constants 9
Rules for Constructing Character Constants 10
Types of C Variables 11
Rules for Constructing Variable Names 11
C Keywords 12
The First C Program 13
Compilation and Execution 19
Receiving Input 21
C Instructions 23
Type Declaration Instruction 24
Arithmetic Instruction 25
Integer and Float Conversions 29
Type Conversion in Assignments 29
Hierarchy of Operations 31
Associativity of Operators 34
Control Instructions in C 37
Summary 37
Exercise 38
The Decision Control Structure 49
Decisions! Decisions! 50
The if Statement 51
The Real Thing 55
Multiple Statements within if 56
The if-else Statement 58

viii
Nested if-elses 61
Forms of if 62
Use of Logical Operators 64
The else if Clause 66
The ! Operator 72
Hierarchy of Operators Revisited 73
A Word of Caution 73
The Conditional Operators 76
Summary 77
Exercise 78
3
...

The Loop Control Structure 97
Loops 98
The while Loop 99
Tips and Traps 101
More Operators 105
The for Loop 107
Nesting of Loops 114
Multiple Initialisations in the for Loop 115
The Odd Loop 116
The break Statement 118
The continue Statement 120
The do-while Loop 121
Summary 124
Exercise 124
The Case Control Structure 135
Decisions Using switch 136
The Tips and Traps 140
switch Versus if-else Ladder 144
The goto Keyword 145
Summary 148
Exercise 149
ix
5
...

Functions & Pointers 157
What is a Function 158
Why Use Functions 165
Passing Values between Functions 166
Scope Rule of Functions 171
Calling Convention 172
One Dicey Issue 173
Advanced Features of Functions 174
Function Declaration and Prototypes 175
Call by Value and Call by Reference 178
An Introduction to Pointers 178

Pointer Notation 179
Back to Function Calls 186
Conclusions 189
Recursion 189
Recursion and Stack 194
Adding Functions to the Library 197
Summary 201
Exercise 201
Data Types Revisited 213
Integers, long and short 214
Integers, signed and unsigned 216
Chars, signed and unsigned 217
Floats and Doubles 219
A Few More Issues… 221
Storage Classes in C 223
Automatic Storage Class 224
Register Storage Class 226
Static Storage Class 227
External Storage Class 230
Which to Use When 233
Summary 234
Exercise 235
x
The C Preprocessor 241
Features of C Preprocessor 242
Macro Expansion 244
Macros with Arguments 248
Macros versus Functions 252
File Inclusion 253
Conditional Compilation 255
#if and #elif Directives 258
Miscellaneous Directives 260
#undef Directive 260
#pragma Directive 261
Summary 263
Exercise 264
7
...
Arrays 269
What are Arrays 270
A Simple Program Using Array 272
More on Arrays 275
Array Initialization 275
Bounds Checking 276
Passing Array Elements to a Function 277
Pointers and Arrays 279
Passing an Entire Array to a Function 286
The Real Thing 287
Two Dimensional Arrays 289

Initializing a 2-Dimensional Array 290
Memory Map of a 2-Dimensional Array 291
Pointers and 2-Dimensional Arrays 292
Pointer to an Array 295
Passing 2-D array to a Function 297
Array of Pointers 300
Three Dimensional Array 302
Summary 304
xi
Exercise 304
Puppetting On Strings 327
What are Strings 328
More about Strings 329
Pointers and Strings 334
Standard Library String Functions 335
strlen( ) 337
strcpy( ) 339
strcat( ) 342
strcmp( ) 343
Two-Dimensional Array of Characters 344
Array of Pointers to Strings 347
Limitation of Array of Pointers to Strings 351
Solution 352
Summary 353
Exercise 354
9
...

11
...

13
...

15
...

17
...

Windows Programming 561
The Role of a Message Box 562
Here Comes the window… 563
More Windows 566
A Real-World Window 567
Creation and Displaying of Window 569
Interaction with Window 570
Reacting to Messages 572
Program Instances 575
Summary 575
Exercise 576
Graphics Under Windows 579
Graphics as of Now 580
Device Independent Drawing 580
xv
Hello Windows 582
Drawing Shapes 586
Types of Pens 590

Types of Brushes 592
Code and Resources 596
Freehand Drawing, the Paintbrush Style 596
Capturing the Mouse 600
Device Context, a Closer Look 601
Displaying a Bitmap 603
Animation at Work 607
WM_CREATE and OnCreate( ) 611
WM_TIMER and OnTimer( ) 611
A Few More Points… 612
Windows, the Endless World… 613
Summary 614
Exercise 615
19
...

21
...
h File 725
Appendix G – Boot Parameters 729
Appendix H – Linux Installation 735
Index 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 Complete Guide To C
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
...


B
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)
(b)
(c)
(d)
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
...

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
...

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 Complete Guide To C
(e)
(f)
(g)
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
...

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
...

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

Chapter 1: Getting Started 5
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
x3x5

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)
(b)
Primary Constants
Secondary Constants
These constants are further categorized as shown in Figure 1
...


8 Complete Guide To C
Figure 1
...

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
...

(b)
(c)
(d)
(e)
(f)

It must not have a decimal point
...

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

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

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
...


The mantissa part may have a positive or negative sign
...

The exponent must have at least one digit, which must be a
positive or negative integer
...

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

Rules for Constructing Character Constants
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)
(b)
(c)
(d)

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
...

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


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 Complete Guide To 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
...


Chapter 1: Getting Started 13
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 Complete Guide To C
(b)
(c)
(d)
(e)
(f)

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
...

C has no specific rules for the position at which a statement is
to be written
...

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 Complete Guide To 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
...

Select New from the File menu
...

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

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
...

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 Complete Guide To 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 ;
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)
(b)
(c)
(d)
C allows only one variable on left-hand side of =
...

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
...

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

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) usual arithmetic statement

b = c * d * b * ( x * y ) C statement
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)
(b)
(c)

An arithmetic operation between an integer and integer
always yields an integer result
...

An operation between an integer and real always yields a real
result
...
Hence the result is real
...

Operation Result Operation Result
5/222/50
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 Complete Guide To 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 Complete Guide To 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
...

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 operation: /
kk = 4 + 3 / 8 + 3 operation: *
kk = 4 + 0 + 3 operation: /
kk = 4 + 3 operation: +
kk = 7 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 Complete Guide To 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

Chapter 1: Getting Started 35
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 Complete Guide To C
Operator Left Right Remark
= a b or b =
3
Left operand is
unambiguous, Right is
not
= b or a = b 3 Right operand is
unambiguous, Left is not
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)
(b)
(c)
The three primary constants and variable types in C are
integer, float and character
...

Do not use a keyword as a variable name
...

Operators having equal precedence are evaluated using
associativity
...

Input/output in C can be achieved using scanf( ) and printf( )
functions
...
422
population in 2006 over time mindovermatter
FLOAT hELLO 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 Complete Guide To C
Operator Left Right Remark
/ 10 5 or 5 / 2
/1
Left operand is
unambiguous, Right
is not

...
( a b ) *(1/ m ) Z 8
...
5 2 a / ( q r ) + + + +
(a) = 2a - b ( b * b ) 2 4ac
(b) X = + +
(c) g v 2v 6
...
7b ( xy + a ) / c - 0
...
56E-03’
(4) All the above
(h) The maximum value that an integer constant can have is
(1) -32767
(2) 32767
(3) 1
...
7014e+38
(i) A C variable cannot start with
(1) An alphabet
(2) A number
(3) A special symbol other than underscore
(4) Both (2) & (3) above
(j) Which of the following statement is wrong
(1) mes = 123
...
6 / a + 2 * n ; which operation will be performed
first?
(1) 6
...
5
(2) 3
(3) 2
(4) 0
(p) The expression, a = 7 / 22 * ( 3
...
28
(2) 6
...
14
(4) 0
(q) The expression, a = 30 * 1000 + 2768 ; evaluates to
(1) 32768
(2) -32768
(3) 113040
(4) 0
(r) The expression x = 4 + 2 % - 8 evaluates to
(1) -6
(2) 6
(3) 4
(4) None of the above
(s) Hierarchy decides which operator
(1) is most important
(2) is used first
(3) is fastest
(4) operates on largest numbers
(t) An integer constant in C must have:
(1) At least one digit

(2) Atleast one decimal point
(3) A comma along with digits
(4) Digits separated by commas
(u) A character variable can never store more than
(1) 32 characters
(2) 8 characters
(3) 254 characters
(4) 1 character
(v) In C a variable cannot contain
(1) Blank spaces

46 Complete Guide To C
(2) Hyphen
(3) Decimal point
(4) All the above
(w) Which of the following is FALSE in C
(1) Keywords can be used as variable names
(2) Variable names can contain a digit
(3) Variable names do not contain a blank space
(4) Capital letters can be used in variable names
(x) In C, Arithmetic instruction cannot contain
(1) variables
(2) constants
(3) variable names on right side of =
(4) constants on left side of =
(y) Which of the following shows the correct hierarchy of
arithmetic operations in C
(1) / + * (2) * - / +
(3) + - / *
(4) * / + (z) What will be the value of d if d is a float after the operation
d = 2 / 7
...
2857
(3) Cannot be determined
(4) None of the above
[H] Write C programs for the following:
(a) Ramesh’s basic salary is input through the keyboard
...
Write a program to calculate
his gross salary
...
) is input through the
keyboard
...

(c) If the marks obtained by a student in five different subjects
are input through the keyboard, find out the aggregate marks
and percentage marks obtained by the student
...


(d) Temperature of a city in Fahrenheit degrees is input through
the keyboard
...

(e) The length & breadth of a rectangle and radius of a circle are
input through the keyboard
...

(f) Two numbers are input through the keyboard into two
locations C and D
...

(g) If a five-digit number is input through the keyboard, write a
program to calculate the sum of its digits
...

(i) If a four-digit number is input through the keyboard, write a
program to obtain the sum of the first and last digit of this
number
...
The percentage of
total literacy is 48
...

(k) A cashier has currency notes of denominations 10, 50 and
100
...

(l) If the total selling price of 15 items and the total profit earned
on them is input through the keyboard, write a program to
find the cost price of one item
...
For example if the number that is input is 12391 then
the output should be displayed as 23402
...
If the weather is fine, then I will go for a
stroll
...

If the pitch takes spin, we would win the match
...
If you like this book, I would write the next
edition
...


W
C language too must be able to perform different sets of actions
depending on the circumstances
...
C has three major decision making instructions—the if
statement, the if-else statement, and the switch statement
...
In this chapter we will explore all these
ways (except switch, which has a separate chapter devoted to it,
later) in which a C program can react to changing circumstances
...
e
...
In fact to execute the instructions sequentially, we don’t
have to do anything at all
...
However, in serious programming
situations, seldom do we want the instructions to be executed
sequentially
...
This kind of
situation is dealt in C programs using a decision control
instruction
...


The if Statement
Like most languages, C uses the keyword if to implement the
decision control instruction
...
The condition following the keyword if is
always enclosed within a pair of parentheses
...
If the
condition is not true then the statement is not executed; instead the
program skips past it
...
The
relational operators allow us to compare two values to see whether
they are equal to each other, unequal, or whether one is greater
than the other
...

this expression is true if
x == y x is equal to y
x != y x is not equal to y
x < y x is less than y
x > y x is greater than y
x <= y x is less than or equal to y
x >= y x is greater than or equal to y

Figure 2
...
Note that = is
used for assignment, whereas, == is used for comparison of two
quantities
...

/* Demonstration of if statement */
main( )
{
int num ;
printf ( "Enter a number less than 10 " ) ;
scanf ( "%d", &num ) ;
if ( num <= 10 )
printf ( "What an obedient servant you are !" ) ;
}
On execution of this program, if you type a number less than or
equal to 10, you get a message on the screen through printf( )
...
The
following flowchart would help you understand the flow of control
in the program
...
2
To make you comfortable with the decision control instruction one
more example has been given below
...
To help you understand it easily, the program is
accompanied by an appropriate flowchart
...
1: While purchasing certain items, a discount of 10%
is offered if the quantity purchased is more than 1000
...


54 Complete Guide To C
INPUT
qty, rate
is
qty > 1000
dis = 10
yes
tot = qty * rate – qty * rate * dis / 100
PRINT
tot
no
STOP
dis = 0
START

Figure 2
...
%f", tot ) ;
}
Here is some sample interaction with the program
...
50
Total expenses = Rs
...
000000
Enter quantity and rate 200 15
...
3100
...
Therefore, the variable

dis, which was earlier set to 0, now gets a new value 10
...

In the second run the condition evaluates to false, as 200 (the value
of qty) isn’t greater than 1000
...

Is the statement dis = 0 necessary? The answer is yes, since in C, a
variable if not specifically initialized contains some unpredictable
value (garbage value)
...
We can even use arithmetic expressions in
the if statement
...
In the first if, the expression evaluates
to 5 and since 5 is non-zero it is considered to be true
...

In the second if, 10 gets assigned to a so the if is now reduced to if
( a ) or if ( 10 )
...

In the third if, -5 is a non-zero number, hence true
...
In place of -5 even if a float like 3
...
So the issue is not whether
the number is integer or float, or whether it is positive or negative
...


Multiple Statements within if
It may so happen that in a program we want more than one
statement to be executed if the expression following if is satisfied
...

Example 2
...
If the number of years for which the employee has
served the organization is greater than 3 then a bonus of Rs
...
If the years of service are not greater
than 3, then the program should do nothing
...
%d", bonus ) ;
}
}
Observe that here the two statements to be executed on satisfaction
of the condition have been enclosed within a pair of braces
...
In other words we
can say that the default scope of the if statement is the immediately
next statement after it
...
4

The if-else Statement
The if statement by itself will execute a single statement, or a
group of statements, when the expression following if evaluates to
true
...
Can
we execute one group of statements if the expression evaluates to
true and another group of statements if the expression evaluates to
false? Of course! This is what is the purpose of the else statement
that is demonstrated in the following example:
Example 2
...
1500, then HRA = 10% of basic
salary and DA = 90% of basic salary
...
1500, then HRA = Rs
...
If the employee's salary is input through the keyboard write
a program to find his gross salary
...
%f", gs ) ;
}

60 Complete Guide To C
Figure 2
...
5
A few points worth noting
...
Similarly, the statements after the
else form the ‘else block’
...
The

statements in the if block and those in the else block have
been indented to the right
...

(c)
(d)

Had there been only one statement to be executed in the if

block and only one statement in the else block we could have
dropped the pair of braces
...
To override this default
scope a pair of braces as shown in the above example must be
used
...

This is called ‘nesting’of ifs
...

/* A quick demo of nested if-else */
main( )
{
int i ;
printf ( "Enter either 1 or 2 " ) ;
scanf ( "%d", &i ) ;
if ( i == 1 )
printf ( "You would go to heaven !" ) ;
else
{
if ( i == 2 )
printf ( "Hell was created with you in mind" ) ;
else
printf ( "How about mother earth !" ) ;
}
}

62 Complete Guide To C
Note that the second if-else construct is nested in the first else
statement
...
If it is false as
well, then the final else statement is executed
...
Inculcate this habit of indentation,
otherwise you would end up writing programs which nobody (you
included) can understand easily at a later date
...
Similarly, in some other program an if-else may
occur in the if block as well
...


Forms of if
The if statement can take any of the following forms:
(a) if ( condition )
do this ;
(b) if ( condition )
{
do this ;
and this ;
}

(c) if ( condition )
do this ;
else
do this ;
(d) if ( condition )
{
do this ;

Chapter 2: The Decision Control Structure 63
and this ;
}
else
{
do this ;
and this ;
}
(e) if ( condition )
do this ;
else
{
if ( condition )
do this ;
else
{
do this ;
and this ;
}
}
(f) if ( condition )
{
if ( condition )
do this ;
else
{
do this ;
and this ;
}
}
else
do this ;

64 Complete Guide To C
Use of Logical Operators
C allows usage of three logical operators, namely, &&, || and !
...

There are several things to note about these logical operators
...
Don’t use the single symbol | and &
...
They are bitwise operators, which we would
examine in Chapter 14
...
Let us see how they are used in
a program
...

Example 2
...
The student gets a
division as per the following rules:
Percentage above or equal to 60 - First division
Percentage between 50 and 59 - Second division
Percentage between 40 and 49 - Third division
Percentage less than 40 - Fail
Write a program to calculate the division obtained by the student
...
These methods are given below
...
Observe that the program uses
nested if-elses
...
As a result the whole
program creeps to the right
...

Care needs to be exercised to match the corresponding pair of
braces
...
The following program illustrates this
...
‘Second division’ gets printed if
both the conditions evaluate to true
...

Two distinct advantages can be cited in favour of this program:
(a)
(b)

The matching (or do I say mismatching) of the ifs with their
corresponding elses gets avoided, since there are no elses in
this program
...
In the previous program the statements went on
creeping to the right
...
This would make
the task of matching the ifs with their corresponding elses and
matching of opening and closing braces that much more
difficult
...
4
...
In this case every else is associated with its previous if
...
Even in
else if ladder the last else is optional
...
It is just a way of
rearranging the else with the if that follows it
...
For example, consider the following
example:
Example 2
...

− If the driver is unmarried, male & above 30 years of age
...

In all other cases the driver is not insured
...

Here after checking a complicated set of instructions the final
output of the program would be one of the two—Either the driver
should be ensured or the driver should not be ensured
...
But before we do
that let us write a program that does not make use of logical
operators
...
In a more real-life
situation there would be more conditions to check leading to the
program creeping to the right
...

As mentioned above, in this example we expect the answer to be
either ‘Driver is insured’ or ‘Driver is not insured’
...

Driver is an unmarried male above 30 years of age
...

Since all these cases lead to the driver being insured, they can be
combined together using && and || as shown in the program
below:
/* Insurance of driver - using logical operators */
main( )
{
char sex, ms ;

70 Complete Guide To C
int age ;
printf ( "Enter age, sex, marital status " ) ;
scanf ( "%d %c %c" &age, &sex, &ms ) ;
if ( ( ms == 'M') || ( ms == 'U' && sex == 'M' && age > 30 ) ||
( ms == 'U' && sex == 'F' && age > 25 ) )
printf ( "Driver is insured" ) ;
else
printf ( "Driver is not insured" ) ;
}
In this program it is important to note that:
− The driver will be insured only if one of the conditions
enclosed in parentheses evaluates to true
...

− Even if one of the conditions in the second parentheses
evaluates to false, then the whole of the second parentheses
evaluates to false
...

Thus we can conclude that the && and || are useful in the
following programming situations:
(a)
(b)

When it is to be tested whether a value falls within a
particular range or not
...


Chapter 2: The Decision Control Structure 71
There can be one more situation other than checking ranges or
yes/no problem where you might find logical operators useful
...

Example 2
...
6
main( )
{
char g ;
int yos, qual, sal ;
printf ( "Enter Gender, Years of Service and
Qualifications ( 0 = G, 1 = PG ):" ) ;
scanf ( "%c%d%d", &g, &yos, &qual ) ;
if ( g == 'm' && yos >= 10 && qual == 1 )
sal = 15000 ;
else if ( ( g == 'm' && yos >= 10 && qual == 0 ) ||
( g == 'm' && yos < 10 && qual == 1 ) )
sal = 10000 ;

72 Complete Guide To C
else if ( g == 'm' && yos < 10 && qual == 0 )
sal = 7000 ;
else if ( g == 'f' && yos >= 10 && qual == 1 )
sal = 12000 ;
else if ( g == 'f' && yos >= 10 && qual == 0 )
sal = 9000 ;
else if ( g == 'f' && yos < 10 && qual == 1 )

sal = 10000 ;
else if ( g == 'f' && yos < 10 && qual == 0 )
sal = 6000 ;
printf ( "\nSalary of Employee = %d", sal ) ;
}

The ! Operator
So far we have used only the logical operators && and ||
...
This
operator reverses the result of the expression it operates on
...
Vice versa, if the
expression evaluates to zero then on applying ! operator to it
makes it 1, a non-zero value
...
Here is an example
of the NOT operator applied to a relational expression
...
In other words, if y is less than
10, the expression will be false, since ( y < 10 ) is true
...

The NOT operator is often used to reverse the logical value of a
single variable, as in the expression
if ( ! flag )

Chapter 2: The Decision Control Structure 73
This is another way of saying
if ( flag == 0 )
Does the NOT operator sound confusing? Avoid it if you want, as
the same thing can be achieved without using the NOT operator
...
Figure 2
...
The higher the position of an operator is in the table, higher is
its priority
...
)
Operators Type
! Logical NOT
* / % Arithmetic and modulus
+ - Arithmetic
< > <= >= Relational
== != Relational
&& Logical AND
|| Logical OR
= Assignment

Figure 2
...

Enter value of i 200
You entered 5
Enter value of i 9999
You entered 5
Surprising? You have entered 200 and 9999, and still you find in
either case the output is ‘You entered 5’
...
We have used the assignment
operator = instead of the relational operator ==
...
And remember that in C ‘truth’ is always nonzero, whereas ‘falsity’ is always zero
...

Another common mistake while using the if statement is to write a
semicolon (;) after the condition, as shown below:
main( )
{
int i ;
printf ( "Enter value of i " ) ;
scanf ( "%d", &i ) ;

Chapter 2: The Decision Control Structure 75
if ( i == 5 ) ;
printf ( "You entered 5" ) ;
}
The ; makes the compiler to interpret the statement as if you have
written it in following manner:
if ( i == 5 )
;
printf ( "You entered 5" ) ;
Here, if the condition evaluates to true the ; (null statement, which
does nothing on execution) gets executed, following which the
printf( ) gets executed
...
Thus, irrespective of whether the condition
evaluates to true or false the printf( ) is bound to get executed
...
Moral is, beware of such
pitfalls
...

Operands Results
x y !x !y x && y x || y

001100
0 non-zero 1 0 0 0
non-zero 0 0 1 0 1
non-zero non-zero 0 0 1 1

Figure 2
...
In fact, they form a kind
of foreshortened if-then-else
...
Let us
understand this with the help of a few examples:
(a) int x, y ;
scanf ( "%d", &x ) ;
y=(x>5?3:4);
This statement will store 3 in y if x is greater than 5,
otherwise it will store 4 in y
...

The following points may be noted about the conditional
operators:

Chapter 2: The Decision Control Structure 77
(a)
(b)
(c)

(a)
It’s not necessary that the conditional operators should be
used only in arithmetic statements
...
: int i ;
scanf ( "%d", &i ) ;
( i == 1 ? printf ( "Amit" ) : printf ( "All and sundry" ) ) ;
Ex
...

int big, a, b, c ;
big = ( a > b ? ( a > c ? 3: 4 ) : ( b > c ? 6: 8 ) ) ;
Check out the following conditional expression:

a>b?g=a:g=b;
This will give you an error ‘Lvalue Required’
...
This is shown below:
a>b?g=a:(g=b);
In absence of parentheses the compiler believes that b is being
assigned to the result of the expression to the left of second =
...

The limitation of the conditional operators is that after the ? or
after the : only one C statement can occur
...
Therefore, in serious C programming conditional
operators aren’t as frequently used as the if-else
...
First
way is to use the if-else statement, second way is to use the

78 Complete Guide To C
conditional operators and third way is to use the switch
statement
...
So, to execute more than one statement they must
be written in a pair of braces
...

However, an else block is always associated with an if
statement
...

&& and || are binary operators, whereas, ! is a unary operator
...
A zero value is considered to be false and a
non-zero value is considered to be true
...


Exercise
if, if-else, Nested if-elses
[A] What would be the output of the following programs:
(a) main( )
{
int a = 300, b, c ;
if ( a >= 400 )
b = 300 ;
c = 200 ;
printf ( "\n%d %d", b, c ) ;

}
(b) main( )
{
int a = 500, b, c ;
if ( a >= 400 )

Chapter 2: The Decision Control Structure 79
b = 300 ;
c = 200 ;
printf ( "\n%d %d", b, c ) ;
}
(c) main( )
{
int x = 10, y = 20 ;
if ( x == y ) ;
printf ( "\n%d %d", x, y ) ;
}
(d) main( )
{
int x = 3, y = 5 ;
if ( x == 3 )
printf ( "\n%d", x ) ;
else ;
printf ( "\n%d", y ) ;
}
(e) main( )
{
int x = 3 ;
float y = 3
...
25, b = 12
...
Also determine how much profit
he made or loss he incurred
...
Write a program to
find out whether it is an odd number or even number
...
Write a program to
determine whether the year is a leap year or not
...
If any year is input through the keyboard
write a program to find out what is the day on 1st January of
this year
...
Write a
program to obtain the reversed number and to determine
whether the original and reversed numbers are equal or not
...

Write a program to check whether a triangle is valid or not,
when the three angles of the triangle are entered through the
keyboard
...

Find the absolute value of a number entered through the
keyboard
...
For example, the area of the rectangle with length = 5
and breadth = 4 is greater than its perimeter
...


84 Complete Guide To C
(k)
(l)

Given the coordinates (x, y) of a center of a circle and it’s radius,
write a program which will determine whether a point lies inside
the circle, on the circle or outside the circle
...
(0, 0)
...
Use the logical
operators && and ||
...

The following table shows the range of ASCII values for
various characters
...

(1) If a person’s health is excellent and the person is between
25 and 35 years of age and lives in a city and is a male
then the premium is Rs
...
2 lakhs
...
3 per thousand
and her policy amount cannot exceed Rs
...

(3) If a person’s health is poor and the person is between 25
and 35 years of age and lives in a village and is a male

90 Complete Guide To C
then the premium is Rs
...
10,000
...

Write a program to output whether the person should be
insured or not, his/her premium rate and maximum amount
for which he/she can be insured
...
7
(iii) Tensile strength must be greater than 5600
The grades are as follows:
Grade is 10 if all three conditions are met
Grade is 9 if conditions (i) and (ii) are met
Grade is 8 if conditions (ii) and (iii) are met
Grade is 7 if conditions (i) and (iii) are met
Grade is 6 if only one condition is met
Grade is 5 if none of the conditions are met
Write a program, which will require the user to give values of
hardness, carbon content and tensile strength of the steel
under consideration and output the grade of the steel
...
For first
5 days the fine is 50 paise, for 6-10 days fine is one rupee and

above 10 days fine is 5 rupees
...
Write a program to
accept the number of days the member is late to return the
book and display the fine or the appropriate message
...
The triangle is valid if the sum of two sides is
greater than the largest of the three sides
...

In a company, worker efficiency is determined on the basis of
the time required for a worker to complete a particular job
...
If the time required by
the worker is between 3 – 4 hours, then the worker is ordered
to improve speed
...
If the time taken by the worker is input
through the keyboard, find the efficiency of the worker
...

(b) If he gets than 55 percent in A he should get 55 percent or
more in B
...

(c) If he gets less than 45 percent in B and 65 percent or more
in A he is allowed to reappear in an examination in B to
qualify
...

Write a program to receive marks in A and B and Output
whether the student has passed, failed or is allowed to
reappear in B
...

(b) If has credit is not OK do not supply
...

(c) If has credit is Ok but the item in stock is less than has
order, supply what is in stock
...

Write a C program to implement the company policy
...

(a) main( )
{
int x, min, max ;
scanf ( "\n%d %d", &max, &x ) ;
if ( x > max )
max = x ;
else
min = x ;
}
(b) main( )
{
int code ;
scanf ( "%d", &code ) ;
if ( code > 1 )
printf ( "\nJerusalem" ) ;
else
if ( code < 1 )
printf ( "\nEddie" ) ;
else
printf ( "\nC Brain" ) ;
}

Chapter 2: The Decision Control Structure 95
(c) main( )
{
float sal ;
printf ("Enter the salary" ) ;
scanf ( "%f", &sal ) ;
if ( sal < 40000 && sal > 25000 )
printf ( "Manager" ) ;
else
if ( sal < 25000 && sal > 15000 )
printf ( "Accountant" ) ;
else

printf ( "Clerk" ) ;
}
[J] Attempt the following:
(a)
(b)
(c)

Using conditional operators determine:
(1) Whether the character entered through the keyboard is a
lower case alphabet or not
...

Write a program using conditional operators to determine
whether a year entered through the keyboard is a leap year or
not
...


96 Complete Guide To C
Nesting of Loops
iple Initialisations in the for Loop
• Th nt
Th ent
oop
• Su
• Ex
he programs that we have developed so far used either a
sequential or a decision control instruction
...


T
• Loops
• The while Loop
Tips and Traps
More Operators
• The for Loop
Mult
• The Odd Loop
e break Stateme
e continue Statem
• The do-while L
mmary
ercise

97
98 Complete Guide To C
These programs were of limited nature, because when executed,

they always performed the same series of actions, in the same way,
exactly once
...
You can probably think of several
examples of this from real life, such as eating a good dinner or
going for a movie
...

There are three methods by way of which we can repeat a part of a

The w
ething
a fixed number of times
...

details each time
...


ops
The versatility of the computer lies in its ability to perform a set of
instructions repeatedly
...
This repetitive o
throug
program
...


hile Loop
It is often the case in programming that you want to do som

Chapter 3: The Loop Control Structure 99
The while loop is i
simple example, w
deally suited for such cases
...
The flowchart shown
count = 1 ;
below would help you to understand the operation of the while
loop
...
1
/* Calculation of simple interest for 3 sets of p, n and r */
main( )
{
int p, n, count ;
float r, si ;
3
No
Yes

START
count = 1
STOP
si = p * n * r / 100
INPUT
p, n, r
PRINT
si
count = count + 1

100 Complete Guide To C
while ( count <= 3 )
{
printf ( "\nEnter values of p, n and r " ) ;
d %f", &p, &n, &r ) ;
n * r / 100 ;
printf ( "Simple interest = Rs
...

f p, n and r 1000 5 13
...
5
mple interest = Rs
...
000000
nter values of p, n and r 3500 5 3
...
The
le interest is written within a pair of
keyword
...
The parentheses
ion
...
675
...
612
...
To begin with the variable count is
initialized to 1 and every time the simple interest logic is executed
the value of count is incremented by one
...


The operation of the while loop is illustrated in the following
figure
...
2

Tips and Traps
The general form of while is as shown below:
initialise loop counter ;
increment loop counter ;
o about while
...
When the
while ( test loop counter using a condition )
{
do this ;
and this ;
}N
te the following points

executed till the condition being teste

102 Complete Guide To C
condition becomes false, the control passes to the first
statement that follows the body of the while loop
...
So long as the expression evaluates to a non-zero
value the statements within the loop would get executed
...
For
;
)
− As a rule the while must test a condition that will eventually
become false, otherwise the loop would be executed forever,
i <= 10 )
%d\n", i ) ;
while ( i <= 10 )
while ( i >= 10 && j <= 15 )
while ( j > 10 &&
he statements within the loop m
f statements
...

main( )
{
int i = 1 ;
while (
printf ( "
}

Chapter 3: The Loop Control Structure 103
p, since i remains equal to 1 forever
...
This is shown below:
i >= 1 )
{
"\nMake the computer literate!" ) ;
− that a loop counter must only be an int
...

a <= 10
...
" ) ;
skers on kittens" ) ;
This is an indefinite loo
Th
main( )
{
while (
printf (
i=i+1;
}
}
Instead of increm
it and still
main( )
{
int i = 5 ;
while (
printf (

i=i-1;
}
}
It is not necessary
can even be
main( )
{
float a = 10
...
and whi
a = a + 0
...
Once
again the increment and decrement could be by any value, not
necessarily 1
...
It’s an
definite loop
...
After that value of i is incremented by 1, therefore it
−W
i <= 10 ) ;
{
"%d\n", i ) ;
What do you think would be the output of the following
program?
main( )
{
while (
printf (
i=i+1;
}
}
No, it
in
tries to become 32768, which falls outside the valid integer
range, so it goes to other side and becomes -32768 which
would certainly satisfy the condition in the while
...

hat will be the output of the following program?
main( )
{
int i = 1 ;
while (
printf (

i=i+1;
}
}

Chapter 3: The Loop Control Structure 105
another indefinite loop, and it doesn’t give any output
all
...
This would make the loop work like this
...
Note that
enclosing printf( ) and i = i +1 within a pair of braces is not

Mo
h are frequently used with
ir usage Complete Guide To Consider a problem wherein
numbers from 1 to 10 are to be printed on the screen
...
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 the
for performing this task can be written using while in the
following different ways:
(a) main( )
{
while (
printf (
i=i+1;
}
}

106 Complete Guide To C
(b)
int i = 1 ;
i <= 10 )

{
"%d\n", i ) ;
at the increment operator ++ increments the value of i
1, every time the statement i++ gets executed
...

(c)
int i = 1 ;
i <= 10 )
{
"%d\n", i ) ;
hat += is a compound assignment operator
...
Similarly, j = j + 10 can also
be written as j += 10
...

However, never use n+++ to increment the value of n by 2,
since C doesn’t recognize the operator
main( )
{
while (
printf (
i += 1 ;
}
}
Note t
in
are -=, *=, / = and %=
...
Since the incrementation of i happens after its
(e)
int i = 0 ;
( ++i <= 10 )

printf ( "%d\n", i ) ;
e ++i <= 10 ), firstly incrementation of
takes place, then the comparison of value of i with 10 is
performed
...
The for allows us to specify three things about
ounter to determine whether its value has
reached the number of repetitions desired
...
When the control reaches printf( ), i has already
been incremented, hence i must be initialized to 0
...


r Loop
Perhaps one rea
are too busy us
a loop in a single line:
(a) Setting a loop counter to an initial value
...


108 Complete Guide To C
The
r ( initialise counter ; test counter ; increment counter )
do this ;
and this ;
down the simple interest program using for
...
The
lowchart is also given below for a better understanding
...
3
/* Calculation of simple interest for 3 sets of p, n and r */
main ( )
{
int p, n, count ;
float r, si ;
for ( count = 1 ; count <= 3 ; count = count + 1 )
{
printf ( "Enter values of p, n, and r " ) ;
scanf ( "%d %d %f", &p, &n, &r ) ;
si = p * n * r / 100 ;
printf ( "Simple Interest = Rs
...

Let us now examine how the for statement gets executed:
− When the for statement is executed for the first time, the value
of count is set to an initial value 1
...
Since count is 1 the
condition is satisfied and the body of the loop is executed for
the first time
...

− Again the test is performed to check whether the new value of
count exceeds 3
...

− The body of the for loop continues to get executed till count
doesn’t exceed the final value 3
...

The following figure would help in further clarifying the concept
of execution of the for loop
...
4
It is important to note that the initialization, testing and
incrementation part of a for loop can be replaced by any valid
expression
...

for ( i = 10 ; i ; i -- )
printf ( "%d", i ) ;
for ( i < 4 ; j = 5 ; j = 0 )
printf ( "%d", i ) ;
for ( i = 1; i <=10 ; printf ( "%d",i++ )
;
for ( scanf ( "%d", &i ) ; i <= 10 ; i++ )
printf ( "%d", i ) ;
Let us now write down the program to print numbers from 1 to 10
in different ways
...


112 Complete Guide To C
(a) main( )
{
int i ;
for ( i = 1 ; i <= 10 ; i = i + 1 )
printf ( "%d\n", i ) ;
}
Note that the initialisation, testing and incrementation of loop
counter is done in the for statement itself
...

Since there is only one statement in the body of the for loop,
the pair of braces have been dropped
...

(b) main( )
{
int i ;
for ( i = 1 ; i <= 10 ; )
{
printf ( "%d\n", i ) ;
i=i+1;
}
}
Here, the incrementation is done within the body of the for

loop and not in the for statement
...

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

Chapter 3: The Loop Control Structure 113
Here the initialisation is done in the declaration statement
itself, but still the semicolon before the condition is necessary
...

(e) main( )
{
int i ;
for ( i = 0 ; i++ < 10 ; )
printf ( "%d\n", i ) ;
}
Here, the comparison as well as the incrementation is done
through the same statement, i++ < 10
...
Note that it is necessary to initialize i to 0
...
Since ++ precedes i
firstly incrementation is done, followed by comparison
...


Nesting of Loops
The way if statements can be nested, similarly whiles and fors can
also be nested
...
The inner loop

Chapter 3: The Loop Control Structure 115
terminates when the value of c exceeds 2, and the outer loop
terminates when the value of r exceeds 3
...
These multiple
indentations make the program easier to understand
...
Not only this, a for loop can occur within
a while loop, or a while within a for
...
For example,
for ( i = 1, j = 2 ; j <= 10 ; j++ )
Multiple statements can also be used in the incrementation
expression of for loop; i
...
, you can increment (or decrement) two
or more variables at the same time
...
This expression may contain
several conditions linked together using logical operators
...
If commas had been used, they could
not also have been used to separate multiple statements in the
initialisation expression, without confusing the compiler
...
However, in real life programming
one comes across a situation when it is not known beforehand how
many times the statements in the loop are to be executed
...

Enter a number 5
square of 5 is 25
Want to enter another number y/n y
Enter a number 7
square of 7 is 49
Want to enter another number y/n n
In this program the do-while loop would keep getting executed till
the user continues to answer y
...
Note that
this loop ensures that statements within it are executed at least
once even if n is supplied first time itself
...

The keyword break allows us to do this
...
A break is usually associated with an
if
...

Example: Write a program to determine whether a number is
prime or not
...

All we have to do to test whether a number is prime or not, is to
divide it successively by all numbers from 2 to one less than itself
...
If no division yields a zero then the number is a prime
number
...

main( )
{
int num, i ;
printf ( "Enter a number " ) ;
scanf ( "%d", &num ) ;
i=2;
while ( i <= num - 1 )
{
if ( num % i == 0 )
{
printf ( "Not a prime number" ) ;
break ;
}
i++ ;
}

Chapter 3: The Loop Control Structure 119
if ( i == num )
printf ( "Prime number" ) ;
}

In this program the moment num % i turns out to be zero, (i
...

num is exactly divisible by i) the message “Not a prime number”
is printed and the control breaks out of the while loop
...

The loop came to an end because the value of i became equal
to num
...
That is, num is indeed a prime
...

The keyword break, breaks the control only from the while in
which it is placed
...

main( )
{
int i = 1 , j = 1 ;
while ( i++ <= 100 )
{
while ( j++ <= 200 )
{
if ( j == 150 )
break ;
else
printf ( "%d %d\n", i, j ) ;
}

120 Complete Guide To C
}
}
In this program when j equals 150, break takes the control outside
the inner while only, since it is placed inside the inner while
...
The keyword continue allows
us to do this
...

A continue is usually associated with an if
...

main( )
{
int i, j ;
for ( i = 1 ; i <= 2 ; i++ )
{
for ( j = 1 ; j <= 2 ; j++ )
{

if ( i == j )
continue ;
printf ( "\n%d %d\n", i, j ) ;
}
}
}
The output of the above program would be
...


The do-while Loop
The do-while loop looks like this:
do
{
this ;
and this ;
and this ;
and this ;
} while ( this condition is true ) ;
There is a minor difference between the working of while and dowhile loops
...
The while tests the condition before executing any of the
statements within the while loop
...
Figure 3
...


122 Complete Guide To C
True
test
increment
False
body of loop
STOP
initialise
START

Figure 3
...
The while, on
the other hand will not execute its statements if the condition fails
for the first time
...

main( )
{
while ( 4 < 1 )
printf ( "Hello there \n") ;
}

Chapter 3: The Loop Control Structure 123
Here, since the condition fails the first time itself, the printf( ) will
not get executed at all
...

main( )
{
do
{
printf ( "Hello there \n") ;
} while ( 4 < 1 ) ;
}
In this program the printf( ) would be executed once, since first
the body of the loop is executed and then the condition is tested
...
This is illustrated in the following example:
break and continue are used with do-while just as they would be
in a while or a for loop
...
A continue sends you straight to
the test at the end of the loop
...

A break statement takes the execution control out of the loop
...

A do-while loop is used to ensure that the statements within
the loop are executed at least once
...

The operators +=, -=, *=, /=, %= are compound assignment
operators
...


Exercise
while Loop
[A] What would be the output of the following programs:
(a) main( )
{
int j ;
while ( j <= 10 )
{
printf ( "\n%d", j ) ;
j=j+1;
}

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

Chapter 3: The Loop Control Structure 125
i++ ;
}
}
(c) main( )
{
int j ;
while ( j <= 10 )
{
printf ( "\n%d", j ) ;
j=j+1;
}
}
(d) main( )
{
int x = 1 ;
while ( x == 1 )
{
x=x-1;
printf ( "\n%d", x ) ;
}
}
(e) main( )
{
int x = 1 ;
while ( x == 1 )
x=x-1;
printf ( "\n%d", x ) ;
}
(f) main( )
{
char x ;

126 Complete Guide To C
while ( x = 0 ; x <= 255 ; x++ )
printf ( "\nAscii value %d Character %c", x, x ) ;
}
(g) main( )
{
int x = 4, y, z ;
y = --x ;
z = x-- ;
printf ( "\n%d %d %d", x, y, z ) ;
}

(h) main( )
{
int x = 4, y = 3, z ;
z = x-- -y ;
printf ( "\n%d %d %d", x, y, z ) ;
}
(i) main( )
{
while ( 'a' < 'b' )
printf ( "\nmalyalam is a palindrome" ) ;
}
(j) main( )
{
int i = 10 ;
while ( i = 20 )
printf ( "\nA computer buff!" ) ;
}
(k) main( )
{
int i ;
while ( i = 10 )
{

Chapter 3: The Loop Control Structure 127
printf ( "\n%d", i ) ;
i=i+1;
}
}
(l) main( )
{
float x = 1
...
1 )
{
printf ( "\n%f", x ) ;
x = x – 0
...

Overtime is paid at the rate of Rs
...
00 per hour for every
hour worked above 40 hours
...

Write a program to find the factorial value of any number
entered through the keyboard
...
Write a
program to find the value of one number raised to the power
of another
...
The ASCII values
vary from 0 to 255
...
If sum of cubes of each digit of the number is
equal to the number itself, then the number is called an

Armstrong number
...
Your program should ensure that the
computer always wins
...

− The computer asks the player to pick 1, 2, 3, or 4
matchsticks
...

− Whoever is forced to pick up the last matchstick
loses the game
...

Write a program to find the octal equivalent of the entered
number
...
Range
is the difference between the smallest and biggest number in
the list
...
In the absence of
parentheses, they will be evaluated in which of the following
order:
1
...
arithmetic, relational, assignment
3
...
assignment, arithmetic, relational
(c) The break statement is used to exit from:
1
...
a for loop
3
...
the main( ) function
(d) A do-while loop is useful when we want that the statements
within the loop must be executed:
1
...
At least once
3
...
None of the above
(e) In what sequence the initialization, testing and execution of
body is done in a do-while loop
1
...
Execution of body, initialization, testing
3
...
None of the above
(f) Which of the following is not an infinite loop
...
int i = 1 ;
while ( 1 )
{
i++ ;
}
2
...
exit
2
...
continue
4
...


(Hint: Use nested loops, break and continue)
(b) Write a program to fill the entire screen with a smiling face
...

(c) Write a program to add first seven terms of the following
series using a for loop:
1
1!
2
2!
3
3! ……

3
...
int y, x = 0 ;
do
{
y=x;
} while ( x == 0 ) ;
(d) Write a program to generate all combinations of 1, 2 and 3
using for loop
...
5 x )

Chapter 3: The Loop Control Structure 133
Write a program, which will produce a table of values of i, y
and x, where y varies from 1 to 6, and, for each value of y, x
varies from 5
...
5 in steps of 0
...

(f) Write a program to produce the following output:
ABCDEFGFEDCBA
ABCDEFFEDCBA
ABCDEEDCBA
ABCDDCBA
ABCCBA
ABBA
AA
(g) Write a program to fill the entire screen with diamond and
heart alternatively
...

(h) Write a program to print the multiplication table of the
number entered by the user
...

29 * 1 = 29
29 * 2 = 58

(i) Write a program to produce the following output:
1
23

456
7 8 9 10

134 Complete Guide To C
(j) Write a program to produce the following output:

1
11
121
1331
14641
(k) A machine is purchased which will produce earning of Rs
...
The machine costs Rs
...
2000 when it is condemned
...

(m) The natural logarithm can be approximated by the following
series
...

xx
x
x
x
x
x−+
x−+⎜⎛−⎝⎠⎟⎞+⎜−⎛⎝
2 3 1 2 ⎛⎜⎝ 1 1 ⎞⎟⎠ 12 1 1 2 1 4 ⎞⎟⎠ +
...
For example, which school to join
or which hotel to visit or still harder which girl to marry (you
almost always end up making a wrong decision is a different
matter altogether!)
...
C provides a special control statement
that allows us to handle such cases effectively; rather than using a
series of if statements
...
Towards the end of the chapter we would also
study a keyword called goto, and understand why we should avoid
its usage in C programming
...
They most often appear as follows:
switch ( integer expression )
{
case constant 1 :
do this ;
case constant 2 :
do this ;
case constant 3 :
do this ;
default :
do this ;
}
The integer expression following the keyword switch is any C
expression that will yield an integer value
...
The keyword case is followed by an integer or a character
constant
...
The “do this” lines in the above form of switch represent
any valid C statement
...

The value it gives is then matched, one by one, against the
constant values that follow the case statements
...
If no
match is found with any of the case statements, only the
statements following the default are executed
...


Consider the following program:
main( )
{
int i = 2 ;
switch ( i )
{
case 1 :
printf ( "I am in case 1 \n" ) ;
case 2 :
printf ( "I am in case 2 \n" ) ;
case 3 :
printf ( "I am in case 3 \n" ) ;
default :
printf ( "I am in default \n" ) ;
}
}
The output of this program would be:
I am in case 2

138 Complete Guide To C
I am in case 3
I am in default
The output is definitely not what we expected! We didn’t expect
the second and third line in the above output
...
Well, yes
...

If you want that only case 2 should get executed, it is upto you to
get out of the switch then and there by using a break statement
...
Note that there is
no need for a break statement after the default, since the control
comes out of the switch anyway
...

STOP
No
case 1
case 2
case 3
case 4
switch ( choice )
{
case 1 :
statement 1 ;
break ;
case 2 :
statement 2 ;
break ;
case 3 :
statement 3 ;
break ;
case 4 :
statement 4 ;
}
statement 1
statement 2
statement 3
statement 4
No
No
No
Yes
Yes
Yes
Yes
START

Figure 4
...
You can in fact put the cases in any
order you please
...

(c) At times we may want to execute a common set of statements
for multiple cases
...

main( )
{
char ch ;
printf ( "Enter any of the alphabet a, b, or c " ) ;
scanf ( "%c", &ch ) ;

142 Complete Guide To C

switch ( ch )
{
case 'a' :
case 'A' :
printf ( "a as in ashar" ) ;
break ;
case 'b' :
case 'B' :
printf ( "b as in brain" ) ;
break ;
case 'c' :
case 'C' :
printf ( "c as in cookie" ) ;
break ;
default :
printf ( "wish you knew what are alphabets" ) ;
}
}
Here, we are making use of the fact that once a case is
satisfied the control simply falls through the case till it
doesn’t encounter a break statement
...
e
...

(d)
(e)
Even if there are multiple statements to be executed in each
case there is no need to enclose them within a pair of braces
(unlike if, and else)
...
If a statement doesn’t belong to any case the compiler
won’t report an error
...
For example, in the following program the printf( )
never goes to work
...

Is switch a replacement for if? Yes and no
...
The disadvantage of switch is that one cannot have a
case in a switch which looks like:
case i <= 20 :
All that we can have after the case is an int constant or a char
constant or an expression that evaluates to one of these
constants
...

The advantage of switch over if is that it leads to a more
structured program and the level of indentation is manageable,

144 Complete Guide To C
more so if there are multiple statements within each case of a
switch
...
Thus
the following switch statements are legal
...
Thus case 3 + 7 is correct, however,
case a + b is incorrect
...
However, use of continue will not take
the control to the beginning of switch as one is likely to
believe
...
Such statements would be called
nested switch statements
...
This aspect of switch is discussed in the
exercise at the end of this chapter
...

These are:
A float expression cannot be tested using a switch

Cases can never have variable expressions (for example it is
wrong to say case a +3 : )
Multiple cases cannot use same expressions
...

case 1 + 2 :

...
Then why use a switch at
all? For speed—switch works faster than an equivalent if-else
ladder
...
As a result, during
execution it simply refers the jump table to decide which case
should be executed, rather than actually checking which case is
satisfied
...
A switch with 10 cases would work
faster than an equivalent if-else ladder
...
Why? If the 10th case is
satisfied then jump table would be referred and statements for the
10th case would be executed
...
Note that a lookup in the jump table is faster than evaluation
of a condition, especially if the condition is complex
...
Hence a switch with two cases would
work slower than an equivalent if-else
...


The goto Keyword
Avoid goto keyword! They make a C programmer’s life miserable
...
And yet many programmers find goto
seductive
...
However, almost always, there
is a more elegant way of writing the same program using if, for,
while and switch
...

The big problem with gotos is that when we do use them we can
never be sure how we got to a certain point in our code
...
So as far as possible skip them
...
Trust me, with good
programming skills goto can always be avoided
...
However,
for sake of completeness of the book, the following program
shows how to use goto
...

Enter the number of goals scored against India 3
To err is human!
Enter the number of goals scored against India 7
About time soccer players learnt C
and said goodbye! adieu! to soccer
A few remarks about the program would make the things clearer
...

− The label can be on a separate line or on the same line as the
statement following it, as in,
sos : printf ( "To err is human!" ) ;
− Any number of gotos can take the control to the same label
...
It is necessary to use
this function since we don't want the statement
printf ( "To err is human!" )
to get executed after execution of the else block
...
The following program
illustrates this
...
Also
write down the same program without using goto
...

The switch keyword is followed by an integer or an
expression that evaluates to an integer
...

The control falls through all the cases unless the break
statement is given
...


Chapter 4: The Case Control Structure 149

Exercise
[A] What would be the output of the following programs:
(a) main( )
{
char suite = 3 ;
switch ( suite )
{
case 1 :
printf ( "\nDiamond" ) ;
case 2 :
printf ( "\nSpade" ) ;
default :
printf ( "\nHeart") ;
}
printf ( "\nI thought one wears a suite" ) ;

}
(b) main( )
{
int c = 3 ;
switch ( c )
{
case 'v' :
printf ( "I am in case v \n" ) ;
break ;
case 3 :
printf ( "I am in case 3 \n" ) ;
break ;
case 12 :
printf ( "I am in case 12 \n" ) ;
break ;
default :
printf ( "I am in default \n" ) ;
}

150 Complete Guide To C
}
(c) main( )
{
int k, j = 2 ;
switch ( k = j + 1 )
{
case 0 :
printf ( "\nTailor") ;
case 1 :
printf ( "\nTutor") ;
case 2 :
printf ( "\nTramp") ;
default :
printf ( "\nPure Simple Egghead!" ) ;
}
}
(d) main( )
{
int i = 0 ;
switch ( i )
{
case 0 :
printf ( "\nCustomers are dicey" ) ;
case 1 :
printf ( "\nMarkets are pricey" ) ;
case 2 :
printf ( "\nInvestors are moody" ) ;
case 3 :
printf ( "\nAt least employees are good" ) ;
}
}

(e) main( )
{
int k ;
float j = 2
...
5 ;
switch ( a )

Chapter 4: The Case Control Structure 153
{
case 0
...
5 :
printf ( "\nThe spirit of C" ) ;
break ;
case 2
...
5 :
printf ( "\nSimply c" ) ;
}
}
(d) main( )
{
int a = 3, b = 4, c ;
c=b–a;
switch ( c )
{
case 1 || 2 :
printf ( "God give me an opportunity to change things" ) ;
break ;

case a || b :
printf ( "God give me an opportunity to run my show" ) ;
break ;
}
}
[C] Write a menu driven program which has following options:
1
...

2
...
Odd or even
4
...

The outline of this program is given below:
/* A menu driven program */
main( )
{
int choice ;
while ( 1 )
{
printf ( "\n1
...
Prime" ) ;
printf ( "\n3
...
Exit" ) ;
printf ( "\nYour choice? " ) ;
scanf ( "%d", &choice ) ;
switch ( choice )
{
case 1 :
/* logic for factorial of a number */
break ;
case 2 :
/* logic for deciding prime number */
break ;
case 3 :
/* logic for odd/even */
break ;
case 4 :
exit( ) ;
}
}
}
Note:

Chapter 4: The Case Control Structure 155
The statement while ( 1 ) puts the entire logic in an infinite loop
...

[D] Write a program which to find the grace marks for a student
using switch
...

− If the student gets first class and the number of subjects he

failed in is greater than 3, then he does not get any grace
...

− If the student gets second class and the number of subjects
he failed in is greater than 2, then he does not get any
grace
...

− If the student gets third class and the number of subjects
he failed in is greater than 1, then he does not get any
grace
...
Man is an intelligent species, but still
cannot perform all of life’s tasks all alone
...
You may call a mechanic to fix up your bike, hire a
gardener to mow your lawn, or rely on a store to supply you
groceries every month
...
It cannot handle all
the tasks by itself
...
In this
chapter we will study these functions
...


K
What is a Function
A function is a self-contained block of statements that perform a
coherent task of some kind
...
As we noted earlier, using a
function is something like hiring a person to do a specific job for
you
...

Suppose you have a task that is always performed exactly in the
same way—say a bimonthly servicing of your motorbike
...
You don’t need to give instructions, because the
mechanic knows his job
...
You assume the bike would be serviced in the usual way, the
mechanic does it and that’s that
...
Actually, we will be looking at two
things—a function that calls or activates the function and the
function itself
...
" ) ;
}
And here’s the output
...

Cry, and you stop the monotony!
Here, main( ) itself is a function and through it we are calling the
function message( )
...
The activity of main( ) is temporarily
suspended; it falls asleep while the message( ) function wakes up
and goes to work
...
Thus, main( ) becomes the ‘calling’ function, whereas
message( ) becomes the ‘called’ function
...
Consider the
following example:

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

160 Complete Guide To C
italy( )
{
printf ( "\nI am in italy" ) ;
}
brazil( )
{
printf ( "\nI am in brazil" ) ;
}
argentina( )
{
printf ( "\nI am in argentina" ) ;
}
The output of the above program when executed would be as
under:
I am in main
I am in italy
I am in brazil
I am in argentina
From this program a number of conclusions can be drawn:
− Any C program contains at least one function
...

− If a C program contains more than one function, then one (and
only one) of these functions must be main( ), because program
execution always begins with main( )
...

− Each function in a program is called in the sequence specified
by the function calls in main( )
...
When main( ) runs out of function calls, the program
ends
...
Except for this fact all C functions enjoy a state of
perfect equality
...
One function can call another function it has already called
but has in the meantime left temporarily in order to call a third
function which will sometime later call the function that has called
it, if you understand what I mean
...

main( )
{

printf ( "\nI am in main" ) ;
italy( ) ;
printf ( "\nI am finally back in main" ) ;
}
italy( )
{
printf ( "\nI am in italy" ) ;
brazil( ) ;
printf ( "\nI am back in italy" ) ;
}
brazil( )
{
printf ( "\nI am in brazil" ) ;
argentina( ) ;
}
argentina( )
{
printf ( "\nI am in argentina" ) ;
}
And the output would look like
...
Trace carefully the way control passes from one
function to another
...
In other words, the main( )
function drives other functions
...

(a)
(b)
(c)
C program is a collection of one or more functions
...
For example,
main( )
{
argentina( ) ;
}
A function is defined when function name is followed by a
pair of braces in which one or more statements may be
present
...
Even
main( ) can be called from other functions
...
For example,
main( )
{
message( ) ;
message( ) ;
}
message( )
{
printf ( "\nJewel Thief!!" ) ;
}
The order in which the functions are defined in a program and
the order in which they get called need not necessarily be
same
...
However, it is advisable to define the functions
in the same order in which they are called
...


(g)
(h)
(i)
A function can call itself
...

We would discuss this aspect of C functions later in this
chapter
...
Thus, the following
program code would be wrong, since argentina( ) is being
defined inside another function, main( )
...
printf( ), scanf( ) etc
...
argentina( ), brazil( ) etc
...
This library of functions is present on
the disk and is written for us by people who write compilers
for us
...
The procedure of calling both types of
functions is exactly same
...
Suppose you have a section of code in your program
that calculates area of a triangle
...
Instead, you would prefer to jump to a ‘section of
code’ that calculates area and then jump back to the place
from where you left off
...

(b) Using functions it becomes easier to write programs and keep
track of what they are doing
...
Separating the code into modular
functions also makes the program easier to design and
understand
...
It is a very bad style of programming
...
Don’t hesitate to write functions that are
called only once
...


166 Complete Guide To C
Passing Values between Functions
The functions that we have used so far haven’t been very flexible
...
Like our
mechanic who always services the motorbike in exactly the same
way, we haven’t been able to influence the functions in the way
they carry out their tasks
...
In short, now we want to communicate
between the ‘calling’ and the ‘called’ functions
...
You have unknowingly used the arguments in the
printf( ) and scanf( ) functions; the format string and the list of
variables used inside the parentheses in these functions are
arguments
...

Consider the following program
...
However, the calculation of sum is
done in a different function called calsum( )
...

/* Sending and receiving values between functions */
main( )
{
int a, b, c, sum ;
printf ( "\nEnter any three numbers " ) ;
scanf ( "%d %d %d", &a, &b, &c ) ;
sum = calsum ( a, b, c ) ;

Chapter 5: Functions & Pointers 167
printf ( "\nSum = %d", sum ) ;
}
calsum ( x, y, z )
int x, y, z ;
{
int d ;
d=x+y+z;
return ( d ) ;
}
And here is the output
...
Any number of arguments can be passed to a
function being called
...


168 Complete Guide To C
Instead of using different variable names x, y and z, we could
have used the same variable names a, b and c
...

(c) There are two methods of declaring the formal arguments
...

calsum ( x, y, z )
int x, y, z ;
Another method is,
calsum ( int x, int y, int z )
This method is called ANSI method and is more commonly
used these days
...
No separate return statement was necessary
to send back the control
...
In the
above program, however, we want to return the sum of x, y
and z
...

The return statement serves two purposes:
(1) On executing the return statement it immediately
transfers the control back to the calling program
...
In the above program
the value of sum of three numbers is being returned
...
Also, the return statement
need not always be present at the end of the called function
...

fun( )
{
char ch ;

printf ( "\nEnter any alphabet " ) ;
scanf ( "%c", &ch ) ;
if ( ch >= 65 && ch <= 90 )
return ( ch ) ;
else
return ( ch + 32 ) ;
}
In this function different return statements will be executed
depending on whether ch is capital or not
...
If a meaningful value is returned then it
should be accepted in the calling program by equating the
called function to some variable
...

return ( a ) ;
return ( 23 ) ;
return ( 12
...
Note
that in this case the parentheses after return are dropped
...

void display( )
{
printf ( "\nHeads I win
...
Thus, the
following statements are invalid
...

(j) If the value of a formal argument is changed in the called
function, the corresponding change does not take place in the
calling function
...
This means that
when values are passed to a called function the values present
in actual arguments are not physically moved to the formal
arguments; just a photocopy of values in actual argument is
made into formal arguments
...
Because by default the scope of a
variable is local to the function in which it is defined
...
Similarly, the variable k is local to the function
display( ) and hence it is not available to main( )
...
Likewise, if we want k to be available to
main( ) we will have to return it to main( ) using the return
statement
...


Calling Convention
Calling convention indicates the order in which arguments are
passed to a function when a function call is encountered
...

Arguments might be passed from right to left
...

Consider the following function call:
fun (a, b, c, d ) ;
In this call it doesn’t matter whether the arguments are passed

from left to right or from right to left
...
For example:
int a = 1 ;
printf ( "%d %d %d", a, ++a, a++ ) ;
It appears that this printf( ) would output 1 2 3
...
Surprisingly, it outputs 3 3 1
...
That is, firstly

Chapter 5: Functions & Pointers 173
1 is passed through the expression a++ and then a is incremented
to 2
...
That is, a is incremented to 3
and then passed
...
e
...
Thus in
right to left order 1, 3, 3 get passed
...
Thus 3 3 1
gets printed
...
h>
clrscr ( ) ;
gotoxy ( 10, 20 ) ;
ch = getch ( a ) ;
Here we are calling three standard library functions
...
This helps the compiler in checking whether the
values being passed and returned are as per the prototype
declaration
...
Hence when the library of functions is provided a set of

...
These files contain the prototypes of
library functions
...
For example, prototypes of all input/output
functions are provided in the file ‘stdio
...
h’, etc
...
h’
...
They would appear
as shown below:

174 Complete Guide To C
void clrscr( ) ;
void gotoxy ( int, int ) ;
int getch( ) ;
Now consider the following function calls:
#include ...

This is because printf( ) accepts variable number of arguments
(sometimes 2 arguments, sometimes 3 arguments, etc
...
h’
...
Similarly, in the
second printf( ) since the format specifier for j has not been
mentioned its value does not get printed
...
Following advanced topics would be
considered here
...


Chapter 5: Functions & Pointers 175
Function Declaration and Prototypes
Any C function by default returns an int value
...
If we desire that a
function should return a value other than an int, then it is necessary
to explicitly mention so in the calling function as well as in the
called function
...
This is how this simple program would look like:
main( )
{
float a, b ;
printf ( "\nEnter any number " ) ;
scanf ( "%f", &a ) ;
b = square ( a ) ;
printf ( "\nSquare of %f is %f", a, b ) ;
}
square ( float x )
{
float y ;
y=x*x;
return ( y ) ;
}
And here are three sample runs of this program
...
000000
Enter any number 1
...
5 is 2
...
5
Square of 2
...
000000

176 Complete Guide To C

The first of these answers is correct
...
5 is definitely
not 2
...
5
...
Therefore,
even though the function square( ) calculates the square of 1
...
25, the problem crops up when this 2
...
square( ) is not capable of returning a float value
...

main( )
{
float square ( float ) ;
float a, b ;
printf ( "\nEnter any number " ) ;
scanf ( "%f", &a ) ;
b = square ( a ) ;
printf ( "\nSquare of %f is %f", a, b ) ;
}
float square ( float x )
{
float y ;
y=x*x;
return ( y ) ;
}
And here is the output
...
5
Square of 1
...
250000
Enter any number 2
...
5 is 6
...
e
...
25 and 6
...
Note
that the function square( ) must be declared in main( ) as
float square ( float ) ;
This statement is often called the prototype declaration of the
square( ) function
...
We have done the prototype
declaration in main( ) because we have called it from main( )
...
Does this mean that we would need
prototype declaration of square( ) in all these functions
...

In practice you may seldom be required to return a value other
than an int, but just in case you are required to, employ the above
method
...
This is made possible by
using the keyword void
...

main( )
{
void gospel( ) ;

gospel( ) ;
}
void gospel( )
{
printf ( "\nViruses are electronic bandits
...
" ) ;
printf ( "\nand chunks of bytes
...
" ) ;
}

178 Complete Guide To C
Here, the gospel( ) function has been defined to return void; means
it would return nothing
...


Call by Value and Call by Reference
By now we are well familiar with how to call functions
...
Such function calls are called ‘calls by value’
...
The examples of call by value are shown
below:
sum = calsum ( a, b, c ) ;
f = factr ( a ) ;
We have also learnt that variables are stored somewhere in
memory
...
What purpose a ‘call by reference’ serves we would
find out a little later
...
This feature of C
functions needs at least an elementary knowledge of a concept
called ‘pointers’
...


An Introduction to Pointers
Which feature of C do beginners find most difficult to understand?
The answer is easy: pointers
...
And why not? It is C’s
clever use of pointers that makes it the excellent language it is
...
For instance,
when a C programmer says that a certain variable is a “pointer”,
what does that mean? It is hard to see how a variable can point to
something, or in a certain direction
...
In our discussion of C pointers, therefore, we will try to
avoid this difficulty by explaining pointers in terms of
programming concepts we already understand
...


Pointer Notation
Consider the declaration,
int i = 3 ;
This declaration tells the C compiler to:
(a) Reserve space in memory to hold the integer value
...

(c) Store the value 3 at this location
...

location name
3
i
location number
value at location
65524

Figure 5
...
The location number 65524 is not a
number to be relied upon, because some other time the computer
may choose a different location for storing the value 3
...

We can print this address number through the following program:
main( )
{
int i = 3 ;
printf ( "\nAddress of i = %u", &i ) ;
printf ( "\nValue of i = %d", i ) ;
}
The output of the above program would be:
Address of i = 65524
Value of i = 3
Look at the first printf( ) statement carefully
...
The expression &i returns
the address of the variable i, which in this case happens to be
65524
...
Hence it is printed out using %u,
which is a format specifier for printing an unsigned integer
...

The other pointer operator available in C is ‘*’, called ‘value at
address’ operator
...

The ‘value at address’ operator is also called ‘indirection’
operator
...

The expression &i gives the address of the variable i
...
It is a variable that contains the address of other
variable (i in this case)
...
Once again, the following memory
map would illustrate the contents of i and j
...
2

182 Complete Guide To C
As you can see, i’s value is 3 and j’s value is i’s address
...
And
since j is a variable that contains the address of i, it is declared as,
int *j ;
This declaration tells the compiler that j will be used to store the
address of an integer value
...

How do we justify the usage of * in the declaration,
int *j ;
Let us go by the meaning of *
...

Thus, int *j would mean, the value at the address contained in j is
an int
...

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

The output of the above program would be:

Chapter 5: Functions & Pointers 183
Address of i = 65524
Address of i = 65524
Address of j = 65522
Value of j = 65524
Value of i = 3
Value of i = 3
Value of i = 3
Work through the above program carefully, taking help of the
memory locations of i and j shown earlier
...
If you don’t
understand the program’s output, or the meanings of &i, &j, *j
and *( &i ), re-read the last few pages
...

Look at the following declarations,
int *alpha ;
char *ch ;
float *s ;
Here, alpha, ch and s are declared as pointer variables, i
...

variables capable of holding addresses
...
) are always going to be whole numbers, therefore
pointers always contain whole numbers
...

The declaration float *s does not mean that s is going to contain a
floating-point value
...
Similarly, char *ch means that
ch is going to contain the address of a char value
...


184 Complete Guide To C
The concept of pointers can be further extended
...
Now this
variable itself might be another pointer
...
The following
example should make this point clear
...
3 would help you in tracing out how the program prints
the above output
...
However, with these addresses too the
relationship between i, j and k can be easily established
...
3
Observe how the variables j and k have been declared,
int i, *j, **k ;
Here, i is an ordinary int, j is a pointer to an int (often called an
integer pointer), whereas k is a pointer to an integer pointer
...
In principle, you would agree that
likewise there could exist a pointer to a pointer to a pointer to a
pointer to a pointer
...
Possibly, till the point we can
comprehend it
...
Beyond this one rarely requires to extend the
definition of a pointer
...


186 Complete Guide To C
Back to Function Calls
Having had the first tryst with pointers let us now get back to what
we had originally set out to learn—the two types of function
calls—call by value and call by reference
...
With this method the changes made to the
formal arguments in the called function have no effect on the
values of actual arguments in the calling function
...

main( )
{
int a = 10, b = 20 ;
swapv ( a, b ) ;
printf ( "\na = %d b = %d", a, b ) ;
}
swapv ( int x, int y )
{
int t ;
t=x;
x=y;
y=t;
printf ( "\nx = %d y = %d", x, y ) ;
}
The output of the above program would be:

Chapter 5: Functions & Pointers 187
x = 20 y = 10
a = 10 b = 20
Note that values of a and b remain unchanged even after
exchanging the values of x and y
...
This means that using these addresses we
would have an access to the actual arguments and hence we would
be able to manipulate them
...

main( )
{
int a = 10, b = 20 ;
swapr ( &a, &b ) ;
printf ( "\na = %d b = %d", a, b ) ;
}
swapr( int *x, int *y )
{
int t ;
t = *x ;
*x = *y ;
*y = t ;
}
The output of the above program would be:
a = 20 b = 10
Note that this program manages to exchange the values of a and b

using their addresses stored in x and y
...
This means
that in general you cannot alter the actual arguments
...

Using a call by reference intelligently we can make a function
return more than one value at a time, which is not possible
ordinarily
...

main( )
{
int radius ;
float area, perimeter ;
printf ( "\nEnter radius of a circle " ) ;
scanf ( "%d", &radius ) ;
areaperi ( radius, &area, &perimeter ) ;
printf ( "Area = %f", area ) ;
printf ( "\nPerimeter = %f", perimeter ) ;
}
areaperi ( int r, float *a, float *p )
{
*a = 3
...
14 * r ;
}
And here is the output
...
500000
Perimeter = 31
...
And since
we are passing the addresses, any change that we make in values
stored at addresses contained in the variables a and p, would make

Chapter 5: Functions & Pointers 189
the change effective in main( )
...

Thus, we have been able to indirectly return two values from a
called function, and hence, have overcome the limitation of the
return statement, which can return only one value from a function
at a time
...

If we want that the value of an actual argument should get

changed in the function being called, pass the actual argument
by reference
...


Recursion
In C, it is possible for the functions to call themselves
...
Sometimes called ‘circular definition’,
recursion is thus the process of defining something in terms of
itself
...
Suppose we want to
calculate the factorial value of an integer
...
For example, 4 factorial is 4 * 3 * 2 * 1
...
Thus
factorial of a number can be expressed in the form of itself
...
However, before we try
to write a recursive function for calculating factorial let us take a
look at the non-recursive function for calculating the factorial
value of an integer
...

Enter any number 3
Factorial value = 6

Chapter 5: Functions & Pointers 191
Work through the above program carefully, till you understand the
logic of the program properly
...

Following is the recursive version of the function to calculate the
factorial value
...
In
the first run when the number entered through scanf( ) is 1, let us
see what action does rec( ) take
...
e
...
Since x turns out to be 1 the condition if ( x == 1 ) is
satisfied and hence 1 (which indeed is the value of 1 factorial) is
returned through the return statement
...
How do we handle the
expression x * rec ( x - 1 )? We multiply x by rec ( x - 1 )
...
We know that the value returned
by rec ( 1 ) is 1, so the expression reduces to (2 * 1), or simply 2
...

In case the value of a is 5, main( ) would call rec( ) with 5 as its
actual argument, and rec( ) will send back the computed value
...
It is possible for the rec( ) that has just been

Chapter 5: Functions & Pointers 193

called to call yet another rec( ), the argument x being decreased in
value by 1 for each of these recursive calls
...
These
successive invocations of the same function are possible because
the C compiler keeps track of which invocation calls which
...
So we
might say what happens is,
rec ( 5 ) returns ( 5 times rec ( 4 ),
which returns ( 4 times rec ( 3 ),
which returns ( 3 times rec ( 2 ),
which returns ( 2 times rec ( 1 ),
which returns ( 1 ) ) ) ) )
Foxed? Well, that is recursion for you in its simplest garbs
...
Possibly Figure 5
...

Assume that the number entered through scanf( ) is 3
...
4 let’s visualize what exactly happens when the recursive
function rec( ) gets called
...
The
first time when rec( ) is called from main( ), x collects 3
...
e
...
This is a recursive
call
...
This time as x is 1, control goes back to
previous rec( ) with the value 1, and f is evaluated as 2
...
The sequence would be grasped
better by following the arrows shown in Figure 5
...
Let it be clear
that while executing the program there do not exist so many copies
of the function rec( )
...

from main( )
rec ( int x )
{
int f ;
if (x == 1)
return ( 1 ) ;
else
f = x * rec ( x – 1 ) ; f = x * rec ( x – 1 )
return ( f ) ;
}
to main( )
rec ( int x )
{
int f ;
if (x == 1)
return ( 1 ) ;
else

; f = x * rec ( x – 1 ) ;
return ( f ) ;
}
rec ( int x )
{
int f ;
if (x == 1)
return ( 1 ) ;
else
return ( f ) ;
}

Figure 5
...


Recursion and Stack
There are different ways in which data can be organized
...

All these different ways of organizing the data are known as data
structures
...


Chapter 5: Functions & Pointers 195
A stack is a Last In First Out (LIFO) data structure
...
You can compare this to the stack of plates in a
cafeteria—the last plate that goes on the stack is the first one to get
out of it
...

main( )
{
int a = 5, b = 2, c ;
c = add ( a, b ) ;
printf ( "sum = %d", c ) ;
}
add ( int i, int j )
{
int sum ;
sum = i + j ;
return sum ;
}
In this program before transferring the execution control to the
function fun( ) the values of parameters a and b are pushed onto
the stack
...
It is
necessary to push this address on the stack
...
In
fun( ) the local variable sum gets pushed on the stack
...
Next
the address of the statement where the control should be returned

is popped up from the stack
...
Before execution of printf( )
begins the two integers that were earlier pushed on the stack are
now popped off
...
Similarly, it would generate code to
clear the stack when the control returns back from fun( )
...
5 shows the contents of the stack at different stages of execution
...
5
Note that in this program popping of sum and address is done by
fun( ), whereas popping of the two integers is done by main( )
...
There are other calling conventions as well where
instead of main( ), fun( ) itself clears the two integers
...
The standard calling convention always uses the right-to-left

Chapter 5: Functions & Pointers 197
order
...

The recursive calls are no different
...
The stack gets unwound when the control returns from
the called function
...

Also, note that while writing recursive functions you must have an
if statement somewhere in the recursive function to force the

function to return without recursive call being executed
...
Soon
the stack would become full and you would get a run-time error
indicating that the stack has become full
...
My advice is to use
printf( ) statement liberally during the development of recursive
function, so that you can watch what is going on and can abort
execution if you see that you have made a mistake
...
Can
we not add our functions to the standard library? And would it
make any sense in doing so? We can add user-defined functions to
the library
...
When we
use these functions (by calling them) we save on their compilation
time as they are available in the library in the compiled form
...

Different compilers provide different utilities to add/delete/modify
functions in the standard library
...
exe’ (Turbo Librarian)
...

Given below are the steps to do so:
(a)
(b)
(c)
(d)
(e)
Write the function definition of factorial( ) in some file, say
‘fact
...

int factorial ( int num )
{
int i, f = 1 ;
for ( i = 1 ; i <= num ; i++ )
f=f*i;
return ( f ) ;
}
Compile the ‘fact
...
A new file called
‘fact
...

Add the function to the library by issuing the command
C:\>tlib math
...
obj
Here, ‘math
...
obj’
is the path of the ‘
...

Declare the prototype of the factorial( ) function in the header
file, say ‘fact
...
This file should be included while calling the

function
...
h"
main( )

Chapter 5: Functions & Pointers 199
{
int f ;
f = factorial ( 5 ) ;
printf ( "%d", f ) ;
}
(f)
(a)
(b)
(c)
Compile and execute the program using Ctrl F9
...

Instead of modifying the existing libraries we can create our own
library
...
Let us 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
...

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 ) ;
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
...

Create a file, say ‘sample
...


#include "myfuncs
...
h’ should be in the same directory
as the file ‘sample
...
If not, then while including ‘myfuncs
...

Go to the ‘Project’ menu and select ‘Open Project…’ option
...
Give the name of the
project, say ‘sample
...

From the ‘Project’ menu select ‘Add Item’
...
Select the file ‘sample
...
Also add the file ‘myfuncs
...

Finally select ‘Done’
...


Chapter 5: Functions & Pointers 201

Summary
(a)
(b)
(c)
(d)
(e)
(f)
(g)
(h)
(i)
To avoid repetition of code and bulky programs functionally
related statements are isolated into a function
...

Function definition defines the body of the function
...
So, there won’t be any clash even if
we give same name to the variables declared in different
functions
...

A function can be called either by value or by reference
...

Recursion is difficult to understand, but in some cases offer a
better solution than loops
...


Exercise

Simple functions, Passing values between functions
[A] What would be the output of the following programs:
(a) main( )
{
printf ( "\nOnly stupids use C?" ) ;
display( ) ;
}
display( )
{
printf ( "\nFools too use C!" ) ;
main( ) ;
}

202 Complete Guide To C
(b) main( )
{
printf ( "\nC to it that C survives" ) ;
main( ) ;
}
(c) main( )
{
int i = 45, c ;
c = check ( i ) ;
printf ( "\n%d", c ) ;
}
check ( int ch )
{
if ( ch >= 45 )
return ( 100 ) ;
else
return ( 10 * 10 ) ;
}
(d) main( )
{
int i = 45, c ;
c = multiply ( i * 1000 ) ;
printf ( "\n%d", c ) ;
}
check ( int ch )
{
if ( ch >= 40000 )
return ( ch / 10 ) ;
else
return ( 10 ) ;
}
[B] Point out the errors, if any, in the following programs:
(a) main( )
{

Chapter 5: Functions & Pointers 203
int i = 3, j = 4, k, l ;
k = addmult ( i, j ) ;

l = addmult ( i, j ) ;
printf ( "\n%d %d", k, l ) ;
}
addmult ( int ii, int jj )
{
int kk, ll ;
kk = ii + jj ;
ll = ii * jj ;
return ( kk, ll ) ;
}
(b) main( )
{
int a ;
a = message( ) ;
}
message( )
{
printf ( "\nViruses are written in C" ) ;
return ;
}
(c) main( )
{
float a = 15
...
The variables commonly used in C functions are available
to all the functions in a program
...
To return the control back to the calling function we must
use the keyword return
...
The same variable names can be used in different
functions without any conflict
...
Every called function must contain a return statement
...
A function may contain more than one return statements
...
Each return statement in a function may return a different
value
...
A function can still be useful even if you don’t pass any
arguments to it and the function doesn’t return any value
back
...
Same names can be used for different functions without
any conflict
...
A function may be called more than once from any other
function
...
It is necessary for a function to return some value
...

(b) Write a function power ( a, b ), to calculate the value of a
raised to b
...
The following table shows the
roman equivalents of decimal numbers:
Decimal Roman Decimal Roman
1 i 100 c
5 v 500 d
10 x 1000 m
50 l

Example:
Roman equivalent of 1988 is mdcccclxxxviii
Roman equivalent of 1525 is mdxxv

(d) Any year is entered through the keyboard
...

(e) A positive integer is entered through the keyboard
...

For example, prime factors of 24 are 2, 2, 2 and 3, whereas
prime factors of 35 are 5 and 7
...
14 * r * r ;
return ( a ) ;
}
(b) main( )
{
void slogan( ) ;
int c = 5 ;
c = slogan( ) ;
printf ( "\n%d", c ) ;
}
void slogan( )
{
printf ( "\nOnly He men use C!" ) ;
}
[F] Answer the following:
(a) Write a function which receives a float and an int from
main( ), finds the product of these two and returns the product
which is printed through main( )
...
Call this
function from main( ) and print the results in main( )
...
Call this function from main( ) and print the results in
main( )
...
5 ;
float *b, *c ;
b = &a ; /* suppose address of a is 1006 */

Chapter 5: Functions & Pointers 209
c=b;
printf ( "\n%u %u %u", &a, b, c ) ;
printf ( "\n%f %f %f %f %f", a, *(&a), *&a, *b, *c ) ;
}
[H] Point out the errors, if any, in the following programs:
(a) main( )
{
int i = 135, a = 135, k ;
k = pass ( i, a ) ;
printf ( "\n%d", k ) ;
}
pass ( int j, int b )
int c ;
{
c=j+b;

return ( c ) ;
}
(b) main( )
{
int p = 23, f = 24 ;
jiaayjo ( &p, &f ) ;
printf ( "\n%d %d", p, f ) ;
}
jiaayjo ( int q, int g )
{
q=q+q;
g=g+g;
}
(c) main( )
{
int k = 35, z ;
z = check ( k ) ;
printf ( "\n%d", z ) ;
}

210 Complete Guide To C
check ( m )
{
int m ;
if ( m > 40 )
return ( 1 ) ;
else
return ( 0 ) ;
}
(d) main( )
{
int i = 35, *z ;
z = function ( &i ) ;
printf ( "\n%d", z ) ;
}
function ( int *m )
{
return ( m + 2 ) ;
}
[I] What would be the output of the following programs:
(a) main( )
{
int i = 0 ;
i++ ;
if ( i <= 5 )
{
printf ( "\nC adds wings to your thoughts" ) ;
exit( ) ;
main( ) ;
}
}

(b) main( )
{
static int i = 0 ;
i++ ;

Chapter 5: Functions & Pointers 211
if ( i <= 5 )
{
printf ( "\n%d", i ) ;
main( ) ;
}
else
exit( ) ;
}
[J] Attempt the following:
(a) A 5-digit positive integer is entered through the keyboard,
write a function to calculate sum of digits of the 5-digit
number:
(1) Without using recursion
(2) Using recursion
(b) A positive integer is entered through the keyboard, write a
program to obtain the prime factors of the number
...

(c) Write a recursive function to obtain the first 25 numbers of a
Fibonacci sequence
...
Following are the first
few terms of the Fibonacci sequence:
1 1 2 3 5 8 13 21 34 55 89
...

(e) Write a recursive function to obtain the running sum of first
25 natural numbers
...

(g) Given three variables x, y, z write a function to circularly shift
their values to right
...
Call the function with variables a, b, c to
circularly shift values
...

(i) If the lengths of the sides of a triangle are denoted by a, b,
and c, then area of triangle is given by
area = S(S − a)(S − b)(S − c)
where, S = ( a + b + c ) / 2
(j) Write a function to compute the distance between two points
and use it to develop another function that will compute the
area of the triangle whose vertices are A(x1, y1), B(x2, y2),
and C(x3, y3)
...

(k) Write a function to compute the greatest common divisor
given by Euclid’s algorithm, exemplified for J = 1980, K =
1617 as follows:
1980 / 1617 = 1 1980 – 1 * 1617 = 363
1617 / 363 = 4 1617 – 4 * 363 = 165
363 / 165 = 2 363 – 2 * 165 = 33
5 / 33 = 5 165 – 5 * 33 = 0
Thus, the greatest common divisor is 33
...
It may seem odd to
many, how C programmers manage with such a tiny set of
data types
...
They
can derive many data types from these three types
...
A C programmer can always invent whatever data type
he needs
...
For example, a char could be an unsigned char or a
signed char
...

Sufficiently confusing? Well, let us take a closer look at these
variations of primary data types in this chapter
...
In this chapter we would be exploring the
different storage classes and their relevance in C programming
...
For a 16-bit compiler like Turbo C or Turbo
C++ the range is –32768 to 32767
...
Here a 16-bit compiler
means that when it compiles a C program it generates machine
language code that is targeted towards working on a 16-bit
microprocessor like Intel 8086/8088
...
Note
that this does not mean that a program compiled using Turbo C
would not work on 32-bit processor
...
This happens because a 32-bit processor provides
support for programs compiled using 16-bit compilers
...
This is precisely what happens on the new
Intel Itanium processors, which have withdrawn support for 16-bit
code
...

This bit is 1 if the number is negative, and 0 if the number is
positive
...
The intention of providing
these variations is to provide integers with different ranges
wherever possible
...
Each
compiler can decide appropriate sizes depending on the operating
system and hardware for which it is being written, subject to the
following rules:
(a)
(b)
(c)
(d)
shorts are at least 2 bytes big
longs are at least 4 bytes big
shorts are never bigger than ints
ints are never bigger than longs
Figure 6
...

Compiler short int long
16-bit (Turbo C/C++) 2 2 4
32-bit (Visual C++) 2 4 4

Figure 6
...
The value of
a long integer typically can vary from -2147483648 to
+2147483647
...

If there are such things as longs, symmetry requires shorts as
well—integers that need less space in memory and thus help speed
up program execution
...
So the declarations made above can be written as,
long i ;
long abc ;
short j ;
short height ;
Naturally, most C programmers prefer this short-cut
...
In such cases we add the suffix ‘L’ or ‘l’ at the end of the
number, as in 23L
...
In such a case we can declare the
variable to be unsigned, as in,
unsigned int num_students ;
With such a declaration, the range of permissible integer values
(for a 16-bit OS) will shift from the range -32768 to +32767 to the
range 0 to 65535
...
This so happens because on declaring the integer as
unsigned, the left-most bit is now free and is not used to store the
sign of the number
...
This is how an unsigned integer can be declared:
unsigned int i ;
unsigned i ;
Like an unsigned int, there also exists a short unsigned int and a
long unsigned int
...


Chars, signed and unsigned
Parallel to signed and unsigned ints (either short or long),
similarly there also exist signed and unsigned chars, both
occupying one byte each, but having different ranges
...

Consider the statement
char ch = 'A' ;
Here what gets stored in ch is the binary equivalent of the ASCII
value of ‘A’ (i
...
binary of 65)
...


218 Complete Guide To C
A signed char is same as an ordinary char and has a range from
-128 to +127; whereas, an unsigned char has a range from 0 to
255
...
Well, not really
...
Hence when value of ch exceeds
+127, an appropriate value from the other side of the range is
picked up and stored in ch
...

Here is another program that would make the concept clearer
...
Well, No! This is an indefinite loop
...
Hence when value of ch is +127 and we perform
ch++ it becomes -128 instead of +128
...
Here onwards ch would take values
like -127, -126, -125,
...
+127, -128, -127, etc
...
How do you

Chapter 6: Data Types Revisited 219
overcome this difficulty? Would declaring ch as an unsigned char
solve the problem? Even this would not serve the purpose since
when ch reaches a value 255, ch++ would try to make it 256
which cannot be stored in an unsigned char
...
However, if we are bent upon
writing the program using unsigned char, it can be done as shown
below
...

main( )
{
unsigned char ch ;

for ( ch = 0 ; ch <= 254 ; ch++ )
printf ( "\n%d %c", ch, ch ) ;
printf ( "\n%d %c", ch, ch ) ;
}

Floats and Doubles
A float occupies four bytes in memory and can range from -3
...
4e38
...
7e308 to
+1
...
A variable of type double can be declared as,
double a, population ;
If the situation demands usage of real numbers that lie even
beyond the range offered by double data type, then there exists a
long double that can range from -1
...
7e4932
...

You would see that most of the times in C programming one is
required to use either chars or ints and cases where floats,
doubles or long doubles would be used are indeed rare
...
Go through the following program
carefully, which shows how to use these different data types
...

main( )
{
char c ;
unsigned char d ;
int i ;
unsigned int j ;
short int k ;
unsigned short int l ;
long int m ;
unsigned long int n ;
float x ;
double y ;
long double z ;
/* char */
scanf ( "%c %c", &c, &d ) ;
printf ( "%c %c", c, d ) ;
/* int */
scanf ( "%d %u", &i, &j ) ;
printf ( "%d %u", i, j ) ;
/* short int */
scanf ( "%d %u", &k, &l ) ;
printf ( "%d %u", k, l ) ;
/* long int */
scanf ( "%ld %lu", &m, &n ) ;
printf ( "%ld %lu", m, n ) ;
/* float, double, long double */
scanf ( "%f %lf %Lf", &x, &y, &z ) ;
printf ( "%f %lf %Lf", x, y, z ) ;

Chapter 6: Data Types Revisited 221
}
The essence of all the data types that we have learnt so far has
been captured in Figure 6
...

Data Type Range Bytes Format
signed char -128 to + 127 1 %c
unsigned char 0 to 255 1 %c
short signed int -32768 to +32767 2 %d
short unsigned int 0 to 65535 2 %u
signed int -32768 to +32767 2 %d
unsigned int 0 to 65535 2 %u
long signed int -2147483648 to +2147483647 4 %ld
long unsigned int 0 to 4294967295 4 %lu
float -3
...
4e38 4 %f
double -1
...
7e308 8 %lf
long double -1
...
7e4932 10 %Lf
Note: The sizes and ranges of int, short and long are compiler
dependent
...


Figure 6
...

(a) We saw earlier that size of an integer is compiler dependent
...
Also, depending
upon the microprocessor for which the compiler targets its
code the accuracy of floating point calculations may change
...
0/7
...
This is because TC/TC++ targets its compiled code
to 8088/8086 (16-bit) microprocessors
...
This emulator has limitations and
hence produces less accurate results
...
In
addition to this increased size there is a performance penalty
since this bigger code would take more time to execute
...
This is because a negative
number is always stored as 2’s compliment of its binary
...
Firstly, binary of 128
is calculated (10000000), then its 1’s compliment is obtained
(01111111)
...
Finally, 2’s compliment of this number, i
...

10000000, gets stored
...
Thus, for -128, 10000000
gets stored
...
As against this, +128 cannot be
stored in a char because its binary 010000000 (left-most 0 is
for positive sign) is a 9-bit number
...

What happens when we attempt to store +128 in a char? The
first number on the negative side, i
...
-128 gets stored
...
But when 10000000 is stored the
left-most bit is 1 and it is treated as a sign bit
...
Similarly, you
can verify that an attempt to store +129 in a char results in
storing -127 in it
...
Vice versa is

Chapter 6: Data Types Revisited 223
also true
...


Storage Classes in C
We have already said all that needs to be said about constants, but
we are not finished with variables
...
In
other words, not only do all variables have a data type, they also
have a ‘storage class’
...
We were able to get away with this
because storage classes have defaults
...
Thus, variables have certain default storage
classes
...
There are basically two
kinds of locations in a computer where such a value may be kept—
Memory and CPU registers
...

Moreover, a variable’s storage class tells us:
(a) Where the variable would be stored
...
(i
...
the default initial value)
...
e
...

(d) What is the life of the variable; i
...
how long would the
variable exist
...


Automatic Storage Class
The features of a variable defined to have an automatic storage
class are as under:
Storage − Memory
...

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

Following program shows how an automatic storage class variable
is declared, and the fact that if the variable is not initialized it
contains a garbage value
...

1211 221
where, 1211 and 221 are garbage values of i and j
...
So always make it a point that you initialize the
automatic variables properly, otherwise you are likely to get
unexpected results
...

Scope and life of an automatic variable is illustrated in the
following program
...
It means the scope of i is local to the
block in which it is defined
...
To catch my point, go through the
following program
...
Once the
control comes out of the innermost block the variable i with value
3 is lost, and hence the i in the second printf( ) refers to i with
value 2
...

Understand the concept of life and scope of an automatic storage
class variable thoroughly before proceeding with the next storage
class
...

Default initial value - Garbage value
...

Life - Till the control remains within the block
in which the variable is defined
...
Therefore, if a variable is
used at many places in a program it is better to declare its storage
class as register
...
We can name their storage class as register
...
Why? Because the number of CPU registers are
limited, and they may be busy doing some other task
...
the variable works as if its storage class
is auto
...

For example, if the microprocessor has 16-bit registers then they
cannot hold a float value or a double value, which require 4 and 8
bytes respectively
...

All that would happen is the compiler would treat the variables to
be of auto storage class
...

Default initial value − Zero
...

Life − Value of the variable persists between
different function calls
...
3 to
understand the difference between the automatic and static
storage classes
...
3
The programs above consist of two functions main( ) and
increment( )
...
Each time it increments the value of i and prints it
...


Chapter 6: Data Types Revisited 229
Like auto variables, static variables are also local to the block in
which they are declared
...

Their values persist
...

In the above example, when variable i is auto, each time
increment( ) is called it is re-initialized to one
...
The result: no
matter how many times we call increment( ), i is initialized to 1
every time
...
It is
never initialized again
...
Because i is static, this value persists
...
This current value of i
(i
...
2) gets printed and then i = i + 1 adds 1 to i to get a value of 3
...
e
...
In short, if the
storage class is static then the statement static int i = 1 is executed
only once, irrespective of how many times the same function is
called
...

main( )
{
int *j ;
int * fun( ) ;
j = fun( ) ;
printf ( "\n%d", *j ) ;
}
int *fun( )
{

230 Complete Guide To C
int k = 35 ;
return ( &k ) ;
}

Here we are returning an address of k from fun( ) and collecting it
in j
...
Then using this pointer we are
printing the value of k
...
Now try
calling any function (even printf( ) ) immediately after the call to
fun( )
...
Why does this
happen? In the first case, when the control returned from fun( )
though k went dead it was still left on the stack
...
But when we
precede the call to printf( ) by a call to any other function, the
stack is now changed, hence we get the garbage value
...

By doing this when the control returns from fun( ), k would not
die
...
Because their values are
kept in memory when the variables are not active, which means
they take up space in memory that could otherwise be used by
other variables
...

Default initial value − Zero
...

Life − As long as the program’s execution
doesn’t come to an end
...
External variables are declared
outside all functions, yet are available to all functions that care to
use them
...

int i ;
main( )
{
printf ( "\ni = %d", i ) ;
increment( ) ;
increment( ) ;
decrement( ) ;
decrement( ) ;
}
increment( )
{
i=i+1;
printf ( "\non incrementing i = %d", i ) ;
}
decrement( )
{
i=i-1;
printf ( "\non decrementing i = %d", i ) ;
}

The output would be:
i=0
on incrementing i = 1
on incrementing i = 2
on decrementing i = 1
on decrementing i = 0

232 Complete Guide To C
As is obvious from the above output, the value of i is available to
the functions increment( ) and decrement( ) since i has been
declared outside all functions
...

int x = 21 ;
main( )
{
extern int y ;
printf ( "\n%d %d", x, y ) ;
}
int y = 31 ;
Here, x and y both are global variables
...
Note the difference between the following:
extern int y ;
int y = 31 ;
Here the first statement is a declaration, whereas the second is the
definition
...

We had to declare y since it is being used in printf( ) before it’s
definition is encountered
...
Also remember that a variable
can be declared several times but can be defined only once
...
When the control reaches the printf( ) in main( ) which x
gets printed? Whenever such a conflict arises, it’s the local
variable that gets preference over the global variable
...
When display( ) is called and control reaches
the printf( ) there is no such conflict
...
e
...

One last thing—a static variable can also be declared outside all
the functions
...
However, the scope of this variable is limited to
the same file in which it is declared
...


Which to Use When
Dennis Ritchie has made available to the C programmer a number
of storage classes with varying features, believing that the
programmer is in a best position to decide which one of these
storage classes is to be used when
...

− Use register storage class for only those variables that are
being used very often in a program
...
Make careful utilization of the
scarce resources
...

− Use extern storage class for only those variables that are being
used by almost all the functions in the program
...
Declaring all the variables as
extern would amount to a lot of wastage of memory space
because these variables would remain active throughout the
life of the program
...
In fact most of the times we
end up using the auto variables, because often it so happens
that once we have used the variables in a function we don’t
mind loosing them
...
There are different format
specifications for all these data types when they are used in
scanf( ) and printf( ) functions
...

By default all the variables are signed
...


Chapter 6: Data Types Revisited 235
(d) We can make use of proper storage classes like auto,
register, static and extern to control four properties of the
variable—storage, default initial value, scope and life
...
5 ;
double b = 13
...
5 ;
main( )
{
float y, float f ( float ) ;
x *= 2
...
3 ;
x -= 4
...
345e454 ;
unsigned double b = 25 ;
printf ( "\n%lf %d", a, b ) ;

Chapter 6: Data Types Revisited 239
}
(e) main( )
{
float a = 25
...

(b) An extern storage class variable is not available to the
functions that precede its definition, unless the variable is
explicitly declared in these functions
...

(d) If the CPU registers are not available, the register storage
class variables are treated as static storage class variables
...

(f) If we try to use register storage class for a float variable
the compiler will flash an error message
...

(h) The default value for automatic variable is zero
...

(j) If a global variable is to be defined, then the extern
keyword is necessary in its declaration
...

[D] Following program calculates the sum of digits of the number
12345
...

main( )
{
int a ;
a = sumdig ( 12345 ) ;
printf ( "\n%d", a ) ;
}
sumdig ( int num )
{
static int sum ;
int a, b ;
a = num % 10 ;
b = ( num - a ) / 10 ;

sum = sum + a ;
if ( b != 0 )
sumdig ( b ) ;
else
return ( sum ) ;
}

7 The C Preprocessor
• Features of C Preprocessor
• Macro Expansion
Macros with Arguments
Macros versus Functions
• File Inclusion
• Conditional Compilation
• #if and #elif Directives
• Miscellaneous Directives
#undef Directive
#pragma Directive
• Summary
• Exercise

241
242 Complete Guide To C
he C preprocessor is exactly what its name implies
...
Preprocessor commands (often
known as directives) form what can almost be considered a
language within C language
...

But preprocessor is such a great convenience that virtually all C
programmers rely on it
...


T
Features of C Preprocessor
There are several steps involved from the stage of writing a C
program to the stage of getting it executed
...
1 shows these
different steps along with the files created during each stage
...
The input and
output to each of these processors is shown in Figure 7
...

Note that if the source code is stored in a file PR1
...
I
...
OBJ
...
EXE
...
Each of these preprocessor directives begin with a #
symbol
...
We would learn the following
preprocessor directives here:
(a) Macro expansion
(b) File inclusion

Chapter 7: The C Preprocessor 243
Text editor
Preprocessor
Compiler
Linker
Executable code (PR1
...
OBJ)
Expanded source code (PR1
...
C)
Hand written program

Figure 7
...
2

244 Complete Guide To C
(c) Conditional Compilation
(d) Miscellaneous directives
Let us understand these features of preprocessor one by one
...

#define UPPER 25
main( )
{
int i ;

for ( i = 1 ; i <= UPPER ; i++ )
printf ( "\n%d", i ) ;
}
In this program instead of writing 25 in the for loop we are writing
it in the form of UPPER, which has already been defined before
main( ) through the statement,
#define UPPER 25
This statement is called ‘macro definition’ or more commonly, just
a ‘macro’
...
Here is another example of macro definition
...
1415
main( )
{
float r = 6
...
1415 are called their corresponding
‘macro expansions’
...
When it sees the #define directive, it goes through the
entire program in search of the macro templates; wherever it finds
one, it replaces the macro template with the appropriate macro
expansion
...

In C programming it is customary to use capital letters for macro
template
...

Note that a macro template and its macro expansion are separated
by blanks or tabs
...

Remember that a macro definition is never to be terminated by a
semicolon
...
why use #define in the above
programs? What have we gained by substituting PI for 3
...

Even though 3
...
For example, if the phrase “\x1B[2J”
causes the screen to clear
...


246 Complete Guide To C

There is perhaps a more important reason for using macro
definition than mere readability
...
1415
appears many times in your program
...
141592
...
However, if you have defined PI in a #define directive,
you only need to make one change, in the #define directive itself:
#define PI 3
...

In short, it is nice to know that you would be able to change values
of a constant at all the places in the program by just making a
change in the #define directive
...

But the same purpose could have been served had we used a
variable pi instead of a macro template PI
...
It’s true that a
variable can be used in this way
...

Firstly, it is inefficient, since the compiler can generate faster and
more compact code for constants than it can for variables
...
And thirdly, there is always a danger that the variable
may inadvertently get altered somewhere in the program
...


Chapter 7: The C Preprocessor 247
Thus, using #define can produce more efficient and more easily
understandable programs
...

Following three examples show places where a #define directive is
popularly used by C programmers
...

#define AND &&
#define OR ||
main( )
{
int f = 1, x = 4, y = 90 ;
if ( ( f < 5 ) AND ( x <= 20 OR y <= 45 ) )
printf ( "\nYour PC will always work fine
...

#define AND &&

#define ARANGE ( a > 25 AND a < 50 )
main( )
{
int a = 30 ;
if ( ARANGE )
printf ( "within range" ) ;
else
printf ( "out of range" ) ;
}

248 Complete Guide To C
A #define directive could be used to replace even an entire C
statement
...

#define FOUND printf ( "The Yankee Doodle Virus" ) ;
main( )
{
char signature ;
if ( signature == 'Y' )
FOUND
else
printf ( "Safe
...

Macros can have arguments, just as functions can
...

#define AREA(x) ( 3
...
25, r2 = 2
...

Area of circle = 122
...
625000

Chapter 7: The C Preprocessor 249
In this program wherever the preprocessor finds the phrase
AREA(x) it expands it into the statement ( 3
...

However, that’s not all that it does
...
14 * x * x )
...
Thus the
statement AREA(r1) is equivalent to:
( 3
...
25, r2 = 2
...
14 * r1 *r1 ;
printf ( "Area of circle = %f\n", a ) ;
a = 3
...
For example, there
should be no blank between AREA and (x) in the definition,
#define AREA(x) ( 3
...
What would happen is, the template would be
expanded to
( r1 ) ( 3
...
Not at all what we wanted
...
Here is an example of what would happen if we
fail to enclose the macro expansion within parentheses
...


Chapter 7: The C Preprocessor 251
What went wrong? The macro was expanded into
j = 64 / 4 * 4 ;

which yielded 64
...
Following program shows how
we can define and use multiple line macros
...

If for any reason you are unable to debug a macro then you
should view the expanded code of the program to see how the
macros are getting expanded
...
C then the expanded source code would be stored

252 Complete Guide To C
in PR1
...
You need to generate this file at the command
prompt by saying:
cpp pr1
...
It generates the
expanded source code and stores it in a file called PR1
...
You
can now open this file and see the expanded source code
...
I gets generated in C:\TC\BIN
directory
...


Macros versus Functions
In the above example a macro was used to calculate the area of the
circle
...
Though macro calls are ‘like’ function calls, they
are not really the same things
...
As
against this, in a function call the control is passed to a function
along with certain arguments, some calculations are performed in
the function and a useful value is returned back from the function
...

If we use a macro hundred times in a program, the macro
expansion goes into our source code at hundred different places,
thus increasing the program size
...

But passing arguments to a function and getting back the returned
value does take time and would therefore slow down the program
...

Moral of the story is—if the macro is simple and sweet like in our
examples, it makes nice shorthand and avoids the overheads
associated with function calls
...


File Inclusion
The second preprocessor directive we’ll explore in this chapter is
file inclusion
...
The preprocessor command for file inclusion looks like
this:
#include "filename"
and it simply causes the entire contents of filename to be inserted
into the source code at that point in the program
...
When and why
this feature is used? It can be used in two cases:
(a) If we have a very large program, the code is best divided into
several different files, each containing a set of related
functions
...
These files are
#included at the beginning of main program file
...
These commonly

254 Complete Guide To C
needed functions and macro definitions can be stored in a file,
and that file can be included in every program we write,
which would add all the statements in this file to our program
as if we have typed them in
...
h
extension
...
The prototypes of all the library functions are grouped
into different categories and then stored in different header files
...
h’, prototypes of console
input/output functions are stored in the header file ‘conio
...

Actually there exist two ways to write #include statement
...
c" This command would look for the file goto
...

#include ...
c
in the specified list of directories only
...
Different C
compilers let you set the search path in different manners
...
On doing this

Chapter 7: The C Preprocessor 255
a dialog box appears
...
We can also specify
multiple include paths separated by ‘;’ (semicolon) as shown
below:
c:\tc\lib ; c:\mylib ; d:\libfiles
The path can contain maximum of 127 characters
...
For example ‘
...


Conditional Compilation
We can, if we want, have the compiler skip over part of a source
code by inserting the preprocessing commands #ifdef and #endif,
which have the general form:
#ifdef macroname
statement 1 ;
statement 2 ;
statement 3 ;
#endif
If macroname has been #defined, the block of code will be
processed as usual; otherwise not
...
It often happens
that a program is changed at the last minute to satisfy a client
...
But veteran
programmers are familiar with the clients who change their
mind and want the old code back again just the way it was
...


One solution in such a situation is to put the old code within a
pair of /* */ combination
...
This would mean we end up with nested comments
...

Therefore the solution is to use conditional compilation as
shown below
...
At a later date, if
we want that these statements should also get compiled all
that we are required to do is to delete the #ifdef and #endif
statements
...
e
...
Suppose an organization has two

Chapter 7: The C Preprocessor 257
different types of computers and you are expected to write a
program that works on both the machines
...
For example:
main( )
{
#ifdef INTEL
code suitable for a Intel PC
#else
code suitable for a Motorola PC
#endif
code common to both the computers
}
When you compile this program it would compile only the
code suitable for a Intel PC and the common code
...
Note that the
working of #ifdef - #else - #endif is similar to the ordinary if else control instruction of C
...

The #ifndef (which means ‘if not defined’) works exactly
opposite to #ifdef
...
h’
which is #included in a file ‘myfile1
...
Now in your program
file if you #include both ‘myfile
...
h’ the
compiler flashes an error ‘Multiple declaration for myfunc’
...
h’ gets included twice
...

/* myfile
...
h’ gets included the preprocessor
checks whether a macro called __myfile_h has been defined
or not
...
Next time we attempt to include the same
file, the inclusion is prevented since __myfile_h already
stands defined
...
In its place we can use any other macro as well
...
If the result of the expression
is nonzero, then subsequent lines upto a #else, #elif or #endif are
compiled, otherwise they are skipped
...

In place of the expression TEST <= 5 other expressions like
( LEVEL == HIGH || LEVEL == LOW ) or ADAPTER ==
CGA can also be used
...
An example that uses such directives is shown below
...
The same
program using this directive can be rewritten as shown below
...

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

Miscellaneous Directives
There are two more preprocessor directives available, though they
are not very commonly used
...
This can be accomplished by means of the
#undef directive
...
Thus the statement,
#undef PENTIUM
would cause the definition of PENTIUM to be removed from the

system
...
In practice seldom are you required to undefine a
macro, but for some reason if you are required to, then you know
that there is something to fall back upon
...
Pragmas vary from one compiler
to another
...
Turbo
C/C++ compiler has got a pragma that allows you to suppress
warnings generated by the compiler
...

(a) #pragma startup and #pragma exit: These directives allow
us to specify functions that are called upon program startup
(before main( )) or program exit (just before the program
terminates)
...

Inside fun1
Inside main
Inside fun2
Note that the functions fun1( ) and fun2( ) should neither
receive nor return any value
...

(b) #pragma warn: This directive tells the compiler whether or
not we want to suppress a specific warning
...

#pragma warn –rvl /* return value */
#pragma warn –par /* parameter not used */
#pragma warn –rch /* unreachable code */

int f1( )
{
int a = 5 ;
}
void f2 ( int x )
{
printf ( "\nInside f2" ) ;
}
int f3( )
{
int x = 6 ;
return x ;
x++ ;
}
void main( )

Chapter 7: The C Preprocessor 263
{
f1( ) ;
f2 ( 7 ) ;
f3( ) ;
}
If you go through the program you can notice three problems
immediately
...

(b) The parameter x that is passed to f2( ) is not being used
anywhere in f2( )
...

If we compile the program we should expect warnings
indicating the above problems
...
If we replace the ‘–’ sign with a ‘+’ then these
warnings would be flashed on compilation
...
For example, if you have written a huge
program and are trying to compile it, then to begin with you
are more interested in locating the errors, rather than the
warnings
...

Once you have located all errors, then you may turn on the
warnings and sort them out
...


264 Complete Guide To C
(b)
(c)
We can make use of various preprocessor directives such as
#define, #include, #ifdef - #else - #endif, #if and #elif in our
program
...


Exercise
[A] Answer the following:
(a) What is a preprocessor directive
1
...
a message from compiler to the linker
3
...
a message from programmer to the microprocessor
(b) Which of the following are correctly formed #define
statements:
#define INCH PER FEET 12
#define SQR (X) ( X * X )
#define SQR(X) X * X
#define SQR(X) ( X * X )
(c) State True or False:
1
...

2
...

3
...

4
...

5
...

6
...


Chapter 7: The C Preprocessor 265
(d) How many #include directives can be there in a given
program file?
(e) What is the difference between the following two #include
directives:
#include "conio
...
h>
(f) A header file is:
1
...
A file that contains definitions and macros
3
...
A file that is present in current working directory
(g) Which of the following is not a preprocessor directive
1
...
#elseif
3
...
#pragma
(h) All macro substitutions in a program are done
1
...
After compilation
3
...
None of the above
(i) In a program the statement:
#include "filename"
is replaced by the contents of the file “filename”
1
...
After Compilation
3
...
None of the above

266 Complete Guide To C
[B] What would be the output of the following program:
(a) main( )
{
int i = 2 ;
#ifdef DEF
i *= i ;
#else
printf ( "\n%d", i ) ;
#endif
}
(b) #define PRODUCT(x) ( x * x )
main( )
{
int i = 3, j ;
j = PRODUCT( i + 1 ) ;
printf ( "\n%d", j ) ;
}
(c) #define PRODUCT(x) ( x * x )
main( )
{
int i = 3, j, k ;
j = PRODUCT( i++ ) ;
k = PRODUCT ( ++i ) ;
printf ( "\n%d %d", j, k ) ;
}
(d) # define SEMI ;
main()
{
int p = 3 SEMI ;
printf ( "%d", p ) SEMI
}

Chapter 7: The C Preprocessor 267
[C] Attempt the following:
(a) Write down macro definitions for the following:
1
...

2
...

3
...
Make
use of the macros you defined in (1) and (2) above
...
To obtain the bigger of two numbers
...
Store
these macro definitions in a file called “areaperi
...
Include
this file in your program, and call the macro definitions for
calculating area and perimeter for different squares, triangles

and circles
...
To find arithmetic mean of two numbers
...
To find absolute value of a number
...
To convert a uppercase alphabet to lowercase
...
To obtain the bigger of two numbers
...
Store these macro definitions in
a file called “interest
...
Include this file in your program, and
use the macro definitions for calculating simple interest and
amount
...
This chapter

T

describes how arrays can be created and manipulated in C
...
I feel it is worthwhile to deal with
these topics together
...
In fact all

arrays make use of pointers internally
...


What are Arrays
For understanding the arrays properly, Complete Guide To Consider the
following program:
main( )
{
int x ;
x=5;
x = 10 ;
printf ( "\nx = %d", x ) ;
}
No doubt, this program will print the value of x as 10
...
e
...
Thus, ordinary variables (the ones which we have
used so far) are capable of holding only one value at a time (as in
the above example)
...

For example, suppose we wish to arrange the percentage marks
obtained by 100 students in ascending order
...
e
...

Construct one variable (called array or subscripted variable)
capable of storing or holding all the hundred values
...
A simple reason for
this is, it would be much easier to handle one variable than
handling 100 different variables
...
Now a
formal definition of an array—An array is a collective name given
to a group of ‘similar quantities’
...
What is important is that the quantities must
be ‘similar’
...
For example, assume the following group of
numbers, which represent percentage marks obtained by five
students
...
Similarly, the fourth number of the group is
referred as per4
...
This is because in C the counting of elements begins with 0
and not with 1
...
In general, the notation would be per[i],
where, i can take a value 0, 1, 2, 3, or 4, depending on the position

of the element being referred
...

Thus, an array is a collection of similar elements
...
Usually,
the array of characters is called a ‘string’, whereas an array of ints
or floats is called simply an array
...
i
...
we cannot have an
array of 10 numbers, of which 5 are ints and 5 are floats
...

main( )
{
int avg, sum = 0 ;
int i ;
int marks[30] ; /* array declaration */
for ( i = 0 ; i <= 29 ; i++ )
{
printf ( "\nEnter marks " ) ;
scanf ( "%d", &marks[i] ) ; /* store data in array */
}
for ( i = 0 ; i <= 29 ; i++ )
sum = sum + marks[i] ; /* read data from an array*/
avg = sum / 30 ;
printf ( "\nAverage marks = %d", avg ) ;
}
There is a lot of new material in this program, so let us take it apart
slowly
...
In our program we have done this with the
statement:

Chapter 8: Arrays 273
int marks[30] ;
Here, int specifies the type of the variable, just as it does with
ordinary variables and the word marks specifies the name of the
variable
...
The number 30 tells how many
elements of the type int will be in our array
...
The bracket ( [ ] ) tells the
compiler that we are dealing with an array
...
This is done with subscript, the number in
the brackets following the array name
...
All the array elements are
numbered, starting with 0
...
In our program we are using the

variable i as a subscript to refer to various elements of the array
...
This ability to use variables
as subscripts is what makes arrays so useful
...
The first
time through the loop, i has a value 0, so the scanf( ) function will
cause the value typed to be stored in the array element marks[0],
the first element of the array
...
This is last time through the loop, which is a good
thing, because there is no array element like marks[30]
...
In so doing, we are
passing the address of this particular array element to the scanf( )
function, rather than its value; which is what scanf( ) requires
...
The for loop is much the same,
but now the body of the loop causes each student’s marks to be
added to a running total stored in a variable called sum
...

for ( i = 0 ; i <= 29 ; i++ )
sum = sum + marks[i] ;
avg = sum / 30 ;
printf ( "\nAverage marks = %d", avg ) ;
To fix our ideas, let us revise whatever we have learnt about
arrays:
(a)
(b)
(c)
(d)
(e)
An array is a collection of similar elements
...

An array is also known as a subscripted variable
...

However big an array its elements are always stored in
contiguous memory locations
...


Chapter 8: Arrays 275

More on Arrays
Array is a very popular data type with C programmers
...
The features which make arrays so convenient to
program would be discussed below, along with the possible pitfalls
in using them
...
We managed to store values in them during program
execution
...
Following are a few examples that demonstrate this
...
3, 34
...
4, -11
...

(b) If the array is initialised where it is declared, mentioning the
dimension of the array is optional as in the 2nd example above
...
And since the array is not
being initialized, all eight values present in it would be garbage
values
...
If the storage class is declared to be static
then all the array elements would have a default initial value as
zero
...
This
arrangement of array elements in memory is shown in Figure 8
...

65508 65510 65512 65514 65516 65518 65520 65522
12 34 66 -45 23 346 77 90

Figure 8
...
Data entered with a subscript
exceeding the array size will simply be placed in memory outside
the array; probably on top of other data, or on the program itself
...
In some cases the computer may just hang
...

main( )

{
int num[40], i ;
for ( i = 0 ; i <= 100 ; i++ )
num[i] = i ;
}

Chapter 8: Arrays 277
Thus, to see to it that we do not reach beyond the array size is
entirely the programmer’s botheration and not the compiler’s
...
In the call by value we pass values of
array elements to the function, whereas in the call by reference we
pass addresses of array elements to the function
...

55 65 75 56 78 78 90
Here, we are passing an individual array element at a time to the
function display( ) and getting it printed in the function display( )
...

And now the call by reference
...

55 65 75 56 78 78 90

Here, we are passing addresses of individual array elements to the
function display( )
...
And since n contains
the address of array element, to print out the array element we are
using the ‘value at address’ operator (*)
...
The purpose of the function
disp( ) is just to display the array elements on the screen
...
You are required to write the
function show( ) on your own
...

main( )
{
int i ;
int marks[ ] = { 55, 65, 75, 56, 78, 78, 90 } ;
for ( i = 0 ; i <= 6 ; i++ )
disp ( &marks[i] ) ;

Chapter 8: Arrays 279
}
disp ( int *n )
{
show ( &n ) ;
}

Pointers and Arrays
To be able to see what pointers have got to do with arrays, let us
first learn some pointer arithmetic
...
5, *y ;
char k = 'c', *z ;
printf ( "\nValue of i = %d", i ) ;
printf ( "\nValue of j = %f", j ) ;
printf ( "\nValue of k = %c", k ) ;
x = &i ;
y = &j ;
z = &k ;
printf ( "\nOriginal address in x = %u", x ) ;
printf ( "\nOriginal address in y = %u", y ) ;
printf ( "\nOriginal address in z = %u", z ) ;
x++ ;
y++ ;
z++ ;
printf ( "\nNew address in x = %u", x ) ;
printf ( "\nNew address in y = %u", y ) ;
printf ( "\nNew address in z = %u", z ) ;
}
Here is the output of the program
...
500000
Value of k = c
Original address in x = 65524
Original address in y = 65520
Original address in z = 65519
New address in x = 65526
New address in y = 65524
New address in z = 65520
Observe the last three lines of the output
...
This so happens because every time a pointer is
incremented it points to the immediately next location of its type
...
Similarly, y points to an
address 4 locations after the current location and z points 1
location after the current location
...

The way a pointer can be incremented, it can be decremented as
well, to point to earlier locations
...
For example,
int i = 4, *j, *k ;
j = &i ;
j=j+1;
j=j+9;
k=j+3;
(b) Subtraction of a number from a pointer
...

One pointer variable can be subtracted from another provided
both variables point to elements of the same array
...
This is illustrated in the
following program
...

Suppose the array begins at location 65502, then the elements
arr[1] and arr[5] would be present at locations 65504 and
65512 respectively, since each integer in the array occupies
two bytes in memory
...
This is because j and i are pointing to locations
that are 4 integers apart
...

(d) Comparison of two pointer variables

282 Complete Guide To C
Pointer variables can be compared provided both variables
point to objects of the same data type
...
The comparison can test for either equality or
inequality
...
The following program
illustrates how the comparison is carried out
...
they would never work out
...

(b) A pointer when incremented always points to an immediately
next location of its type
...
The
following figure shows how this array is located in memory
...
2
Here is a program that prints out the memory locations in which
the elements of this array are stored
...
%d ", i ) ;
printf ( "address = %u", &num[i] ) ;
}
}
The output of this program would look like this:
element no
...
1 address = 65514
element no
...
3 address = 65518
element no
...
5 address = 65522
Note that the array elements are stored in contiguous memory
locations, each element occupying two bytes, since it is an integer

284 Complete Guide To C
array
...

Our next two programs show ways in which we can access the
elements of this array
...
This method has in fact been
given here for easy comparison with the next method, which
accesses the array elements using pointers
...
These are
printed using the statements,
printf ( "\naddress = %u ", j ) ;
printf ( "element = %d", *j ) ;
On incrementing j it points to the next memory location of its type
(that is location no
...
But location no
...
e
...

and so on till the last element of the array has been printed
...
However, from
the point of view of convenience in programming we should
observe the following:
Array elements should be accessed using pointers if the elements
are to be accessed in a fixed order, say from beginning to end, or
from end to beginning, or every alternate element or any such
definite logic
...
However, in
this case also, accessing the elements by pointers would work
faster than subscripts
...

Let us now see how to pass an entire array to a function rather than

its individual elements
...
Note that the address of the zeroth element is being
passed to the display( ) function
...
Thus, just passing the address of the zeroth element of the
array to a function is as good as passing the entire array to the
function
...
Note that the address of the zeroth
element (many a times called the base address) can also be passed
by just passing the name of the array
...
Once again consider the following array
...
3

288 Complete Guide To C
This is how we would declare the above array in C,
int num[ ] = { 24, 34, 12, 44, 56, 17 } ;
We also know that on mentioning the name of the array we get its
base address
...
One can easily see that
*num and *( num + 0 ) both refer to 24
...
In fact, this is what the C compiler does
internally
...
This means that all the following
notations are same:

num[i]
*( num + i )
*( i + num )
i[num]
And here is a program to prove my point
...
It is also
possible for arrays to have two or more dimensions
...

Here is a sample program that stores roll number and marks
obtained by a student side by side in a matrix
...
and marks" ) ;
scanf ( "%d %d", &stud[i][0], &stud[i][1] ) ;
}
for ( i = 0 ; i <= 3 ; i++ )
printf ( "\n%d %d", stud[i][0], stud[i][1] ) ;
}
There are two parts to the program—in the first part through a for
loop we read in the values of roll no
...

Look at the scanf( ) statement used in the first for loop:
scanf ( "%d %d", &stud[i][0], &stud[i][1] ) ;

290 Complete Guide To C
In stud[i][0] and stud[i][1] the first subscript of the variable stud,

is row number which changes for every student
...
or the first column
which contains the marks
...
The complete array arrangement is
shown below
...
no
...
no
...
0 1234 56
row no
...
2 1434 80
row no
...
4
Thus, 1234 is stored in stud[0][0], 56 is stored in stud[0][1] and
so on
...

In our sample program the array elements have been stored
rowwise and accessed rowwise
...
Traditionally, the array elements are
being stored and accessed rowwise; therefore we would also stick
to the same strategy
...


Chapter 8: Arrays 291
int stud[4][2] = {
{ 1234, 56 },
{ 1212, 33 },
{ 1434, 80 },
{ 1312, 78 }
};
or even this would work
...

It is important to remember that while initializing a 2-D array it is
necessary to mention the second (column) dimension, whereas the
first dimension (row) is optional
...


Memory Map of a 2-Dimensional Array
Let us reiterate the arrangement of array elements in a twodimensional array of students, which
contains roll nos
...


292 Complete Guide To C
The array arrangement shown in Figure 8
...
This is because memory doesn’t contain rows and columns
...
The
arrangement of array elements of a two-dimensional array in
memory is shown below:
s[0][0] s[0][1] s[1][0] s[1][1] s[2][0] s[2][1] s[3][0] s[3][1]
1212 1434
65508 65510 65512 65514 65516 65518 65520 65522
1234 56 33 80 1312 78

Figure 8
...
Only the
procedure is slightly difficult to understand
...


Pointers and 2-Dimensional Arrays
The C language embodies an unusual but powerful capability—it
can treat parts of arrays as arrays
...
This is a very important fact if we wish to access array
elements of a two-dimensional array using pointers
...
We refer
to an element of a one-dimensional array using a single subscript
...
More specifically, s[0] gives the address of the zeroth
one-dimensional array, s[1] gives the address of the first onedimensional array and so on
...

/* Demo: 2-D array is an array of arrays */
main( )
{
int s[4][2] = {
{ 1234, 56 },
{ 1212, 33 },
{ 1434, 80 },
{ 1312, 78 }
};
int i ;
for ( i = 0 ; i <= 3 ; i++ )
printf ( "\nAddress of %d th 1-D array = %u", i, s[i] ) ;
}
And here is the output
...
The compiler knows that
s is an array containing 4 one-dimensional arrays, each containing
2 integers
...
These one-dimensional arrays are placed
linearly (zeroth 1-D array followed by first 1-D array, etc
...

Figure 8
...
From Figure 8
...

Now, we have been able to reach each one-dimensional array
...
Suppose we
want to refer to the element s[2][1]
using pointers
...
Obviously ( 65516 + 1 ) would give the address 65518
...
And the value at this
address can be obtained by using the value at address operator,
saying *( s[2] + 1 )
...

Similarly, *( s[2] + 1 ) is same as, *( *( s + 2 ) + 1 )
...

/* Pointer notation to access 2-D array elements */
main( )
{
int s[4][2] = {
{ 1234, 56 },
{ 1212, 33 },
{ 1434, 80 },
{ 1312, 78 }
};
int i, j ;
for ( i = 0 ; i <= 3 ; i++ )
{
printf ( "\n" ) ;

for ( j = 0 ; j <= 1 ; j++ )
printf ( "%d ", *( *( s + i ) + j ) ) ;
}
}
And here is the output
...
The following program shows how to build and use it
...

1234 56
1212 33
1434 80
1312 78
Here p is a pointer to an array of two integers
...
Absence of them
would make p an array of 2 integer pointers
...
In the outer for loop each
time we store the address of a new one-dimensional array
...
This address is then assigned to an integer
pointer pint
...

But why should we use a pointer to an array to print elements of a
2-D array
...
This is discussed in the next
section
...
These are illustrated in the following program
...
Then
through the two for loops using the expression * ( q + i * col + j )
we have reached the appropriate element in the array
...
Let us see whether the expression * ( q + i * col + j ) does
give this element or not
...
7 to understand this
...
7
The expression * ( q + i * col + j ) becomes * ( 65502 + 2 * 4 + 3)
...
Since 65502 is address of an
integer, * ( 65502 + 11 ) turns out to be * (65524)
...
This is indeed same as a[2][3]
...
* no
...
)
In the show( ) function we have defined q to be a pointer to an
array of 4 integers through the declaration:

300 Complete Guide To C
int ( *q )[4] ;
To begin with, q holds the base address of the zeroth 1-D array,
i
...
4001 (refer Figure 8
...
This address is then assigned to p, an
int pointer, and then using this pointer all elements of the zeroth 1D array are accessed
...
This is because, q is a pointer to zeroth 1-D array and
adding 1 to it would give us the address of the next 1-D array
...

In the third function print( ), the declaration of q looks like this:
int q[ ][4] ;

This is same as int ( *q )[4], where q is pointer to an array of 4
integers
...
We could have
used the same expression in show( ) as well
...
Since a pointer variable
always contains an address, an array of pointers would be nothing
but a collection of addresses
...
All rules that apply to an
ordinary array apply to the array of pointers as well
...

main( )
{
int *arr[4] ; /* array of integer pointers */

Chapter 8: Arrays 301
int i = 31, j = 5, k = 19, l = 71, m ;
arr[0] = &i ;
arr[1] = &j ;
arr[2] = &k ;
arr[3] = &l ;
for ( m = 0 ; m <= 3 ; m++ )
printf ( "%d ", * ( arr[m] ) ) ;
}
Figure 8
...
As you can observe, arr contains addresses of
isolated int variables i, j, k and l
...

65516 65514 65512 65510
65518 65520 65522 65524
arr[0] arr[1] arr[2] arr[3]
31
65516 65514 65512 65510
ijk
5 19 71
l`

Figure 8
...
The following program would justify this
...


Three-Dimensional Array
We aren’t going to show a programming example that uses a threedimensional array
...
However, an example of initializing a three-dimensional
array will consolidate your understanding of subscripts:
int arr[3][4][2] = {
{
{ 2, 4 },
{ 7, 8 },
{ 3, 4 },
{ 5, 6 }
},
{
{ 7, 6 },
{ 3, 4 },
{ 5, 3 },
{ 2, 3 }
},
{
{ 8, 9 },
{ 7, 2 },
{ 3, 4 },
{ 5, 1 },
}
};
A three-dimensional array can be thought of as an array of arrays
of arrays
...
In other words, a one-dimensional
array of two elements is constructed first
...
Then, three such twodimensional
arrays are placed one behind the other to yield a threedimensional array containing three 2dimensional arrays
...
Figure
8
...

56
2
2nd 2-D Array
1st 2-D Array
0th 2-D Array
78
33
3
44
4
241
89
76

Figure 8
...
In memory the same array elements are stored
linearly as shown in Figure 8
...

0th 2-D Array 1st 2-D Array 2nd 2-D Array
247834567634532389723451
65478 65494 65510

Figure 8
...
We can therefore say that the
element 1 can be referred as arr[2][3][1]
...
Can we not refer to this element using pointer notation? Of
course, yes
...

Compiler doesn’t perform bounds checking on an array
...
In a 1-D array, zeroth element is a single value,
whereas, in a 2-D array this element is a 1-D array
...

Array elements are stored in contiguous memory locations
and so they can be accessed using pointers
...


Exercise
Simple arrays
[A] What would be the output of the following programs:
(a) main( )

Chapter 8: Arrays 305
{
int num[26], temp ;
num[0] = 100 ;
num[25] = 200 ;
temp = num[25] ;
num[25] = num[0] ;

num[0] = temp ;
printf ( "\n%d %d", num[0], num[25] ) ;
}
(b) main( )
{
int array[26], i ;
for ( i = 0 ; i <= 25 ; i++ )
{
array[i] = 'A' + i ;
printf ( "\n%d %c", array[i], array[i] ) ;
}
}
(c) main( )
{
int sub[50], i ;
for ( i = 0 ; i <= 48 ; i++ ) ;
{
sub[i] = i ;
printf ( "\n%d", sub[i] ) ;
}
}
[B] Point out the errors, if any, in the following program
segments:
(a) /* mixed has some char and some int values */
int char mixed[100] ;
main( )
{
int a[10], i ;

306 Complete Guide To C
for ( i = 1 ; i <= 10 ; i++ )
{
scanf ( "%d", a[i] ) ;
printf ( "%d", a[i] ) ;
}
}
(b) main( )
{
int size ;
scanf ( "%d", &size ) ;
int arr[size] ;
for ( i = 1 ; i <= size ; i++ )
{
scanf ( "%d", arr[i] ) ;
printf ( "%d", arr[i] ) ;
}
}
(c) main( )
{
int i, a = 2, b = 3 ;
int arr[ 2 + 3 ] ;

for ( i = 0 ; i < a+b ; i++ )
{
scanf ( "%d", &arr[i] ) ;
printf ( "\n%d", arr[i] ) ;
}
}
[C] Answer the following:
(a) An array is a collection of
1
...
the same data type scattered throughout memory
3
...
different data types placed next to each other in memory

Chapter 8: Arrays 307
(b) Are the following array declarations correct?
int a (25) ;
int size = 10, b[size] ;
int c = {0,1,2} ;
(c) Which element of the array does this expression reference?
num[4]
(d) What is the difference between the 5’s in these two
expressions? (Select the correct answer)
int num[5] ;
num[5] = 11 ;
1
...
first is array size, second is particular element
3
...
both specify array size
(e) State whether the following statements are True or False:
1
...

2
...
It is necessary to initialize the array at the time of
declaration
...
The expression num[27] designates the twenty-eighth
element in the array
...
The number to be searched is entered through the
keyboard by the user
...


308 Complete Guide To C
(b) Twenty-five numbers are entered from the keyboard into an
array
...

(c) Implement the Selection Sort, Bubble Sort and Insertion sort
algorithms on a set of 25 numbers
...
11 for the
logic of the algorithms)
− Selection sort

− Bubble Sort
− Insertion Sort
Selection Sort
Iteration 1 Iteration 2
0 44 33 33 22 0 11 0 11 0 11
1 33 44 44 44 1 44 1 44 1 33
2 55 55 55 55 2 55 2 55 2 55
3 22 22 22 33 3 33 3 33 3 44
4 11 11 11 11 4 22 4 22 4 22

Iteration 3 Iteration 4
Result
0 11 0 11 0 11 0 11
1 22 1 22 1 22 1 22
2 55 2 44 2 33 2 33
3 44 3 55 3 55 3 44
4 33 4 33 4 44 4 55

Figure 8
...
11 (b)
Insertion Sort
Iteration 1 Iteration 2 Iteration 3 Iteration 4 Result
44 33 33 22 0 11
33 44 44 33 1 22
55 55 55 44 2 33
22 22 22 55 3 44
11 11 11 11 4 55

Figure 8
...
This procedure is
called sieve of Eratosthenes
...

step 3 Proceed to the next non-zero element and set all its
multiples to zero
...

More on arrays, Arrays and pointers

[E] What would be the output of the following programs:
(a) main( )
{
int b[ ] = { 10, 20, 30, 40, 50 } ;
int i ;
for ( i = 0 ; i <= 4 ; i++ )
printf ( "\n%d" *( b + i ) ) ;
}
(b) main( )
{
int b[ ] = { 0, 20, 0, 40, 5 } ;
int i, *k ;
k=b;
for ( i = 0 ; i <= 4 ; i++ )
{
printf ( "\n%d" *k ) ;

Chapter 8: Arrays 311
k++ ;
}
}
(c) main( )
{
int a[ ] = { 2, 4, 6, 8, 10 } ;
int i ;
change ( a, 5 ) ;
for ( i = 0 ; i <= 4 ; i++ )
printf( "\n%d", a[i] ) ;
}
change ( int *b, int n )
{
int i ;
for ( i = 0 ; i < n ; i++ )
*( b + i ) = *( b + i ) + 5 ;
}
(d) main( )
{
int a[5], i, b = 16 ;
for ( i = 0 ; i < 5 ; i++ )
a[i] = 2 * i ;
f ( a, b ) ;
for ( i = 0 ; i < 5 ; i++ )
printf ( "\n%d", a[i] ) ;
printf( "\n%d", b ) ;
}
f ( int *x, int y )
{
int i ;
for ( i = 0 ; i < 5 ; i++ )
*( x + i ) += 2 ;
y += 2 ;

}

312 Complete Guide To C
(e) main( )
{
static int a[5] ;
int i ;
for ( i = 0 ; i <= 4 ; i++ )
printf ( "\n%d", a[i] ) ;
}
(f) main( )
{
int a[5] = { 5, 1, 15, 20, 25 } ;
int i, j, k = 1, m ;
i = ++a[1] ;
j = a[1]++ ;
m = a[i++] ;
printf ( "\n%d %d %d", i, j, m ) ;
}
[F] Point out the errors, if any, in the following programs:
(a) main( )
{
int array[6] = { 1, 2, 3, 4, 5, 6 } ;
int i ;
for ( i = 0 ; i <= 25 ; i++ )
printf ( "\n%d", array[i] ) ;
}
(b) main( )
{
int sub[50], i ;
for ( i = 1 ; i <= 50 ; i++ )
{
sub[i] = i ;
printf ( "\n%d" , sub[i] ) ;
}
}

Chapter 8: Arrays 313
(c) main( )
{
int a[ ] = { 10, 20, 30, 40, 50 } ;
int j ;
j = a ; /* store the address of zeroth element */
j=j+3;
printf ( "\n%d" *j ) ;
}
(d) main( )
{
float a[ ] = { 13
...
5, 1
...
4, 3
...
24, 1
...
5, 5
...
5 } ;
float *j, *k ;
j=a;
k=a+4;
j=j*2;
k=k/2;
printf ( "\n%d %d", *j, *k ) ;
}
(f) main( )
{
int max = 5 ;
float arr[max] ;
for ( i = 0 ; i < max ; i++ )
scanf ( "%f", &arr[i] ) ;
}

314 Complete Guide To C
[G] Answer the following:
(a) What would happen if you try to put so many values into an
array when you initialize it that the size of the array is
exceeded?
1
...
possible system malfunction
3
...
other data may be overwritten
(b) In an array int arr[12] the word arr represents the
a_________ of the array
(c) What would happen if you put too few elements in an array
when you initialize it?
1
...
possible system malfunction
3
...
unused elements will be filled with 0’s or garbage
(d) What would happen if you assign a value to an element of an
array whose subscript exceeds the size of the array?
1
...
nothing, it’s done all the time
3
...
error message from the compiler
(e) When you pass an array as an argument to a function, what
actually gets passed?
1
...
values of the elements of the array
3
...
number of elements of the array

Chapter 8: Arrays 315
(f) Which of these are reasons for using pointers?

1
...
To refer to keywords such as for and if
3
...
To refer to particular programs more conveniently
(g) If you don’t initialize a static array, what would be the
elements set to?
1
...
an undetermined value
3
...
the character constant '\0'
[H] State True or False:
(a)
(b)
(c)
Address of a floating-point variable is always a whole
number
...
float ptr ;
6
...
*float ptr ;
8
...

main( )
{
int j, *ptr ;
*ptr = 35 ;
printf ( "\n%d", j ) ;
}

316 Complete Guide To C
(d) if int s[5] is a one-dimensional array of integers, which of the
following refers to the third element in the array?
9
...
*( s + 3 )
11
...
s + 2
[I] Attempt the following:
(a) Write a program to copy the contents of one array into another
in the reverse order
...

(c) Find the smallest number in an array using pointers
...
The

characters that are displayed on the screen are stored in a
special memory called VDU memory (not to be confused with
ordinary memory)
...
The first of these bytes
contains the ASCII value of the character being displayed,
whereas, the second byte contains the colour in which the
character is displayed
...
Therefore the colour of this
character would be present at location number 0xB8000000 +
1
...

With this knowledge write a program which when executed
would keep converting every capital letter on the screen to
small case letter and every small case letter to capital letter
...

This is an activity of a rampant Virus called Dancing Dolls
...

More than one dimension
[J] What would be the output of the following programs:
(a) main( )
{
int n[3][3] = {
2, 4, 3,
6, 8, 5,
3, 5, 1
};
printf ( "\n%d %d %d", *n, n[3][3], n[2][2] ) ;
}
(b) main( )
{
int n[3][3] = {
2, 4, 3,
6, 8, 5,
3, 5, 1
};
int i, *ptr ;

318 Complete Guide To C
ptr = n ;
for ( i = 0 ; i <= 8 ; i++ )
printf ( "\n%d", *( ptr + i ) ) ;
}
(c) main( )
{
int n[3][3] = {
2, 4, 3,

6, 8, 5,
3, 5, 1
};
int i, j ;
for ( i = 0 ; i <= 2 ; i++ )
for ( j = 0 ; j <= 2 ; j++ )
printf ( "\n%d %d", n[i][j], *( *( n + i ) + j ) ) ;
}
[K] Point out the errors, if any, in the following programs:
(a) main( )
{
int twod[ ][ ] = {
2, 4,
6, 8
};
printf ( "\n%d", twod ) ;
}
(b) main( )
{
int three[3][ ] = {
2, 4, 3,
6, 8, 2,
2, 3 ,1
};
printf ( "\n%d", three[1][1] ) ;

Chapter 8: Arrays 319
}
[L] Attempt the following:
(a) How will you initialize a three-dimensional array
threed[3][2][3]? How will you refer the first and last element
in this array?
(b) Write a program to pick up the largest number from any 5 row
by 5 column matrix
...
The
transpose of a matrix is obtained by exchanging the elements
of each row with the elements of the corresponding column
...
These pieces
can be moved horizontally or vertically
...
12
As you can see there is a blank at bottom right corner
...
Display the numbers in the
above order
...


If user hits say, right arrow key then the piece with a number
5 should move to the right and blank should replace the
original position of 5
...
If left arrow key or up arrow key is hit then no
action should be taken
...

Keep track of the number of moves in which the user manages
to arrange the numbers in ascending order
...

How do we tackle the arrow keys? We cannot receive them
using scanf( ) function
...
Use the following
function in your program
...
Don’t worry about how this function is
written
...
The scan codes for
the arrow keys are:
up arrow key – 72 down arrow key – 80
left arrow key – 75 right arrow key – 77
/* Returns scan code of the key that has been hit */
#include "dos
...
h
...
h
...

(1) Write a program to add two 6 x 6 matrices
...

(3) Write a program to sort all the elements of a 4 x 4 matrix
...

(f) Match the following with reference to the following program
segment:
int i, j, = 25;
int *pi, *pj = & j;
……
...
/* more lines of program */
……
...
The value
assigned to i begin at (hexadecimal) address F9C and the
value assigned to j begins at address F9E
...

1
...
30
2
...
F9E
3
...
35
4
...
FA2

322 Complete Guide To C
5
...
F9C
6
...
67
7
...
unspecified
8
...
65
9
...
F9E
10
...
F9E
k
...
F9D
(g) Match the following with reference to the following segment:
int x[3][5] = {
{ 1, 2, 3, 4, 5 },
{ 6, 7, 8, 9, 10 },
{ 11, 12, 13, 14, 15 }
}, *n = &x ;
1
...
9
2
...
13
3
...
4
4
...
3
5
...
2
6
...
12
7
...
14
8
...
7
9
...
1
10
...
8
k
...
10
m
...
*( i + 3 ) a
...
s[i[7]]
...
2
3
...
y c
...
i[i[1]-i[2]] d
...
i[s[3]
...
16
6
...
15
7
...
25
8
...
y + 10 h
...
( *(s + *( i + 1) / *i ) )
...
1
10
...
100
k
...
20
(i) Match the following with reference to the following program
segment:
unsigned int arr[3][3] = {
2, 4, 6,
9, 1, 10,
16, 64, 5
};
1
...
64
2
...
18
3
...
6
4
...
3
5
...
0
6
...
16
7
...
1
8
...
11
9
...
20
10
...
2
k
...
4
(j) Write a program that interchanges the odd and even
components of an array
...


324 Complete Guide To C
(l) Write a function to find the norm of a matrix
...

(m) Given an array p[5], write a function to shift it circularly left
by two positions
...
Call this function for a
(4 x 5 ) matrix and get its rows left shifted
...
Write a program to obtain the
Determinant values of this matrix
...

-6, -12, 8, 13, 11, 6, 7, 2, -6, -9, -10, 11, 10, 9, 2
The formula for standard deviation is

n
xx
i

( − )2

where x
i is the data item and x is the mean
...

Area = (1 / 2 ) ab sin ( angle )
Given the following 6 triangular pieces of land, write a
program to find their area and determine which is largest,
Plot No
...
4 80
...
78
2 155
...
62 0
...
3 97
...
35

Chapter 8: Arrays 325
4 160
...
25 9
...
6 68
...
25
6 149
...
0 1
...
22 102
...
87 100
...
85 97
...
23 97
...
06 98
...
29 98
...
29 100
...
14 97
...
12 91
...
71 94
...
15 94
...
0 1
...
5 2
...
5 3
...
5 5
...
5 6
...
5 7
...
0 9
...
0 10
...
5 12
...
0 14
...
Write a program to find the distance of
last point from the first point (sum of distance between
consecutive points)
...
With this knowledge under your belt,
you should be ready to handle strings, which are, simply put, a
special kind of array
...


I
What are Strings
The way a group of integers can be stored in an integer array,
similarly a group of characters can be stored in a character array
...
Many
languages internally treat strings as character arrays, but somehow
conceal this fact from the programmer
...

A string constant is a one-dimensional array of characters
terminated by a null ( ‘\0’ )
...
What character is this? It looks like
two characters, but it is actually only one character, with the \
indicating that what follows it is something special
...
Note that ‘\0’ and ‘0’ are not same
...
Figure 9
...
Note that the elements
of the character array are stored in contiguous memory locations
...
In fact, a string not terminated by a ‘\0’ is not really a string,
but merely a collection of characters
...
1
65518 65519 65520 65521 65522 65523 65524 65525
H A E S L E R \0

C concedes the fact that you would use strings very often and
hence provides a shortcut for initializing strings
...
C inserts the
null character automatically
...

/* Program to demonstrate printing of a string */
main( )

{
char name[ ] = "Klinsman" ;
int i = 0 ;
while ( i <= 7 )
{
printf ( "%c", name[i] ) ;
i++ ;
}

330 Complete Guide To C
}
And here is the output
...
We have initialized a character array, and then printed
out the elements of this array within a while loop
...

Following program illustrates this
...

Klinsman
This program doesn’t rely on the length of the string (number of
characters in it) to print out its contents and hence is definitely
more general than the earlier one
...

main( )
{
char name[ ] = "Klinsman" ;
char *ptr ;

Chapter 9: Puppetting On Strings 331
ptr = name ; /* store base address of string */
while ( *ptr != `\0' )
{
printf ( "%c", *ptr ) ;
ptr++ ;
}
}
As with the integer array, by mentioning the name of the array we
get the base address (address of the zeroth element) of the array
...
This derives from two facts: array elements are stored in
contiguous memory locations and on incrementing a pointer it
points to the immediately next location of its type
...

In fact, the character array elements can be accessed exactly in the
same way as the elements of an integer array
...

This is because printf( ) function has got a sweet and simple way
of doing it, as shown below
...

main( )
{
char name[ ] = "Klinsman" ;
printf ( "%s", name ) ;
}
The %s used in printf( ) is a format specification for printing out a
string
...

main( )
{
char name[25] ;
printf ( "Enter your name " ) ;
scanf ( "%s", name ) ;
printf ( "Hello %s!", name ) ;
}
And here is a sample run of the program
...
Once enter is hit, scanf( ) places a ‘\0’ in the array
...


Chapter 9: Puppetting On Strings 333
While entering the string using scanf( ) we must be cautious about
two things:
(a)
(b)

The length of the string should not exceed the dimension of
the character array
...
Hence, if you
carelessly exceed the bounds there is always a danger of
overwriting something important, and in that event, you
would have nobody to blame but yourselves
...

Therefore names such as ‘Debashish Roy’ would be
unacceptable
...
The usage of functions gets( ) and
its counterpart puts( ) is shown below
...

Enter your name Debashish Roy
Hello!
Debashish Roy
The program and the output are self-explanatory except for
the fact that, puts( ) can display only one string at a time
(hence the use of two puts( ) in the program above)
...
Though gets( ) is capable of receiving only

334 Complete Guide To C
one string at a time, the plus point with gets( ) is that it can
receive a multi-word string
...


Pointers and Strings
Suppose we wish to store “Hello”
...
This
is shown below:
char str[ ] = "Hello" ;
char *p = "Hello" ;
There is a subtle difference in usage of these two forms
...
This is shown in the
following program
...
Unlike strings, such an operation is
perfectly valid with char pointers
...
Figure 9
...

Function Use
strlen Finds length of a string
strlwr Converts a string to lowercase
strupr Converts a string to uppercase
strcat Appends one string at the end of another
strncat Appends first n characters of a string at the end of
another

336 Complete Guide To C
strcpy Copies a string into another
strncpy Copies first n characters of one string into another
strcmp Compares two strings
strncmp Compares first n characters of two strings
strcmpi Compares two strings without regard to case ("i" denotes
that this function ignores case)
stricmp Compares two strings without regard to case (identical to
strcmpi)
strnicmp Compares first n characters of two strings without regard
to case
strdup Duplicates a string
strchr Finds first occurrence of a given character in a string
strrchr Finds last occurrence of a given character in a string
strstr Finds first occurrence of a given string in another string
strset Sets all characters of string to a given character
strnset Sets first n characters of a string to a given character
strrev Reverses string

Figure 9
...
This will also illustrate how the library
functions in general handle strings
...


strlen( )
This function counts the number of characters present in a string
...

main( )
{
char arr[ ] = "Bamboozled" ;
int len1, len2 ;

Chapter 9: Puppetting On Strings 337
len1 = strlen ( arr ) ;
len2 = strlen ( "Humpty Dumpty" ) ;
printf ( "\nstring = %s length = %d", arr, len1 ) ;
printf ( "\nstring = %s length = %d", "Humpty Dumpty", len2 ) ;
}
The output would be
...
While calculating the length it doesn’t count
‘\0’
...
Can we not write a function xstrlen( ) which imitates
the standard library function strlen( )? Let us give it a try
...


string = Bamboozled length = 10
string = Humpty Dumpty length = 13
The function xstrlen( ) is fairly simple
...
Or in other
words keep counting characters till the pointer s doesn’t point to
‘\0’
...
The
base addresses of the source and target strings should be supplied
to this function
...

main( )
{
char source[ ] = "Sayonara" ;

Chapter 9: Puppetting On Strings 339
char target[20] ;
strcpy ( target, source ) ;
printf ( "\nsource string = %s", source ) ;
printf ( "\ntarget string = %s", target ) ;
}
And here is the output
...
It is our responsibility to
see to it that the target string’s dimension is big enough to hold the
string being copied into it
...
There is no short cut for this
...

main( )
{
char source[ ] = "Sayonara" ;
char target[20] ;
xstrcpy ( target, source ) ;
printf ( "\nsource string = %s", source ) ;
printf ( "\ntarget string = %s", target ) ;
}
xstrcpy ( char *t, char *s )
{
while ( *s != '\0' )
{
*t = *s ;
s++ ;

340 Complete Guide To C
t++ ;
}
*t = '\0' ;
}

The output of the program would be
...

If you look at the prototype of strcpy( ) standard library function,
it looks like this…
strcpy ( char *t, const char *s ) ;
We didn’t use the keyword const in our version of xstrcpy( ) and
still our function worked correctly
...

s=s-8;
*s = 'K' ;
This would change the source string to “Kayonara”
...
Thus the const
qualifier ensures that your program does not inadvertently alter a
variable that you intended to be a constant
...

We can use const in several situations
...

char *p = "Hello" ; /* pointer is variable, so is string */
*p = 'M' ; /* works */
p = "Bye" ; /* works */
const char *q = "Hello" ; /* string is fixed pointer is not */
*q = 'M' ; /* error */
q = "Bye" ; /* works */
char const *s = "Hello" ; /* string is fixed pointer is not */
*s = 'M' ; /* error */
s = "Bye" ; /* works */
char * const t = "Hello" ; /* pointer is fixed string is not */
*t = 'M' ; /* works */
t = "Bye" ; /* error */

const char * const u = "Hello" ; /* string is fixed so is pointer */
*u = 'M' ; /* error */
u = "Bye" ; /* error */

342 Complete Guide To C
The keyword const can be used in context of ordinary variables
like int, float, etc
...

main( )
{
float r, a ;
const float pi = 3
...
For example, “Bombay” and “Nagpur” on concatenation
would result into a string “BombayNagpur”
...

main( )
{
char source[ ] = "Folks!" ;
char target[30] = "Hello" ;
strcat ( target, source ) ;
printf ( "\nsource string = %s", source ) ;
printf ( "\ntarget string = %s", target ) ;
}
And here is the output
...
I leave it to you to develop your own xstrcat( ) on
lines of xstrlen( ) and xstrcpy( )
...
The two strings are compared character
by character until there is a mismatch or end of one of the strings
is reached, whichever occurs first
...
If they’re not, it returns the numeric
difference between the ASCII values of the first non-matching
pairs of characters
...

main( )
{
char string1[ ] = "Jerry" ;
char string2[ ] = "Ferry" ;

int i, j, k ;
i = strcmp ( string1, "Jerry" ) ;
j = strcmp ( string1, string2 ) ;
k = strcmp ( string1, "Jerry boy" ) ;
printf ( "\n%d %d %d", i, j, k ) ;
}
And here is the output
...
In the
second call, the first character of “Jerry” doesn't match with the
first character of “Ferry” and the result is 4, which is the numeric

344 Complete Guide To C
difference between ASCII value of ‘J’ and ASCII value of ‘F’
...
The value returned is -32, which is the value
of null character minus the ASCII value of space, i
...
, ‘\0’ minus
‘ ’, which is equal to -32
...
All we usually
want to know is whether or not the first string is alphabetically
before the second string
...
Any non-zero value means there
is a mismatch
...


Two-Dimensional Array of Characters
In the last chapter we saw several examples of 2-dimensional
integer arrays
...
Our example program asks you to type your name
...
Here’s the program
...

Enter your name dinesh
Sorry, you are a trespasser
Enter your name raman
Welcome, you can enter the palace
Notice how the two-dimensional character array has been
initialized
...
The first subscript gives the number of names in the
array, while the second subscript gives the length of each item in
the array
...

for ( i = 0 ; i <= 5 ; i++ )
scanf ( "%s", &masterlist[i][0] ) ;

346 Complete Guide To C
While comparing the strings through strcmp( ), note that the
addresses of the strings are being passed to strcmp( )
...

The variable flag is used to keep a record of whether the control
did reach inside the if or not
...
Later through the loop if the names match, flag is
set to FOUND
...

The names would be stored in the memory as shown in Figure 9
...

Note that each string ends with a ‘\0’
...

65454 a k s h a y \0
65464 p a r a g \0
65474 r a m a n \0
65484 s r i n i v a s \0
65494 g o p a l \0
65504 r a j e s h \0 65513
(last location)

Figure 9
...
are the base addresses of
successive names
...
For example,
even though 10 bytes are reserved for storing the name “akshay”,
it occupies only 7 bytes
...
Similarly, for
each name there is some amount of wastage
...
Can this not be
avoided? Yes, it can be
...


Array of Pointers to Strings
As we know, a pointer variable always contains an address
...
Let us see how the names in the earlier
example can be stored in the array of pointers
...
It contains base
addresses of respective names
...
This is depicted in Figure 9
...


348 Complete Guide To C
Figure 9
...
As against this, in array of pointers, the strings occupy only
41 bytes—a net saving of 19 bytes
...
But realize that actually 19 bytes are not saved, since
12 bytes are sacrificed for storing the addresses in the array
names[ ]
...

Another reason to use an array of pointers to store strings is to

obtain greater ease in manipulation of the strings
...
The first one uses a two-dimensional
array of characters to store the names, whereas the second uses an
array of pointers to strings
...
We want to exchange the position of the names
“raman” and “srinivas”
...

Original: raman srinivas
New: srinivas raman
Note that in this program to exchange the names we are required to
exchange corresponding characters of the two names
...

Let us see, if the number of exchanges can be reduced by using an
array of pointers to strings
...

main( )
{
char *names[ ] = {

350 Complete Guide To C
"akshay",
"parag",
"raman",
"srinivas",
"gopal",
"rajesh"
};
char *temp ;
printf ( "Original: %s %s", names[2], names[3] ) ;

temp = names[2] ;
names[2] = names[3] ;
names[3] = temp ;
printf ( "\nNew: %s %s", names[2], names[3] ) ;
}
And here is the output
...
In this program all that
we are required to do is exchange the addresses (of the names)
stored in the array of pointers, rather than the names themselves
...
This makes handling strings very convenient
...
That is why, even though
in principle strings can be stored and handled through a twodimensional array of characters, in actual
practice it is the array of
pointers to strings, which is more commonly used
...
However,
when we are using an array of pointers to strings we can initialize
the strings at the place where we are declaring the array, but we
cannot receive the strings from keyboard using scanf( )
...

main( )
{
char *names[6] ;
int i ;
for ( i = 0 ; i <= 5 ; i++ )
{
printf ( "\nEnter name " ) ;
scanf ( "%s", names[i] ) ;
}
}
The program doesn’t work because; when we are declaring the
array it is containing garbage values
...


Solution
If we are bent upon receiving the strings from keyboard using
scanf( ) and then storing their addresses in an array of pointers to
strings we can do it in a slightly round about manner as shown
below
...
h"
main( )

352 Complete Guide To C
{
char *names[6] ;
char n[50] ;
int len, i ;
char *p ;
for ( i = 0 ; i <= 5 ; i++ )
{
printf ( "\nEnter name " ) ;
scanf ( "%s", n ) ;
len = strlen ( n ) ;
p = malloc ( len + 1 ) ;
strcpy ( p, n ) ;
names[i] = p ;
}
for ( i = 0 ; i <= 5 ; i++ )
printf ( "\n%s", names[i] ) ;
}
Here we have first received a name using scanf( ) in a string n[ ]
...
This memory allocation has
been done using a standard library function called malloc( )
...
The
address returned by this function is always of the type void *
...
Typecasting is discussed in detail in Chapter 15
...
h’
...

But why did we not use array to allocate memory? This is because
with arrays we have to commit to the size of the array at the time
of writing the program
...
In other
words, when we use arrays static memory allocation takes place
...
The argument that we pass to malloc( ) can be a
variable whose value can change during execution
...

This solution suffers in performance because we need to allocate
memory and then do the copying of string for each name received
through the keyboard
...

Being an array, all the characters of a string are stored in
contiguous memory locations
...

Both printf( ) and puts( ) can handle multi-word strings
...
More importantly we imitated
some of these functions to learn how these standard library
functions are written
...

malloc( ) function can be used to allocate space in memory on
the fly during execution of the program
...

A string is terminated by a ______ character, which is written
as ______
...

The array elements are always stored in _________ memory
locations
...

Write a program that extracts part of the given string from the
specified position
...

Moreover, if the position from where the string is to be
extracted is given and the number of characters to be
extracted is 0 then the program should extract entire string
from the specified position
...

Write a program that replaces two or more consecutive blanks
in a string by a single blank
...

Receive two strings str1 and str2 and check if str1 is
embedded in any of the strings in str[ ]
...

char *str[ ] = {
"We will teach you how to
...
all through C!"
};
For example if str1 contains "mountain" and str2 contains
"car", then the second string in str should get changed to
"Move a car"
...

Write a program to reverse the strings stored in the following
array of pointers to strings:
char *s[ ] = {
"To err is human
...
",
"One needs to know C!!"
};

Chapter 9: Puppetting On Strings 359
Hint: Write a function xstrrev ( string ) which should reverse
the contents of one string
...

(d) Develop a program that receives the month and year from the
keyboard as integers and prints the calendar in the following
format
...
With this as the base the calendar should be
generated
...

Hint: Use the getkey( ) function discussed in Chapter 8,
problem number [L](c)
...

An inventory table is updated for each division and for each
product as they are received
...

(b) Write a program to take a transaction and update the
inventory
...

A dequeue is an ordered set of elements in which elements
may be inserted or retrieved from either end
...
Exceptional
conditions such as dequeue full or empty should be indicated
...

Write a program to delete all vowels from a sentence
...

Write a program that will read a line and delete from it all
occurrences of the word ‘the’
...

Write a program to count the number of occurrences of any
two vowels in succession in a line of text
...


10 Structures
• 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

363
364 Complete Guide To C
hich mechanic is good enough who knows how to repair
only one type of vehicle? None
...
It wouldn’t have been so popular had it been
able to handle only all ints, or all floats or all chars at a time
...
Instead we deal with entities that are
collections of things, each thing having its own attributes, just as
the entity we call a ‘book’ is a collection of things such as title,
author, call number, publisher, number of pages, date of
publication, etc
...

For dealing with such collections, C provides a data type called
‘structure’
...
And structure is the topic
of this chapter
...
These two data types can
handle a great variety of situations
...

For example, suppose you want to store data about a book
...
If data about say 3 such books is to
be stored, then we can follow two approaches:
(a)
(b)
Construct individual arrays, one for storing names, another for
storing prices and still another for storing number of pages
...

Let us examine these two approaches one by one
...
Let us begin with a program that uses
arrays
...
of pages of 3 books\n" ) ;
for ( i = 0 ; i <= 2 ; i++ )
scanf ( "%c %f %d", &name[i], &price[i], &pages[i] );
printf ( "\nAnd this is what you entered\n" ) ;
for ( i = 0 ; i <= 2 ; i++ )
printf ( "%c %f %d\n", name[i], price[i], pages[i] );
}
And here is the sample run
...
of pages of 3 books
A 100
...
50 682
F 233
...
000000 354
C 256
...
700000 512
This approach no doubt allows you to store names, prices and
number of pages
...


366 Complete Guide To C
The program becomes more difficult to handle as the number of
items relating to the book go on increasing
...
To solve
this problem, C provides a special data type—the structure
...

These data types may or may not be of the same type
...

main( )
{
struct book

{
char name ;
float price ;
int pages ;
};
struct book b1, b2, b3 ;
printf ( "\nEnter names, prices & no
...
name, &b1
...
pages ) ;
scanf ( "%c %f %d", &b2
...
price, &b2
...
name, &b3
...
pages ) ;
printf ( "\nAnd this is what you entered" ) ;
printf ( "\n%c %f %d", b1
...
price, b1
...
name, b2
...
pages ) ;
printf ( "\n%c %f %d", b3
...
price, b3
...

Enter names, prices and no
...
00 354
C 256
...
70 512

Chapter 10: Structures 367
And this is what you entered
A 100
...
500000 682
F 233
...


Declaring a Structure
In our example program, the following statement declares the
structure type:
struct book
{
char name ;
float price ;
int pages ;
};
This statement defines a new data type called struct book
...
The general form of a structure declaration statement is
given below:
struct
{
structure element 1 ;
structure element 2 ;
structure element 3 ;

...


368 Complete Guide To C
};
Once the new structure data type has been defined one or more
variables can be declared to be of that type
...
It makes available
space to hold all the elements in the structure—in this case, 7
bytes—one for name, four for price and two for pages
...

If we so desire, we can combine the declaration of the structure
type and the structure variables in one statement
...

struct book
{
char name ;
float price ;
int pages ;
} b1, b2, b3 ;
or even
...
The format used is quite
similar to that used to initiate arrays
...
00, 550 } ;
struct book b2 = { "Physics", 150
...

It is important to understand that a structure type declaration
does not tell the compiler to reserve any space in memory
...

Usually structure type declaration appears at the top of the
source code file, before any variables or functions are defined
...


370 Complete Guide To C
Accessing Structure Elements
Having declared the structure type and the structure variables, let
us see how the elements of the structure can be accessed
...
Structures use a different scheme
...
)
operator
...
pages
Similarly, to refer to price we would use,
b1
...


How Structure Elements are Stored
Whatever be the elements of a structure, they are always stored in
contiguous memory locations
...
00, 550 } ;
printf ( "\nAddress of name = %u", &b1
...
price ) ;
printf ( "\nAddress of pages = %u", &b1
...

Address of name = 65518
Address of price = 65519
Address of pages = 65523

Actually the structure elements are stored in memory as shown in
the Figure 10
...

65518 65519 65523
‘B’ 130
...
name b1
...
pages

Figure 10
...
All it does is, it receives values into various structure
elements and output these values
...
show how structure types are created, how structure
variables are declared and how individual elements of a structure
variable are referenced
...
A better approach would
be to use an array of structures
...


372 Complete Guide To C
/* Usage of an array of structures */
main( )
{
struct book
{
char name ;
float price ;
int pages ;
};
struct book b[100] ;
int i ;
for ( i = 0 ; i <= 99 ; i++ )
{
printf ( "\nEnter name, price and pages " ) ;
scanf ( "%c %f %d", &b[i]
...
price, &b[i]
...
name, b[i]
...
pages ) ;
}
linkfloat( )
{
float a = 0, *b ;
b = &a ; /* cause emulator to be linked */
a = *b ; /* suppress the warning - variable not used */
}
Now a few comments about the program:
(a) Notice how the array of structures is declared
...

(b) The syntax we use to reference each element of the array b is
similar to the syntax used for arrays of ints and chars
...
price
...
pages
...
He first defined array as a collection
of similar elements; then realized that dissimilar data types
that are often found in real life cannot be handled using
arrays, therefore created a new data type called structure
...
Therefore he
allowed us to create an array of structures; an array of similar
data types which themselves are a collection of dissimilar data
types
...
Since each element of this array is
a structure, and since all structure elements are always stored
in adjacent locations you can very well visualise the
arrangement of array of structures in memory
...

What is the function linkfloat( ) doing here? If you don’t
define it you are bound to get the error "Floating Point
Formats Not Linked" with majority of C Compilers
...
A floating point emulator is used to manipulate
floating point numbers in runtime library functions like

374 Complete Guide To C
scanf( ) and atof( )
...
The most common is
using scanf( ) to read a float in an array of structures as
shown in our program
...
It forces linking of the
floating-point emulator into an application
...


Additional Features of Structures
Let us now explore the intricacies of structures with a view of
programming convenience
...
It is not necessary to copy the structure elements
piece-meal
...
This is shown in the following example
...
50 } ;
struct employee e2, e3 ;
/* piece-meal copying */
strcpy ( e2
...
name ) ;
e2
...
age ;

Chapter 10: Structures 375
e2
...
salary ;
/* copying all elements at one go */
e3 = e2 ;
printf ( "\n%s %d %f", e1
...
age, e1
...
name, e2
...
salary ) ;
printf ( "\n%s %d %f", e3
...
age, e3
...

Sanjay 30 5500
...
500000
Sanjay 30 5500
...

As we saw earlier, for copying arrays we have to copy the
contents of the array element by element
...
Had this not been so, we would
have been required to copy structure variables element by
element
...

(b) One structure can be nested within another structure
...
The following
program shows nested structures at work
...
name, e
...
phone ) ;
printf ( "\ncity = %s pin = %d", e
...
city, e
...
pin ) ;
}
And here is the output
...
For this the dot operator is
used twice, as in the expression,
e
...
pin or e
...
city
Of course, the nesting process need not stop at this level
...
till the
time we can comprehend the structure ourselves
...
engine
...
large
...

(c) Like an ordinary variable, a structure variable can also be
passed to a function
...
Let us
examine both the approaches one by one using suitable
programs
...
name, b1
...
callno ) ;
}
display ( char *s, char *t, int n )
{
printf ( "\n%s %s %d", s, t, n ) ;
}
And here is the output
...
Therefore, when we call
the function display( ) using,
display ( b1
...
author, b1
...
Thus, this is a mixed
call—a call by reference as well as a call by value
...
A better way would be to pass the
entire structure variable at a time
...

struct book
{
char name[25] ;
char author[25] ;
int callno ;
};
main( )
{
struct book b1 = { "Complete Guide To C", "YPK", 101 } ;
display ( b1 ) ;
}
display ( struct book b )
{
printf ( "\n%s %s %d", b
...
author, b
...

Complete Guide To C YPK 101
Note that here the calling of function display( ) becomes quite
compact,
display ( b1 ) ;

Chapter 10: Structures 379
Having collected what is being passed to the display( )
function, the question comes, how do we define the formal
arguments in the function
...
Therefore, it becomes necessary to define
the structure type struct book outside main( ), so that it
becomes known to all functions in the program
...
Such pointers are known as ‘structure pointers’
...

main( )
{

struct book
{
char name[25] ;
char author[25] ;
int callno ;
};
struct book b1 = { "Complete Guide To C", "YPK", 101 } ;
struct book *ptr ;
ptr = &b1 ;
printf ( "\n%s %s %d", b1
...
author, b1
...
The second printf( ) however is
peculiar
...
name or ptr
...
In such cases
C provides an operator ->, called an arrow operator to refer to
the structure elements
...
’ structure operator, there must always be a structure
variable, whereas on the left hand side of the ‘->’ operator
there must always be a pointer to a structure
...
2
...
name b1
...
callno
Complete Guide To C YPK 101
ptr
65524
65472

Figure 10
...
The following program demonstrates this
...

Complete Guide To C YPK 101
Again note that to access the structure elements using pointer
to a structure we have to use the ‘->’ operator
...

(e) Consider the following code snippet:
struct emp
{
int a ;
char ch ;
float s ;
};
struct emp e ;
printf ( "%u %u %u", &e
...
ch, &e
...


382 Complete Guide To C
However, if we run the same program using VC++ compiler
then the output turns out to be:
1245044 1245048 1245052
It can be observed from this output that the float doesn’t get
stored immediately after the char
...
Let us understand the reason for
this
...
The architecture of this microprocessor
is such that it is able to fetch the data that is present at an
address, which is a multiple of four much faster than the data
present at any other address
...
That’s the reason why there were three holes created
between the char and the float
...
For example,
suppose we wish to read the contents of the boot sector (first
sector on the floppy/hard disk) into a structure
...

The #pragma pack directive offers a way to fulfill this
requirement
...
The pragma takes effect at the first
structure declaration after the pragma is seen
...

The following code shows how to use this directive
...
a, &e
...
s ) ;
Here, #pragma pack ( 1 ) lets each structure element to begin
on a 1-byte boundary as justified by the output of the program
given below:
1245044 1245048 1245049

Uses of Structures
Where are structures useful? The immediate application that
comes to the mind is Database Management
...
But
mind you, use of structures stretches much beyond database
management
...
Some of these applications would be discussed

in Chapters 16 to 19
...

Structure elements can be accessed through a structure
variable using a dot (
...

Structure elements can be accessed through a pointer to a
structure using the arrow (->) operator
...

It is possible to pass a structure variable to a function either
by value or by address
...


Exercise
[A] What would be the output of the following programs:
(a) main( )
{
struct gospel
{
int num ;
char mess1[50] ;
char mess2[50] ;
}m;
m
...
mess1, "If all that you have is hammer" ) ;
strcpy ( m
...
num, m
...
mess2 ) ;
}

Chapter 10: Structures 385
(b) struct gospel
{
int num ;
char mess1[50] ;
char mess2[50] ;
} m1 = { 2, "If you are driven by success",
"make sure that it is a quality drive"
};
main( )
{
struct gospel m2, m3 ;
m2 = m1 ;
m3 = m2 ;

printf ( "\n%d %s %s", m1
...
mess1, m3
...
name, "Hacker" ) ;
age = 25 ;
printf ( "\n%s %d", e
...
name, e
...
signature, v
...
55 } ;
f ( var ) ;
g ( &var ) ;
}
f ( struct s v )
{
printf ( "\n%c %d %f", v -> ch, v -> i, v -> a ) ;
}

Chapter 10: Structures 387
g ( struct s *v )
{
printf ( "\n%c %d %f", v
...
i, v
...
i = 100 ;
var2
...
p = &var2 ;
var2
...
p -> i, var2
...
What would you
prefer, an array or a structure?
(b) Given the statement,
maruti
...
bolts = 25 ;
which of the following is True?
1
...
structure engine is nested within structure maruti
3
...
structure maruti is nested within structure bolts
(c) State True or False:
1
...


388 Complete Guide To C
2
...

3
...

(d) struct time
{
int hours ;

int minutes ;
int seconds ;
}t;
struct time *tt ;
tt = &t ;
Looking at the above declarations, which of the following
refers to seconds correctly:
1
...
seconds
2
...
seconds
3
...
t
4
...

(a) Write a function to print names of all students who joined
in a particular year
...


Chapter 10: Structures 389
(b) Create a structure to specify data of customers in a bank
...
Assume maximum of 200 customers in the bank
...
100
...
no, amount, code (1 for deposit, 0 for withdrawal)
Write a program to give a message, “The balance is
insufficient for the specified withdrawal”
...
The other characteristics of parts to
be specified in a structure are: Year of manufacture, material
and quantity manufactured
...

(b) Write a program to retrieve information on parts with
serial numbers between BB1 and CC6
...
Create an array of structure to hold
records of 20 such cricketer and then write a program to read
these records and arrange them in ascending order by average
runs
...

(e) There is a structure called employee that holds information
like employee code, name, date of joining
...

Then ask the user to enter current date
...

(f) Write a menu driven program that depicts the working of a
library
...
Add book information
2
...
List all books of given author
4
...
List the count of books in the library
6
...
Exit
Create a structure called library to hold accession number,
title of the book, author name, price of the book, and flag
indicating whether book is issued or not
...
To store date
use structure say date that contains three members namely
date, month and year
...

(h) Linked list is a very common data structure often used to store
similar data in memory
...
The
individual elements are stored “somewhere” in memory,
rather like a family dispersed, but still bound together
...
Thus, a linked list is a collection of elements called
nodes, each of which stores two item of information—an
element of the list, and a link, i
...
, a pointer or an address that
indicates explicitly the location of the node containing the
successor of this list element
...

Also write a function display( ) which display all the nodes
present in the linked list
...
This end is often known as ‘top’ of stack
...
There are several application where stack can be put to
use
...
Write a program to implement
a stack using a linked list
...
Write a
program to implement a queue using a linked list
...
In keeping with this intention he
deliberately omitted everything related with Input/Output
(I/O) from his definition of the language
...
), or for sending data to the output devices (like
say VDU, disk, etc
...


A
Types of I/O
Though C has no provision for I/O, it of course has to be dealt with
at some point or the other
...
Each
Operating System has its own facility for inputting and outputting
data from and to the files and devices
...

The developers of C Compilers do just that
...
These libraries are
available with all C compilers
...

Do understand that the I/O facilities with different operating
systems would be different
...
For
example, the standard library function printf( ) for DOS-based C
compiler has been written keeping in mind the way DOS outputs
characters to screen
...
We as programmers do not have to
bother about which printf( ) has been written in what manner
...
Same is true about all other standard
library functions available for I/O
...
These can
be classified into three broad categories:
(a) Console I/O functions - Functions to receive input
from keyboard and write
output to VDU
...

In this chapter we would be discussing only Console I/O functions
...


Console I/O Functions
The screen and keyboard together are called a console
...
The basic
difference between them is that the formatted functions allow the
input read from the keyboard or the output displayed on the VDU
to be formatted as per our requirements
...
can be
controlled using formatted functions
...
1
...


396 Complete Guide To C
Console Input/Output functions
Formatted functions Unformatted functions
Type Input Output Type Input Output
char scanf( ) printf( ) char getch( )
getche( )
getchar( )
putch( )
putchar( )
int scanf( ) printf( ) int - float scanf( ) printf( ) float - string scanf( ) printf( ) string gets( ) puts( )

Figure 11
...
1 the functions printf( ), and
scanf( ) fall under the category of formatted console I/O functions
...
Let us discuss these
functions one by one
...
Well, better late than never
...

printf ( "format string", list of variables ) ;
The format string can contain:
Characters that are simply printed as they are
Conversion specifications that begin with a % sign
(a)
(b)

Chapter 11: Console Input/Output 397
(c) Escape sequences that begin with a \ sign
For example, look at the following program:
main( )
{
int avg = 346 ;
float per = 69
...

Average = 346
Percentage = 69
...
For this it examines the format string from left to right
...
In this
example Average = is dumped on the screen
...
In this example, the moment %d is met the
variable avg is picked up and its value is printed
...
In this
example, the moment \n is met it places the cursor at the beginning
of the next line
...

Format Specifications
The %d and %f used in the printf( ) are called format specifiers
...
Following is the list of format
specifiers that can be used with the printf( ) function
...
2
We can provide following optional specifiers in the format
specifications
...
Decimal point separating field width from precision
(precision stands for the number of places after the
decimal point)
dd Digits specifying precision
- Minus sign for left justifying the output in the
specified field width

Figure 11
...

The field-width specifier tells printf( ) how many columns on
screen should be used while printing a value
...
If the value to be printed happens not to fill up the
entire field, the value is right justified and is padded with blanks
on the left
...
Here is an example that should
make this point clear
...

Columns 0123456789012345678901234567890
weight is 63 kg
weight is 63 kg
weight is 63 kg
weight is 63 kg
weight is 63 kg
Specifying the field width can be useful in creating tables of
numeric values, as the following program demonstrates
...
0, 13
...
9 ) ;

400 Complete Guide To C
printf ( "\n%f %f %f", 305
...
9, 3005
...

5
...
500000 133
...
000000 1200
...
300000
Even though the numbers have been printed, the numbers have not
been lined up properly and hence are hard to read
...

main( )
{
printf ( "\n%10
...
1f %10
...
0, 13
...
9 ) ;
printf ( "\n%10
...
1f %10
...
0, 1200
...
3 );
}
This results into a much better output
...
0 13
...
9
305
...
9 3005
...
The following program would clarify this point:
/* Formatting strings with printf( ) */
main( )
{
char firstname1[ ] = "Sandy" ;
char surname1[ ] = "Malya" ;
char firstname2[ ] = "AjayKumar" ;
char surname2[ ] = "Gurubaxani" ;
printf ( "\n%20s%20s", firstname1, surname1 ) ;
printf ( "\n%20s%20s", firstname2, surname2 ) ;

Chapter 11: Console Input/Output 401
}
And here’s the output
...
This helps lining up names of different lengths
properly
...

Escape Sequences
We saw earlier how the newline character, \n, when inserted in a
printf( )’s format string, takes the cursor to the beginning of the
next line
...

The following example shows usage of \n and a new escape
sequence \t, called ‘tab’
...

A 80-column screen usually has 10 tab stops
...
Printing a tab
takes the cursor to the beginning of next printing zone
...


main( )
{
printf ( "You\tmust\tbe\tcrazy\nto\thate\tthis\tbook" ) ;
}

402 Complete Guide To C
And here’s the output
...
The
tab and newline are probably the most commonly used escape
sequences, but there are others as well
...
4 shows a
complete list of these escape sequences
...
Seq
...
Seq
...
4
The first few of these escape sequences are more or less selfexplanatory
...
\r takes the cursor to the beginning of the line in
which it is currently placed
...
Form feed advances the computer
stationery attached to the printer to the top of the next page
...
the single quote,
double quote, and the backslash can be printed by preceding them
with the backslash
...

He said, "Let's do it!"
So far we have been describing printf( )’s specification as if we
are forced to use only %d for an integer, only %c for a char, only
%s for a string and so on
...
In fact, printf( )
uses the specification that we mention and attempts to perform the
specified conversion, and does its best to produce a proper result
...
Sometimes the result is useful, as in the
case we ask printf( ) to print ASCII value of a character using
%d
...

The following program shows a few of these conversions, some
sensible, some weird
...
55 ;
char s[ ] = "hello there !" ;
printf ( "\n%c %d %f", ch, ch, ch ) ;
printf ( "\n%s %d %f", s, s, s ) ;
printf ( "\n%c %d %f",i ,i, i ) ;
printf ( "\n%f %d\n", a, a ) ;
}
And here’s the output
...
000000
hello there ! 3280 9362831782501783000000000000000000000000000
...
000000

404 Complete Guide To C
12
...
Some
of the conversions you would find are quite sensible
...
scanf( ) allows us to
enter data from keyboard that will be formatted in a certain way
...
This is necessary because the values received from
keyboard must be dropped into variables corresponding to these
addresses
...
Do not
include these escape sequences in the format string
...


sprintf( ) and sscanf( ) Functions
The sprintf( ) function works similar to the printf( ) function
except for one small difference
...
The following program illustrates this
...
14 ;
char str[20] ;
printf ( "\n%d %c %f", i, ch, a ) ;
sprintf ( str, "%d %c %f", i, ch, a ) ;
printf ( "\n%s", str ) ;
}
In this program the printf( ) prints out the values of i, ch and a on
the screen, whereas sprintf( ) stores these values in the character

array str
...
Once
str has been built, its contents can be displayed on the screen
...

The counterpart of sprintf( ) is the sscanf( ) function
...
The sscanf( ) function
comes in handy for in-memory conversion of characters to values
...
The usage of
sscanf( ) is same as scanf( ), except that the first argument is the
string from which reading is to take place
...
For openers let us look at
those which handle one character at a time
...

However, for some situations the scanf( ) function has one glaring
weakness
...
However, we often want a function
that will read a single character the instant it is typed without
waiting for the Enter key to be hit
...
These functions return the
character that has been most recently typed
...
As against this getch( ) just returns the character that
you typed without echoing it on the screen
...
The difference between getchar( ) and
fgetchar( ) is that the former is a macro whereas the latter is a
function
...

main( )
{
char ch ;
printf ( "\nPress any key to continue" ) ;
getch( ) ; /* will not echo the character */
printf ( "\nType any character" ) ;
ch = getche( ) ; /* will echo the character typed */
printf ( "\nType any character" ) ;
getchar( ) ; /* will echo character, must be followed by enter key */
printf ( "\nContinue Y/N" ) ;
fgetchar( ) ; /* will echo character, must be followed by enter key */
}
And here is a sample run of this program
...
They print
a character on the screen
...
The
following program illustrates this
...

AAAZZZ
The limitation of putch( ), putchar( ) and fputchar( ) is that they
can output only one character at a time
...
Why is it needed?
Because scanf( ) function has some limitations while receiving
string of characters, as the following example illustrates
...

Enter name Jonty Rhodes
Jonty
Surprised? Where did “Rhodes” go? It never got stored in the array
name[ ], because the moment the blank was typed after “Jonty”
scanf( ) assumed that the name being entered has ended
...
The solution to this
problem is to use gets( ) function
...
It is terminated when an Enter key is hit
...

More exactly, gets( ) gets a newline (\n) terminated string of
characters from the keyboard and replaces the \n with a \0
...
It
outputs a string to the screen
...
If we attempt to print
two strings using puts( ), only the first one gets printed
...


Summary
(a)
(b)
(c)
(d)
(e)
(f)
There is no keyword available in C for doing input/output
...

There are several functions available for performing console
input/output
...

There are several format specifiers and escape sequences
available to format input and output
...


Exercise
[A] What would be the output of the following programs:
(a) main( )
{
char ch ;
ch = getchar( ) ;
if ( islower ( ch ) )
putchar ( toupper ( ch ) ) ;
else
putchar ( tolower ( ch ) ) ;

410 Complete Guide To C

}
(b) main( )
{
int i = 2 ;
float f = 2
...
3f\t%4s", i, f, str ) ;
}
(c) main( )
{
printf ( "More often than \b\b not \rthe person who \
wins is the one who thinks he can!" ) ;
}
(d) char p[ ] = "The sixth sick sheikh's sixth ship is sick" ;
main( )
{
int i = 0 ;
while ( p[i] != '\0' )
{
putch ( p[i] ) ;
i++ ;
}
}
[B] Point out the errors, if any, in the following programs:
(a) main( )
{
int i ;
char a[ ] = "Hello" ;
while ( a != '\0' )
{
printf ( "%c", *a ) ;
a++ ;
}
}

Chapter 11: Console Input/Output 411
(b) main( )
{
double dval ;
scanf ( "%f", &dval ) ;
printf ( "\nDouble Value = %lf", dval ) ;
}
(c) main( )
{
int ival ;
scanf ( "%d\n", &n ) ;
printf ( "\nInteger Value = %d", ival ) ;
}
(d) main( )
{
char *mess[5] ;

for ( i = 0 ; i < 5 ; i++ )
scanf ( "%s", mess[i] ) ;
}
(e) main( )
{
int dd, mm, yy ;
printf ( "\nEnter day, month and year\n" ) ;
scanf ( "%d%*c%d%*c%d", &dd, &mm, &yy ) ;
printf ( "The date is: %d - %d - %d", dd, mm, yy ) ;
}
(f) main( )
{
char text ;
sprintf ( text, "%4d\t%2
...
452, "Merry Go Round" ) ;
printf ( "\n%s", text ) ;
}
(g) main( )
{
char buffer[50] ;

412 Complete Guide To C
int no = 97;
double val = 2
...
2lf %s", &no, &val, name ) ;
printf ( "\n%s", buffer ) ;
printf ( "\n%d %lf %s", no, val, name ) ;
}
[C] Answer the following:
(a)
(b)
(c)
To receive the string "We have got the guts, you get the
glory!!" in an array char str[100] which of the following
functions would you use?
1
...
gets ( str ) ;
3
...
fgetchar ( str ) ;
Which function would you use if a single key were to be
received through the keyboard?
1
...
gets( )
3
...
getchar( )
If an integer is to be entered through the keyboard, which
function would you use?
1
...
gets( )

3
...
getchar( )

Chapter 11: Console Input/Output 413
(d)
(e)
(f)
(g)
(a)
(b)
If a character string is to be received through the keyboard
which function would work faster?
1
...
gets( )
What is the difference between getchar( ), fgetchar( ),
getch( ) and getche( )?
The format string of a printf( ) function can contain:
1
...
Character, integers and floats
3
...
Inverted commas, percentage sign and backslash character
A field-width specifier in a printf( ) function:
1
...
Specifies the maximum value of a number
3
...
Specifies how many columns will be used to print the
number
[D] Answer the following:
Write down two functions xgets( ) and xputs( ) which work
similar to the standard library functions gets( ) and puts( )
...
A
sample usage of getint( ) is shown below:
main( )
{
int a ;

414 Complete Guide To C
a = getint( ) ;
printf ( "you entered %d", a )
}

12 File Input/Output
• 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

415
416 Complete Guide To C
ften it is not enough to just display the data on the screen
...
It would be inappropriate to
store this data in memory for one more reason
...
So
if we need the same data again it would have to be either entered
through the keyboard again or would have to be regenerated
programmatically
...
At such times it becomes necessary to store the data in a
manner that can be later retrieved and displayed either in part or in
whole
...
This chapter
discusses how file I/O operations can be performed
...
All data stored on the disk is in binary
form
...
However, this does not affect the C programmer
since he has to use only the library functions written for the
particular OS to be able to perform input/output
...
This is illustrated in Figure
12
...

Our program C Library OS
functions
Disk

Figure 12
...

These are:
(a)
(b)
(c)
(d)
(e)
(f)
Creation of a new file
Opening an existing file
Reading from a file
Writing to a file
Moving to a specific location in a file (seeking)
Closing a file
Let us now write a program to read a file and display its contents
on the screen
...
Here is the listing…
/* Display contents of a file on screen
...
h"
main( )
{
FILE *fp ;
char ch ;
fp = fopen ( "PR1
...
C’ on the screen
...


Opening a File
Before we can read (or write) information from (to) a file on a disk
we must open the file
...
It would open a file “PR1
...

Note that “r” is a string and not a character; hence the double
quotes and not single quotes
...

Then it loads the file from the disk into a place in memory
called buffer
...

Why do we need a buffer at all? Imagine how inefficient it would
be to actually access the disk every time we want to read a
character from it
...
On a floppy disk system, the drive motor has to actually
start rotating the disk from a standstill position every time the disk
is accessed
...
This is where a buffer comes in
...
This is shown in Figure 12
...


Chapter 12: File Input/Output 419
DISK
Memory
PR1
...
2
Same argument also applies to writing information in a file
...

To be able to successfully read from a file information like mode
of opening, size of file, place in the file from where the next read
operation would be performed, etc
...
Since all
this information is inter-related, all of it is gathered together by
fopen( ) in a structure called FILE
...
We have declared fp as
FILE *fp ;

420 Complete Guide To C
The FILE structure has been defined in the header file “stdio
...
Therefore, it is
necessary to #include this file
...
This pointer is one of the elements of the structure to
which fp is pointing (refer Figure 12
...

To read the file’s contents from memory there exists a function

called fgetc( )
...
Note that once the file has been opened, we no
longer refer to the file by its name, but through the file pointer fp
...

There has to be a way to break out of this while
...
the moment we reach the end of file
...
This character is inserted beyond the last character in the
file, when it is created
...
The EOF macro has been defined in the
file “stdio
...
In place of the function fgetc( ) we could have as
well used the macro getc( ) with the same effect
...
As each character is read we display it on the
screen
...


Trouble in Opening a File
There is a possibility that when we try to open a file using the
function fopen( ), the file may not be opened
...
And you obviously cannot
read a file that doesn’t exist
...

Crux of the matter is that it is important for any program that
accesses disk files to check whether a file has been opened
successfully before trying to read or write to the file
...
h”
as #define NULL 0)
...

#include "stdio
...
C", "r" ) ;
if ( fp == NULL )
{
puts ( "cannot open file" ) ;
exit( ) ;
}
}

422 Complete Guide To C
Closing the File
When we have finished reading from the file, we need to close it
...
Note that to close the file we don’t use
the filename but the file pointer fp
...

In this program we have opened the file for reading
...
This time
too a buffer would get associated with it
...
When we close this file using fclose( )
three operations would be performed:
(a)
(b)
(c)
The characters in the buffer would be written to the file on the
disk
...

The buffer would be eliminated from memory
...
In such a case the buffer’s contents would
be written to the disk the moment it becomes full
...


Counting Characters, Tabs, Spaces, …
Having understood the first file I/O program in detail let us now
try our hand at one more
...
Here is the program…

Chapter 12: File Input/Output 423
/* Count chars, spaces, tabs and newlines in a file */
# include "stdio
...
C", "r" ) ;
while ( 1 )
{
ch = fgetc ( fp ) ;
if ( ch == EOF )
break ;
noc++ ;
if ( ch == ' ' )
nob++ ;

if ( ch == '\n' )
nol++ ;
if ( ch == '\t' )
not++ ;
}
fclose ( fp ) ;
printf ( "\nNumber of characters = %d", noc ) ;
printf ( "\nNumber of blanks = %d", nob ) ;
printf ( "\nNumber of tabs = %d", not ) ;
printf ( "\nNumber of lines = %d", nol ) ;
}

424 Complete Guide To C
Here is a sample run
...
C”, which I had on my
disk
...

I believe the program is self-explanatory
...
Let us now try a program that needs
to open a file for writing
...
Its counterpart is a function called fputc( ) which
writes characters to a file
...
This program takes the
contents of a file and copies them into another file, character by
character
...
h"
main( )
{
FILE *fs, *ft ;
char ch ;
fs = fopen ( "pr1
...
c", "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 ) ;
}
fclose ( fs ) ;
fclose ( ft ) ;
}
I hope most of the stuff in the program can be easily understood,
since it has already been dealt with in the earlier section
...
Let us see how it works
...
However, putch( ) function
always writes to the VDU, whereas, fputc( ) writes to the file
...
The writing process continues
till all characters from the source file have been written to the
target file, following which the while loop terminates
...
To copy files with extension
...
COM, we need to
open the files in binary mode, a topic that would be dealt with in
sufficient detail in a later section
...
However, “r” is but one of the several modes in which
we can open a file
...
The tasks performed by fopen( ) when
a file is opened in each of these modes are also mentioned
...
If the file is opened successfully fopen( )
loads it into memory and sets up a pointer which points to
the first character in it
...

Operations possible – reading from the file
...
If the file exists, its contents are overwritten
...
Returns
NULL, if unable to open file
...

"a" Searches file
...
If the file doesn’t exist, a new file is
created
...

Operations possible - adding new contents at the end of file
...
If is opened successfully fopen( ) loads it into
memory and sets up a pointer which points to the first

character in it
...


Chapter 12: File Input/Output 427
Operations possible - reading existing contents, writing new
contents, modifying existing contents of the file
...
If the file exists, its contents are overwritten
...
Returns NULL,
if unable to open file
...

"a+" Searches file
...
If the file doesn’t exist, a new file is
created
...

Operations possible - reading existing contents, appending
new contents to end of file
...


String (line) I/O in Files
For many purposes, character I/O is just what is needed
...

Reading or writing strings of characters from and to files is as easy
as reading and writing individual characters
...

/* Receives strings from keyboard and writes them to file */
#include "stdio
...
TXT", "w" ) ;
if ( fp == NULL )
{
puts ( "Cannot open file" ) ;
exit( ) ;
}
printf ( "\nEnter a few lines of text:\n" ) ;
while ( strlen ( gets ( s ) ) > 0 )
{
fputs ( s, fp ) ;
fputs ( "\n", fp ) ;
}
fclose ( fp ) ;
}
And here is a sample run of the program
...
To terminate
the execution of the program, hit enter at the beginning of a line
...

We have set up a character array to receive the string; the fputs( )
function then writes the contents of the array to the disk
...

Here is a program that reads strings from a disk file
...
h"
main( )
{
FILE *fp ;
char s[80] ;
fp = fopen ( "POEM
...

Shining and bright, they are forever,
so true about diamonds,
more so of memories,
especially yours !
The function fgets( ) takes three arguments
...
This argument prevents fgets( ) from reading in too
long a string and overflowing the array
...
When all the lines from
the file have been read, we attempt to read one more line, in which
case fgets( ) returns a NULL
...
If we use that program to count the
number of characters present in the above poem (stored in the file
“POEM
...
The
same file if seen in the directory, would be reported to contain 105
characters
...
Here \r stands for carriage return and \n for linefeed
...
Thus when we write the first line of the poem and a “\n”
using two calls to fputs( ), what gets written to the file is
Shining and bright, they are forever,\r\n
When the same line is read back into the array s[ ] using fgets( ),
the array contains
Shining and bright, they are forever,\n\0
Thus conversion of \n to \r\n during writing and \r\n conversion to
\n during reading is a feature of the standard library functions and
not that of the OS
...
In our poem there are four lines, therefore there is a
discrepancy of four characters (105 - 101)
...
What if we want to read or write numbers from/to file?
Furthermore, what if we desire to read/write a combination of
characters, strings and numbers? For this first we would organize
this dissimilar data together in a structure and then use fprintf( )

Chapter 12: File Input/Output 431
and fscanf( ) library functions to read/write data from/to file
...

/* Writes records to a file using structure */
#include "stdio
...
DAT", "w" ) ;
if ( fp == NULL )
{
puts ( "Cannot open file" ) ;
exit( ) ;
}
while ( another == 'Y' )
{
printf ( "\nEnter name, age and basic salary: " ) ;
scanf ( "%s %d %f", e
...
age, &e
...
name, e
...
bs ) ;
printf ( "Add another record (Y/N) " ) ;
fflush ( stdin ) ;

another = getche( ) ;
}
fclose ( fp ) ;

432 Complete Guide To C
}
And here is the output of the program
...
50
Add another record (Y/N) Y
Enter name, age and basic salary: Sameer 21 1300
...
55
Add another record (Y/N) N
In this program we are just reading the data into a structure
variable using scanf( ), and then dumping it into a disk file using
fprintf( )
...
The
procedure ends when the user supplies ‘N’ for the question ‘Add
another record (Y/N)’
...
This function is similar
to printf( ), except that a FILE pointer is included as the first
argument
...
In fact all the format conventions of
printf( ) function work with fprintf( ) as well
...
The reason is to get rid of a peculiarity of scanf( )
...
What
scanf( ) does is it assigns name, age and salary to appropriate
variables and keeps the enter key unread in the keyboard buffer
...
To avoid this problem
we use the function fflush( )
...
The argument to fflush( )
must be the buffer which we want to flush out
...


Chapter 12: File Input/Output 433
Let us now write a program that reads the employee records
created by the above program
...

/* Read records from a file using structure */
#include "stdio
...
DAT", "r" ) ;
if ( fp == NULL )
{
puts ( "Cannot open file" ) ;
exit( ) ;
}
while ( fscanf ( fp, "%s %d %f", e
...
age, &e
...
name, e
...
bs ) ;
fclose ( fp ) ;
}
And here is the output of the program
...
500000
Sameer 21 1300
...
500000

434 Complete Guide To C
Text Files and Binary Files
All the programs that we wrote in this chapter so far worked on
text files
...

A text file contains only textual information like alphabets, digits
and special symbols
...
A good example of a text file is
any C program, say PR1
...

As against this, a binary file is merely a collection of bytes
...
EXE), or music data stored in a wave file or a picture stored
in a graphic file
...
If on
opening the file you can make out what is displayed then it is a
text file, otherwise it is a binary file
...
We can improve the same
program to make it capable of copying text as well as binary files
as shown below
...
h"
main( )
{
FILE *fs, *ft ;
int ch ;
fs = fopen ( "pr1
...
exe", "wb" ) ;

Chapter 12: File Input/Output 435
if ( ft == NULL )
{

puts ( "Cannot open target file" ) ;
fclose ( fs ) ;
exit( ) ;
}
while ( 1 )
{
ch = fgetc ( fs ) ;
if ( ch == EOF )
break ;
else
fputc ( ch, ft ) ;
}
fclose ( fs ) ;
fclose ( ft ) ;
}
Using this program we can comfortably copy text as well as binary
files
...
While opening the file in text
mode we can use either “r” or “rt”, but since text mode is the
default mode we usually drop the ‘t’
...
These are:
(a)
(b)
(c)
Handling of newlines
Representation of end of file
Storage of numbers
Let us explore these three differences
...
Likewise, the carriage return-linefeed
combination on the disk is converted back into a newline when the
file is read by a C program
...

Text versus Binary Mode: End of File
The second difference between text and binary modes is in the way
the end-of-file is detected
...
If this character is detected at any point in the
file, the read function would return the EOF signal to the program
...
The binary mode files
keep track of the end of file from the number of characters present
in the directory entry of the file
...
If a file stores numbers in binary mode, it is important

that binary mode only be used for reading the numbers back, since
one of the numbers we store might well be the number 26
(hexadecimal 1A)
...

Thus the two modes are not compatible
...

Similarly, the file that has been written in binary mode must be
read back only in binary mode
...
It is important to understand how
numerical data is stored on the disk by fprintf( )
...

Are numbers stored as they are in memory, two bytes for an
integer, four bytes for a float, and so on? No
...
Thus, 1234, even
though it occupies two bytes in memory, when transferred to the
disk using fprintf( ), would occupy four bytes, one byte per
character
...
56 would
occupy 7 bytes on disk
...

Hence if large amount of numerical data is to be stored in a disk
file, using text mode may turn out to be inefficient
...
It means each number would occupy same number
of bytes on disk as it occupies in memory
...
This is
because when the file is opened in text mode, each number is
stored as a character string
...
), writing structures

438 Complete Guide To C
using fprintf( ), or reading them using fscanf( ), becomes
quite clumsy
...
This makes use of two functions fread( ) and
fwrite( )
...

/* Receives records from keyboard and writes them to a file in binary mode */

#include "stdio
...
DAT", "wb" ) ;
if ( fp == NULL )
{
puts ( "Cannot open file" ) ;
exit( ) ;
}
while ( another == 'Y' )
{
printf ( "\nEnter name, age and basic salary: " ) ;
scanf ( "%s %d %f", e
...
age, &e
...

Enter name, age and basic salary: Suresh 24 1250
...
60
Add another record (Y/N) Y
Enter name, age and basic salary: Harish 28 1400
...
Note, however, that the
file “EMP
...

The information obtained from the keyboard about the employee is
placed in the structure variable e
...

The second argument is the size of the structure in bytes
...
The
sizeof( ) operator gives the size of the variable in bytes
...


440 Complete Guide To C
The third argument is the number of such structures that we want
to write at one time
...
Had we had an array of structures, for example,
we might have wanted to write the entire array at once
...

Now, let us write a program to read back the records written to the
disk by the previous program
...
h"
main( )
{
FILE *fp ;
struct emp
{
char name[40] ;
int age ;
float bs ;
};
struct emp e ;
fp = fopen ( "EMP
...
name, e
...
bs ) ;
fclose ( fp ) ;
}

Chapter 12: File Input/Output 441
Here, the fread( ) function causes the data read from the disk to be
placed in the structure variable e
...
The function fread( ) returns the number of
records read
...
1 in this case
...
By testing for this situation, we know
when to stop reading
...
Note that even if the number of elements
belonging to the structure increases, the format of fread( ) and
fwrite( ) remains same
...
However, in

any serious database management application, we will have to
combine all that we have learnt in a proper manner to make sense
...

There is a provision to Add, Modify, List and Delete records, the
operations that are imperative in any database management
...

− Listing records means displaying the existing records on the
screen
...

− While modifying records, first we must ask the user which
record he intends to modify
...
On
modifying the record, the existing record gets overwritten by
the new record
...

− Observe carefully the way the file has been opened, first for
reading & writing, and if this fails (the first time you run this
program it would certainly fail, because that time the file is not
existing), for writing and reading
...

− Note that the file is being opened only once and closed only
once, which is quite logical
...
The parameters passed to gotoxy( ) are column number
followed by row number
...

/* A menu-driven program for elementary database management */
#include "stdio
...
DAT", "rb+" ) ;
if ( fp == NULL )
{
fp = fopen ( "EMP
...
Add Records" ) ;
gotoxy ( 30, 12 ) ;
printf ( "2
...
Modify Records" ) ;
gotoxy ( 30, 16 ) ;
printf ( "4
...
Exit" ) ;
gotoxy ( 30, 20 ) ;
printf ( "Your choice" ) ;
fflush ( stdin ) ;
choice = getche( ) ;

444 Complete Guide To C
switch ( choice )
{
case '1' :
fseek ( fp, 0 , SEEK_END ) ;
another = 'Y' ;
while ( another == 'Y' )
{
printf ( "\nEnter name, age and basic sal
...
name, &e
...
bs ) ;
fwrite ( &e, recsize, 1, fp ) ;
printf ( "\nAdd another Record (Y/N) " ) ;
fflush ( stdin ) ;
another = getche( ) ;
}
break ;
case '2' :
rewind ( fp ) ;
while ( fread ( &e, recsize, 1, fp ) == 1 )
printf ( "\n%s %d %f", e
...
age, e
...
name, empname ) == 0 )
{
printf ( "\nEnter new name, age & bs" ) ;
scanf ( "%s %d %f", e
...
age,
&e
...
DAT", "wb" ) ;
rewind ( fp ) ;
while ( fread ( &e, recsize, 1, fp ) == 1 )
{
if ( strcmp ( e
...
DAT" ) ;
rename ( "TEMP
...
DAT" ) ;
fp = fopen ( "EMP
...
A pointer is initiated whenever we
open a file
...
To be precise this pointer is present in the
structure to which the file pointer returned by fopen( ) points to
...
On closing a file the pointer is
deactivated
...
Similarly, fwrite( ) always writes the
record where the pointer is currently placed
...

The fseek( ) function lets us move the pointer from one record to
another
...
SEEK_CUR is a macro defined in “stdio
...

Similarly, the following fseek( ) would place the pointer beyond
the last record in the file
...
The third argument could be SEEK_END, SEEK_CUR
or SEEK_SET
...
SEEK_END means move the pointer from the
end of the file, SEEK_CUR means move the pointer with
reference to its current position and SEEK_SET means move the
pointer with reference to the beginning of the file
...
It returns this position as a long int
which is an offset from the beginning of the file
...
A
sample call to ftell( ) is shown below:
position = ftell ( fp ) ;
where position is a long int
...
There is only one
way data can be written or read in low level disk I/O functions—as
a buffer full of bytes
...

However, unlike fwrite( ), the programmer must set up the buffer
for the data, place the appropriate values in it before writing, and
take them out after writing
...

Low level disk I/O functions offer following advantages:
(a)
(b)
Since these functions parallel the methods that the OS uses to
write to the disk, they are more efficient than the high level
disk I/O functions
...

Let us now write a program that uses low level disk input/output
functions
...
In that program we had read the file character by
character using fgetc( )
...
Instead of performing the I/O on
a character by character basis we can read a chunk of bytes from
the source file and then write this chunk into the target file
...
While doing so we would
manage the buffer ourselves, rather than relying on the library
functions to do so
...

Here is a program which shows how this can be done
...
com and
...
h"
#include "types
...
h" */
#include "stat
...
h" */
main ( int argc, char *argv[ ] )
{
char buffer[ 512 ], source [ 128 ], target [ 128 ] ;
int inhandle, outhandle, bytes ;
printf ( "\nEnter source file name" ) ;
gets ( source ) ;
inhandle = open ( source, O_RDONLY | O_BINARY ) ;
if ( inhandle == -1 )
{
puts ( "Cannot open file" ) ;
exit( ) ;
}

printf ( "\nEnter target file name" ) ;
gets ( target ) ;
outhandle = open ( target, O_CREAT | O_BINARY | O_WRONLY,
S_IWRITE ) ;
if ( inhandle == -1 )
{
puts ( "Cannot open file" ) ;
close ( inhandle ) ;
exit( ) ;
}
while ( 1 )
{
bytes = read ( inhandle, buffer, 512 ) ;
if ( bytes > 0 )
write ( outhandle, buffer, bytes ) ;
else

450 Complete Guide To C
break ;
}
close ( inhandle ) ;
close ( outhandle ) ;
}
Declaring the Buffer
The first difference that you will notice in this program is that we
declare a character buffer,
char buffer[512] ;
This is the buffer in which the data read from the disk will be
placed
...

Depending on the operating system, buffers of certain sizes are
handled more efficiently than others
...

As in high level disk I/O, the file must be opened before we can
access it
...
As
usual, we have to supply to open( ), the filename and the mode in
which we want to open the file
...
h”
...
Note
that the file “stdio
...
When
two or more O-flags are used together, they are combined using
the bitwise OR operator ( | )
...

The other statement used in our program to open the file is,
outhandle = open ( target, O_CREAT | O_BINARY | O_WRONLY,
S_IWRITE ) ;
Note that since the target file is not existing when it is being
opened we have used the O_CREAT flag, and since we want to
write to the file and not read from it, therefore we have used
O_WRONLY
...

Whenever O_CREAT flag is used, another argument must be
added to open( ) function to indicate the read/write status of the
file to be created
...

Permission arguments could be any of the following:
S_IWRITE - Writing to the file permitted
S_IREAD - Reading from the file permitted

452 Complete Guide To C
To use these permissions, both the files “types
...
h” must
be #included in the program alongwith “fcntl
...

File Handles
Instead of returning a FILE pointer as fopen( ) did, in low level
disk I/O, open( ) returns an integer value called ‘file handle’
...
If open( ) returns a value of -1, it means that the
file couldn’t be successfully opened
...
The first argument is
the file handle, the second is the address of the buffer and the third
is the maximum number of bytes we want to read
...

This is an important number, since it may very well be less than
the buffer size (512 bytes), and we will need to know just how full
the buffer is before we can do anything with its contents
...

For copying the file, we must use both the read( ) and the write( )
functions in a while loop
...
This is assigned to the variable bytes
...
The variable bytes
therefore is used to tell write( ), as to how many bytes to write
from the buffer to the target file
...


I/O Under Windows
As said earlier I/O in C is carried out using functions present in the
library that comes with the C compiler targeted for a specific OS
...
Hence there is a possibility that what is written by
one application to the console may get overwritten by the output
sent by another application to the console
...
It uses
a separate mechanism to send output to a window representing an
application
...

Though under Windows console I/O functions are not used, still
functions like fprintf( ), fscanf( ), fread( ), fwrite( ), sprintf( ),
sscanf( ) work exactly same under Windows as well
...

Different operations that can be performed on a file are—
creation of a new file, opening an existing file, reading from a
file, writing to a file, moving to a specific location in a file
(seeking) and closing a file
...

A file can be a text file or a binary file depending upon its
contents
...


454 Complete Guide To C
(f)
(g)
Many library functions convert a number to a numeric string
before writing it to a file, thereby using more space on disk
...

In low level file I/O we can do the buffer management
ourselves
...
h"
main( )
{
FILE *fp ;
openfile ( "Myfile
...
h"
main( )
{
FILE *fp ;
char c ;
fp = fopen ( "TRY
...
dat" ;
FILE *fp ;
fp = fopen ( fname, "tr" ) ;
if ( fp == NULL )
printf ( "\nUnable to open file
...
C", "r" ) ;
while ( fgets ( str, 80, fp ) != EOF )
fputs ( str ) ;
fclose ( fp ) ;
}
(e) #include "stdio
...
c", "wb" ) ;
for ( i = 0 ; i <= 10 ; i++ )
{
puts ( "\nEnter name " ) ;
gets ( name ) ;
fwrite ( name, size of ( name ), 1, fp ) ;
}
close ( fp ) ;
}
(h) main( )
{
FILE *fp ;
char name[20] = "Ajay" ;
int i ;
fp = fopen ( "students
...
h"
main( )
{
int fp ;
fp = open ( "pr22
...
c", READ | BINARY ) ;
if ( fp == -1 )
puts ( "cannot open file" ) ;

else
close ( fp ) ;
}
[B] Answer the following:
(a)
(b)
(c)
The macro FILE is defined in which of the following files:
1
...
h
2
...
c
3
...
h
4
...
h
If a file contains the line “I am a boy\r\n” then on reading this
line into the array str[ ] using fgets( ) what would str[ ]
contain?
1
...
I am a boy\r\0
3
...
I am a boy
State True or False:
1
...

2
...

3
...


458 Complete Guide To C
4
...

(d)
(e)
(f)
(g)
(h)
(i)
(j)
On opening a file for reading which of the following activities
are performed:
1
...

2
...

3
...

4
...

Is it necessary that a file created in text mode must always be
opened in text mode for subsequent operations?
State True or False:
A file opened in binary mode and read using fgetc( ) would
report the same number of characters in the file as reported by
DOS’s DIR command
...
c", "r" ) ;
what happens if,
− ‘myfile
...
c’ exists on the disk
What is the purpose of the library function fflush( )?
While using the statement,
fp = fopen ( "myfile
...
c’ does not exist on the disk
...
c’ exists on the disk
A floating-point array contains percentage marks obtained by
students in an examination
...
c’, in which mode would you open the file and why?

Chapter 12: File Input/Output 459
[C] Attempt the following:
(a)
(b)
(c)
(d)
(e)
(f)
(g)
(h)
Write a program to read a file and display contents with its
line numbers
...

Write a program to add the contents of one file at the end of
another
...
Write a program to read
these records and display them in sorted order by name
...
While doing so
replace all lowercase characters to their equivalent uppercase
characters
...
If one file has less number
of lines than the other, the remaining lines from the larger file
should be simply copied into the target file
...
Make following provisions:
Display the contents inside a box drawn with opposite corner
co-ordinates being ( 0, 1 ) and ( 79, 23 )
...
The moment one screenful of file
has been displayed, flash a message ‘Press any key
...
When a key is hit, the next page’s contents should be
displayed, and so on till the end of file
...

For example, if character read from the source file is ‘A’,
then convert this into a new character by offsetting ‘A’
by a fixed value, say 128, and then writing the new
character to the target file
...

For example, if character ‘A’ is read from the source file,
and if we have decided that every ‘A’ is to be substituted
by ‘!’, then a ‘!’ would be written to the target file in
place of every ‘A’ Similarly, every ‘B’ would be
substituted by ‘5’ and so on
...
DAT’ there are 100 records with the
following structure:
struct customer
{
int accno ;
char name[30] ;
float balance ;
};
In another file ‘TRANSACTIONS
...
Write a program to update
‘CUSTOMER
...
e
...
DAT’ by adding
amount to balance for the corresponding accno
...

However, while subtracting the amount make sure that the
amount should not get overdrawn, i
...
at least 100 Rs
...

(j)
(k)
There are 100 records present in a file with the following
structure:
struct date
{
int d, m, y ;
};

struct employee
{
int empcode[6] ;
char empname[20] ;
struct date join_date ;
float salary ;
};
Write a program to read these records, arrange them in
ascending order of join_date and write them in to a target
file
...

(l)
(m)
(n)
(o)
Given a list of names of students in a class, write a program to
store the names in a file on disk
...

Assume that a Master file contains two fields, Roll no
...
At the end of the year, a set of students
join the class and another set leaves
...

Write a program to create another file that contains the
updated list of names and roll numbers
...
The updated file should also be in
ascending order by roll numbers
...

− Create a file of employee data with following information:
employee number, name, sex, gross salary
...

− If an employee with serial number 25 (say) leaves, delete
the record by making gross salary 0
...

Write a program to implement the above operations
...


Chapter 12: File Input/Output 463
(p)
(q)
(r)
You are given a data file EMPLOYEE
...
Records are
entered into the data file in ascending order of employee
number, empno
...
Write a program segment to read
the data file records sequentially and display the list of
missing employee numbers
...
TXT” consisting of a
maximum of 50 lines of text, each line with a maximum
of 80 characters
...

− Display the total number of four letter words in the text
file
...

Write a program to read a list of words, sort the words in
alphabetical order and display them one word per line
...
Output format
should be:
Total Number of words in the list is _______
Alphabetical listing of words is:
-----------

464 Complete Guide To C
-----Assume the end of the list is indicated by ZZZZZZ and there
are maximum in 25 words in the Text file
...
TXT’
(b) Print each word in reverse order
Example,
Input: INDIA IS MY COUNTRY
Output: AIDNI SI YM YRTNUOC
Assume that each word length is maximum of 10 characters

and each word is separated by newline/blank characters
...
TXT’ and
print it on the printer in cut-sheets, introducing page breaks at
the end of every 50 lines and a pause message on the screen at
the end of every page for the user to change the paper
...
There are still some more issues related with
input/output that remain to be understood
...


I
Using argc and argv
To execute the file-copy programs that we saw in Chapter 12 we
are required to first type the program, compile it, and then execute
it
...
It means the program must be
executable at command prompt (A> or C> if you are using
MS-DOS, Start | Run dialog if you are using Windows and $
prompt if you are using Unix)
...
C PR2
...
C is the source filename and PR2
...

The first improvement is simple
...
EXE) can be created in Turbo C/C++ by using the key
F9 to compile the program
...
Under Unix
this is not required since in Unix every time we compile a program
we always get an executable file
...
This is
illustrated below:

Chapter 13: More Issues In Input/Output 467
#include "stdio
...
The function main( ) can
have two arguments, traditionally named as argc and argv
...
When the program is executed, the strings on the command
line are passed to main( )
...
The argument argc is set to the number of
strings given on the command line
...
C PR2
...
C”
argv[2] would contain base address of the string “PR2
...
In our program this has been done through,
if ( argc != 3 )
{
printf ( "Improper number of arguments" ) ;
exit( ) ;
}

Chapter 13: More Issues In Input/Output 469
Rest of the program is same as the earlier file-copy program
...
It can be executed at command
prompt
...

One final comment
...
Here, first fgetc ( fs ) gets the character
from the file, assigns it to the variable ch, and then ch is compared
against EOF
...

There is one more way of writing the while loop
...
Hence we use the ! operator to negate this 0 to the truth
value
...

Note that in each one of them the following three methods for
opening a file are same, since in each one of them, essentially a
base address of the string (pointer to a string) is being passed to
fopen( )
...
C" , "r" ) ;
fs = fopen ( filename, "r" ) ;
fs = fopen ( argv[1] , "r" ) ;

Detecting Errors in Reading/Writing
Not at all times when we perform a read or write operation on a
file are we successful in doing so
...

The standard library function ferror( ) reports any error that might
have occurred during a read/write operation on a file
...
The following program illustrates the usage of ferror( )
...
h"
main( )
{
FILE *fp ;
char ch ;
fp = fopen ( "TRIAL", "w" ) ;
while ( !feof ( fp ) )
{
ch = fgetc ( fp ) ;
if ( ferror( ) )
{

Chapter 13: More Issues In Input/Output 471
printf ( "Error in reading file" ) ;
break ;
}
else
printf ( "%c", ch ) ;
}
fclose ( fp ) ;
}
In this program the fgetc( ) function would obviously fail first time
around since the file has been opened for writing, whereas fgetc( )
is attempting to read from the file
...

Instead of printing the error message using printf( ) we can use the
standard library function perror( ) which prints the error message
specified by the compiler
...


if ( ferror( ) )
{
perror ( "TRIAL" ) ;
break ;
}
Note that when the error occurs the error message that is displayed
is:
TRIAL: Permission denied
This means we can precede the system error message with any
message of our choice
...


472 Complete Guide To C
Standard I/O Devices
To perform reading or writing operations on a file we need to use
the function fopen( ), which sets up a file pointer to refer to this
file
...
To
access these pointers we need not use fopen( )
...
1
Standard File pointer Description
stdin standard input device (Keyboard)
stdout standard output device (VDU)
stderr standard error device (VDU)

Figure 13
...
We can use this
statement without any need to use fopen( ) or fclose( ) function
calls
...
They stand for standard printing
device and standard auxiliary device (serial port)
...
It reads a file
from the disk and prints it on the printer
...
h"
main( )
{
FILE *fp ;
char ch ;

Chapter 13: More Issues In Input/Output 473
fp = fopen ( "poem
...
Note that although we opened the file on the
disk we didn’t open stdprn, the printer
...

Note that these standard file pointers have been defined in the file
“stdio
...
Therefore, it is necessary to include this file in the
program that uses these standard file pointers
...
This is done through a
process called ‘redirection’
...
In
other words, the OS makes certain assumptions about where input

474 Complete Guide To C
should come from and where output should go
...

For example, using redirection the output of the program that
normally goes to the VDU can be sent to the disk or the printer
without really making a provision for it in the program
...

Similarly, redirection can be used to read information from disk
file directly into a program, instead of receiving the input from
keyboard
...
Let us understand this process with the help of a program
...
We’ll start by considering the simple program
shown below:
/* File name: util
...
h"<+>
main( )
{
char ch ;
while ( ( ch = getc ( stdin ) ) != EOF )
putc ( ch, stdout ) ;
}
On compiling this program we would get an executable file
UTIL
...
Normally, when we execute this file, the putc( )
function will cause whatever we type to be printed on screen, until
we don’t type Ctrl-Z, at which point the program will terminate, as

Chapter 13: More Issues In Input/Output 475
shown in the following sample run
...


C>UTIL
...
EXE > POEM
...
TXT
...
TXT? Yes, by using the TYPE command as
follows:
C>TYPE POEM
...
The redirection
operator, ‘>’, causes any output intended for the screen to be
written to the file whose name follows the operator
...
Any
output normally sent to the screen can be redirected to a disk file
...
c*/
main( )
{
int ch ;
for ( ch = 0 ; ch <= 255 ; ch++ )
printf ( "\n%d %c", ch, ch ) ;
}
When this program is compiled and then executed at command
prompt using the redirection operator,
C>ASCII
...
TXT
the output is written to the file
...

DOS predefines a number of filenames for its own use
...
Output can be
redirected to the printer by using this filename
...
exe” program this way:
C>ASCII
...


Redirecting the Input
We can also redirect input to a program so that, instead of reading

a character from the keyboard, a program reads it from a file
...

To redirect the input, we need to have a file containing something
to be displayed
...
TXT
containing the following lines:

Chapter 13: More Issues In Input/Output 477
Let's start at the very beginning,
A very good place to start!
We’ll assume that using some text editor these lines have been
placed in the file NEWPOEM
...
Now, we use the input
redirection operator ‘<’ before the file, as shown below:
C>UTIL
...
TXT
Let's start at the very beginning,
A very good place to start!
C>
The lines are printed on the screen with no further effort on our
part
...
C perform
the work of the TYPE command
...
Such a program is called a filter
...

C>UTIL < NEWPOEM
...
TXT
In this case our program receives the redirected input from the file
NEWPOEM
...
TXT
...
TXT to the
printer we can use the following command:
C>UTIL < NEWPOEM
...
This is because

478 Complete Guide To C
the output file is erased before it’s written to
...

Redirection can be a powerful tool for developing utility programs
to examine or alter data in files
...
Another OS
operator can be used to relate two programs directly, so that the
output of one is fed directly into another, with no files involved
...
We won’t pursue this topic, but you can read about it in the
OS help/manual
...

The command line argument argv contains values passed to
the program, whereas, argc contains number of arguments
...

We can use the standard file pointer stdout to send output to
the standard output device such as a monitor
...

Redirection allows a program to read from or write to files at
command prompt
...


Exercise
[A] Answer the following:
How will you use the following program to
− Copy the contents of one file into another
...

− Create a new file and add some text to it
...

#include "stdio
...
We can send arguments at command line even if we
define main( ) function without parameters
...
To use standard file pointers we don’t need to open the
file using fopen( )
...
Using stdaux we can send output to the printer if printer is
attached to the serial port
...
The zeroth element of the argv array is always the name
of the exe file
...
The
usage of the program is shown below
...
The usage of the program is shown below
...
switch can be any
one of the arithmetic or comparison operators
...
If comparison operator is supplied then the output
should be True or False
...
The smallest element in memory on which we are
able to operate as yet is a byte; and we operated on it by
making use of the data type char
...
Being
able to operate on a bit level, can be very important in
programming, especially when a program must interact directly

with the hardware
...
Let us
now delve inside the byte and see how it is constructed and how it
can be manipulated effectively
...
bit
by bit
...

These permit the programmer to access and manipulate individual
bits within a piece of data
...
1
...
1
These operators can operate upon ints and chars but not on floats
and doubles
...
Bits are numbered from zero onwards, increasing from
right to left as shown below:
76543210
12 11 10 9 8 7 6 5 4 3 2 1 0
Character
16-bit Integer
15 14 13

Figure 14
...
The task of
showbits( ) is to display the binary representation of any integer or
character value
...

/* Print binary equivalent of integers using showbits( ) function */
main( )
{
int j ;
for ( j = 0 ; j <<= 5 ; j++ )
{
printf ( "\nDecimal %d is same as binary ", j ) ;
showbits ( j ) ;
}

484 Complete Guide To C

}
And here is the output
...


One’s Complement Operator
On taking one’s complement of a number, all 1’s present in the
number are changed to 0’s and all 0’s are changed to 1’s
...
Similarly, one’s
complement of 1111 is 0000
...
Thus,
one’s complement of 65 means one’s complement of 0000 0000
0100 0001, which is binary equivalent of 65
...
One’s complement
operator is represented by the symbol ~
...

main( )
{
int j, k ;
for ( j = 0 ; j <= 3 ; j++ )
{
printf ( "\nDecimal %d is same as binary ", j ) ;
showbits ( j ) ;
k = ~j ;
printf ( "\nOne’s complement of %d is ", j ) ;

Chapter 14: Operations On Bits 485
showbits ( k ) ;
}
}
And here is the output of the above program
...
h"
main( )
{

encrypt( ) ;
}
encrypt( )
{
FILE *fs, *ft ;
char ch ;
fs = fopen ( "SOURCE
...
C”, "w" ) ; /* encrypted file */
if ( fs == NULL || ft == NULL )
{

486 Complete Guide To C
printf ( "\nFile opening error!" ) ;
exit ( 1 ) ;
}
while ( ( ch = getc ( fs ) ) != EOF )
putc ( ~ch, ft ) ;
fclose ( fs ) ;
fclose ( ft ) ;
}
How would you write the corresponding decrypt function? Would
there be any problem in tackling the end of file marker? It may be
recalled here that the end of file in text files is indicated by a
character whose ASCII value is 26
...
It needs two
operands
...
The
number of places the bits are shifted depends on the number
following the operator (i
...
its right operand)
...

Similarly, ch >> 5 would shift all bits 5 places to the right
...

Note that as the bits are shifted to the right, blanks are created on
the left
...
They are always
filled with zeros
...

main( )
{

Chapter 14: Operations On Bits 487
int i = 5225, j, k ;
printf ( "\nDecimal %d is same as binary ", i ) ;
showbits ( i ) ;
for ( j = 0 ; j <= 5 ; j++ )
{
k = i >>j ;
printf ( "\n%d right shift %d gives ", i, j ) ;
showbits ( k ) ;
}

}
The output of the above program would be
...
Thus,
64 >> 1 gives 32
64 >> 2 gives 16
128 >> 2 gives 32
but,
27 >> 1 is 13
49 >> 1 is 24
...
If a is negative than its left most bit (sign bit) would
be 1
...
For example, if a contains -1, its binary representation
would be 1111111111111111
...
However, on the
machine on which we executed this expression the result turns out
to be 1111111111111111
...


Left Shift Operator
This is similar to the right shift operator, the only difference being
that the bits are shifted to the left, and for each bit shifted, a 0 is
added to the right of the number
...

main( )
{
int i = 5225, j, k ;
printf ( "\nDecimal %d is same as ", i ) ;
showbits ( i ) ;
for ( j = 0 ; j <= 4 ; j++ )
{
k = i <printf ( "\n%d left shift %d gives ", i, j ) ;
showbits ( k ) ;
}
}
The output of the above program would be
...

In DOS/Windows the date on which a file is created (or modified)
is stored as a 2-byte entry in the 32 byte directory entry of that file
...
Remember that DOS/Windows doesn’t
store the date (day, month, and year) of file creation as a 8 byte
string, but as a codified 2 byte entry, thereby saving 6 bytes for
each file entry in the directory
...
3
...
3
DOS/Windows converts the actual date into a 2-byte value using
the following formula:
date = 512 * ( year - 1980 ) + 32 * month + day
Suppose 09/03/1990 is the date, then on conversion the date will
be,
date = 512 * ( 1990 - 1980 ) + 32 * 3 + 9 = 5225

490 Complete Guide To C
The binary equivalent of 5225 is 0001 0100 0110 1001
...

Figure 14
...

When we issue the command DIR or use Windows Explorer to list
the files, the file’s date is again presented on the screen in the
usual date format of mm/dd/yy
...

When we take a look at Figure 14
...
Separating each of them is a
matter of applying the bitwise operators
...
Just see, how
...
5
On similar lines, left shifting by 7, followed by right shifting by 12
yields month
...
6
Finally, for obtaining the day, left shift date by 11 and then right
shift the result by 11
...
Right shifting by 11 gives
0000000000001001
...

Date = 5225
Year = 1990 Month = 3 Day = 9

Bitwise AND Operator
This operator is represented as &
...
The & operator operates on two
operands
...
Hence both the operands must be
of the same type (either char or int)
...
The & operator operates on a pair of bits to
yield a resultant bit
...
7

494 Complete Guide To C
This can be represented in a more understandable form as a ‘Truth
Table’ shown in Figure 14
...

&01
000
101

Figure 14
...
The rules given in the Figure
14
...

7
this result
With this operand
yields
This operand when
ANDed bitwise
76543210
10000010
6543210
11000011
7654210
1010
3
1010

Figure 14
...

Thus, it must be clear that the operation is being performed on
individual bits, and the operation performed on one pair of bits is

Chapter 14: Operations On Bits 495
completely independent of the operation performed on the other
pairs
...
This is explained in the
following example
...
Since we want
to check the bit number 3, the second operand for the AND
operation should be 1 * 23, which is equal to 8
...

Then the ANDing operation would be,
10101101 Original bit pattern
00001000 AND mask
-------------00001000 Resulting bit pattern
The resulting value we get in this case is 8, i
...
The result turned out to be 8 since the third bit of
the first operand was ON
...

Thus, depending upon the bit number to be checked in the first
operand we decide the second operand, and on ANDing these two
operands the result decides whether the bit was ON or OFF
...
The following program puts
this logic into action
...

Value of i = 65
and its fifth bit is off
whereas its sixth bit is on
In every file entry present in the directory, there is an attribute
byte
...
The AND operator can be used to check the
status of the bits of this attribute byte
...
10
...
1 Read only

...
Hidden


...
System

...
Volume label entry

...
Sub-directory entry

...
Archive bit

...
Unused
1
...
10
Now, suppose we want to check whether a file is a hidden file or
not
...
From the above bit classification
of attribute byte, we only need to check whether bit number 1 is
ON or OFF
...
Similarly, it can be checked whether the file is a
system file or not, whether the file is read-only file or not, and so
on
...


498 Complete Guide To C
If the first operand happens to be 00000111, then to switch OFF
bit number 1, our AND mask bit pattern should be 11111101
...
Therefore, irrespective of whether the first bit is ON or
OFF previously, it is switched OFF
...

Let’s summarize the uses of bitwise AND operator:
(a)
(b)
It is used to check whether a particular bit in a number is ON
or OFF
...


Bitwise OR Operator
Another important bitwise operator is the OR operator which is
represented as |
...

|01
001
111

Figure 14
...

11010000 Original bit pattern
00000111 OR mask
------------11010111 Resulting bit pattern
Bitwise OR operator is usually used to put ON a particular bit in a
number
...
If we want to put ON bit
number 3, then the OR mask to be used would be 00001000
...


Bitwise XOR Operator
The XOR operator is represented as ^ and is also called an
Exclusive OR Operator
...
The truth table for the XOR operator is
given below
...
12
XOR operator is used to toggle a bit ON or OFF
...
This
is shown in the following program
...
Now we
have sufficient knowledge of bitwise operators and hence are in a
position to understand it
...

showbits ( int n )
{
int i, k, andmask ;
for ( i = 15 ; i >= 0 ; i-- )
{
andmask = 1 << i ;
k = n & andmask ;
k == 0 ? printf ( "0" ) : printf ( "1" ) ;
}
}
All that is being done in this function is using an AND operator
and a variable andmask we are checking the status of individual

bits
...

First time through the loop, the variable andmask will contain the
value 1000000000000000, which is obtained by left-shifting 1,

Chapter 14: Operations On Bits 501
fifteen places
...
If k contains 0 then printf( ) will print out 0 otherwise it
will print out 1
...
This checks whether the next most significant
bit is 1 or 0, and prints it out accordingly
...


Summary
(a)
(b)
(c)
(d)
(e)
(f)
(g)
(a)
To help manipulate hardware oriented data—individual bits
rather than bytes a set of bitwise operators are used
...

The one’s complement converts all zeros in its operand to 1s
and all 1s to 0s
...

The bitwise AND operators is useful in testing whether a bit is
on/off and in putting off a particular bit
...

The XOR operator works almost same as the OR operator
except one minor variation
...
The bit number 0 to 6, each represent 7
colors of a rainbow, i
...
bit 0 represents violet, 1 represents

502 Complete Guide To C
indigo, and so on
...

(b)
(c)
A company planning to launch a new newspaper in market

conducts a survey
...

Write a program, which reads data of 10 respondents through
keyboard, and stores the information in an array of integers
...

In an inter-college competition, various sports and games are
played between different colleges like cricket, basketball,
football, hockey, lawn tennis, table tennis, carom and chess
...
The college

Chapter 14: Operations On Bits 503
that wins in 5 or more than 5 games is awarded the Champion
of Champions trophy
...

(d)
(e)
An animal could be either a canine (dog, wolf, fox, etc
...
), a cetacean (whale, narwhal,
etc
...
The information
whether a particular animal is canine, feline, cetacean, or
marsupial is stored in bit number 0, 1, 2 and 3 respectively of
a integer variable called type
...

For the following animal, complete the program to determine
whether the animal is a herbivore or a carnivore
...

struct animal
{
char name[30] ;

int type ;
}
struct animal a = { "OCELOT", 18 } ;
The time field in the directory entry is 2 bytes long
...
Write a function which would
receive the two-byte time entry and return to the calling
function, the hours, minutes and seconds
...
13
HHHHHMMMMMMSSSSS
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

(f)
(g)
In order to save disk space information about student is stored
in an integer variable
...
The bit number 4 to 7 stores
stream Mechanical, Chemical, Electronics and IT
...
Based on the given data, write a
program that asks for the room number and displays the
information about the student, if its data exists in the array
...
Thus we are through with the
language elements that were there to learn
...
Now it is time to move on to more serious stuff
...
Obviously we should choose the 32-bit platform
because that is what is in commercial use today and would remain
so until 64-bit environment takes over in future
...
Contrasted with this, 16-bit compilers offer a very simple
environment that a novice can master quickly
...
In today’s commercial
world 16-bit operating environments like DOS are more or less
dead
...
In this chapter we would
explore how C programming is done under Windows
...


Which Windows…
To a common user the differences amongst various versions of
Windows like Windows 95,98, ME, NT, 2000, XP, Server 2003 is
limited to only visual appearances—things like color of the title
bar, shape of the buttons, desktop, task bar, programs menu etc
...
Architecturally there are
huge differences amongst them
...
Windows

Chapter 16: C Under Windows 537
95, 98, ME fall under the Consumer Windows, whereas Windows
NT, 2000, XP, Server 2003 fall under the Windows NT Family
...

Microsoft no longer provides support for Consumer Windows
...
So in the rest of this book whenever I refer to Windows
I mean Windows NT family, unless explicitly specified
...


Integers
Under 16-bit environment the size of integer is of 2 bytes
...

Hence its range is -2147483648 to +2147483647
...
But what if we wish to
store the age of a person in an integer? It would be improper to
sacrifice a 4-byte integer when we know that the number to be
stored in it is hardly going to exceed hundred
...


The Use of typedef
Take a look at the following declarations:
COLORREF color ;
HANDLE h ;
WPARAM w ;
LPARAM l ;
BOOL b ;

538 Complete Guide To C
Are COLORREF, HANDLE, etc
...
They are merely
typedef’s of the normal integer datatype
...
There are two reasons why Windows-based C programs
heavily make use of typedefs
...
For example a program may print documents,
send mails, perform file I/O, manage multiple threads of
execution, draw in a window, play sound files, perform
operations over the network apart from normal data
processing tasks
...
In such a program if we start
using the normal integer data type to represent variables that
hold different entities we would soon lose track of what that
integer value actually represents
...

At several places in Windows programming we are required
to gather and work with dissimilar but inter-related data
...
But when we define any
structure variable we are required to precede it with the
keyword struct
...
You would agree
that the following declarations
RECT r ;
int i ;
are more logical than
struct RECT r ;
int i ;
Imagine a situation where each programmer typedefs the integer
to represent a color in different ways
...
All these
have been stored in header files
...


Pointers in the 32-bit World
In a 16-bit world (like MS-DOS) we could run only one
application at a time
...
As
only one program (task) could run at a time this environment was

540 Complete Guide To C
called single-tasking environment
...
Under 32bit environment like Windows several programs reside and work
in memory at the same time
...
But the moment there are multiple programs running
in memory there is a possibility of conflict if two programs
simultaneously access the machine resources
...
To channelize the access without resulting into
conflict between applications several new mechanisms were
created in the Microprocessor & OS
...
This is not a
Windows OS book
...
These topics are ‘Memory
Management and Device Access’
...
To add to this, under Windows several
such applications run in memory simultaneously
...
Hence Windows had to evolve a new
memory management model
...
Whenever we
store a value at a memory location the address of this memory
location has to be stored in the CPU register at some point in time
...
This means
that we can store 232 unique addresses in the registers at different
times
...
As pointers store addresses, every pointer under
32-bit environment also became a 4-byte entity
...

Hence Windows uses a memory model which makes use of as
much of physical memory (say 128 MB) as has been installed and
simulates the balance amount of memory (4 GB – 128 MB) on the
hard disk
...
Thus memory management is
demand based
...

They have to be first brought into physical memory before they
can get executed
...
If this new program
needs more memory than what is available right now, then some of
the existing programs (or their parts) would be transferred to the
disk in order to free the physical memory to accommodate the new
program
...
Here
page stands for a block of memory (usually of size 4096 bytes)
...
This keeps on
happening without a common user’s knowledge all the time while
working with Windows
...

When the program is paged in (from disk to memory) there is
no guarantee that it would be brought back to the same

physical location where it was before it was paged out
...
Suppose we have a pointer pointing to some data
present in a page
...
Hence under Windows the pointer never
holds the physical address of any memory location
...
What is this virtual address? At

542 Complete Guide To C
its name suggests it is certainly not a real address
...
These parts when used in conjunction
with a CPU register called CR3 and contents of two tables called
Page Directory Table and Page Table leads to the actual physical
address
...
1
...
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
...
Index Page Table Index Page Byte Offset
21 11
Page Directory Page Table Target Page
PT0
PFN n
PT1
PT n
PFN 0

Page Frames

Page Directory
Register
Physical Memory

Chapter 16: C Under Windows 543
offset (from the start of the page) of the physical memory location
to be accessed
...

Hence an application can never directly reach a physical address
...


Device Access
All devices under Windows are shared amongst all the running
programs
...
The access to a device is routed through a device

driver program, which finally accesses the device
...
It is device driver’s responsibility to ensure that
multiple requests coming from different applications are handled
without causing any conflict
...


DOS Programming Model
Typical 16-bit environments like DOS use a sequential
programming model
...
The path along which the
control flows from start to finish may vary during each execution
depending on the input that the program receives or the conditions
under which it is run
...

C programs written in this model begin execution with main( )
(often called entry point) and then call other functions present in
the program
...
In this programming
model it is the program and not the operating system that
determines which function gets called and when
...
If the program wishes it can take help of the OS to carry

544 Complete Guide To C
out jobs like console I/O, file I/O, printing, etc
...
the program has to call another set of
functions called ROM-BIOS functions
...
Hence to call them the program had to use a
mechanism called interrupts
...
Moreover, communication with these functions
has to be done using CPU registers
...

To an extent these difficulties are reduced by providing library
functions that in turn call the DOS/BIOS functions using
interrupts
...
DOS functions either call BIOS functions or
directly access the hardware
...
This has to be done because either there are no
DOS/BIOS functions to do this, or if they are there their reach is
limited
...
2 captures the essence of the DOS programming model
...
2
From the above discussion you can gather that there are several
limitations in the DOS programming model
...
EXE) for that program
...


546 Complete Guide To C
Inconsistent Look and Feel
Every DOS program has a different user interface that the user has
to get used to before he can start getting work out of the program
...
This happened
because DOS/BIOS doesn’t provide any functions for creating
user interface elements like menus
...
For
example, if we are to position the cursor on the screen using a
BIOS function we are required to remember the following details:
Interrupt number – 16
CPU Registers to be used:
AH – 2 (service number)
DH – Row number where cursor is to be positioned
DL – Column number where cursor is to be positioned
While using these interrupt numbers and registers there is always a
chance of error
...
This is because for every
new piece of hardware introduced there are new interrupt numbers
and new register details
...


Chapter 16: C Under Windows 547
Moreover the DOS programmer has to write lot of code to detect
the hardware on which his program is running and suitably make
use of the relevant interrupts and registers
...
As a result the programmer
has to spend more time in understanding the hardware than in the
actual application programming
...

Another change that the user may feel and appreciate is the ability
of Windows OS to execute several programs simultaneously,
switching effortlessly from one to another by pointing at windows
and clicking them with the mouse
...
However, from the
programmer’s point of view programming for Windows is a whole
new ball game!
Windows programming model is designed with a view to:
(a)
(b)
(c)
(d)
Eliminate the messy calling mechanism of DOS
Permit true reuse of commonly used functions
Provide consistent look and feel for all applications
Eliminate hardware dependency
Let us discuss how Windows programming model achieves this
...
These functions are called API (Application
Programming Interface) functions
...
They help an application to perform
various tasks such as creating a window, drawing a line,
performing file input/output, etc
...
Imagine how much disk space would have
been wasted had each of these functions become part of the EXE

file of each program
...
DLL
...
A DLL is a binary file
that provides a library of functions
...
These functions can also be shared
between several applications running in Windows
...
As a result, the size of EXE files does not go out of
hand
...
You would like
to do this for two reasons:
(a)
(b)
Sharing common code between different executable files
...

The Windows API functions come in three DLL files
...
3
lists these filenames along with purpose of each
...
DLL Contains functions that are responsible
for window management, including
menus, cursors, communications,
timer etc
...
DLL Contains functions for graphics drawing
and painting
KERNEL32
...


Figure 16
...
As a result, user doesn’t have
to spend long periods of time mastering a new program
...
A
window is identified by a title bar
...
The display of information
too large to fit on a single screen can be viewed using scroll bars
...
One dialog box is found in almost every
Windows program
...
This dialog box looks the same
(or very similar) in many different Windows programs, and it is
almost always invoked from the same menu option
...
The menus and dialog boxes
allow user to experiment with a new program and explore its
features
...
Although most functions of Windows
programs can be controlled through the keyboard, using the mouse
is often easier for many chores
...
All menus have the same keyboard and
mouse interfaces because Windows—rather than the application
program—handles this job
...
Thus an application can easily communicate with
OS
...
Let us understand why it does so with the help of
an example
...
The menu item can be selected either using the
keyboard or using the mouse
...
Sooner
or later the user would press the key or click the mouse to select
the menu-item
...
The occurrence of this event is sensed by the keyboard or
mouse device driver
...
Windows would in turn notify the application
about the occurrence of this event
...
Thus the OS has communicated with the application
...
This API function in turn
communicates with the device driver of the graphics card (that
drives the screen) to display the string
...
This is shown
in Figure 16
...


Chapter 16: C Under Windows 551
Hardware
API Call Message
Device Driver
Windows OS
Application

Figure 16
...
Doing so would not affect the application at
all
...
Any differences that may
be there in the new set of mouse and keyboard would be handled
the device driver and not by the application program
...
In short hardware independence at work!
At times a change of device may necessitate a change in the device
driver program, but never a change in the application
...
For each event a message is sent to the program and the
program reacts to it
...
As a result, the order of

552 Complete Guide To C
calling the functions in the program (that react to different
messages) is dictated by the order of occurrence of events
...

That’s really all that is there to event-driven programming
...
Just when that time is, no
one except the user can really say
...
In addition to this some events may occur without
any user interaction
...
Not
only this, occurrence of one event may trigger a few more events
...
Naturally, a question comes—in which
order would these messages get processed by the application
...
The messages in the queue
are processed in First In First Out (FIFO) order
...
There is one queue,
which is common for all applications
...
In addition there is one queue per
application
...
Let us understand the need for maintaining so many
queues
...
The OS retrieves
this message finds out with regard to which application the
message has been sent
...
Refer Figure 16
...

Application2 Application2
Msg
...
Queue
Application1
Event Event
Device Driver Device Driver
Other OS
Mess
Other
Messa
System Msg
...
Msg
...
5
I think now we have covered enough ground to be able to actually
start C under Windows programming
...
Here is the
program…
#include ...
Firstly take
a look at the output that it produces
...
6
Let us now look at the steps that one needs to carry to create and
execute this program:
(a)
(b)
(c)
(d)
Start VC++ from ‘Start | Programs | Microsoft Visual C++
6
...
The VC++ IDE window will get displayed
...
Click on OK
...
Click on OK
...

Select ‘An empty project’ option and click ‘Finish’ button
...
Close it by
clicking on OK
...
Give the file
name as ‘sample1
...
Click on OK
...
c’ file that gets opened in

the VC++ IDE
...

To execute the program follow the steps mentioned below:
From the Build menu, select ‘Build sample1
...

Assuming that no errors were reported in the program, select
‘Execute sample1
...

Let us now try to understand the program
...
Thus
WinMain( ) becomes the entry point for a Windows program
...
It indicates the calling
convention used by the WinMain( ) function
...

Whether the caller function or called function removes the
arguments from the stack at the end of the call
...
Both these calling
conventions pass arguments to functions from right to left
...
All

556 Complete Guide To C
API functions use __stdcall calling convention
...

HINSTANCE and LPSTR are nothing but typedefs
...
These macros
are defined in ‘windows
...
This header file must always be
included while writing a C program under Windows
...
In place of these we can use i, j, k and l
respectively
...

− WinMain( ) receives four parameters which are as under:
hInstance: This is the ‘instance handle’ for the running
application
...
We will use this value in many Windows
functions to identify an application’s data
...

The entity could be an application, a window, an icon, a
brush, a cursor, a bitmap, a file, a device or any such entity
...
What is
important is that there is a unique handle for each entity and
we can refer and reach the entity only using its handle
...
Now it
always contains a value 0
...

lpszCmdLine: This is a pointer to a character string
containing the command line arguments passed to the
program
...


Chapter 16: C Under Windows 557
nCmdShow: This is an integer value that is passed to the
function
...

− The MessageBox( ) function pops up a message box whose
title is ‘Title’ and which contains a message ‘Hello!’
...

− Instead of printing ‘Hello!’ in the message box we can print
the command line arguments that the user may supply while
executing the program
...
7
...
7
Note from Figure 16
...
exe’ is the name of our
application, whereas, ‘abc ijk xyz’ represents command line
arguments
...
This string can be printed using the following
statement:
MessageBox ( 0, lpszCmdline, "Title", 0 ) ;
If the entire command line including the filename is to be
retrieved we can use the GetCommandLine( ) function
...
According to this convention the variable name begins
with a lower case letter or letters that denotes the data type of the
variable
...
Prefixes are
often combined to form other prefixes, as lpsz in lpszCmdLine
stands for ‘long pointer to a zero terminated string’
...
This is because when a transition happens from say a
16-bit code to 32-bit code then a whole lot of variable names have
to be changed
...
When this code is ported to a 32-bit environment
wParam had to be changed to lParam since in this environment

every integer is 4 bytes long
...
Hence the usage of this convention is
nowadays discouraged
...
To use a twobyte integer pre-qualify it with short
...

Windows programming involves a heavy usage of typedefs
...

Entry point of every Windows program is a function called
WinMain( )
...

Windows uses a Demand-based Virtual Memory Model to
manage memory
...

Windows maintains a system message queue common for all
applications
...

Calling convention decides the order in which the parameters
are passed to a function and whether the calling function or
the called function clears the stack
...


Hungarian notation though good its usage is not
recommended any more
...

A Windows program can directly call a device driver program
for a device
...

DOS functions are called using an interrupt mechanism
...

Size of a pointer under Windows depends upon whether it is
near or far
...

One of the parameters of WinMain( ) called hPrevInstance
is no longer relevant
...

Write a program that displays three buttons ‘Yes’, ‘No’
‘Cancel’ in the message box
...

Write a program that displays command line arguments
including file name in a message box
...
I
hope Chapter 16 has been able to bring about this change
...
This is what this chapter intends to do
...


E
The Role of a Message Box
Often we are required to display certain results on the screen
during the course of execution of a program
...
In a sequential DOS based program we can easily
achieve this using printf( ) statements
...
So you can imagine what chaos would it create if
all running applications are permitted to write to the screen
...

Hence no Windows program is permitted to write anything directly
to the screen
...
Using
it we can display intermediate results during the course of
execution of a program
...
There are numerous variations that you can try with the
MessageBox( )
...
Though the above message boxes give you
flexibility in displaying results, button, icons, there is a limit to
which you can stretch them
...
in the message box
...
To achieve this we need to create a full-fledged
window
...


Here Comes the window…
Before we proceed with the actual creation of a window it would
be a good idea to identify the various elements of it
...
1
...
1
Note that every window drawn on the screen need not necessarily
have every element shown in the above figure
...

Let us now create a simple program that creates a window on the
screen
...
h>

564 Complete Guide To C
int _stdcall WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow )
{
HWND h ;
h = CreateWindow ( “BUTTON”, “Hit Me”, WS_OVERLAPPEDWINDOW,
10, 10, 150, 100, 0, 0, i, 0 ) ;
ShowWindow ( h, nCmdShow ) ;
MessageBox ( 0, “Hi!”, “Waiting”, MB_OK ) ;
return 0 ;
}
Here is the output of the program…
Figure 17
...
Every window enjoys certain
properties—background color, shape of cursor, shape of icon, etc
...

The meaning of ‘class’ here is ‘type’
...
Once a window class is registered we
can create several windows of that type
...
There are several predefined window classes
...
Our program
has created one such window using the predefined BUTTON class
...
This function requires several parameters
starting with the window class
...
The third
parameter specifies the window style
...
The
next four parameters specify the window’s initial position and
size—the x and y screen coordinates of the window’s top left
corner and the window’s width and height in pixels
...
The last parameter is the
pointer to the window-creation data
...
But don’t get scared of it
...
You
can always use MSDN (Microsoft Developer Network) help to
understand the minute details of each parameter
...
0 product
...
msdn
...
com/library
...
We still are to display it on the screen
...
CreateWindow( )
returns handle of the created window
...
The
second parameter passed to ShowWindow( ) signifies whether the
window would appear minimized, maximized or normal
...
We have passed nCmdShow as the second
parameter
...
Hence our program displays a normal sized window
...
All these macros
are #defined in the ‘Windows
...


On executing this program a window and a message box appears
on the screen as shown in the Figure 17
...
The window and the
message box disappear as soon as we click on OK
...

You can try to remove the call to MessageBox( ) and see the
result
...
Thus a call to MessageBox( ) serves the similar
purpose as getch( ) does in sequential programming
...
The program to do this is given below
...
h>
int _stdcall WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow )
{
HWND h[10] ;
int x ;
for ( x = 0 ; x <= 9 ; x++ )
{

Chapter 17: Windows Programming 567
h[x] = CreateWindow ( "BUTTON", "Press Me",
WS_OVERLAPPEDWINDOW, x * 20,
x * 20, 150, 100, 0, 0, i, 0 ) ;
ShowWindow ( h[x], l ) ;
}
MessageBox ( 0, "Hi!", "Waiting", 0 ) ;
return 0 ;
}
Figure 17
...
You may experiment a bit by changing the name
of the window class to EDIT and see the result
...

For creating such a window there is no standard window class
available
...
Instead of straightway jumping to a program that draws

568 Complete Guide To C
shapes in a window let us first write a program that creates a
window using our window class and lets us interact with it
...
h>
#include "helper
...
4
appears on the screen
...
We
can stretch its size by dragging its boundaries
...

Figure 17
...


Creation and Displaying of Window
Creating and displaying a window on the screen is a 4-step
process
...

Registering the window class with the OS
...

Displaying the window on the screen
...
This structure contains several

570 Complete Guide To C
elements
...
Registration

of a window class, creation of a window and displaying of a
window involves calling of API functions RegisterClassEx( ),
CreateWindow( ) and ShowWindow( ) respectively
...
h’
...
The complete listing of
‘helper
...
Alternatively you can
download it from the following link:
www
...
com/books/letusc/sourcecode/helper
...
h’ file
...
Remember to copy this
file to your project directory—the directory in which you are going
to create this program
...


Interaction with Window
As and when the user interacts with the window—by stretching its
boundaries or clicking the buttons in the title bar, etc
...
Our
application should now pick them up from the message queue and
process them
...
For example, a mouse click
message would contain additional information like handle to the
window with which the user has interacted, the coordinates of

Chapter 17: Windows Programming 571
mouse cursor and the status of mouse buttons
...
h’
...

In WinMain( ) this MSG structure is retrieved from the message
queue by calling the API function GetMessage( )
...
GetMessage( ) would pick the message info
from the message queue and place it in the structure variable
passed to it
...

After picking up the message from the message queue we need to
process it
...
This function does several activities
...


From the handle it figures out the window class based on
which the window has been created
...

Well I didn’t tell you earlier that in InitInstance( ) while
filling the WNDCLASSEX structure one of the elements has
been set up with the address of a user-defined function called
WndProc( )
...

Since several messages get posted into the message queue picking
of the message and processing it should be done repeatedly
...
When GetMessage( ) encounters a
message with id WM_QUIT it returns a 0
...


572 Complete Guide To C
Reacting to Messages
As we saw in the previous section, for every message picked up
from the message queue the control is transferred to the
WndProc( ) function
...
The first parameter
is the handle to the window for which the message has been
received
...

LRESULT is a typedef of a long int and represents the return
value of this function
...

This typedef has been done in ‘windows
...
CALLBACK
indicates that the WndProc function has been registered with
Windows (through WNDCLASSEX structure in InitInstance( ) )
with an intention that Windows would call this back (through
DispatchMessage( ) function)
...
If the id is WM_DESTROY then we have called the
function OnDestroy( )
...
In OnDestroy( ) function we have called the API
function PostQuitMessage( )
...
As we saw earlier, when this
message is picked up the message loop and WinMain( ) is
terminated
...
Here we have simply made a call to
DefWindowProc( ) API function
...
The
default processing for different message would be different
...

Actually speaking when we close the window a WM_CLOSE
message is posted into the message queue
...
The DefWindowProc( ) function destroys
the window and places a WM_DESTROY message in the
message queue
...

That brings us to the end of a lonnngggg explanation! You can
now heave a sigh of relief
...
A very clear understanding of it
would help you make a good Windows programmer
...
5
...
5

Chapter 17: Windows Programming 575

Program Instances
Windows allows you to run more than one copy of a program at a
time
...
Each running copy of a program is
called a ‘program instance’
...
It
shares a single copy of the program’s code between all running
instances
...
All three instances share the same code, but will have
separate memory areas to hold the text data being edited
...
The program logic to edit the files
is the same for every instance, so there is no reason why a single
copy of Notepad’s code cannot be shared
...

Message boxes are often used to ascertain the flow of a
program
...

The CreateWindow( ) API function creates the window in
memory
...

A ‘window class’ specifies various properties of the window
that we are creating
...
h’ contains declaration of several
macros used in Windows programming
...

A message contains the message id and additional information
about the message
...

If we don’t handle a message received by our application then
the DefWindowProc( ) function is called to do the default
processing
...

(b) Calling the MessageBox( ) function displays the specified
string in console window
...

(d) The ShowWindow( ) function can display only the
maximized window
...

(f) Window classes are similar to classes in C++
...

(h) The style WS_OVERLAPPED | WS_CAPTION |
WS_MINIMIZEBOX will create a window with caption bar
and minimize box only
...

[B] Answer the following:
(a) Outline the steps that a typical Windows program follows
during execution
...

(c) How would you minimize a window programmatically?
(d) What would happen if we do not place WM_QUIT message
in the message queue when the user tries to close the window
...

(f) What is the difference between GetMessage( ) and
DispatchMessage( ) function?
(g) Write a program, which receives an integer as a command line
argument, creates a button window, and based on the value of
the integer displays button window as maximized / minimized
/ normal
...


578 Complete Guide To C

18 Graphics Under
Windows
• Graphics as of Now
• Device Independent Drawing
• 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

579
580 Complete Guide To C
ince times immemorial colors and shapes have fascinated
mankind like nothing else
...
In fact the graphical ability of Windows has played a very
important role in its success story
...


S
Graphics as of Now
World has progressed much beyond 16 colors and 640 x 480
resolution graphics that Turbo C/C++ compilers offered under
MS-DOS environment
...
7 million colors
...
So much so that a 16-color graphics program
built using Turbo C working on a poor resolution almost hurts the
eye
...
I am sure that this chapter will
help you understand and appreciate these new capabilities
...
A Windows program that works on a VGA
display will work without modification on an SVGA or on a XGA
display that Windows supports
...
We will explore how the device context can be
used for both text and graphics output, and how using the device
context keeps our programs from interfering with each other on the
screen
...
Device independence means that
the same program should be able to work using different screens,
keyboards and printers without modification to the program
...
If you have ever had to update
the code of an MS-DOS program for the latest printer, plotter,
video display, or keyboard, you will recognize device
independence as a huge advantage for the developer
...
A Windows program knows where (screen/printer) its
output is being sent
...
This is
because Windows uses a standard and consistent way to send the
output to screen/printer
...
Different DC’s are associated
with different devices
...
Any
drawing that we do using the screen DC is directed to the screen
...
Thus, the only thing that changes from drawing to screen
and drawing to printer is the DC that is used
...
The output data is sent to the screen/printer using its
DC, and then Windows and the Device Driver for the device takes
care of sending it to the real hardware
...

The part of Windows that converts the Windows graphics function
calls to the actual commands sent to the hardware is the GDI, or
Graphics Device Interface
...
DLL and is stored in the Windows System directory
...
DLL into memory when it is
needed for graphical output
...
DLL
...
SYS for VGA video screen and
HPPLC
...
Drivers are just programs
that assist the GDI in converting Windows graphics commands to
hardware commands
...
The GDI provides this
insulation by calling the appropriate device driver in response to
windows graphics function calls
...
Note that though we are displaying text under Windows

even text gets drawn graphically in the window
...

# include ...
h"
void OnPaint ( HWND ) ;
void OnDestroy ( HWND ) ;
int __stdcall WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdline, int nCmdShow )
{
MSG m ;
/* Perform application initialization */
InitInstance ( hInstance, nCmdShow, "Text" ) ;

Chapter 18: Graphics Under Windows 583
/* Main message loop */
while ( GetMessage ( &m, NULL, 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 ;
case WM_PAINT :
OnPaint ( hWnd ) ;
break ;
default :
return DefWindowProc ( hWnd, message, wParam, lParam ) ;
}
return 0 ;
}
void OnDestroy ( HWND hWnd )
{
PostQuitMessage ( 0 ) ;
}
void OnPaint ( HWND hWnd )
{
HDC hdc ;
PAINTSTRUCT ps ;
HFONT hfont ;
LOGFONT f = { 0 } ;
HGDIOBJ holdfont ;
char *fonts[ ] = { "Arial", "Times New Roman", "Comic Sans MS" } ;
int i ;

584 Complete Guide To C
hdc = BeginPaint ( hWnd, &ps ) ;
for ( i = 0 ; i < 3 ; i++ )

{
strcpy ( f
...
lfHeight = 40 * ( i + 1 ) ; /* font height */
f
...
1
appears
...
1

Chapter 18: Graphics Under Windows 585
Drawing to a window involves handling the WM_PAINT
message
...
This redrawing would be required in
the following situations:
(a)
(b)
(c)
(d)
(e)
When the Window is displayed for the first time
...

When some portion of the window is overlapped by another
window and the overlapped window is dismissed
...

When the window is dragged out of the screen and then
brought back into the screen
...
In this case the window saves the area
overlapped by the cursor and restores it when the cursor moves to
another position
...
Within OnPaint( ) we have called the API
function BeginPaint( )
...
Additionally it also fills the PAINTSTRUCT
structure with information about the area of the window which
needs to be repainted
...
After obtaining the device context handle, the
control enters a loop
...
Each time through the loop we have setup a
LOGFONT structure f
...
Note
that in addition to these there are other font properties that may be
setup
...
Once the font properties have been setup we have
called the CreateFontIndirect( ) API function to create the font
...
Then using the
information in the font file and the font properties setup in the
LOGFONT structure it creates a font in memory
...
This handle is then passed to the SelectObject( ) API
function to get the font into the DC
...
Next we have used the SetTextColor( ) API
function to set the color of the text to be displayed through
TextOut( )
...
Note that each
color component can take a value from 0 to 255
...

With hfont only one font can be associated at a time
...
Once outside the loop we
have called the EndPaint( ) API function to release the DC
handle
...

In place of TextOut( ) we can also use the DrawText( ) API
function
...
You can explore this function on your own
...
Instead of showing the
entire program given below is the listing of OnPaint( )
...
Here onwards I
would be showing only the OnPaint( ) handler unless otherwise
required
...
2
appears
...
2
For drawing any shape we need a pen to draw its boundary and a
brush to paint the area enclosed by it
...
The default pen is a solid pen of black color and the
default brush is white in color
...

As before, we begin by obtaining a handle to the DC using
BeginPaint( ) function
...
The second
parameter of this function specifies the color of the brush
...
Next we have selected this brush in the DC
...

Once we have selected the brush into the DC we are ready to draw
the shapes
...
Similarly for drawing a rectangle we
have used the Rectangle( ) function
...
In RoundRect ( x1, y1, x2, y2, x3, y3 ), x1, y1 represents
the x and y-coordinates of the upper-left corner of the rectangle
...
x3, y3 specify the width and height of the ellipse
used to draw the rounded corners
...

Parameters of Ellipse( ) specify coordinates of bounding rectangle
of the ellipse
...

The center of the arc is the center of the bounding rectangle
specified by x1, y1 and x2, y2
...
x3, y3 and x4, y4 specify the x and y-coordinates of the

arc’s starting point and ending point respectively
...
Each point in the
array is a POINT structure
...
The system closes the polygon
automatically, if necessary, by drawing a line from the last vertex
to the first
...


Types of Pens
In the previous program we have used the default solid black pen
of thickness 1 pixel
...
The following OnPaint( )
handler shows how this can be achieved
...
3
appears
...
3
A new pen can be created using the CreatePen( ) API function
...
Different macros like PS_SOLID, PS_DOT, etc
...
h’ to represent different pen styles
...


Types of Brushes
The way we can create different types of pens, we can also create
three different types of brushes
...
Let us now write a program that shows
how to build these brushes and then use them to fill rectangles
...

void OnPaint ( HWND hWnd )
{
HDC hdc ;
PAINTSTRUCT ps ;
HBRUSH hbr ;

Chapter 18: Graphics Under Windows 593
HGDIOBJ holdbr ;
HBITMAP hbmp ;
hdc = BeginPaint ( hWnd, &ps ) ;
hbr = CreateSolidBrush ( RGB (255, 0, 0 ) ) ;
holdbr = SelectObject ( hdc, hbr ) ;
Rectangle ( hdc, 5, 5, 105, 100 ) ;
SelectObject ( hdc, holdbr ) ;
DeleteObject ( hbr ) ;
hbr = CreateHatchBrush ( HS_CROSS, RGB ( 255, 0, 0 ) ) ;
holdbr = SelectObject ( hdc, hbr ) ;
Rectangle ( hdc, 125, 5, 225, 100 ) ;
SelectObject ( hdc, holdbr ) ;
DeleteObject ( hbr ) ;
hbmp = LoadBitmap ( hInst, MAKEINTRESOURCE ( IDB_BITMAP1 ) ) ;
hbr = CreatePatternBrush ( hbmp ) ;
holdbr = SelectObject ( hdc, hbr ) ;
Rectangle ( hdc, 245, 5, 345, 100 ) ;
SelectObject ( hdc, holdbr ) ;
DeleteObject ( hbr ) ;
DeleteObject ( hbmp ) ;

EndPaint ( hWnd, &ps ) ;
DeleteObject ( hbr ) ;
}

594 Complete Guide To C
On execution of this program the window shown in Figure 18
...

Figure 18
...
Creating and using a solid brush and hatched brush
is simple
...
For the hatch brush we
have used the style HS_CROSS
...
h’ that you can experiment with
...
Instead of creating this pattern, we have used a
readymade bitmap file
...

Bitmaps, menus, icons, cursors that a Windows program may use
are its resources
...
If so done
we do not have to ship these resources separately
...
Instead we need to carry out the steps
mentioned below to add a bitmap file to the project
...
0 select the
‘Resource’ option
...

Select the suitable
...

From the ‘File’ menu select the save option to save the
generated resource script file (Script1
...
When we select
‘Save’ one more file called ‘resource
...

Add the ‘Script1
...

While using the bitmap in the program it is always referred using
an id
...
h’
...
bmp file
on the disk
...
rc’ file
...
h’ file in the program
...
We have done this using the LoadBitmap( ) API
function
...
When InitInstance( ) function is
called from WinMain( ) it stores the instance handle in a global

variable hInst
...
The
second parameter passed to it is a string representing the bitmap
...
The LoadBitmap( ) function
returns the handle to the bitmap
...
This brush is then selected into
the DC and then a rectangle is drawn using it
...
On the other hand
if the bitmap is smaller than the rectangle it is suitably replicated
...


596 Complete Guide To C
Code and Resources
A program consists of both instructions and static data
...

Static data are character strings, data to create fonts, bitmaps, etc
...
The Windows term
for static data is ‘Resource data’, or simply ‘Resources’
...
Separating the code from the resource
data has other advantages like reducing memory demands and
making programs more portable
...


Freehand Drawing, the Paintbrush Style
Even if you are knee high in computers I am sure you must have
used PaintBrush
...
Let us see if we too can achieve this
...
Then as we move the mouse on the table with the left
mouse button depressed the freehand drawing should get drawn in
the window
...

The mouse input comes in the form of messages
...
Let us
now see how these messages are tackled for drawing freehand
...
5
appears
...
We can then drag the
mouse on the table to draw the freehand
...


Chapter 18: Graphics Under Windows 599
Figure 18
...
However,
if we do so the freehand would be broken at several places
...
A solution to this
problem is to construct the freehand using small little line
segments
...
These lines
are so small is size that you would not even recognize that the
freehand has been drawn by connecting these small lines
...
When the
WM_LBUTTONDOWN message arrives the WndProc( )
function calls the handler OnLButtonDown( )
...

These coordinates are obtained in lParam in WndProc( )
...
The LOWORD and HIWORD macros have been
used to separate out these x and y - coordinates from lParam
...

When OnMouseMove( ) gets called it checks whether the left
mouse button stands depressed
...
If it does, then the
current mouse coordinates are set up in the global variables x2, y2
...
Next time around x2, y2 should
become the starting of the next line
...

Note that here we have obtained the DC handle using the API
function GetDC( )
...

Also, the handle obtained using GetDC( ) should be released using
a call to ReleaseDC( ) function
...
Can you draw any
conclusions?

Capturing the Mouse
If in the process of drawing the freehand the mouse cursor goes
outside the client area then the window below our window would

Chapter 18: Graphics Under Windows 601
start getting mouse messages
...
If this has to be avoided then we should ensure that
our window continues to receive mouse messages even when the
cursor goes out of the client area of our window
...

We have captured the mouse in OnLButtonDown( ) handler by
calling the API function SetCapture( )
...
In the
OnLButtonUp( ) handler we have released the captured mouse by
calling the ReleaseCapture( ) API function
...
In fact a DC is
nothing but a structure that holds handles of various drawing
objects like font, pen, brush, etc
...
6
...
Bitmap
400
White Brush
200
Black Pen
Default Drawing Objects
App2
Drawing Object
1000
Blue
Brush
900
Red
Pen
HPEN
HBRUSH
HBITMAP
HFONT
Screen DC
800

...


...


...

Other Info
200
400
600

Figure 18
...
6:
(a)
(b)
(c)
The DC doesn’t hold the drawing objects like pen, brush, etc
...

With each DC a default monochrome bitmap of size 1 pixel x
1 pixel is associated
...
are shared by
different DCs in same or different applications
...

Two different applications would need two different DCs
even though both would be used to draw to the same screen
...

A common Device Driver would serve the drawing requests
coming from different applications
...

Screen and printer DC is OK, but what purpose would a memory
DC serve? Well, that is what the next program would explain
...
How about drawing images on the screen?
Windows does not permit displaying a bitmap image directly using
a screen DC
...
To account for such possibilities while

displaying a bitmap Windows uses a different mechanism—a
‘Memory DC’
The way anything drawn using a screen DC goes to screen,
anything drawn using a printer DC goes to a printer, similarly
anything drawn using a memory DC goes to memory (RAM)
...
(Note that this handle was of little use In case of
screen/printer DC)
...
You would
agree 1 x 1 is too small a place to draw even a small line
...

How can this be done? Simple, just replace the handle of the 1 x 1
bitmap with the handle of a bigger and colored bitmap object
...
7
...


...

Memory DC after selecting bitmap
40000
200
Black Pen
400
White Brush
40000
190x220 24 –color
bitmap
800
New O/P Device Font
HPEN
HBRUSH
HBITMAP
HFONT
200
Other Info
400
405
800

...


...
7
What purpose would just increasing the bitmap size/color would
serve? Whatever we draw here would get drawn on the bitmap but
would still not be visible
...

Before transferring the image to the screen DC we need to make
the memory DC compatible with the screen DC
...
Looking at these values the screen
device driver would suitably adjust the colors when the pixels in

Chapter 18: Graphics Under Windows 605
the bitmap of memory DC is transferred to screen DC using
BitBlt( ) function
...
The program merely displays the image of a vulture in a
window
...
7
...
7
As usual we begin our drawing activity in OnPaint( ) by first
getting the screen DC using the BeginPaint( ) function
...
Its usage is similar to what we saw while
creating a pattern brush in an earlier section of this chapter
...
To do this we have called
the API function CreateCompatibleDC( )
...
The function
in turn returns the handle to the memory DC
...
Lastly, we have
performed a bit block transfer (a bit by bit copy) from memory DC
to screen DC using the function BitBlt( )
...

We have made the call to BitBlt( ) as shown below:
BitBlt ( hdc, 10, 20, 190, 220, hmemdc, 0, 0, SRCCOPY ) ;

Chapter 18: Graphics Under Windows 607
Let us now understand its parameters
...
If we give 10, 20 then
the image from 10, 20 to bottom right corner of the bitmap would
get blitted
...
These
codes define how the color data for the source rectangle is to be
combined with the color data for the destination rectangle to
achieve the final color
...


Animation at Work
Speed is the essence of life
...
So let us now see how to achieve this
animation and sound effect
...

Prepare the image for later display
...

Check for collisions while displaying the prepared image
...
As the ball strikes the walls of the

608 Complete Guide To C
window a noise occurs
...
Given
below is the WndProc( ) function
and the various message handlers that help achieve animation and
sound effect
...
right - 22 ;
y = rand( ) % r
...
wav", NULL, SND_FILENAME | SND_ASYNC ) ;
}
else if ( x > ( r
...
right - wd ;
dx = -10 ;
PlaySound ("chord
...
wav", NULL, SND_FILENAME | SND_ASYNC ) ;
}
else if ( y > ( r
...
bottom - ht ;
dy = -10 ;
PlaySound ( "chord
...
For these messages we have called the handlers
OnCreate( ) and OnTimer( ) respectively
...
Since usually a window is created only once, the one-time
activity that is to be carried out in a program is usually done in
OnCreate( ) handler
...
To do this it
would be necessary to blit the ball image several times
...
As this is a one-time activity

it has been done in the handler function OnCreate( )
...

Apart from preparing the image for blitting we have also done
some intialialisations like setting up values in some variables to
indicate the initial position of the ball
...
This function tells Windows to post a
message WM_TIMER into the message queue of our application
every 50 milliseconds
...

Use a Windows mechanism of timer
...

The first method would seriously hamper the responsiveness of the
program
...
The second choice is better because it makes
the program event driven
...
At other times the application is free to handle other
messages that come to its queue
...
We have also
checked if the ball has hit the boundaries of the window
...


A Few More Points…
A few more points worth noting before we close our discussion on
animation…
(a)
(b)
(c)
(d)
(e)
One application can set up multiple timers to do different jobs
at different intervals
...
In
our case we have specified the id as 1
...
Each time it would pass the timer id
as additional information about the message
...
While erasing we have used the raster
operation code WHITENESS
...
Thus red colored
pixels of ball would get ignored leading to erasure of the ball
in the window
...

We want that every time we run the application the initial
position of the ball should be different
...
However, this function doesn’t

Chapter 18: Graphics Under Windows 613
generate true random numbers
...
This has been achieved by
making the call
srand ( time ( NULL ) ) ;
Here time( ) is function that returns the time
...

(f)
(g)
(h)
(i)
To be able to use rand( ) and srand( ) functions include the
file ‘stdlib
...
Similarly for time( ) function to work include
the file ‘time
...

In the call to the PlaySound( ) function the first parameter is
the name of the wave file that is to be played
...
The
third parameter is a set of flags
...

To be able to use the PlaySound( ) function we need to link
the library ‘winmm
...
This is done by using ‘Project |
Settings’ menu item
...
In the ‘Link’ tab of this dialog mention the name
‘winmm
...

When the application terminates we have to instruct Windows
not to send WM_TIMER messages to our application any
more
...


Windows, the Endless World…
The biggest hurdle in Windows programming is a sound
understanding of its programming model
...
Once you have understood it
thoroughly rest is just a matter of understanding and calling the
suitable API functions to get your job done
...
It covers areas like Networking, Internet
programming, Telephony, Drawing and Printing, Device I/O,
Imaging, Messaging, Multimedia, Windowing, Database
programming, Shell programming, to name a few
...
No matter
how many programs that we write under Windows, several still
remain to be written
...
The intention all along was not to catch fish for you but
to show you how to catch fish so that you can do fishing all your
life
...

Good luck and happy fishing!

Summary
(a) In DOS, programmers had to write separate graphics code for
every new video adapter
...

(b) A Windows program cannot draw directly on an output device
like screen or printer
...

(c) When the window is displayed for the first time, or when it is
moved or resized OnPaint( ) handler gets called
...

(j) A device context is a structure containing information
required to draw on a display surface
...

(e) To draw using a new pen or brush it is necessary to select
them into the device context
...

(g) RGB is a macro representing the Red, Green and Blue
elements of a color
...

(h) Animation involves repeatedly drawing the same image at
successive positions
...

(b) The WM_PAINT message is generated whenever the client
area of the window needs to be redrawn
...

(d) The default pen in the DC is a solid pen of white color
...

(f) BeginPaint( ) and GetDC( ) can be used interchangeably
...

(h) WM_PAINT message is raised when the window contents are
scrolled
...

(j) The WM_CREATE message arrives whenever a window is
displayed
...

(c) How Windows manages the code and various resources of a
program?
(d) Explain the Windows mechanism of timer
...

[C] Attempt the following:
(a) Write a program, which displays "hello" at any place in the
window where you click the left mouse button
...

(b) Write a program that would draw a line by joining the new
point where you have clicked the left mouse button with the
last point where you clicked the left mouse button
...

(d) Write a program to create chessboard like boxes (8 X 8) in the
client area
...

(e) Write a program that displays only the upper half of a bitmap
of size 40 x 40
...


19 Interaction With
Hardware
• Hardware Interaction
• Hardware Interaction, DOS Perspective

• Hardware Interaction, Windows Perspective
• Communication with Storage Devices
The ReadSector( ) Function
• Accessing Other Storage Devices
• Communication with Keyboard
Dynamic Linking
Windows Hooks
• Caps Locked, Permanently
• Did You Press It TTwwiiccee…
...
This chapter is for the second breed of
programmers
...
Because
it is they who first understand the default working of different
mechanisms that Windows uses and then are able to make those
mechanisms work to their advantage
...
Read on and I am sure you
would be on your path to become a powerful Windows
programmer
...
However, its reach is not limited to interaction
with peripherals
...
Thus more correctly,
interaction with hardware would mean interaction with any chip
other than the microprocessor
...
For example, if the user presses a key or
clicks the mouse button then our program may do something
...

For example, on ticking of a timer our program may want to
do something
...
For example, a program may want to
send a character to the printer, or a program may want to
read/write the contents of a sector from the hard disk
...


Hardware Interaction, DOS Perspective
Under DOS whenever an external event (like pressing a key or
ticking of timer) occurs a signal called hardware interrupt gets
generated
...
As a
reaction to the occurrence of an interrupt a table called Interrupt
Vector Table (IVT) is looked up
...
It is
populated with addresses of different BIOS routines during
booting
...
Once the control
reaches the BIOS routine, the code in the BIOS routine interacts
with the hardware
...
Since these routines serve the interrupts
they are often called ‘Interrupt Service Routines’ or simply ISRs
...
1 to understand this mechanism
...
1
If we want that instead of the default ISR our routine should get
called then it is necessary to store the address of this routine in
IVT
...
For example, we may register our ISR in
IVT to gain finer control over the way key-hits from the keyboard
are tackled
...

Explicit communication with the hardware can be done in four
different ways
...
2
...
2
Let us now discuss the pros and cons of using these different
methods to interact with the hardware
...
These functions can either directly interact with the
hardware or they may call BIOS functions which in turn
interact with the hardware
...
However, since DOS functions do not have names
they have to be called through the mechanism of interrupts
...

Moreover, communication with these functions has to be done
using CPU registers
...

So one has to know details of different CPU registers, how to
use them, which one to use when, etc
...
For other operations like generating graphics,
carrying out serial communication, etc
...

Note that there are some functions in ROM-BIOS that do
same jobs as equivalent DOS functions
...
Hence they have to be called using interrupts and
involve heavy usage of registers
...
Good examples of these functions are printf( ) /
scanf( ) / getch( ) for interaction with console, absread( ) /
abswrite( ) for interaction with disk, bioscom( ) for
interaction with serial port, etc
...
Hence at
some point of time one has to learn how to call DOS/BIOS
functions
...
This has to be done because either there are no
library functions or DOS/BIOS functions to do this, or if they
are there their reach is limited
...
The library functions as well as
the DOS/BIOS functions are unable to do this
...

However, direct interaction with the hardware is difficult
because one has to have good knowledge of technical details
of the chip to be able to do so
...


Chapter 19: Interaction With Hardware 623

Hardware Interaction, Windows Perspective
Like DOS, under Windows too a hardware interrupt gets generated
whenever an external event occurs
...
Unlike DOS the
IDT contains addresses of various kernel routines (instead of BIOS
routines)
...
When
the kernel routine is called, it in turn calls the ISR present in the
appropriate device driver
...

Two questions may now occur to you:
(a)
(b)
Why the kernel routine does not interact with the hardware
directly?
Why the ISR of the device driver not registered directly in the
IDT?
Let us find answer to the first question
...
As new pieces of hardware come
into existence new code has to be written to be able to interact with
them
...
This is practically impossible
...
With every new piece of hardware a
new device driver is provided
...

Let us now answer the second question
...
If the processor
architecture changes then the kernel is bound to change
...
All processor architectures may not use IDT for the
registration and lookup mechanism
...

Refer Figure 19
...

Microprocessor
looks up IDT Suitable
Kernel
routine
is
called
IDT
Address
of ISR1
Address
of ISR2
Kernel
routine1
Kernel
routine2
Suitable
ISR is
called
Key hit / Mouse click
generates an interrupt
Microprocessor
ISR
Device Driver
Suitable
ISR is
called
ISR
Device Driver

Figure 19
...

Under Windows explicit communication with hardware is much
different than the way it was done under DOS
...
To avoid conflict between
different programs accessing the same device simultaneously

Chapter 19: Interaction With Hardware 625
Windows does not permit an application program to directly
access any of the devices
...
These functions have names so calling
them is much easier than calling DOS/BIOS functions
...
It is the device driver

program that finally accesses the device
...
It
is device driver’s responsibility to ensure that multiple requests
coming from different applications are handled without causing
any conflict
...

One last question—won’t the API change if a new device comes
into existence? No it won’t
...
All that would change is the device driver program
for the new device
...
This is
shown in Figure 19
...
4

626 Complete Guide To C
Communication with Storage Devices
Since DOS is commercially dead the rest of the chapter would
focus on communication with the devices under Windows
platform
...

Let us begin with the one that interacts with the simplest storage
device, namely the floppy disk
...
Let us understand
how the information is laid out on a floppy disk
...
Of these, the Boot Sector
contains information about how the disk is organized
...
The files and the directories are stored in the
Data Space
...
The FAT contains information about
where the files and directories are stored in the data space
...
5 shows the four logical parts of a 1
...


Chapter 19: Interaction With Hardware 627
BS - Boot Sector F1 - First copy of FAT
F2 - Second copy of FAT D - Root directory structure
DS - Data space
9
10
2
3
1
16
17
D

F2
D
654
7
8
DS
DS DS
D DS
D
D
DD
D
D
D
D
DDD
13 14 15
12
11
10 18 18
5
2
3
4
1
6
7
8
9
DS
F2 F2 F2
F1
F1
F1
F2
BS
F1
F1 F1
F1
F1
17
15
16
F2
F2
13 14
12
11 F2
F2
F1
Side 0, Track 0 Side 0, Track 1

Figure 19
...
But why on earth would we

ever like to do this? Well, that’s what all Windows-based Antiviral softwares do when they scan for
boot sector viruses
...
h>
# include ...
h>
# include ...
\\A:", 0, 1, &b ) ;
printf ( "Boot Sector name: %s\n", b
...
bps ) ;
printf ( "Sectors per Cluster: %d\n", b
...
6
and Appendix G*/
}
void ReadSector ( char *src, int ss, int num, void* buff )
{
HANDLE h ;
unsigned int br ;
h = CreateFile ( src, GENERIC_READ,
FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0 ) ;
SetFilePointer ( h, ( ss * 512 ), NULL, FILE_BEGIN ) ;
ReadFile ( h, buff, 512 * num, &br, NULL ) )
CloseHandle ( h ) ;

Chapter 19: Interaction With Hardware 629
}
The boot sector contains two parts—‘Boot Parameters’ and ‘Disk

Bootstrap Program’
...
Figure 19
...

Description Length Typical Values
Jump instruction 3 EB3C90
OEM name 8 MSWIN4
...
Root directory entries 2 224
Total sectors 2 2880
Media descriptor 1 F0
Sectors per FAT 2 9
Sectors per track 2 18
No
...
6

630 Complete Guide To C
Using the breakup of bytes shown in Figure 19
...
Notice the usage of #pragma
pack to ensure that all elements of the structure are aligned on a 1byte boundary, rather than the default 4-byte boundary
...
This
is because we want to display the boot sector contents on the
screen rather than in a window
...
Remember that our aim is to interact with the
floppy, and not in drawing and painting in a window
...
So the program is still a Windows application
...
A console application always begins with main( ) rather
than WinMain( )
...
The ReadSector( ) function is quite similar to the
absread( ) library function available in Turbo C/C++ under DOS
...
The syntax for this string is \\machine-name\storagedevice name
...
\\A:, we have used ‘
...
A

...

Needless to say, A: refers to the floppy drive
...
We have specified this as 0
which means the boot sector in case of a floppy disk
...
This
parameter is specified as 1 since the boot sector occupies only a
single sector
...
Here we
have passed the address of the boot structure variable b
...


Chapter 19: Interaction With Hardware 631
Once the contents of the boot sector have been read into the
structure variable b we have displayed the first few of them on the
screen using printf( )
...


The ReadSector( ) Function
With the preliminaries over let us now concentrate on the real stuff
in this program, i
...
the ReadSector( ) function
...
Anytime we are
to communicate with a device we have to firstly call this API
function
...
Windows treats all devices just like files on disk
...

The CreateFile( ) API function takes several parameters
...
The
second parameter is a set of flags that are used to specify the
desired access to the file (representing the device) about to be
opened
...
The third
parameter specifies the sharing access for the file (device)
...
In
general while interacting with any hardware the sharing flag for
the file (device) must always be set to this value since every piece
of hardware is shared amongst all the running applications
...

Since we are not concerned with security here we have specified
the value as 0
...
When using CreateFile( ) for device access
we must always specify this parameter as OPEN_EXISTING
...
The remaining two parameters are
not used when using CreateFile( ) API function for device access
...
If the call to
CreateFile( ) succeeds then we obtain a handle to the file (device)
...
Since
every sector is 512 bytes long, to read from the nth sector we need
to set the file pointer to the 512 * n bytes from the start of the file
...
The
second parameter is the byte offset from where the reading is to
begin
...
We
have specified the third parameter as FILE_BEGIN which means
the byte offset is relative to the start of the file
...
The ReadFile( ) function is very easy to
use
...
The third parameter is the count of bytes that
have to be read
...
The fourth parameter to ReadFile( ) is the
address of an unsigned int variable which is set up with the count
of bytes that the function was successfully able to read
...

Though ReadSector( ) doesn’t need it, there does exist a
counterpart of the ReadFile( ) function
...

This API function can be used to write to the file (device)
...
Note

Chapter 19: Interaction With Hardware 633
that when WriteFile( ) is to be used we need to specify the
GENERIC_WRITE flag in the call to CreateFile( ) API
function
...

void WriteSector ( char *src, int ss, int num, void* buff )
{
HANDLE h ;
unsigned int br ;
h = CreateFile ( src, GENERIC_WRITE,
FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0 ) ;
SetFilePointer ( h, ( ss * 512 ), NULL, FILE_BEGIN ) ;
WriteFile ( h, buff, 512 * num, &br, NULL ) )
CloseHandle ( h ) ;
}

Accessing Other Storage Devices
Note that the mechanism of reading from or writing to any device
remains standard under Windows
...
Here are some sample calls for
reading/writing from/to various devices:
ReadSector ( "\\\\
...
\\d:", 0, 1, buffer ) ; /* reading from a CD-ROM drive */
WriteSector ( "\\\\
...
\\physicaldrive0", 0, 1, &b ) ; /* reading partition table */
Here are a few interesting points that you must note
...

To read from storage devices like hard disk drive or CD-ROM
or ZIP drive, etc
...

The string can be in the range \\
...
\Z:
...
Note that CD-ROMs follow a different storage
organization known as CD File System (CDFS)
...
Details
like the place at which each partition begins and ends, the size
of each partition, whether it is a bootable partition or not, etc
...
This table is often called
‘Partition Table’
...
\physicaldrive0
...
\physicaldrive0 we can also read contents of any
other parts of the disk
...
If we are to read from the second hard disk we
need to use 1 in place of 0
...

These are WM_KEYDOWN, WM_KEYUP and WM_CHAR
...
The additional information in
case of these messages is the code of the key being pressed or
released
...
If we wish to
avoid all this checking we can tackle the WM_CHAR message
instead
...
However, if we wish to go a step
further and deal with the keyboard we need to tackle it differently
...
Once it
becomes on it should remain permanently on
...

If we hit a key A then B should appear on the screen, if we hit
a B then C should occur and so on
...
To be able to achieve these effect we need
understand two important mechanisms—‘Dynamic Linking’ and
‘Windows Hooks’
...


Dynamic Linking
As we saw in Chapter 16, Windows permits linking of libraries
stored in a
...
A
...
It contains functions that can be
shared between several applications running in memory
...
Since hooks are used to alter the messaging
mechanism on a system-wide basis the code for hooking has to be
written in a DLL
...
Since the DLL cannot execute on its own we need a separate
program that would load and execute the DLL
...
For
example, for keyboard messages there is a keyboard hook, for
mouse messages there is mouse hook, etc
...
Here we would restrict our
discussion only to the keyboard hook
...
This is
illustrated in Figure 19
...

Application2 Application2
Msg
...
Queue
Application1
Place key code in System
Msg
...
queue
Kernel Routine
Device Driver ISR

Figure 19
...
7 here is a list of steps that are carried
out when we press a key from the keyboard:

Chapter 19: Interaction With Hardware 637
(a)
(b)
(c)
(d)

(e)
(a)
(b)
(c)
(a)
(b)
On pressing a key an interrupt occurs and the corresponding
kernel routine gets called
...

The ISR communicates with the keyboard controller and
obtains the code of the key pressed
...

The OS retrieves the message from the System Message
Queue and posts it into the message queue of the application
with regard to which the key has been pressed
...
We simply need to register our hook procedure with the
OS
...
Since our hook procedure gets a first shot at the message it
can now alter the working in the following three ways:
It can suppress the message altogether
It can change the message
It can post more messages into the System Message Queue
using the keybd_event( ) function
...


Caps Locked, Permanently
Let us now write a program that keeps the CapsLock permanently
on
...
In fact there would be
two programs:
A DLL containing a hook procedure that achieves the
CapsLock effect
...

Given below is the source code of the DLL program
...
c */
# include ...

From the ‘Project’ tab select ‘Win32 Dynamic-Link Library’
and click on the ‘Next’ button
...

Select ‘File | New’ option
...
c’
...

Compile the program to generate the
...

Note that this program doesn’t contain WinMain( ) since the
program on compilation should not execute on its own
...
This function acts as

entry point of the DLL program
...

When the application loads the DLL the DllMain( ) function
would be called
...


640 Complete Guide To C
Those functions in a DLL that can be called from outside it are
called exported functions
...

To indicate to the compiler that a function in a DLL is an exported
function we have to pre-qualify it with __declspec ( dllexport )
...
This
second program is a normal GUI application created in the same
way that we did applications in Chapters 17 and 18
...
c */
HINSTANCE h ;
void OnCreate ( HWND hWnd )
{
BOOL ( CALLBACK *p )( ) ;
h = LoadLibrary ( "hook
...
In OnCreate( ) we have loaded the
DLL containing the hook procedure
...
Once the DLL is loaded we have
obtained the address of the exported function installhook( ) using
the GetProcAddress( ) API function
...

Using this pointer we have then called the installhook( ) function
...
hkb stores the handle of the hook
installed
...
e
...
Inside this
function we have written code to ensure that the CapsLock always
remains on
...
If it so then it necessary to call the next
hook procedure
...

Note that there can be several hook procedures installed by
different programs, thus forming a chain of hook procedures
...
This means the last hook
procedure installed is the first one to get called
...
If it is so, then we have checked
the previous state of the key before the message was sent
...
If it is off (0th bit of state variable is
0) then we have turned on the CapsLock by simulating a keypress
...
Note that keybd_event( ) creates a keyboard message
from the parameters that we pass to it and posts it into the system
message queue
...

A word of caution! When we use keybd_event( ) to post keyboard
message for a simulated CapsLock keypress, once again our hook
procedure would be called when these messages are retrieved from
the system message queue
...

When we close the application window as usual the OnDestroy( )
would be called
...
In the
removehook( ) function we have unregistered our hook procedure
by calling the UnhookWindowsHookEx( ) API function
...
As a
result our hook procedure is now removed from the hook chain
...
Having unhooked

our hook procedure the control would return to OnDestroy( )
handler where we have promptly unload the DLL from memory by
calling the FreeLibrary( ) API function
...
dll’ file should be
copied into the directory of the application’s EXE before executing
the EXE
...

With the power of windows hooks below your belt you are into the
league of power programmers of Windows
...
How about writing a program that would
make every key pressed in any Windows application appear twice
...

LRESULT __declspec ( dllexport ) __stdcall KeyboardProc ( int nCode,
WPARAM wParam, LPARAM lParam )
{
static BYTE key ;
static BOOL flag = FALSE ;
if ( nCode < 0 )
return CallNextHookEx ( hkb, nCode, wParam, lParam ) ;
if ( ( nCode == HC_ACTION ) &&
( ( DWORD ) lParam & 0x80000000 ) == 0 )
{
if ( flag == FALSE )
{
key = wParam ;
keybd_event ( key , 0, KEYEVENTF_EXTENDEDKEY, 0 ) ;
flag = TRUE ;
}
else
{
if ( key == ( BYTE ) wParam )
flag = FALSE ;
}
}
return CallNextHookEx ( hkb, nCode, wParam, lParam ) ;

644 Complete Guide To C
}
In this hook procedure once again we have checked if the nCode
parameter contains a value HC_ACTION
...
If the present state
of the key is ‘pressed’ (31th bit of lParam is 0) then we have
posted the message for the same key into the system message
queue by calling the keybd_event( )
...
Can you imagine which? The message that we
post, once retrieved, would again bring the control to our hook
procedure
...
This would go on and on
...

Note that the rest of the functions in the DLL file are exactly same
as in the previous program
...


Mangling Keys
How about one more program to bolster your confidence? Let us
try one that would mangle every key that is pressed
...
This would be fairly
straight-forward
...
Also, further processing
of key has to be prevented
...
This is shown in the
following hook procedure
...
These programs keep a log of
every key that is pressed while entering passwords or credit card
numbers
...
With the knowledge that you have
gained from the past three programs this may not be a big deal
...


646 Complete Guide To C
(b)
(c)
(a)
(b)
(c)
These programs also hide themselves from the Task Manager
so that the user cannot terminate them
...
Once the logged keys are
known it would be possible to break into the system
...
There are many
good things that they can be put to use for
...
Such keyboards also come with special programs which
when installed know how to tackle these special keys
...

Many demo programs once executed automatically move the
mouse pointer to a menu or a toolbar or any such item to
demonstrate some feature of the software
...

For physically impaired persons a keyboard can be simulated
on the screen and the mouse clicks on this keyboard can be
communicated to Windows as actual key hits
...

There can be many more such examples
...


Chapter 19: Interaction With Hardware 647

Summary
(a)
(b)
(c)
(d)
(e)
(f)
(g)
(h)
(i)
(a)
(b)
(c)

Hardware interaction can happen in two ways: (1) When the
user interacts with the hardware and the program reacts to it
...

In DOS when the user interacts with the hardware an ISR gets
called which interacts with the hardware
...

In DOS when the program has to interact with the hardware it
can do so by using library functions, DOS/BIOS routines or
by directly interacting with the hardware
...

Under Windows to gain finer control over the hardware we
are required to write a device driver program
...

Different strings have to be passed to the CreateFile( )
functions for interacting with different devices
...

Windows hook procedures should be written in a DLL since
they work on a system wide basis
...


Exercise
[A] State True or False:
In MS-DOS on occurrence of an interrupt values from IDT
are used to call the appropriate kernel routine
...

Under Windows an application can interact with the hardware
by directly calling its device driver’s routines
...

ReadSector( ) and WriteSector( ) are API functions
...


The Windows API function to stop communication with a
device is CloseFile( )
...

[B] Answer the following:
How is hardware interaction under Windows different that
that under DOS?
What is the advantage of writing code in a DLL?
Explain the Windows hooks mechanism
...
Refer
Appendix G for details about the contents of the boot sector
...

Write a program that closes any window just by placing the
cursor on the ‘Close’ button in the title bar of it
...
Since its
humble beginning about a decade ago, Linux has steadily
drawn the attention of programmers across the globe and has
successfully created a community of its own
...
You can look at the hot discussions
and the flame wars on this issue on numerous sites on the internet
...
The last 4 chapters
concentrated on Windows programming
...
Without any further
discussions let us now set out on the Linux voyage
...


T
What is Linux
Linux is a clone of the Unix operating system
...
It
has all the features you would expect in a modern OS
...
The kernel of Linux is available in source code form
...
Several programs, frameworks, utilities have
been built around the Linux kernel
...
Hence many organizations
have come forward to make this job easy
...
Moreover, they also provide installation scripts
for easy installations of the Linux OS and applications
...
Each of them contain the same kernel

Chapter 19: Interaction With Hardware 651
but may contain different application programs, libraries,
frameworks, installation scripts, utilities, etc
...

Linux was first developed for x86-based PCs (386 or higher)
...
Thus Linux works on
literally every conceivable microprocessor architecture
...
For simplicity (in my opinion) I have
chosen the following combination:
Linux Distribution - Red Hat Linux 9
...
1-10
Editor - KWrite
Compiler - GNU C and C++ compiler (gcc)
We would be using and discussing these in the sections to follow
...
It is same to the
extent of using language elements like data types, control
instructions and the overall syntax
...
For example, a printf( )
would work under all OSs, but the way it is defined is likely to be
different for different OSs
...


652 Complete Guide To C
But there the similarity ends
...
For example, if we are to write a C program
that would create a Window and display a message “hello” at the
point where the user clicks the left mouse button
...
This is because the mechanisms for creating
a window, reporting a mouse click, handling a mouse click,
displaying the message, closing the window, etc
...
In short the
programming architecture (better known as programming model)
for each OS is different
...


The ‘Hello Linux’ Program
As with any new platform we would begin our journey in the
Linux world by creating a ‘hello world’ program
...

int main( )
{
printf ( "Hello Linux\n" ) ;
return 0 ;
}
The program is exactly same as compared to a console program
under DOS/Windows
...
So what is the
difference? The difference is in the way programs are typed,
compiled and executed
...

The first hurdle to cross is the typing of this program
...
This is because it is a very simple yet elegant

Chapter 19: Interaction With Hardware 653
editor compared to other editors like ‘vi’ or ‘emacs’
...
Installation of Linux and KDE is discussed in Appendix H
...
Assuming that you have been able to start KWrite
successfully, carry out the following steps:
(a)
(b)

(c)
(d)
(e)
(f)
Type the program and save it under the name ‘hello
...

At the command prompt switch to the directory containing
‘hello
...

Now compile the program using the gcc compiler as shown
below:
# gcc hello
...
out’
...

Execute the program using the following command
...
/a
...

Having created a Hello Linux program and gone through the editcompile-execute cycle once let us
now turn our attention to Linux
specific programming
...


Processes
Gone are the days when only one job (task) could be executed in
memory at any time
...
Hence
these OSs are aptly called ‘Multitasking’ OSs
...
Even though it
may appear that several processes are being executed by the
microprocessor simultaneously, in actuality it is not so
...
Thus each process gets
the microprocessor’s attention in a round robin manner
...
Thus at any given moment
if we take the snapshot of memory only one process is being
executed by the microprocessor
...

The scheduling of processes is done by a program called
‘Scheduler’ which is a vital component of the Linux OS
...
Before switching over to the
next thread it stores the information about the current process
...
When this process again gets the time
slot these values are restored
...
Note that
Linux uses preemptive scheduling, meaning thereby that the
context switch is performed as soon as the time slot allocated to
the process is over, no matter whether the process has completed

its job or not
...
This ID is often known
as processes ID or simply PID
...
Here is the program that
achieves this…

Chapter 19: Interaction With Hardware 655
int main( )
{
printf ( "Process ID = %d", getpid( ) ) ;
}
Here getpid( ) is a library function which returns the process ID
of the calling process
...
Every time we run the
program a new process is created
...
This can be verified by executing the
program several times—each time it would produce a different
output
...
From this process
we can create another process
...
The way to achieve this is by using a
library function called fork( )
...
Here is a program that
demonstrates this…
# include ...
You can notice that all the
statements after the fork( ) are executed twice—once by the parent
process and second time by the child process
...

But why on earth would we like to do this? At times we want our
program to perform two jobs simultaneously
...
Let me give you an example
...
The GIF file should continue to play till file copy is

taking place
...
Since both these jobs are inter-related they
cannot be performed in two different programs
...
Both jobs should be performed
simultaneously
...
The following program shows how this can
be achieved
...
Hence I have
skipped the actual code for file copying and playing the animated
GIF file
...
h>
int main( )
{
int pid ;
pid = fork( ) ;
if ( pid == 0 )
{
printf ( "In child process\n" ) ;
/* code to play animated GIF file */

Chapter 19: Interaction With Hardware 657
}
else
{
printf ( "In parent process\n" ) ;
/* code to copy file */
}
}
As we know, fork( ) creates a child process and duplicates the
code of the parent process in the child process
...

Thus the duplication code inside fork( ) is executed once, whereas
the remaining code inside it is executed in both the parent as well
as the child process
...
When control
returns from fork( ) of the parent process it returns the PID of the
child process, whereas when control returns from fork( ) of the
child process it always returns a 0
...
We have done this in our program using an if statement
...

Let us now write one more program
...
In the child process we would
print the PID of child and its parent, whereas in the parent process
we would print the PID of the parent and its child
...
h>
int main( )
{
int pid ;
pid = fork( ) ;
if ( pid == 0 )

658 Complete Guide To C
{
printf ( "Child : Hello I am the child process\n" ) ;
printf ( "Child : Child’s PID: %d\n", getpid( ) ) ;
printf ( "Child : Parent’s PID: %d\n”, getppid( ) ) ;
}
else
{
printf ( "Parent : Hello I am the parent process\n" ) ;
printf ( "Parent : Parent’s PID: %d\n”, getpid( ) ) ;
printf ( "Parent : Child’s PID: %d\n", pid ) ;
}
}
Given below is the output of the program:
Child : Hello I am the child process
Child : Child's PID: 4706
Child : Parent's PID: 4705
Parent : Hello I am the Parent process
Parent : Parent's PID: 4705
Parent : Child's PID: 4706
In addition to getpid( ) there is another related function that we
have used in this program—getppid( )
...

You can tally the PIDs from the output and convince yourself that
you have understood the fork( ) function well
...
So make sure that you understand
it thoroughly
...
Thus there is a inverted tree like structure of all the
processes running in memory
...
If we want to get a list of all the running
processes in memory we can do so using the ps command as
shown below
...


More Processes
Suppose we want to execute a program on the disk as part of a
child process
...
Note that there is a family of exec library functions, each

basically does the same job but with a minor variation
...
execv( ) also does
the same job as execl( ) except that the command line arguments
can be passed to it in the form of an array of pointers to strings
...

Let us now see a program that uses execl( ) to run a new program
in the child process
...
h>
int main( )
{
int pid ;
pid = fork( ) ;
if ( pid == 0 )
{
execl ( "/bin/ls","-al", "/etc", NULL ) ;
printf ( "Child: After exec( )\n") ;
}
else
printf ( "Parent process\n" ) ;
}

660 Complete Guide To C
After forking a child process we have called the execl( ) function
...
The first
parameter to execl( ) is the absolute path of the program to be
executed
...
The last parameter is an
end of argument marker which must always be NULL
...
Note that the printf( ) below the call to execl( ) function is
not executed
...
In our case the child process’s
memory was overwritten by the code and data of the ls program
...

It would make little sense in calling execl( ) before fork( )
...
As a result, no statement beyond
the call to execl( ) would ever get executed
...


Zombies and Orphans
We know that the ps –A command lists all the running processes
...
This table is called ‘Process Table’
...
This integer value indicates the reason why the process

was terminated
...
This act of querying

Chapter 19: Interaction With Hardware 661
deletes the entry of the terminated process from the process table
and returns the exit code to the parent that raised the query
...
Let us discuss
both these possibilities
...
Such a process in Linux terminology is known as a ‘Zombie’
process
...

Moral is, a parent process should query the process table
immediately after the child process has terminated
...

What if the parent terminates without querying
...

Immediately, the father of all processes—init—adopts the
orphaned process
...

Parent terminates earlier than the child
Since every parent process is launched from the Linux shell, the
parent of the parent is the shell process
...
Thus a proper
cleanup happens for the parent process
...
Immediately the init process
would adopt it and when its execution is over init would query the
process table to clean up the entry for the child process
...

Thus, when a zombie or an orphan gets created the OS takes over
and ensures that a proper cleanup of the relevant process table

662 Complete Guide To C
entry happens
...
Note that here cleanup is
important (it happens anyway)
...
It is because, it is the exit code that
would give indication about whether the job assigned to the
process was completed successfully or not
...

# include ...
h>
int main( )
{

unsigned int i = 0 ;
int pid, status ;
pid = fork( ) ;
if ( pid == 0 )
{
while ( i < 4294967295U )
i++ ;
printf ( "The child is now terminating\n" ) ;
}
else
{
waitpid ( pid, &status, 0 ) ;
if ( WIFEXITED ( status ) )
printf ( "Parent: Child terminated normally\n" ) ;
else
printf ( "Parent: Child terminated abnormally\n" ) ;
}
return 0 ;
}
In this program we have applied a big loop in the child process
...

From within the parent process we have made a call to the
waitpid( ) function
...
This ensures that the child process never becomes orphaned
...
As a result of querying,
the child process does not become a zombie
...
The second
parameter is the address of an integer variable which is set up with
the exit status code of the child process
...
We have not used this parameter and hence we have
passed a 0
...
This macro takes
the status value as a parameter and returns a non-zero value if the
process terminated normally
...


One Interesting Fact
When we use fork( ) to create a child process the child process
does not contain the entire data and code of the parent process
...
Even this is not so
...
Linux internally manages to intelligently
share it
...
Till the
time both the processes do not change the value of the variables
they keep getting shared
...
Instead a new copy of the variable is made for the
process that is attempting to change it
...


664 Complete Guide To C
Summary
(a)
(b)
(c)
(d)
(e)
(f)
(g)
(h)
(i)
(j)
(k)
(l)
(m)
(n)
(o)
(a)
(b)
(c)
Linux is a free OS whose kernel was built by Linus Trovalds
and friends
...

C programs under Linux can be compiled using the popular
gcc compiler
...
Processes are
scheduled by a special program called ‘Scheduler’
...

Init process is the father of all processes
...

execl( ) function overwrites the image (code and data) of the
calling process
...

ps command can be used to get a list of all processes
...

A ‘Zombie’ is a child process that has terminated but its
parent is running and has not called a function to get the exit
code of the child process
...

Orphaned processes are adopted by init process
automatically
...


Exercise
[A] State True or False:
We can modify the kernel of Linux OS
...

Basic scheduling unit in Linux is a file
...

The scheduler process is the father of all processes
...

fork( ) completely duplicates the code and data of the parent
process into the child process
...

fork( ) is called twice but returns once
...

Every orphan process is essentially an orphan process
...
What would be the output of the program if the
command line argument is * ?
What purpose do the functions getpid( ), getppid( ),
getpppid( ) serve?
Rewrite the program in the section ‘Zombies and Orphans’
replacing the while loop with a call to the sleep( ) function
...
This is true in
real life as well as in programming
...
A worthwhile
program has to communicate with the outside world in general and
with the OS in particular
...
In this
chapter let us explore how this communication happens under
Linux
...

These library functions got the job done by communication with
the Linux OS
...
The reverse communication—from the OS to
the program—is achieved using a mechanism called ‘Signal’
...

int main( )
{
while ( 1 )
printf ( "Pogram Running\n" ) ;
return 0 ;
}
The program is fairly straightforward
...
When the program is running
we can terminate it by pressing the Ctrl + C
...
The kernel reacts to this

by sending a signal to our program
...
In this

Chapter 21: More Linux Programming 669
default signal handler there is code to terminate the program
...

But how on earth would the default signal handler get called
...
There are several signals that can be sent to a program
...
To avoid
remembering these numbers, they have been defined as macros
like SIGINT, SIGKILL, SIGCONT, etc
...
h’
...
If we
do not decide to handle a signal then against that signal ID the
address of the default signal handler function is present
...

INT in SIGINT stands for interrupt
...
This is shown in the following
program:
# include ...
Inside sighandler\n" ) ;
}
int main( )
{
signal ( SIGINT, ( void* ) sighandler ) ;
while ( 1 )
printf ( "Program Running\n" ) ;
return 0 ;
}
In this program we have registered a signal handler for the SIGINT
signal by using the signal( ) library function
...
The second parameter is the address of a function that
should get called whenever the signal is received by our program
...

Now when we press Ctrl + C the registered handler, namely,
sighandler( ) would get called
...
Inside sighandler’ and return the
control back to main( )
...
So only
way to terminate it is to kill the running process from a different
terminal
...
How to start a new instace of command prompt
is discussed in Appendix H
...
Note down the process id of a
...
Finally kill ‘a
...
out was tty1 and its
process id turned out to be 3276
...

If we wish we can abort the execution of the program in the signal
handler itself by using the exit ( 0 ) beyond the printf( )
...
That is, when a signal is
received no matter what our program is doing, the signal handler
would immediately get called
...


Chapter 21: More Linux Programming 671

Handling Multiple Signals
Now that we know how to handle one signal, let us try to handle
multiple signals
...
h>
# include ...
h>
void inthandler ( int signum )
{
printf ( "\nSIGINT Received\n" ) ;
}
void termhandler ( int signum )
{
printf ( "\nSIGTERM Received\n" ) ;
}
void conthandler ( int signum )
{
printf ( "\nSIGCONT Received\n" ) ;
}
int main( )
{
signal ( SIGINT, inthandler ) ;
signal ( SIGTERM, termhandler ) ;
signal ( SIGCONT, conthandler ) ;
while ( 1 )
printf ( "\rProgram Running" ) ;
return 0 ;
}

672 Complete Guide To C
In this program apart from SIGINT we have additionally
registered two new signals, namely, SIGTERM and SIGCONT
...
After registering the signals we enter
a infinite while loop to print the ‘Program running’ message on the
screen
...
e
...
However,
when we try to kill the program from the second terminal using the
kill command the program does not terminate
...
The default handler for the message terminates
the program
...
e
...
As a
result the printf( ) statement in the termhandler( ) function gets
executed and the message ‘SIGTERM Received’ gets displayed on
the screen
...
Then how are we supposed to terminate the program?
Simple
...
A SIGKILL signal terminates the program
...
Such signals are often known as un-catchable signals
...

Note that even if a process attempts to handle the SIGKILL signal
by registering a handler for it still the control would always land in
the default SIGKILL handler which would terminate the program
...
One such process that makes uses
of this signal is a system shutdown process
...
However, after the
grace period is over it forcibly terminates all the remaining
processes using the SIGKILL signal
...

A process under Linux can be suspended using the Ctrl + Z
command
...
e
...
This gives rise to the un-catchable SIGSTOP signal
...
As a result of which the
suspended program resumes its execution and receives the
SIGCONT signal (CONT means continue execution)
...
This is
shown in the following program:
# include ...
h>
# include ...
Thus the same signal handler function would get
called when one of the three signals are received
...
In our
program we have made use of the switch-case construct to print a
different message for each of the three signals
...
That is, we can register separate
signal handlers for some of the signals and a common handler for

Chapter 21: More Linux Programming 675
some other signals
...


Blocking Signals
Sometimes we may want that flow of execution of a critical/timecritical portion of the program should
not be hampered by the
occurrence of one or more signals
...
Once we are through with the critical/timecritical code we can unblock the
signals(s)
...

When the signals are unblocked the process immediately receives
all the pending signals one after another
...
Instead of completely
ignoring the signals or letting the signals interrupt the execution, it

is preferable to block the signals for the moment and deliver them
some time later
...
Here is the program…
# include ...
h>
# include ...
h>
void sighandler ( int signum )
{
switch ( signum )
{
case SIGTERM :
printf ( "SIGTERM Received\n" ) ;
break ;
case SIGINT :
printf ( "SIGINT Received\n" ) ;
break ;

676 Complete Guide To C
case SIGCONT :
printf ( "SIGCONT Received\n" ) ;
break ;
}
}
int main( )
{
char buffer [ 80 ] = "\0” ;
sigset_t block ;
signal ( SIGTERM, sighandler ) ;
signal ( SIGINT, sighandler ) ;
signal ( SIGCONT, sighandler ) ;
sigemptyset ( &block ) ;
sigaddset ( &block, SIGTERM ) ;
sigaddset ( &block, SIGINT ) ;
sigprocmask ( SIG_BLOCK, &block, NULL ) ;
while ( strcmp ( buffer,"n" ) != 0 )
{
printf ( "Enter a String: " ) ;
gets ( buffer ) ;
puts ( buffer ) ;
}
sigprocmask ( SIG_UNBLOCK, &block, NULL ) ;
while ( 1 )
printf ( "\rProgram Running" ) ;
return 0 ;
}
In this program we have registered a common handler for the
SIGINT, SIGTERM and SIGCONT signals
...


Additionally, we want that this activity of receiving input should
not be interrupted by the SIGINT or the SIGTERM signals
...
So before we proceed
with the loop we must block the SIGINT and SIGTERM signals
...

This blocking and unblocking of signals can be achieved using the
sigprocmask( ) library function
...
The next
parameter is the address of a structure (typedefed as sigset_t) that
describes a set of signals that we want to block/unblock
...

There are library functions that help us to populate the sigset_t
structure
...
The only parameter that this function
accepts is the address of the sigset_t variable
...
To block the SIGINT and SIGTERM we have to add
the signals to the empty set of signals
...
The first parameter of
sigaddset( ) is the address of the sigset_t variable and the second
parameter is the ID of the signal that we wish to add to the existing
set of signals
...
This is done so that we can easily
check that till the time the loop that receives input is not over the
program cannot be terminated using Ctrl + C or kill command
since the signals are blocked
...
As a result, pending signals, if any, are immediately
delivered to the program
...
Once we are through
with the loop the signal handlers would be called
...
As you know, in a GUI program
events occur typically when we click on the window, type a
character, close the window, repaint the window, etc
...
0 to create the GUI applications
...
Refer Appendix H for
installation of this toolkit
...

/* mywindow
...
h>
int main ( int argc, char *argv[ ] )

{
GtkWidget *p ;
gtk_init ( &argc, &argv ) ;
p = gtk_window_new ( GTK_WINDOW_TOPLEVEL ) ;
gtk_window_set_title ( p , "Sample Window" ) ;
g_signal_connect ( p, "destroy", gtk_main_quit, NULL ) ;
gtk_widget_set_size_request ( p, 300, 300 ) ;
gtk_widget_show ( p ) ;
gtk_main( ) ;
return 0 ;
}

Chapter 21: More Linux Programming 679
We need to compile this program as follows:
gcc mywindow
...
0 - -cflags - -libs`
Here we are compiling the program ‘mywindow
...
Note the
quotes that we have used in the command
...
1
The GTK library provides a large number of functions that makes
it very easy for us to create GUI programs
...
To create a simple window we have to
carry out the following steps:

680 Complete Guide To C
(a)
(b)
(c)
(d)
(e)
Initialize the GTK library with a call to gtk_init( ) function
...

Next, call the gtk_window_new( ) function to create a top
level window
...
A top level window can be
created by specifying the GTK_WINDOW_TOPLEVEL
value
...
The widget object is a structure
(GtkWidget) variable that stores lots of information including
the attributes of window it represents
...

Set the title for the window by making a call to
gtk_window_set_title( ) function
...
The second
parameter is a string describing the text to be displayed in the
title of the window
...
The destroy
signal is received whenever we try to close the window
...
GTK provides a
ready-made function called gtk_main_quit( ) that does this
job
...
This can be achieved using the g_signal_connect( )
function
...
The second parameter is a string that specifies the
name of the signal
...
We have not used the fourth parameter
...
The second and the

Chapter 21: More Linux Programming 681
third parameters specify the height and the width of the
window respectively
...

Wait in a loop to receive events for the window
...

How about another program that draws a few shapes in the
window? Here is the program…
/* myshapes
...
h>
int expose_event ( GtkWidget *widget, GdkEventExpose *event )
{
GdkGC* p ;
GdkPoint arr [ 5] = { 250, 150, 250, 300, 300, 350, 400, 300, 320, 190 } ;
p = gdk_gc_new ( widget -> window ) ;
gdk_draw_line ( widget -> window, p, 10, 10, 200, 10 ) ;
gdk_draw_rectangle ( widget -> window, p, TRUE, 10, 20, 200, 100 ) ;
gdk_draw_arc ( widget -> window, p, TRUE, 200, 10, 200, 200,
2880, -2880*2 ) ;
gdk_draw_polygon ( widget -> window, p, TRUE , arr, 5 ) ;
gdk_gc_unref ( p ) ;
return TRUE ;
}
int main( int argc, char *argv[ ] )
{
GtkWidget *p ;
gtk_init ( &argc, &argv ) ;

682 Complete Guide To C
p = gtk_window_new ( GTK_WINDOW_TOPLEVEL ) ;
gtk_window_set_title ( p, "Sample Window" ) ;
g_signal_connect ( p, "destroy", gtk_main_quit, NULL ) ;
g_signal_connect ( p , "expose_event", expose_event, NULL ) ;
gtk_widget_set_size_request ( p, 500, 500 ) ;
gtk_widget_show ( p ) ;
gtk_main( ) ;
return 0 ;

}
Given below is the output of the program
...
2
This program is similar to the first one
...
This signal is sent to our process whenever the window
needs to be redrawn
...
This is

684 Complete Guide To C
because a expose_event signal would be sent to our application
which would immediately redraw the shapes in our window
...
In order to draw in the window we need
to obtain a graphics context for the window using the
gdk_gc_new( ) function
...
This pointer must be passed to the
drawing functions like gdk_draw_line( ), gdk_draw_rectangle(),
gdk_draw_arc( ), gdk_draw_polygon( ), etc
...


Where Do You Go From Here
You have now understood signal processing, the heart of
programming under Linux
...
Complete Linux programming deserves a book on its own
...
I am sure that if you have taken a good look at it you can try the
rest yourselves
...

The Linux OS communicates with a program by means of
signals
...

A term signal (SIGTERM) is sent to the program when we
use the kill command
...


The kill –SIGKILL variation of the kill command generates
an un-catchable SIGKILL signal that terminates a process
...

Blocked signals are delivered to the process when the signals
are unblocked
...

A SIGSTOP signal is un-catchable signal
...

A process receives the SIGCONT signal when it resumes
execution
...


Exercise
[A] State True or False:
All signals registered signals must have a separate signal
handler
...

Only one signal can be blocked at a time
...

If our signal handler gets called the default signal handler
automatically gets called
...

Multiple signals can be registered at a time using a single call
to signal( ) function
...

[B] Answer the following:
How does the Linux OS know if we have registered a signal
or not?
What happens when we register a handler for a signal?

686 Complete Guide To C
(c)
(d)
(e)
Write a program to verify that SIGSTOP and SIGKILL
signals are un-catchable signals
...
From inside the handler for SIGINT signal write an
infinite loop to print the message ‘Processing Signal’
...
Run the
program once again and press Ctrl + C once then use the kill
command
...


A Precedence
Table
687
688 Complete Guide To C
Description Operator Associativity
Function expression ( ) Left to Right
Array Expression [ ] Left to Right
Structure operator -> Left to Right
Structure operator
...
1

690 Complete Guide To C

B Standard Library
Functions
• Standard Library Functions
• Arithmetic Functions
• Data Conversion Functions
• Character Classification Functions
• String Manipulation Functions
• Searching and Sorting Functions
• I/O Functions
• File Handling Functions
• Directory Control Functions
• Buffer Manipulation Functions
• Disk I/O Functions
• Memory Allocation Functions
• Process Control Functions
• Graphics Functions
• Time Related Functions
• Miscellaneous Functions
• DOS Interface Functions

691
692 Complete Guide To C
et alone discussing each standard library function in detail,
even a complete list of these functions would occupy scores
of pages
...
I have tried to
reach a compromise and have given a list of standard library
functions that are more popularly used so that you know what to
search for in the manual
...


L
Following is the list of selected standard library functions
...


Arithmetic Functions
Function Use
abs Returns the absolute value of an integer
cos Calculates cosine
cosh Calculates hyperbolic cosine
exp Raises the exponential e to the xth power
fabs Finds absolute value
floor Finds largest integer less than or equal to argument
fmod Finds floating-point remainder
hypot Calculates hypotenuse of right triangle
log Calculates natural logarithm
log10 Calculates base 10 logarithm
modf Breaks down argument into integer and fractional parts
pow Calculates a value raised to a power
sin Calculates sine
sinh Calculates hyperbolic sine
sqrt Finds square root
tan Calculates tangent
tanh Calculates hyperbolic tangent

Appendix B: Standard Library Functions 693
Data Conversion Functions
Function Use
atof Converts string to float
atoi Converts string to int
atol Converts string to long
ecvt Converts double to string
fcvt Converts double to string
gcvt Converts double to string
itoa Converts int to string
ltoa Converts long to string
strtod Converts string to double
strtol Converts string to long integer
strtoul Converts string to an unsigned long integer
ultoa Converts unsigned long to string

Character classification Functions
Function Use
isalnum Tests for alphanumeric character
isalpha Tests for alphabetic character
isdigit Tests for decimal digit
islower Tests for lowercase character
isspace Tests for white space character
isupper Tests for uppercase character
isxdigit Tests for hexadecimal digit
tolower Tests character and converts to lowercase if uppercase
toupper Tests character and converts to uppercase if lowercase

694 Complete Guide To C
String Manipulation Functions
Function Use
strcat Appends one string to another
strchr Finds first occurrence of a given character in a string
strcmp Compares two strings
strcmpi Compares two strings without regard to case
strcpy Copies one string to another
strdup Duplicates a string
stricmp Compares two strings without regard to case (identical to
strcmpi)
strlen Finds length of a string
strlwr Converts a string to lowercase
strncat Appends a portion of one string to another
strncmp Compares a portion of one string with portion of another
string
strncpy Copies a given number of characters of one string to another
strnicmp Compares a portion of one string with a portion of another
without regard to case
strrchr Finds last occurrence of a given character in a string
strrev Reverses a string
strset Sets all characters in a string to a given character
strstr Finds first occurrence of a given string in another string
strupr Converts a string to uppercase

Searching and Sorting Functions
Function Use
bsearch Performs binary search
lfind Performs linear search for a given value
qsort Performs quick sort

Appendix B: Standard Library Functions 695
I/O Functions
Function Use
Close Closes a file
fclose Closes a file
feof Detects end-of-file
fgetc Reads a character from a file
fgetchar Reads a character from keyboard (function version)
fgets Reads a string from a file
fopen Opens a file
fprintf Writes formatted data to a file
fputc Writes a character to a file
fputchar Writes a character to screen (function version)
fputs Writes a string to a file
fscanf Reads formatted data from a file
fseek Repositions file pointer to given location
ftell Gets current file pointer position
getc Reads a character from a file (macro version)
getch Reads a character from the keyboard
getche Reads a character from keyboard and echoes it
getchar Reads a character from keyboard (macro version)
gets Reads a line from keyboard
inport Reads a two-byte word from the specified I/O port
inportb Reads one byte from the specified I/O port

kbhit Checks for a keystroke at the keyboard
lseek Repositions file pointer to a given location
open Opens a file
outport Writes a two-byte word to the specified I/O port
outportb Writes one byte to the specified I/O port
printf Writes formatted data to screen
putc Writes a character to a file (macro version)
putch Writes a character to the screen
putchar Writes a character to screen (macro version)
puts Writes a line to file
read Reads data from a file

696 Complete Guide To C
rewind Repositions file pointer to beginning of a file
scanf Reads formatted data from keyboard
sscanf Reads formatted input from a string
sprintf Writes formatted output to a string
tell Gets current file pointer position
write Writes data to a file

File Handling Functions
Function Use
remove Deletes file
rename Renames file
unlink Deletes file

Directory Control Functions
Function Use
chdir Changes current working directory
getcwd Gets current working directory
fnsplit Splits a full path name into its components
findfirst Searches a disk directory
findnext Continues findfirst search
mkdir Makes a new directory
rmdir Removes a directory

Buffer Manipulation Functions
Function Use
memchr Returns a pointer to the first occurrence, within a specified
number of characters, of a given character in the buffer
memcmp Compares a specified number of characters from two
buffers

Appendix B: Standard Library Functions 697
memcpy Copies a specified number of characters from one buffer to
another
memicmp Compares a specified number of characters from two
buffers without regard to the case of the characters
memmove Copies a specified number of characters from one buffer to
another
memset Uses a given character to initialize a specified number of
bytes in the buffer

Disk I/O Functions
Function Use
absread Reads absolute disk sectors
abswrite Writes absolute disk sectors
biosdisk Performs BIOS disk services
getdisk Gets current drive number

setdisk Sets current disk drive

Memory Allocation Functions
Function Use
calloc Allocates a block of memory
farmalloc Allocates memory from far heap
farfree Frees a block from far heap
free Frees a block allocated with malloc
malloc Allocates a block of memory
realloc Reallocates a block of memory

Process Control Functions
Function Use
abort Aborts a process
atexit Executes function at program termination

698 Complete Guide To C
execl Executes child process with argument list
exit Terminates the process
spawnl Executes child process with argument list
spawnlp Executes child process using PATH variable and argument
list
system Executes an MS-DOS command

Graphics Functions
Function Use
arc Draws an arc
ellipse Draws an ellipse
floodfill Fills an area of the screen with the current color
getimage Stores a screen image in memory
getlinestyle Obtains the current line style
getpixel Obtains the pixel’s value
lineto Draws a line from the current graphic output position to the
specified point
moveto Moves the current graphic output position to a specified
point
pieslice Draws a pie-slice-shaped figure
putimage Retrieves an image from memory and displays it
rectangle Draws a rectangle
setcolor Sets the current color
setlinestyle Sets the current line style
putpixel Plots a pixel at a specified point
setviewport Limits graphic output and positions the logical origin
within the limited area

Time Related Functions
Function Use
clock Returns the elapsed CPU time for a process
difftime Computes the difference between two times

Appendix B: Standard Library Functions 699
ftime Gets current system time as structure
strdate Returns the current system date as a string
strtime Returns the current system time as a string
time Gets current system time as long integer
setdate Sets DOS date
getdate Gets system date

Miscellaneous Functions

Function Use
delay Suspends execution for an interval (milliseconds)
getenv Gets value of environment variable
getpsp Gets the Program Segment Prefix
perror Prints error message
putenv Adds or modifies value of environment variable
random Generates random numbers
randomize Initializes random number generation with a random value
based on time
sound Turns PC speaker on at specified frequency
nosound Turns PC speaker off

DOS Interface Functions
Function Use
FP_OFF Returns offset portion of a far pointer
FP_SEG Returns segment portion of a far pointer
getvect Gets the current value of the specified interrupt vector
keep Installs terminate-and-stay-resident (TSR) programs
int86 Issues interrupts
int86x Issues interrupts with segment register values
intdos Issues interrupt 21h using registers other than DX and AL
intdosx Issues interrupt 21h using segment register values
MK_FP Makes a far pointer

700 Complete Guide To C
segread Returns current values of segment registers
setvect Sets the current value of the specified interrupt vector

C Chasing The
Bugs
701
702 Complete Guide To C
programmers are great innovators of our times
...
There is no shortage of
horror stories about programs that took twenty times to ‘debug’ as
they did to ‘write’
...
A typical C programmer’s ‘morning after’
is red eyes, blue face and a pile of crumpled printouts and dozens
of reference books all over the floor
...
But how do we chase them away
...
I thought if I make a list of more common programming
mistakes it might be of help
...
But as you would realize surely a great help!

C

[1] Omitting the ampersand before the variables used in scanf( )
...
Another
common mistake with scanf( ) is to give blanks either just
before the format string or immediately after the format string
as in,
int choice ;
scanf ( " %d ", choice ) ;
Note that this is not a mistake, but till you don't understand
scanf( ) thoroughly, this is going to cause trouble
...
Thus, the correct form would be,
int choice ;
scanf ( "%d", &choice ) ;

Appendix C: Chasing The Bugs 703
[2] Using the operator = instead of the operator = =
...
But,
actually we have fallen in an indefinite loop
...

[3] Ending a loop with a semicolon
...

main( )
{
int j = 1 ;
while ( j <= 100 ) ;
{
printf ( "\nCompguard" ) ;
j++ ;
}
}

704 Complete Guide To C
Inadvertently, we have fallen in an indefinite loop
...
This in effect makes the compiler
feel that you wanted the loop to work in the following
manner:

while ( j <= 100 ) ;
This is an indefinite loop since j never gets incremented and
hence eternally remains less that 100
...

Remember that if a break is not included at the end of a case,
then execution will continue into the next case
...

However, this sometimes turns out to be a blessing in
disguise
...
This example has been succinctly explained in Chapter
4
...

It is a common error to believe that the way the keyword
break is used with loops and a switch; similarly the keyword
continue can also be used with them
...

[6] A mismatch in the number, type and order of actual and formal
arguments
...
When romanise( ) receives these
arguments into formal arguments they must be received in the
same order
...

[7] Omitting provisions for returning a non-integer value from a
function
...
5 ) ;
then while defining area_circle( ) function later in the
program, care should be taken to make it capable of returning
a floating point value
...

[8] Inserting a semicolon at the end of a macro definition
...
This usually happens because a C
programmer becomes habitual to ending all statements with a
semicolon
...
For example,
#define UPPER 25 ;
would lead to a syntax error if used in an expression such as
if ( counter == UPPER )
This is because on preprocessing, the if statement would take
the form
if ( counter == 25 )
[9] Omitting parentheses around a macro expansion
...
This so happens because on preprocessing
the arithmetic statement takes the following form:
a = 25 / 5 * 5 ;

Appendix C: Chasing The Bugs 707
[10] Leaving a blank space between the macro template and the
macro expansion
...

[11] Using an expression that has side effects in a macro call
...

[12] Confusing a character constant and a character string
...
In the statement

708 Complete Guide To C
ch = "z" ;

a pointer to the character string “a” is assigned to ch
...

main( )
{
int num[50], i ;
for ( i = 1 ; i <= 50 ; i++ )
num[i] = i * i ;
}
Here, in the array num there is no such element as num[50],
since array counting begins with 0 and not 1
...
If not
taken care of, in extreme cases the above code might even
hang the computer
...

Remember each character array ends with a ‘\0’, therefore its
dimension should be declared big enough to hold the normal
characters as well as the ‘\0’
...

[15] Confusing the precedences of the various operators
...
c", "r" ) ;
while ( ch = getc ( fp ) != EOF )
putch ( ch ) ;
fclose ( fp ) ;
}
Here, the value returned by getc( ) will be first compared with
EOF, since != has a higher priority than =
...
The correct form of the above while would
be,
while ( ( ch = getc ( fp ) ) != EOF )
putch ( ch ) ;
[16] Confusing the operator -> with the operator
...

Remember, on the left of the operator
...
Following example
demonstrates this
...
age ) ;
ee = &e ;
printf ( "\n%d", ee->>age ) ;
}
[17] Forgetting to use the far keyword for referring memory locations
beyond the data segment
...
Thus, the correct declaration
would look like,
unsigned int far *s ;
The far pointers are 4-byte pointers and are specific to DOS
...

[18] Exceeding the range of integers and chars
...
Reason is, ch has been declared
as a char and the valid range of char constant is -128 to
+127
...
Naturally the condition is satisfied and the
control remains within the loop externally
...
At times we may want to create our own
library of functions
...
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’
...

Create a file ‘myfuncs
...

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

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( )

Appendix C: Creating Libraries 703
{
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
...

Compile and execute the project using Ctrl F9
...
The reason for this is—
everything a computer does is based on binary numbers,
and hexadecimal notation is a convenient way of expressing binary
numbers
...


W
Numbering Systems
When we talk about different numbering systems we are really
talking about the base of the numbering system
...
What in fact is the ‘base’ of the numbering system? Base
represents number of digits you can use before you run out of
digits
...
That’s the time we put
a 1 in the column to the left - the ten’s column - and start again in
the one’s column with 0, as shown below:
0
1
2
3
4
5
6
7
8
9 last available digit
10 start using a new column
11
12
13

Appendix D: Hexadecimal Numbering 715
14

...

Since decimal numbering system is a base 10 numbering system
any number in it is constructed using some combination of digits 0
to 9
...
However, the choice of 10 as a
base is quite arbitrary, having its origin possibly in the fact that
man has 10 fingers
...
For
example, if we wanted to use base 8 or octal numbering system,
which uses only eight digits (0 to 7), here’s how the counting
would look like:
0
1
2
3
4
5
6
7 last available digit
10 start using a new column
11
12

...

Similarly, a hexadecimal numbering system has a base 16
...
The hex digits A to F

are usually written in capitals, but lowercase letters are also
perfectly acceptable
...


...
For
example, we use a base 60 numbering system, for measuring
minutes and seconds
...

The moral is that any base can be used in a numbering system,
although some bases are convenient than others
...
For example,
when we write the decimal number 342, we mean,
3 times 100 (square of 10)
+ 4 times 10
+ 2 times 1
Similarly, if we use number 342 as a hex number, we mean,
3 times 256 (square of 16)

Appendix D: Hexadecimal Numbering 717
+ 4 times 16
+ 2 times 1

Relation Between Binary and Hex
As it turns out, computers are more comfortable with binary
numbering system
...
This means you can’t count very far before you need to start
using the next column:
0
1 last available digit
10 start using a new column

11

...

Binary numbering system is a natural system for computers
because each of the thousands of electronic circuits in the
computer can be in one of the two states—on or off
...
0 and 1 are called bits, a
short-form of binary digits
...
Every hex digit represents four bits
of binary information (Refer Figure D
...
In binary numbering
system 4 bits taken at a time can give rise to sixteen different
numbers, so the only way to represent each of these sixteen 4-bit
binary numbers in a simple and short way is to use a base sixteen
numbering system
...
One way is to find it decimal equivalent by multiplying
each binary digit with an appropriate power of 2 as shown below:

718 Complete Guide To C
1* 2 + 1* 2 + 0 * 2 + 0 * 2 + 0 * 2 + 1* 2 + 0 * 2 + 1* 2
which is equal to 197
...
1
Another method is much simpler
...
1
...

These happen to be C and 5
...
You would agree this is a easier way to represent
the binary number than to find its decimal equivalent
...
In fact, since
there are only 16 hex digits, it’s fairly easy to memorize the binary
equivalent of each one
...
You are already getting the feel of it
...
Thus,
1100 0101 0011 1010 binary is C53A hex
...
Try your hand at converting some binary
numbers and vice versa
...


E ASCII Chart

719
720 Complete Guide To C
here are 256 distinct characters used by IBM compatible
family of microcomputers
...
These can be grouped as under:

Character Type No
...
1
Out of the 256 character set, the first 128 are often called ASCII
characters and the next 128 as Extended ASCII characters
...
The following simple
program can generate the ASCII chart:
main( )
{
int ch ;
for ( ch = 0 ; ch <<= 255 ; ch++ )
printf ( "%d %c\n", ch, ch ) ;
}
This chart is shown on the following page
...
For convenience these characters are shown in Figure E
...


Appendix E: ASCII Chart 721

╕184
209

╒╤
212╘
198╞

190 ╛196
╪ ╡181
213

216


205═

186

201


187


203

╠204 ╬ ╣185
206

╚╩╝
199


211

╟╫
215


214


189

╢182

208

╥ ╖183
210
188
202
200

─917
┌─
218 129


197


192└ 193┴

195

191

┤ 180
┘ 217
194┬
Figure E
...
68 D 90 Z 112 p

3 ♥ 25 ↓ 47 / 69 E 91 [ 113 q
4 ♦ 26 → 48 0 70 F 92 \ 114 r
5 ♣ 27 ← 49 1 71 G 93 ] 115 s
6 ♠ 28 ⌐ 50 2 72 H 94 ^ 116 t
7 ● 29 ↔ 51 3 73 I 95 _ 117 u
8 ◘ 30 ▲ 52 4 74 J 96 ` 118 v
9 ○ 31 ▼ 53 5 75 K 97 a 119 w
10 ◙ 32 54 6 76 L 98 b 120 x
11 ♂ 33 ! 55 7 77 M 99 c 121 y
12 ♀ 34 " 56 8 78 N 100 d 122 z
13 ♪ 35 # 57 9 79 O 101 e 123 {
14 ♫ 36 $ 58 : 80 P 102 f 124 |
15 ☼ 37 % 59 ; 81 Q 103 g 125 }
16 ► 38 & 60 < 82 R 104 h 126 ~
17 ◄ 39 ’ 61 = 83 S 105 i 127 мн
18 ↕ 40 ( 62 > 84 T 106 j 128 Ç
19 ‼ 41 ) 63 ? 85 U 107 k 129 ü
20 ¶ 42 * 64 @ 86 V 108 l 130 é
21 § 43 + 65 A 87 W 109 m 131 â

Appendix E: ASCII Chart 723
Value Char Value Char Value Char Value Char Value Char Value Char
132 ä 154 Ü 176 ░ 198 ╞ 220 ▄ 242 ≥
133 à 155 ¢ 177 ▒ 199 ╟ 221 ▌ 243 ≤
134 å 156 £ 178 ▓ 200 ╚ 222 ▐ 244 ⌠
135 ç 157 ¥ 179 │ 201 ╔ 223 ▀ 245 ⌡
136 ê 158 ₧ 180 ┤ 202 ╩ 224 α 246 ÷
137 ë 159 ƒ 181 ╡ 203 ╦ 225 β 247 ≈
138 è 160 á 182 ╢ 204 ╠ 226 Г 248 °
139 ï 161 í 183 ╖ 205 ═ 227 π 249 •
140 î 162 ó 184 ╕ 206 ╬ 228 Σ 250 ·
141 ì 163 ú 185 ╣ 207 ╧ 229 σ 251 √
142 Ä 164 ñ 186 ║ 208 ╨ 230 µ 252 η
143 Å 165 Ñ 187 ╗ 209 ╤ 231 τ 253 ²
144 É 166 ª 188 ╝ 210 ╥ 232 Φ 254 ■
145 æ 167 º 189 ╜ 211 ╙ 233 θ 255
146 Æ 168 ¿ 190 ╛ 212 ╘ 234 Ω
147 ô 169 ⌐ 191 ┐ 213 ╒ 235 δ
148 ö 170 ¬ 192 └ 214 ╓ 236 ∞
149 ò 171 ½ 193 ┴ 215 ╫ 237 ø
150 û 172 ¼ 194 ┬ 216 ╪ 238 Є
151 ù 173 ¡ 195 ├ 217 ┘ 239 ∩
152 ÿ 174 « 196 ─ 218 ┌ 240 ≡
153 Ö 175 » 197 ┼ 219 █ 241 ±

724 Complete Guide To C

F Helper
...

*/
BOOL InitInstance ( HINSTANCE hInstance, int nCmdShow, char* pTitle )
{
char classname[ ] = "MyWindowClass" ;
HWND hWnd ;
WNDCLASSEX wcex ;
wcex
...
style = CS_HREDRAW | CS_VREDRAW ;
wcex
...
cbClsExtra = 0 ;
wcex
...
hInstance = hInstance ;
wcex
...
hCursor = LoadCursor ( NULL, IDC_ARROW ) ;
wcex
...
lpszMenuName = NULL ;
wcex
...
hIconSm = NULL ;
if ( !RegisterClassEx ( &wcex ) )
return FALSE ;
hInst = hInstance ; // Store instance handle in our global variable
hWnd = CreateWindow ( classname, pTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL,
NULL, hInstance, NULL ) ;
if ( !hWnd )

Appendix F: Helper
...
That is, drive A is drive
number 0, drive B is
drive number 1, drive C is drive number 2, etc
...
Each
drive consists of four logical parts—Boot Sector, File Allocation
Table (FAT), Directory and Data space
...
This group of sectors is often known as a
cluster
...
As the capacity goes on increasing,
so also does the maximum cluster number
...
In a 12-bit FAT each entry is of 12
bits
...

Similarly, in case of a 16-bit FAT the maximum cluster number is
216 (65536)
...
Only 28 of the 32 bits are used in this FAT)
...
For example, the 32-bit FAT system is supported only
in Win 95 OSR2 version or later
...


T
In Chapter 19 Figure 19
...
Given below are the contents of a
boot sector of 16-bit FAT and a 32-bit FAT
...
1
Bytes per sector 2 512
Sectors per cluster 1 64
Reserved sectors 2 1
Number of FAT copies 1 2
Max
...
of sides 2 255
Hidden sectors 4 63
Huge sectors 4 4192902
BIOS drive number 1 128
Reserved sectors 1 1
Boot signature 1 41
Volume ID 4 4084677574
Volume label 11 ICIT
File system type 8 FAT16

Figure G
...
These are shown in Figure G
...


732 Complete Guide To C
Description Length Typical Values
Jump instruction 3 EB5890
OEM name 8 MSWIN4
...
of sides 2 255
Hidden sectors 2 63
High word of hidden sectors 4 63
Huge sectors 4 4192902
High word of huge sectors 2 4192902
Sectors per FAT 2 4095
High word of sectors per FAT 2 4095
Drive description flag 2 0
File system version 2 0
Root directory starting cluster 2 2
High word of root directory
starting cluster
22
File system information sector 2 1
Back up boot sector 2 6
Reserved 6 0
continued…

Appendix G: Boot Parameters 733
…continued
BIOS drive number 1 128
Reserved 1 0
Boot signature 1 41
Volume ID 4 649825316
Volume label 11 ICIT
File system type 8 FAT32

Figure G
...
The entries ‘Number of hidden sectors’ and
‘Huge sectors’ have now been made 4-byte entries
...

The number of sectors per FAT in a 32-bit file system is likely to
exceed what can be accommodated in two bytes
...
The value of ‘Sectors per FAT’ is now
stored as a 4-byte entity, with the similar arrangement of low word
and high word as discussed earlier
...

The ‘Drive description flag’ is a two-byte entity
...
The low four bits of this

entry contains the 0-based FAT number of the active FAT
...


734 Complete Guide To C
In the entry ‘File system version number’ the high byte contains
the major version number, whereas, the low byte contains the
minor version number
...
This file system information consists of the fields shown
in Figure G
...

Description Length
File system signature 4
Total number of free clusters 4
Sector number of the next free cluster 4
Reserved 6

Figure G
...
The entry ‘Backup boot sector’ contains a
value 0FFFFh is there is no backup boot sector
...


H Linux Installation
735
736 Complete Guide To C
his appendix gives the steps that are to be carried out for
installing Red Hat Linux 9
...
In addition I have also
indicated a few commands that are necessary to compile
and execute the programs given in Chapters 20 and 21
...


T
(a)
(b)
(c)
(d)
(e)
(f)
(g)
(h)
(i)
(j)
(k)
(l)
(m)
(n)
(o)

(p)
(q)
(r)
Configure the system to boot from CDROM drive
...

Hit ‘Enter’ key when the ‘boot’ prompt appears
...

Click on the ‘Next’ button in the ‘Welcome’ screen
...

Click on the ‘Next’ button in the ‘Keyboard’ screen
...

Select the ‘Custom’ option in the ‘Installation Type’ screen
and then click on the ‘Next’ button
...

Select the ‘Keep all partitions and use existing free space’
option in the ‘Automatic Partitioning’ screen and then click
on the ‘Next’ button
...

Click on the ‘Next’ button in the ‘Boot loader configuration’
screen
...

Click on the ‘Next’ button in the ‘Firewall configuration’
screen
...

Select a suitable option in the ‘Time zone offset’ screen and
click on the ‘Next’ button
...

Click on the ‘Next’ button in the ‘Authentication
configuration’ screen
...

Select ‘No’ option in the ‘Boot diskette creation’ screen
Click on the ‘Next’ button in the ‘Graphical Interface (x)
configuration’ screen
...


In the ‘Customize graphical configuration’ screen select the
‘Graphical’ option and then click on ‘Next’ button
...


Using Red Hat Linux
For logging into the system enter the username and password and
select the session as KDE (K Desktop Environment)
...
In this dialog in the command edit
box type KWrite and then click on the Ok button
...

To compile the program you need to go the command prompt
...

KMenu | System Tools | Terminal
Once at the command prompt you can use the gcc compiler to
compile and execute your programs
...



Title: Complete Guide To C Language
Description: Complete Guide To C language, With Exercises, Useful Referance Book to First Year Undergraduate to Last Year Graduate