UG - B.Sc. - Computer Science - 130 13 Programming in C - 8070
UG - B.Sc. - Computer Science - 130 13 Programming in C - 8070
sruIncrease
oC eht fothe
ezifont
s tnosize
f ehof
t esthe
aerCourse
cnI .1 Name.
.egaP revoC e2.ht nuse
i rethe
daefollowing
h a sa gniwasolaloheader
f eht esin
u the
.2 Cover Page.
YTISREVINUALAGAPPA
APPAGALAUNIVERSITY
B.Sc. [Computer Science]
elcyC drihT eht ni )46.3:APGC( CA[Accredited
AN yb edarGwith
’+A’’A+’
htiwGrade
detidby
ercNAAC
cA[ (CGPA:3.64) in the Third Cycle
]CGU-DRHM yb ytisrevinU I–yrogeand
taC Graded
sa dedarasG Category–I
dna University by MHRD-UGC]
300 036 – IDUKIARA
KARAIKUDI
K – 630 003
130 13 NOITACUDE ECNATSIDDIRECTORATE
FO ETAROTCEOF
RIDDISTANCE EDUCATION
PROGRAMMING IN C
I - Semester
PROGRAMMING IN C
B.Sc. [Computer Science]
130 13
itnem sYou
a egaare
p reinstructed
voc eht etatodpupdate
u ot dethe
tcurcover
tsni erpage
a uoYas mentioned below:
.emaN e1.sruIncrease
oC eht fothe
ezifont
s tnosize
f ehof
t esthe
aerCourse
cnI .1 Name.
aP revoC e2.ht nuse
i rethe
daefollowing
h a sa gniwasolaloheader
f eht esin
u the
.2 Cover Page.
ISREVINUALAGAPPA
APPAGALAUNIVERSITY
B.Sc. [Computer Science]
rihT eht ni )46.3:APGC( CA[Accredited
AN yb edarGwith
’+A’’A+’
htiwGrade
detidby
ercNAAC
cA[ (CGPA:3.64) in the Third Cycle
]CGU-DRHM yb ytisrevinU I–yrogeand
taC Graded
sa dedarasG Category–I
dna University by MHRD-UGC]
300 036 – IDUKIARA
KARAIKUDI
K
ITACUDE ECNATSIDDIRECTORATE
FO ETAROTCEOF
– 630 003
RIDDISTANCE EDUCATION
PROGRAMMING IN C
I - Semester
ALAGAPPA UNIVERSITY
[Accredited with ‘A+’ Grade by NAAC (CGPA:3.64) in the Third Cycle
and Graded as Category–I University by MHRD-UGC]
(A State University Established by the Government of Tamil Nadu)
KARAIKUDI – 630 003
PROGRAMMING IN C
Authors
Rohit Khurana, CEO, ITL Education Solutions Ltd.
Unit (1)
Dr. Subburaj Ramasamy, Former Senior Director, Department of Information Technology, Government of India
Units (2-14)
"The copyright shall be vested with Alagappa University"
All rights reserved. No part of this publication which is material protected by this copyright notice
may be reproduced or transmitted or utilized or stored in any form or by any means now known or
hereinafter invented, electronic, digital or mechanical, including photocopying, scanning, recording
or by any information storage or retrieval system, without prior written permission from the Alagappa
University, Karaikudi, Tamil Nadu.
Information contained in this book has been published by VIKAS® Publishing House Pvt. Ltd. and has
been obtained by its Authors from sources believed to be reliable and are correct to the best of their
knowledge. However, the Alagappa University, Publisher and its Authors shall in no event be liable for
any errors, omissions or damages arising out of use of this information and specifically disclaim any
implied warranties or merchantability or fitness for any particular use.
Work Order No. AU/DDE/DE1-238/Preparation and Printing of Course Materials/2018 Dated 30.08.2018 Copies - 500
SYLLABI-BOOK MAPPING TABLE
Programming in C
Syllabi Mapping in Book
BLOCK 1: INTRODUCTION
Unit-1: Introduction and Features: History of C, Importance Unit-1: Introduction and Features
of C, Basic Structure of C Program, Character set, Tokens, (Pages 1-11);
Keywords and Identifiers Unit-2: Constants,
Unit-2: Constants and Variables and Data Types: Declaration Variables and Data Types
of Variables, Defining Symbolic Constants, Declaring a Variable (Pages 12-34);
as a Constant Unit-3: Operators and Expressions
Unit-3: Operators and Expressions: Arithmetic, Relational, (Pages 35-48)
Logical, Assignment Operators, Arithmetic Expression, Evaluation
of Expressions, Precedence of Arithmetic Operators
BLOCK 4 : POINTERS
Unit-10: Pointers
Unit-10: Pointers: Basics, Declaring, Initialization of Pointer
Variables, Address of Variable, Accessing a Variable through its (Pages 177-190);
Pointer Unit-11: Pointer as Functions
Unit-11: Pointer as Functions: Chain of Pointers, Pointer (Pages 191-204);
Increments and Scale Factors Unit-12: Strings with Pointer
Unit-12: Strings with Pointer: Pointers and Character Strings, (Pages 205-215)
Pointers and Structures
BLOCK 5 : FILES
Unit-13: Introduction: Introduction, Defining, Opening and Unit-13: Introduction to Files
Closing Files, I/O Operations on Files (Pages 216-230)
Unit-14: Error Handling Methods: Error Handling During I/O Unit-14: Error Handling Methods
Operations, Command Line Arguments (Pages 231-240)
CONTENTS
INTRODUCTION
BLOCK I: INTRODUCTION
UNIT 1 INTRODUCTION AND FEATURES 1-11
1.0 Introduction
1.1 Objectives
1.2 Basic Concepts of Programming in C
1.3 Concept of Structured Programming
1.4 History of C Language
1.5 Basics of C
1.5.1 C Character Set; 1.5.2 C Tokens
1.5.3 The Structure of a C Program; 1.5.4 Advantages of C
1.6 Answers to Check Your Progress Questions
1.7 Summary
1.8 Key Words
1.9 Self Assessment Questions and Exercises
1.10 Further Readings
Self-Instructional
8 Material
Introduction and Features
BLOCK - I
INTRODUCTION
NOTES
UNIT 1 INTRODUCTION AND
FEATURES
Structure
1.0 Introduction
1.1 Objectives
1.2 Basic Concepts of Programming in C
1.3 Concept of Structured Programming
1.4 History of C Language
1.5 Basics of C
1.5.1 C Character Set
1.5.2 C Tokens
1.5.3 The Structure of a C Program
1.5.4 Advantages of C
1.6 Answers to Check Your Progress Questions
1.7 Summary
1.8 Key Words
1.9 Self Assessment Questions and Exercises
1.10 Further Readings
1.0 INTRODUCTION
1.1 OBJECTIVES
NOTES
1.2 BASIC CONCEPTS OF PROGRAMMING IN C
Designed and developed by Brian Kernighan and Dennis Ritchie, at The Bell
Research Labs in 1972, the ‘C’ programming language is one of the most popular
computer languages in today’s computer world. It was created so as to allow the
programmer access to almost all of the machine’s internals—registers, I/O slots
and absolute addresses. In addition to this, ‘C’ allows for as much data handling
and programmed text modularization as is needed to allow very complex multi-
programmer projects to be constructed in an organized and timely fashion.
Although this language was originally intended to run under UNIX, there
has been a great interest in running it under the MS-DOS operating system on the
IBM PC and compatibles. It is an excellent language for this environment because
of the simplicity of expression, the compactness of the code, and the wide range
of applicability.
Also, due to the simplicity and ease of writing a C compiler, it is usually the
first high level language available on any new computer, including microcomputers,
minicomputers, and mainframes.
Programming in C can be a great help in the areas where you need to use
Assembly Language but would prefer to keep it simple to write and easy to maintain
the program. The time saved in coding of C can be quite rewarding in such cases.
Even though the C language has a good record when programs are
transported from one implementation to another, there are differences in compilers
that you will find anytime you try to use another compiler. You come to know of
many differences when you use nonstandard extensions such as calls to the DOS
BIOS when using MS-DOS. Nevertheless, these differences can be minimized
by careful choice of programming constructs.
When the C programming language gained popularity among users, using a
wide range of computers, representatives of the software sector met to propose a
standard set of rules for the use of the C programming language. The group
represented all sectors of the software industry and after many meetings, and
many preliminary drafts, they finally wrote an acceptable standard for the C
language. It has been accepted by the American National Standards Institute
(ANSI), and by the International Standards Organization (ISO). Although
implementation of the program is not compulsory, it would be the loss of the
individual/organization not opting for it.
Self-Instructional
2 Material
Introduction and Features
1.3 CONCEPT OF STRUCTURED
PROGRAMMING
subroutine-8 subroutine-9
Self-Instructional
Material 3
Introduction and Features control passes
from main to add()
add ()
main() {
{
NOTES add(): .
find (): .
delete(): .
modify():
} }
control passes
from add() to main
find()
{
.
.
.
}
1.5 BASICS OF C
This section discusses some basic concepts of C which lay the foundation for
harnessing the features and capabilities of this language. First the basic elements
Self-Instructional
4 Material
required to construct simple C statements will be discussed. This includes the Introduction and Features
Special Characters
+ > / [ \
! ; “ ] {
< * . % }
: ^ , ~ #
- ( = _ |
? ) ‘ &
Apart from the upper and lower case letters, decimal digits and special
characters, C also uses a combination of characters. For example, the escape
sequences such as ‘\b’, ‘\c’ and ‘\t’ are a combination of the special character ‘\’
and a letter (‘b’, ‘c’ and ‘t’).
1.5.2 C Tokens
A token is defined as the smallest unit of a program. When a program is compiled,
the compiler scans the source code and parses it into tokens to find the syntax
errors. C tokens are broadly classified into the following.
Keywords
The predefined words that have special significance in any language are known as
keywords. Every keyword is reserved for a specific purpose and hence cannot
be used as variable or function names. All the keywords of C are listed in
Table 1.2.
Table 1.2 C Keywords
Keywords
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 Self-Instructional
Material 5
Introduction and Features Identifiers
The names given to uniquely identify various programming elements like variables,
arrays and functions are known as identifiers. An identifier must be unique in a
NOTES program. It must contain only upper case and lower case letters, underscore
character ( _ ) or digits 0 to 9 in any order, except that the first character cannot
be a digit. Other special characters such as ‘*’, ‘;’ and white space characters
(tabs, space and newline) are not allowed. Since C is a case-sensitive language,
an identifier in the upper case is different from that in lower case.
Constants
Constants, also known as literals, are the values that a program cannot modify
during its execution. For example, ‘391’, ‘Byron’, ‘51.072’ and ‘p’ are all
constants. Based on the type of value (data), C constants are broadly classified
into three categories, namely, numeric (or integer) constants, real constants and
character constants.
Operators
The symbols which represent various computations (such as addition, subtraction,
etc.) performed on various data items are known as operators. The data items
on which the operators act are known as operands. Depending on the function
they perform, C operators are classified into various categories. This includes
arithmetic operators, relational operators, logical operators, the conditional
operator assignment operators, bitwise operators and other operator.
Depending on the number of operands, C operators are broadly classified
into three categories, namely, unary operators (work on only one operand), binary
operators (work on two operators) and ternary operators (work on three
operators).
Punctuators
Punctuators, also known as separators, are tokens that serve different purposes
based on the context in which they are used. Some punctuators are used as
operators, some are used to demarcate a portion of the program and so on. The
various punctuators defined in C are asterisk ‘*’, braces ‘{ }’, brackets ‘[ ]’,
colon ‘:’, comma ‘,’, ellipsis ‘…’, equal to ‘=’, semicolon ‘;’, parentheses
‘( )’ and pound (hash) ‘#’.
1.5.3 The Structure of a C Program
Programs are a sequence of instructions or statements. These statements form the
structure of a C program. To understand the structure of a program, consider
Figure 1.3.
Self-Instructional
6 Material
Introduction and Features
NOTES
1.5.4 Advantages of C
Some of the advantages of C language are as follows.
Readability: It is easier to learn and understand because it is very close to
human languages.
Machine independent: Programs written in C language are portable as codes.
Once written they can be used on different platforms (machines) also.
Self-Instructional
8 Material
Easy debugging: Programs written in this language are easy for debugging. Introduction and Features
Debugging means to rectify the errors in a program. High-level languages
require an interpreter or a compiler to detect error(s) and helps programmers
to correct errors.
Easy maintenance: Programs written in C are modified easily as they are NOTES
similar to human languages.
Reusability: C codes are reusable, that is, once the programs are loaded
into a library they can be used by other applications also.
Structured programming: Code written in C can be broken down into
several functional programs. This can be developed independently and then
combined into a single program.
Low development cost: Programs written in C language increase
programmers’ productivity (number of lines of code generated per hour).
Easy documentation: Programs written in C provide easy documentation
for future maintenance.
1.7 SUMMARY
Programming in C can be a great help in the areas where you need to use
Assembly Language but would prefer to keep it simple to write and easy to
maintain the program.
Structured programming (also known as procedural programming) was a
powerful and an easy approach of writing complex programs. In procedural
programming, programs are divided into different procedures (also known
as functions, routines or subroutines) and each procedure contains a set of
Self-Instructional
Material 9
Introduction and Features instructions that performs a specific task. This approach follows the top-
down approach for designing the program.
C is a general-purpose high-level programming language that was developed
by Dennis Ritchie at the Bell Laboratories, USA in the early 70s. The
NOTES
language was named ‘C’ because it was the successor to a language named
‘B’, which was developed by Ken Thompson in 1969–70. Dennis Ritchie
extended the features of B and turned-into C by adding some more features
in it. C was developed as a high-level language that could be used to rewrite
the UNIX operating system which was earlier written in assembly language.
A character set can be defined as a set of characters that either individually
or in combination, represents a meaning in a language. In C, a character set
includes the upper case (A–Z) and lower case (a–z) letters, decimal digits
(0–9), blank spaces (tabs, new line, space, etc.) and special characters
(characters that perform a specific action based on the context in which
they are used).
The predefined words that have special significance in any language are
known as keywords. Every keyword is reserved for a specific purpose
and hence cannot be used as variable or function names.
Constants, also known as literals, are the values that a program cannot
modify during its execution.
The symbols which represent various computations (such as addition,
subtraction, etc.) performed on various data items are known as operators.
Punctuators, also known as separators, are tokens that serve different
purposes based on the context in which they are used.
The structure of a C program can be broadly classified into header files
and the main () function.
The first executable instruction in all C programs is the main() function. That
is, programs begin their execution from this instruction.
Self-Instructional
10 Material
Introduction and Features
1.9 SELF ASSESSMENT QUESTIONS AND
EXERCISES
Self-Instructional
Material 11
Constants, Variables and
Data Types
UNIT 2 CONSTANTS, VARIABLES
AND DATA TYPES
NOTES
Structure
2.0 Introduction
2.1 Objectives
2.2 Elementary Data Types
2.2.1 Fundamental Data Types
2.2.2 Maximum and Minimum Magnitudes
2.3 Variable Declarations
2.4 Syntax and Semantics
2.5 Reserved Words
2.6 Constants
2.6.1 Integer Constants
2.6.2 Character Constants
2.6.3 Floating Point or Real Numbers
2.6.4 Enumeration Constant
2.6.5 String Constants
2.6.6 Symbolic Constants
2.7 Answers to Check Your Progress Questions
2.8 Summary
2.9 Key Words
2.10 Self Assessment Questions and Exercises
2.11 Further Readings
2.0 INTRODUCTION
In this unit, you will learn about the data types, variables and constants. In C, data
types refer to the system used for declaring constants and variables of different
types. The type of data determines how much space it occupies in the memory of
the computer system and how the bit pattern stored is interpreted. Variables are
identifiers which refer to the data items stored at particular memory locations.
Constants are the programming elements whose values are fixed during the execution
of a program.
2.1 OBJECTIVES
Self-Instructional
12 Material
Constants, Variables and
2.2 ELEMENTARY DATA TYPES Data Types
Data is used in a program to get information. In a program used to find out the
greater of two numbers, the numbers are data, and the output which says which NOTES
number is greater, is information. C is a versatile language and handles many different
types of data in an elegant manner.
Bit stands for binary digit, i.e., 0 or 1. Each byte is a collection of 8 bits, i.e.,
8 consecutive bits of ‘0’ or ‘1’. Data is handled in a computer generally in terms of
bytes and therefore, will be in the form of multiples of 8 bits. Each ASCII character
is represented by one byte.
2.2.1 Fundamental Data Types
An item that holds data is also called an object. An object has a name or an
identifier associated with it. Each object can hold a specific type of data. There
are five basic data types in C, as follows:
(i) Character
(ii) Integer
(iii) Real numbers
(iv) Void
(v) Enum
You have to first understand how a computer works. Assume that two
numbers a and b are to be multiplied. First, the two numbers have to be stored in
the memory. Then the required calculation has to be performed. The result has
also to be stored in memory. Each number is of a specific data type; for instance,
all three of them can be declared to be integers. Each data type occupies a specific
size in the memory. What does one mean by size? It is the amount of storage
space required; each bit needs one storage space. One byte needs eight storage
spaces. If a number is of type integer declared as int, it is stored in 2 bytes. The
number depending on its type gets stored in different forms. If a number is of float
type, it takes 4 bytes to store it. All characters can be represented according to
the ASCII table and hence, 1 byte, i.e., 8 bits are good enough to store a character,
which is represented as char.
These sizes may vary from computer to computer. The header files
<limits.h> and <float.h> contain information about the sizes of the
data types.
Real numbers can be expressed with single precision or double precision.
Double precision means that real numbers can be expressed more precisely.
Double precision also means more digits in mantissa. The type ‘float’ means
single precision and ‘double’ means a double precision real number. Table
2.1 indicates the size of various data types.
Self-Instructional
Material 13
Constants, Variables and Table 2.1 Size of Data Types
Data Types
Data Type Size
char 1 byte
int 2 bytes
NOTES float 4 bytes
double 8 bytes
The names of variables and constants are identifiers. The names are made up of
alphabets, digits and underscore, but the first character of an identifier must be an
alphabet. C allows up to 31 characters for the identifier (names) and therefore, the
naming of the variables should be carried out in an easily understandable manner.
For example, in the program for the calculation of,
Simple interest I = pnr/100,
you can declare them with actual names,
Self-Instructional
14 Material
p = principal, r = rate_of_interest, n = number_of_ Constants, Variables and
Data Types
years
Naturally, programmers may not like typing long names for fear of making mistakes
elsewhere in the program apart from being reluctant to increase their typing
NOTES
workload. Meaningful names can, however, be assigned to data types even with
few letters. For example,
p = princ; r = intrate; n = years
Some compilers may allow names with up to 31 (thirty-one) characters, but may
consider the first eight characters for all purposes. Hence, a programmer could
coin shorter yet meaningful names, instead of using single alphabets for variable
names. One should, however, be careful not to use the reserved words, such as
the 32 keywords, for variable names as they have a specific meaning to the compiler.
If they are used as variable names, then the compiler will get confused. Be careful
not to use the reserved words as identifiers.
A program to find out the square of integer 5 is given as follows:
/*Example 2.1*/
/*program to find square of 5*/
#include <stdio.h>
int main()
{
printf(“square of %d= %d”, 5, 5*5);
}
You have now achieved the objective of finding the square of 5. Later on,
you may want to find out the square of another number, say 7, for example. We
would have to write the same program again replacing 5 by 7 and then compile
and run it. This would waste a lot of time. To save time, we can, therefore, write a
general-purpose program as shown in Example 2.2.
/*Example 2.2*/
/*program to find square of any given number*/
#include <stdio.h>
int main()
{
int num;
printf(“Enter the integer whose square is to be found\n”);
scanf(“%d”, &num);
Self-Instructional
Material 15
Constants, Variables and printf(“square of %d= %d”, num, num*num);
Data Types
}
Here, we define num as an integer variable. When ‘&’ precedes num, it indicates
NOTES the memory address of num.
At the first printf, the message appears as it is and the cursor goes to
the next line because of the new line character \n at the end of the message, but
before the closing quotation mark. The next statement is new to you. It is used to
receive an integer typed on the console. You can type in any integer number, and
the number typed will be stored in the memory at the memory location named
‘num’. The purpose of the statement is, therefore, to get the integer (because of
the appearance of %d within quotes) and it is stored at the memory address ‘num’.
The next statement prints the number typed and its square.
When you execute the program, the following message appears on the
monitor:
Enter the integer whose square is to be found.
Since we want to find out the square of 25 type:
25
The next time you may want to find out the square of another number, say 121.
Then simply run the program and when prompted, type 121 to get the answer.
Here the number whose square has to be found out has been declared as a
variable. The variable has a name and is stored at the location pointed to by the
variable name. Therefore, the execution of the program for finding out the square
of any number is easy with the above modification.
Variables and constants are fundamental data types. A variable can be
assigned only one value at a time, but can change value during program execution.
A constant, as the name indicates, cannot be assigned a different value during
program execution. For example, PI, if declared as a constant, cannot have its
value varied in a given program. If PI has been declared as a constant = 3.14, it
cannot be reassigned any other value in the program. Programs may declare a
number of constants. Variables are similarly useful for any programming language.
If PI has been declared as a variable, then it can be changed in the program to
any value. This is one difference between a variable and a constant. Whether an
identifier is constant or variable depends on how it is declared. Both variables and
constants belong to one of the data types like int, float, etc. The convention
in ‘C’ is to indicate the names of constants by the upper case letters.
PI
SIGMA
Self-Instructional
16 Material
Variable names are, on the other hand, indicated by the lower case letters. Constants, Variables and
Data Types
int a
float xy
Self-Instructional
Material 17
Constants, Variables and Therefore, it is obvious that a long double occupies 10 bytes and stores long
Data Types
floating-point numbers with double precision.
Note that the size of short int will be either equal to or less than the size of
an integer variable.
NOTES
Variables, which require more than 1 byte for storage, will be stored
consecutively in the memory.
You have learnt in the previous sections about variables, constants, tokens,
identifiers, keywords and elementary data types. For syntax and semantics, the
storage specifiers in C are auto, static, extern, register and
typedef and the storage modifiers are const and volatile. The storage
specifiers and modifiers might appear before or after the type name in a declaration
but by convention they come before the type name. The semantics of each keyword
is specified at the time of declaration. Table 2.2 summarizes the storage specifiers
and their functions:
The syntax for storage keywords and functions is flexible which supports declaration
part only. A variable can be declared using register and volatile, but
Self-Instructional
18 Material
the compiling part depends on a compiler which decides how to interpret it as per Constants, Variables and
Data Types
the set rules.
aa int_val1;
bb int_val2;
Table 2.3 shows the semantics of storage specifiers.
Table 2.3 Semantics of Storage Class Specifiers
Now, let us discuss about storage modifiers, i.e., const and volatile. A
type qualifier is used to refine the declaration of a variable, a function and parameters
by specifying if:
The value of a variable can be changed.
The value of a variable must always be read from memory rather than from
a register.
Standard C language recognizes the following two qualifiers:
const
volatile
Any type can be qualified by the type qualifiers const or volatile. In C
code, const keyword is frequently used but volatile is used often. The
const value is one you can not to modify. The compiler may therefore be able
to make certain optimizations, such as placing a constqualified variable in read
Self-Instructional
Material 19
Constants, Variables and only memory. However, a constqualified variable is not a true constant, i.e., it
Data Types
does not qualify as a constant expression which C requires in certain situations,
such as in array declaration, case labels and initializers for variables with static
duration global and static variables. A volatile value is one that
NOTES might change unexpectedly. This situation only arises when you are directly accessing
special hardware registers, usually at the time of writing the software files for device
drivers. The compiler should not assume that a volatile qualified variable
which contains the last value that was written to it. The compiler should therefore
avoid making any optimizations which would suppress the volatile qualified
variable. Examples of volatile locations would be a clock register or a device
control and status register which causes the specified peripheral devices to perform
an action each time the register was written to.
Const Qualifier: The const qualifier is used to tell C that the variable value
cannot change after initialization and is declared in the following way:
const float pi=3.14159;
Now, pi cannot be changed at a later time within the program. Another way to
define a constant is using the #define preprocessor which has the advantage
that it does not use any storage. In simple declarations, the type qualifier is simply
another keyword in the type name along with the basic type and the storage class.
For example, the following code involves all declarations of type qualifiers.
const int i;
const float f;
extern volatile unsigned long int ul;
Volatile Qualifier: The volatile qualifier declares a data type that can have its
value changed in ways outside the control or detection of the compiler, such as a
variable updated by the system clock or by another program. This prevents the
compiler from optimizing code referring to the object by storing the object’s value
in a register and re-reading it from there rather than from memory where it may
have changed.
The reserved words have special meaning within the language and are predefined
in the language’s formal specifications. Typically, reserved words include labels
for primitive data types in languages that support a type system and identify
programming constructs, such as data types, loops, blocks, conditionals and
Self-Instructional
20 Material
branches. The list of reserved words in a language are defined when a language is Constants, Variables and
Data Types
developed. Reserved words may not be redefined by the programmer, unlike
predefined functions, methods or subroutines, which can often be overridden in
some capacity.
NOTES
The syntax rules or grammar of C defines certain symbols and keywords to have
a unique meaning within a C program. These symbols and keywords are known
as reserved words and must not be used for declaring data and variables. This is
because most of the facilities which C offers are in libraries that are included in
programs. Once a library has been included in a program, its functions are defined
and you cannot use these reserved words as user-defined keywords, for example
variables. As per C syntax specifications, all of these reserved words must be in
lower case. Each is considered to be a single word like the special keywords. The
word symbols cannot be redefined within the C program, i.e., they cannot be
used for anything other than their predefined and intended use. The C language
uses a number of keywords such as int, char and while. A keyword has
a special meaning in the context of a C program and can be used for that specific
purpose only, for example int can be used only to specify that the data type is
integer. All keywords are written in lowercase letters only. Thus, int is a keyword
but Int and INT are not. Keywords are the reserved words. It means you
cannot use them as identifiers. Table 2.4 shows the list of reserved words, which
are not used in declaring variables:
2.6 CONSTANTS
The following are the types of constants:
Integer constant
Character constant
Float constant
Enumeration constant
String constant
Symbolic constant
All these types are explained below. Self-Instructional
Material 21
Constants, Variables and 2.6.1 Integer Constants
Data Types
The following are the types of integers:
int
NOTES unsigned int
long
unsigned long
Variations in integer types
We can use the sign bit also for holding the value. In such cases, the variable will
be called unsigned int. The maximum value of an unsigned int
will be equal to 65535 because we are using the Most Significant Bit (MSB) also
for storing the value. The minimum value will obviously be 0.
A long integer is represented as long int or simply long. The maximum
and minimum values of long are given below:
LONG MAX + 2147483647
LONG MIN – 2147483647
Unless otherwise specified, integers or long integers will be signed, i.e., the
first bit will be reserved for the sign. The long int obviously uses 4 bytes or
32 bits.
The magnitudes of long can also be doubled by using an unsigned long
integer denoted as unsigned long.
However, integers are not suitable for very low values and very large values.
This can be overcome by floating point or real numbers.
An integer constant may be suffixed by the letter u or U to specify that it
is an unsigned integer. Similarly, if the integer is suffixed with l or L,
it signifies a long integer. If we specify unsigned long integer
we suffix the constant with ul or UL.
The following are the examples of valid and invalid integers:
Valid integers
+345 /* integer */
345 /* integer */
–345 /* integer */
729u /* unsigned integer */
729U /* unsigned integer */
–112345L /* Long integer */
112345UL /* Unsigned Long integer */
+112345l /* Long integer */
112345l /* Long integer - if no sign precedes, it is a
positive number */
Self-Instructional
22 Material
Invalid integers Constants, Variables and
Data Types
345.0 /* decimal point not allowed */
112, 345L /* no comma allowed */
112 345UL /* = blank not allowed */
NOTES
112890345L /* exceeds the maximum */
+112 345UL /* unsigned cannot have + */
(345l /* ( not allowed */
–345s /* illegal characters */
We have so far considered only decimal numbers. The C language, however,
entertains other type of numbers as well. The octal numbers will be preceded by
0 (zero).
The following are examples of valid and invalid octal numbers:
Valid octal number
0346
0547
0120
Invalid octal number
0394 /* 8 or 9 are not allowed in an octal number
*/
0 x 345 /* prefix has to be zero only */
The C language also supports hexadecimal numbers. Here, since the base
is 16, we use alphabets also in the numbers as given in Table 2.5.
Table 2.5
a or A for 10
b or B for 11
c or C for 12
d or D for 13
e or E for 14
f or F for 15
Self-Instructional
Material 23
Constants, Variables and Invalid hexadecimal numbers
Data Types
0x, 123 /* no comma */
0x /* cannot be empty */
NOTES 0A00 /* x is missing */
2.6.2 Character Constants
A character constant is a single character enclosed in single quotes as in ‘x’.
Characters can be alphabets, digits or special symbols.
The following are examples of valid and invalid character constants:
Valid character constants
‘A’
‘Z’
‘C’
‘c’
Invalid character constants
‘\n’
‘\t’
‘\u’
‘\b’
AA
‘AA’
“AA”
‘1a’
A character constant represents its integer value as defined in the character set of
the machine. Therefore, you can add 2 characters. For example, the ASCII values
of digit 1 = 49 and C = 67. When we add these values we get code 116 whose
equivalent character is t.
Let us verify this with the following example:
/* Example 2.4
demonstrates that chars can be treated like integers*/
#include <stdio.h>
int main()
{
const char ALPHA1=‘1';
char alpha2=’C’;
char alpha3;
alpha3=ALPHA1+alpha2;
putchar(alpha3);
Self-Instructional }
24 Material
Result of the program Constants, Variables and
Data Types
t
Therefore, characters can be treated like integers as well, although they are
declared as character variables and constants. Since characters are of type int,
NOTES
we could add them. Characters can also be defined as integers as given in Example
2.5.
/* Example 2.5
Demonstrates that a char can also be declared as int*/
#include <stdio.h>
int main()
{
int x;
x=’1'+’C’;
printf(“x as integer=%d\n”, x);/*x printed as integer*/
printf(“x as character=%c\n”, x);/*x printed as character*/
}
Result of the program
x as integer=116
x as character=t
2.6.3 Floating Point or Real Numbers
Let us enumerate the difference between floating point and integer numbers.
Integers are whole numbers without decimal points but a float has always a
decimal point. Even if the number is a whole number, it is written with a
decimal point. For instance, 42 is an integer, while 42.0 is floating-point
number.
Floating-point numbers occupy more space for storage as we have already
seen.
A real number in the simple form consists of a whole number followed by
the decimal point and also one or more decimal numbers following the decimal
point, which makes the fractional part. This form of representation is known as
fractional form. It must have a decimal point. It could be either positive or negative.
As usual the default sign is positive. No commas or blanks or special characters
are allowed in between.
The following are the examples of valid and invalid float types:
Valid floats
144.00
226.012
Invalid floats
+144 /* no decimal point */
1,44.0 /* comma not allowed */ Self-Instructional
Material 25
Constants, Variables and Scientific notation: Floating-point numbers can also be expressed in scientific
Data Types
notation. For example, 3.0 E2 is a floating-point number. The value of the
number will be equal to 3.0 × 102 = 300.0.
Instead of the upper case E, the lower case e can be used as in
NOTES
0.453 e + 05, which will be equal to 0.453 × 105 = 45300
There are two parts in the scientific notation of a real number, which are as follows:
(i) Mantissa (before E)
(ii) Exponent (after E)
In the scientific form the following rules are to be observed:
The mantissa part can be positive or negative.
The exponent must have at least one digit, which can be a positive or negative
integer. Remember the exponent cannot be a floating-point number.
type float is a single precision number occupying a storage space of
4 bytes.
type double represents floating-point numbers of double precision
and hence occupies 8 bytes.
If you look at the file <float.h> you will find the maximum and minimum
floating-point numbers as given below.
FLT – MAX 1E + 37 maximum floating point number
FLT – MIN 1E – 37 minimum floating point number
Floating-point constants The constants are suffixed as given below:
F or f – float
no suffix – double
L or l – long double
If an integer is suffixed with L or l, then it is a long integer.
If a float is suffixed with L or l, then it is a long double floating-point
number.
Examples
Valid floating-point constants
1.0 e 5
123.0 f /* float */
11123.05 /* double */
23467.34 e 5 l /* long double */
Invalid real constants
245.0 /* invalid float, but valid double */
456 /* It is an integer */
1.0 e 5.0 /* exponent cannot be a real number */
Self-Instructional
26 Material
When they are declared as variables, they can be declared as follows: Constants, Variables and
Data Types
float a = 3.12;
float a, b, c;
float val1;
NOTES
float val2;
long double val3;
The values of constants cannot be altered in programs. They can be defined as
follows:
const int PRINC = 1000;
const float INT_RATE = 0.12 f;
The values of PRINC and INT_RATE cannot be changed in the program even
by introducing another assignment statement when they are declared as constants
using const. Example 2.6 verifies this statement:
/*Example 2.6
Demonstrates that constants cannot be changed
even with assignment statements. To verify, include
statements 7, 8 & 9 in the program by removing
the comment specifiers at the beginning of the program
statement 7 and the end of statement 9*/
#include<stdio.h>
main()
{
const int PRINC =1000;
const float INTST=0.12f;
printf(“PRINCIPAL=%d INTEREST=%f\n”, PRINC, INTST);
/*PRINC =2000;
INTST=0.24f;
printf(“PRINCIPAL=%d INTEREST=%f\n”, PRINC, INTST);*/
}
Key in the example and execute the program. After successful compilation, you
will get the result as follows:
Result of the program
PRINCIPAL = 1000; INTEREST = 0.1200
Now include the second part of the program by removing /* and */ at
statements 7 and 9, respectively. Earlier this was treated as a comment. Now this
part will get included in the program. Now compile it. You will get a compilation
error. This is due to your attempt to redefine the constants PRINC and INTST,
which is not allowed. Incidentally, the technique of including or excluding a program
segment at will using /* and */ is a convenient method for program development.
Self-Instructional
Material 27
Constants, Variables and 2.6.4 Enumeration Constant
Data Types
The keyword for this data type is enum. We can define guardian as follows:
enum guardian
NOTES {
father,
husband,
guardian
};
Note that there are no semicolons, but only a comma after the members
except the last member. There is not even a comma after the last member. There is
no conflict between both guardians. The top one is enum and the bottom one is
a member of enum guardian. See the similarity between structure, union
and enum. The enum variables can be declared as follows:
enum guardian emp1, emp2, emp3;
This is similar to structures and unions. The first part is the declaration of the
data type. The second part is the declaration of the variable.
The initial values can be assigned in a simpler manner as given below:
emp1 = husband;
emp2 = guardian;
emp3 = father;
We have to assign only those declared as part of the enum declaration.
Assigning constants not declared will cause error. The compiler treats the
enumerators given within the braces as constants. The first enumerator father will
be treated as 0, the husband as 1 and the guardian as 2. Therefore it is strictly as
per the natural order starting from 0.
The enumerated data type is never used alone. It is used in conjunction with other
data types. We can write a program using enum and struct as shown in
Example 2.7.
/*Example 2.7
enum within structure*/
#include <stdio.h>
main()
{
enum guardian
{
father,
husband,
relative
};
Self-Instructional
28 Material
struct employee Constants, Variables and
Data Types
{
char *name;
float basic;
NOTES
char *birthdate;
enum guardian guard;
}emp[2];
int i;
emp[0].name=”RAM”;
emp[0].basic= 20000.00;
emp[0].birthdate= “19/11/1948”;
emp[0].guard= father;
emp[1].name=”SITA”;
emp[1].basic= 12000.00;
emp[1].birthdate= “19/11/1958”;
emp[1].guard=husband;
for(i=0;i<2;i++)
{
if( emp[i].basic ==12000)
{
printf(“Name:%s\nbirthdate:%s\nguardian:
%d\n”,
emp[i].name, emp[i]. birthdate,
emp[i].guard);
}
}
}
Result of the program
Name:SITA
birthdate:19/11/1958
guardian: 1
The program clearly assigns the relationships between the employee
and the guardian. enum guardian is the data type, and guard is a
variable of this type.
However, when you are printing emp [i]. guard, you are printing an
integer. Hence 0, 1 or 2 will only be printed for the status, and this is a limitation.
This can be overcome by modifying the program. The program modified with a
switch statement is given in Example 2.8.
/*Example 2.8 expanding enum*/
#include <stdio.h>
Self-Instructional
Material 29
Constants, Variables and main()
Data Types
{ enum guardian
{ father,
husband,
NOTES relative };
struct employee
{
char *name;
float basic;
char *birthdate;
enum guardian guard;
}emp[2];
int i;
emp[0].name=”RAM”;
emp[0].basic= 20000.00;
emp[0].birthdate= “19/11/1948”;
emp[0].guard= father;
emp[1].name=”SITA”;
emp[1].basic= 12000.00;
emp[1].birthdate= “19/11/1958”;
emp[1].guard=husband;
for(i=0;i<2;i++)
{
if( emp[i].basic ==12000)
{printf(“Name:%s\nbirthdate:%s\nguardian:”,
emp[i].name, emp[i]. birthdate);
switch(emp[i].guard)
{ case 0:printf(“father\n”);
break;
case 1:printf(“husband\n”);
break;
case 2:printf(“relative\n”);
break;
}
}
}
}
Result of the program
Name:SITA
birthdate:19/11/1958
guardian:husband
Self-Instructional
30 Material
Even though the conversion of an integer to actual name is additional work, enum Constants, Variables and
Data Types
is an useful construct since it improves readability in addition to number of other
advantages.
For example, we can define boolean as follows:
NOTES
enum boolean {
false,
true
};
Here ‘false’ will contain an integer value 0 and true 1. This can be used
to assign values for ‘found’ in our sorting programs. We can define found as
follows after declaring boolean.
enum boolean found;
We have allowed the system to assign integer values to the members of enum,
but we can also assign specific values to the various members of enum. When
values are assigned, then it takes precedence over what the system assigns.
We can define boolean as:
enum boolean
{ yes = 1,
no = 0
};
This is similar to defining using #define. The #define equivalent for this
will be:
#define yes 1
#define no 0
Although #define and enum provide a way to associate symbolic names
such as boolean with constants, there are difference between them. The differences
are:
(i) enum can generate values itself unlike #define where you have to specify
the replacement constant.
(ii) The compilers need not check the validity of what is stored in the enum
variable, but the #define replacement constant will be checked for
valildity.
(iii) It is possible to print out the values of enum variables in symbolic form,
but this is not possible with # define. Anyway, either of them can be
used depending on the context.
2.6.5 String Constants
A character constant is a single character enclosed within single quotes. A string
constant is a number of characters, arranged consecutively and enclosed within
double quotes.
Self-Instructional
Material 31
Constants, Variables and Examples of valid strings:
Data Types
“God”
“is within me”
“ ”
NOTES
You may be surprised about the third string constant, which has no character.
This is called a NULL or empty string and is allowed in C.
The string constant can contain blanks, special characters, quotation marks,
etc. within the string. In order to distinguish the end of a string constant, the compiler
places a null character \0 (back slash followed by zero) at the end of each string
before the quotation mark. The null character is not visible when the string appears
on the screen. The programmer does not include the null character either. It is the
compiler which automatically inserts the null character at the end of every string.
Invalid string:
‘Yoga’ /* should be enclosed in double quotes */
2.6.6 Symbolic Constants
The format for symbolic constant is as follows:
# define name constant
For example, we can define:
# define INITIAL 1
Which defines INITIAL as 1.
The INITIAL type of definition is called symbolic constants. They are not
variables and hence, they are not defined as part of the declarations of variables.
They are specified on top of the program before the main function. The symbolic
constants are to be written in capital or upper case letters. Wherever the symbolic
constant names appear in the program, the compiler will replace them with the
corresponding replacement constants defined in the # define statement. In
this case, 1 will be substituted wherever INITIAL appears in the program. Note
that there is no semicolon at the end of the # define statement.
2.8 SUMMARY
An item that holds data is also called an object. An object has a name or an
identifier associated with it. Each object can hold a specific type of data.
There are five basic data types in C, as follows: Character, Integer, Real
numbers, Void and Enum.
The sizes of data type may vary from computer to computer. The header
files <limits.h> and <float.h> contain information about the sizes
of the data types.
The names of variables and constants are identifiers. The names are made
up of alphabets, digits and underscore, but the first character of an identifier
must be an alphabet.
Variables and constants are fundamental data types. A variable can be
assigned only one value at a time, but can change value during program
execution. A constant, as the name indicates, cannot be assigned a different
value during program execution.
The storage specifiers in C are auto, static, extern, register
and typedef and the storage modifiers are const and volatile.
The reserved words have special meaning within the language and are
predefined in the language’s formal specifications.
A character constant is a single character enclosed in single quotes as in
‘x’. Characters can be alphabets, digits or special symbols.
A string constant is a number of characters, arranged consecutively and
enclosed within double quotes.
Self-Instructional
Material 33
Constants, Variables and
Data Types 2.9 KEY WORDS
Variable: These are the identifiers whose value changes during the execution
NOTES of a program.
Constants: These are programming elements whose values are fixed during
the execution of a program.
Self-Instructional
34 Material
Operators and Expressions
3.0 INTRODUCTION
In this unit, you will learn about the operators and evaluation of expressions. The
symbols which represent various computations (such as addition, subtraction, etc.)
performed on various data items are known as operators. The data items on which
the operators act are known as operands. Depending on the function they perform,
C operators are classified into various categories. This includes arithmetic
operators, relational operators, logical operators, the conditional operator
assignment operators, bitwise operators and other operator. Operators,
functions, constants and variables are combined together to form expressions.
The expressions give a result when computed.
3.1 OBJECTIVES
Self-Instructional
Material 35
Operators and Expressions
3.2 TYPES OF OPERATORS
Self-Instructional
38 Material
For example, Operators and Expressions
i = 3;
Note: 3 is an expression
const A = 3; NOTES
‘C’ allows multiple assignments in the following form:
identifier 1 = identifier 2 = .....= expression.
For example,
a = b = z = 25;
However, you should know the difference between an assignment operator
and an equality operator. In other languages, both are represented by =.
In ‘C’ the equality operator is expressed as = = and assignment as =.
Shorthand Assignment Operators
You have been looking at simple and easily understandable assignment statements.
This can be written in a different manner when the RHS includes LHS; or in other
words, when the result of computation is stored in one of the variables in the RHS.
The general form is exp1 = exp1 + exp2.
This can be also written as exp1 + = exp2.
Examples:
simple form special form
a = a + b; a += b;
a = a + 1; a += 1;
a= a – b; a – = b;
a = a – 2; a – = 2;
a = a*b; a*= b;
a = a*(b + c); a*= b + c;
a = a/b; a / = b;
a = a/2; a / = 2;
d = d – (a + b); d – = a + b
The assignment operators =, + =, – =, * =, / =, % =, have the
same precedence or priority; however, they all have a much lower priority or
precedence than the arithmetic operators. Therefore, the arithmetic operations
will be carried out first before they are used to assign the values.
3.2.5 Conditional Operator
The condition operator is also termed as ternary operator and is denoted by?:
The syntax for the conditional operator is as follows:
Self-Instructional
Material 39
Operators and Expressions (Condition)? statement1: statement2;
What does it mean? If the condition is true, execute statement1; else, execute
statement2. The conditional operator is quite handy in simple situations as follows:
NOTES (a > b)? print a greater
: print b greater
Thus, the operator has to be used in simple situations. If nothing is written in the
position corresponding to else, then it means nothing is to be done when the
condition is false.
An example is as follows:
/*Example 3.1
Demonstrates use of the ? operator*/
#include <stdio.h>
int main()
{
unsigned int a,b;
printf (“enter two integers\n”);
scanf(“%u%u”, &a, &b);
(a==b)?printf(“you typed equal numbers\n”):
printf(“numbers not equal\n”);
}
Result of the program
enter two integers
123 456
numbers not equal
3.2.6 Increment and Decrement Operators
C contains two increment and decrement operators which are present in postfix
and prefix forms. Both forms are used to increment or decrement the appropriate
variable. The statement ++i (prefix form) increments i before using its value,
while i++ (postfix form) increments it after its value has been used. Both the
forms will produce different outputs when evaluated.
Increment operator ++
The ++ (increment) operator adds 1 to the value of a scalar operand or if the
operand is a pointer then increments the operand by the size of the object to
which it points. The operand receives the result of the increment operation. The
operand must be a modifiable lvalue of arithmetic or pointer type. You can
put ++ before or after the operand. If it appears before the operand, the operand
is incremented first and then used in the expression. If you put ++ after the operand,
the value of the operand is used in the expression before the operand is
incremented. The following statement shows the increment operator concept:
play = ++play1 + play2++;
Self-Instructional
40 Material
This statement is similar to the following expressions: Operators and Expressions
Self-Instructional
Material 41
Operators and Expressions
3.3 EXPRESSION IN C
ab–c a * b – c
(m + n) (x + y) (m + n) * (x + y)
(ab / c) a * b / c
(x / y) + c x / y + c
Evaluation of Expressions
Expressions in C are evaluated using an assignment statement of the following
form: variable = expression;
variable is any valid C variable name. When the statement is encountered
then the expression is evaluated to replace the previous value of the variable
on the left hand side. All variables used in the expression must be assigned values
so that no error occurs at the time of evaluation. The following are some examples
of evaluation statements:
x = a * b – c;
y = b / c * a;
z = a – b / c + d;
The following program illustrates the effect of presence of parenthesis in expressions.
/*Example 3.3
void main ()
{
float a, b, c, x, y, z;
a = 9;
b = 12;
c = 3;
x = a – b / 3 + c * 2 – 1;
y = a – b / (3 + c) * (2 – 1);
Self-Instructional
42 Material
z = a – ( b / (3 + c) * 2) – 1; Operators and Expressions
printf (“x = %fn”,x);
printf (“y = %fn”,y);
printf (“z = %fn”,z);
NOTES
}
Result of the program
x = 10.00
y = 7.00
z = 4.00
An arithmetic expression without parenthesis will be evaluated from left to right
using the rules of precedence of operators. The two distinct priority levels of
arithmetic operators in C are as follows:
High priority * / %
Low priority + -
Rules for Evaluation of Expression
The following are the rules for evaluation of expression in C language:
First parenthesized sub expressions are evaluated from left to right.
If parenthesis is nested, the evaluation begins with the innermost sub
expression.
The precedence rule is applied in determining the order of application of
operators in evaluating sub expressions.
The associability rule is applied when two or more operators of the same
precedence level appear in the sub expression.
Arithmetic expressions are evaluated from left to right using the rules of
precedence.
When parenthesis is used, the expressions within the parenthesis assume
the highest priority.
Types of Expressions
The three types of expressions in C language are as follows:
1. Arithmetic: It evaluates a number, for example a=12;.
2. String: It evaluates character or text string, for example ‘text’ or
‘12345’.
3. Logical: It retains ‘true’ or ‘false’ value.
Conditional Expression in C
The conditional expression holds two values based on the generated condition.
The following syntax is used to write a conditional expression:
(condition) ? val1 : val2;
Self-Instructional
Material 43
Operators and Expressions In C, the standard expression can be declared as follows:
Status_of_person = (age >= 18) ? “adult” : “minor”;
In this conditional expression either of the two values can be returned which is
NOTES based on the value of age. If age is greater than 18 the assigned value to the
Status_of_person will be ‘adult’, and if age is less than 18 then the assigned value
will be ‘minor’.
Self-Instructional
44 Material
the following statements, the value of 5 is assigned to both a and b because of the Operators and Expressions
Self-Instructional
Material 45
Operators and Expressions
3.6 SUMMARY
Self-Instructional
48 Material
Managing I/O Operations
BLOCK - II
I/O OPERATIONS AND DECISION MAKING
NOTES
UNIT 4 MANAGING I/O
OPERATIONS
Structure
4.0 Introduction
4.1 Objectives
4.2 Input/Output Functions
4.2.1 Use of printf()
4.2.2 Single Character Input/Output
4.2.3 Strings—gets() and puts()
4.3 Answers to Check Your Progress Questions
4.4 Summary
4.5 Key Words
4.6 Self Assessment Questions and Exercises
4.7 Further Readings
4.0 INTRODUCTION
In this unit, you will learn about the various types of functions for reading and
writing data on the console. The input and output functions of a computer facilitate
interactions between the computer and the user. The user has to input data in
order to process it in the computer and get the result as the output. The printf
() statement can be programmed to give the output in the desired manner. The
functions gets () and puts () are appropriate when strings are to be received
from the screen or sent to the screen without errors.
4.1 OBJECTIVES
The input and output functions of a computer facilitate communication with the
external world. They also facilitate interaction between the computer and the user. Self-Instructional
Material 49
Managing I/O Operations The user has to input data in order to process it in the computer and get the result
as output. The peripheral device for input is the keyboard. Keying in of the input
data into the computer at run-time is achieved easily by library functions, which
are supplied along with the ‘C’ compiler and have been standardized. The functions,
NOTES which enable keying in of the input data in the keyboard, are given as follows:
scanf()
getchar()
getch()
getche()
gets()
The computer communicates its output, i.e., the result of computation, either
through the console video monitor, printer, disk drive or input/output ports. Since
we are learning ‘C’ through the PC, we will get the output through the video
monitor. Just as there are library functions for input, there are standard library
functions for output as well. They are given as follows:
printf()
putchar()
putch()
puts()
Giving input and getting output are achieved by using the standard library
functions. Note that all the function names are followed by parentheses. The
parentheses are meant for passing arguments or getting arguments. The arguments
may be absent in certain functions as in the case of main(). However, function
names must be followed by parentheses to indicate to the compiler that they are
functions. Arguments can be either variables or constants.
4.2.1 Use of printf()
Initially, formatted input/output statements will be discussed. Here, one must
categorically specify the data type of variables to be read or written and their
formats. The printf() and scanf() are formatted input and output
statements. The printf() statement can be programmed to give the output in
the desired manner. Example 4.1 is given below to illustrate the use of the
printf() function in printing the required values.
/*Example 4.1*/
/* To demonstrate the print function*/
#include <stdio.h>
main()
{
printf(“welcome to more serious programming\n”);
}
Self-Instructional
50 Material
Here the first statement after the comment line directs the compiler to include Managing I/O Operations
the standard input/output header file. Note that in the printf() statement
whatever is given within quotes except those immediately following ‘\’ and ‘%’
symbols will be printed as it is. Those with the ‘\’ symbol like ‘\n’, ‘\t’ are
escape sequences. Those of the ‘%’ symbol such as ‘%d’, ‘%f’ are known NOTES
as conversion characters. They have a specific meaning to the printf()
function.
Result of Program
welcome to more serious programming
Then the cursor will go to the next line. The cursor is made to go to the next
line because of the new line character \n. The escape sequences carry out the
functions assigned when their turn for execution is reached in the printf()
statement.
Now correct the statement as given below:
printf(“\tWelcome”); and execute the program.
Welcome will appear from the first tab.
Execute the program again. You will find that the message is printed from
the next available tab position on the same line.
4.2.2 Single Character Input/Output
Characters can be scanned through the scanf() function and printed through
the printf() function as given in Example 4.2.
/*Example 4.2*/
/*input and output of character through scanf() and printf()*/
#include<stdio.h>
int main()
{
char alpha;
printf(“Enter a character\n”);
scanf(“%c”, &alpha);
printf(“\n The character typed by you is:- %c\n”, alpha);
}
The program is simple to understand.
A variable alpha is declared of type char. The message directs the user
to enter a character. The scanf() function uses the conversion character %c
since we have to scan a character type variable. The (ampersand) &alpha indicates
the address where the scanned character is to be stored.
There are two points to be noted here. We have to specify the format as %c
and after entering the character, we have to hit the Return key. The interaction
with the computer while executing the program was captured and given below:
Enter a character
S
Self-Instructional
Material 51
Managing I/O Operations The character typed by you is:- S
4.2.3 Strings—gets() and puts()
A string is an array of characters. The functions gets() and puts() are
NOTES appropriate when strings are to be received from the screen or sent to the screen
without errors.
Standard Library for Strings
There are a number of library functions for string manipulation as given below:
strlen (CS)—returns the length of string CS.
char * strcpy (s, ct)—copy string ct to string s, including NULL
and return s.
char * strcat (s, ct)—concatenate string ct to end of string s;
return s.
int strcmp (cs, ct)—compare string cs to string ct; return < 0
if cs < ct,
0 if cs = = ct or > 0 if cs > ct
char * strchr (cs, c)—returns the pointer to the first occurrence
of c in cs or NULL if not present.
There are some more string functions.
If these are to be used, <string.h> should be included before the
main function.
Use of gets() and puts()
One can use scanf() to receive strings from the screen. The program using
scanf() for reading a name is as follows:
char name [25];
scanf (“ %s “, name);
Strings can be declared as an array of characters as shown above. In the
scanf() function, when we get the array of characters as a string, it is enough
to indicate the name of the array without a subscript. When we get a string, there
is no need for writing ‘&’ in the scanf() function. We can indicate the name
of the string variable itself.
Strings may contain blanks in between. If you use a scanf() function to
get the string with a space in between such as ‘Rama Krishnan’, Krishnan will not
be taken note of since space is an indicator of the end of entry of the input. But
gets() will take all that is entered till the enter key is pressed. Therefore, after
entering the full name, the enter() key can be pressed. Thus, using gets()
is a better way for strings. We can get a string in a much simpler way using gets().
The syntax for gets is, gets(name);
Similarly puts() can be used for printing a variable or a constant as
given below:
Self-Instructional
52 Material
puts (name); Managing I/O Operations
puts (“Enter the word”);
However, there is a limitation. printf() can be used to print more than
one variable and scanf() to get more than one variable at a time in a single
NOTES
statement. However, puts() can output only one variable and gets() can
input only one variable in one statement. In order to input or output more than one
variable, separate statements have to be written for each variable. As you know
that gets() and puts() are unformatted I/O functions, there are no format
specifications associated with them.
We will take another interesting example. If a word is a palindrome, we will
get the same word when we read the characters from the right to the left as well.
Examples are : nun
malayalam
These words when read from either side give the same name. We will write
a program to check whether a word is a palindrome or not.
This program uses a library function called strlen(). The function
strlen(str) returns the size or length of the given string. Now let us look at
the program.
/*Example 4.3*/
/* To check whether a string is palindrome*/
#include <stdio.h>
#include <string.h>
#define FALSE 0
int main()
{
int flag = 1;
int right, left, n;
char w[50]; /* maximum width of string 50*/
puts(“Enter string to be checked for palindrome”);
gets(w);
n=strlen(w)-1;
for ((left = 0, right = n); left <= n/2; ++left,
– —right)
{
if (w[left]!=w[right])
{
Flag = FALSE;
break;
}
}
Self-Instructional
Material 53
Managing I/O Operations if (flag)
{
puts(w);
puts(“is a palindrome”);
NOTES
}
else
printf(“%s is NOT a palindrome”);
}
Result of the program
Enter string to be checked for palindrome
palap
palap
is a palindrome
If strlen() or gets() or puts() are used in a program, we have
to include <string.h> before the main().
Step 1
Now let us analyse the functioning of the above example.
We are defining a symbolic constant FALSE as 0.
We initialize flag as 1. We define a string w as an array of 50 characters.
gets(w); returns the word typed and stores it from location &w [0]
Let us assume that we typed ‘nun’ and analyse what happens in the program.
strlen (w) will return the length of the word typed. In this case
strlen (w) = 3.
We subtract this by 1 to get the subscript of the rightmost character. The
subscript of the leftmost character is obviously 0.
We are initializing the for loop with the following:
left = 0 right = n = 2
flag = 1
We check whether left < = n/2 and
Since it is so, we check whether w [0]! = w [2].
The condition is false since w[0] = w[2] = ‘n’.
Therefore, the groups of statements following if are skipped : flag remains 1.
Step 2
Now left is incremented to 1 and right is decremented to 1.
Again w[1] ! = w[1] is false, flag remains 1.
Therefore, control returns to the for statement.
Self-Instructional
54 Material
Now, left = 2 right = 0 Managing I/O Operations
Since left is greater than n/2, control comes out of the for loop. Now
the statement if (flag) will be executed.
It will check whether flag is true. In this case, flag is still true. NOTES
Therefore, the computer prints that the word is palindrome. If the word is
not a palindrome, then what happens?
Let us now assume that we typed ‘book’ and see what happens in the
program.
To start with, left = 0 right = 3
w [left] ! = w[right],
Therefore, the statements within the { } will be executed, flag will be set
to false and then the break statement will be executed.
The statement break causes immediate exit from the loop. Now flag is
false. Therefore, the else statement is executed to say that the word is NOT a
palindrome.
4.4 SUMMARY
Self-Instructional
Material 55
Managing I/O Operations A string is an array of characters. The functions gets() and puts()
are appropriate when strings are to be received from the screen or sent to
the screen without errors.
NOTES
4.5 KEY WORDS
Self-Instructional
56 Material
Decision Making and
BRANCHING
NOTES
Structure
5.0 Introduction
5.1 Objectives
5.2 Conditional Statements
5.2.1 If Statement
5.2.2 If...else Statement
5.2.3 Nesting of the if...else Statements
5.2.4 Logical Operators and Branching
5.2.5 Conditional Operator and If...else
5.3 switch Statement
5.4 break, continue, goto Statements
5.5 Concept of Loops
5.5.1 Iteration Using if
5.5.2 For Statement
5.5.3 Other Forms of for Loop
5.5.4 The while Loop
5.5.5 Do ... While Loop
5.6 Answers to Check Your Progress Questions
5.7 Summary
5.8 Key Words
5.9 Self Assessment Questions and Exercises
5.10 Further Readings
5.0 INTRODUCTION
In this unit, you will learn about the control statements used in C programs. These
are used for solving complex problems. Depending on the occurrence of a particular
situation, if and else keywords are used for branching to different segments
of the program. C is ideal for handling branching because the syntax is clear and
unambiguous. If the condition is true, then a single statement or group of statements
following if will be executed. If more than one statement is to be executed, then the
statements are grouped within braces. To perform the same operation a number
of times, loop or iteration is used. In this unit, you will also learn about while,
do …while, switch, break, continue and return statements.
5.1 OBJECTIVES
Self-Instructional
58 Material
Each open curly brace has to have a matching closing curly brace. In Example Decision Making and
Branching
3.4 the first closing curly brace corresponds to the if statement and the second
one to the main function. Execute the program by first keying in two equal valued
unsigned integers.
NOTES
Result of the program
enter two integers
56 56
you typed equal numbers
After you are satisfied, you can try the program with unequal numbers.
You will not get any message.
5.2.2 If...else Statement
We did not get any message when the numbers were unequal and this can be
avoided by using the else statement.
The usage of if .. else is shown below.
if (condition true)
{
statements s1
}
else
{
statements s2
}
statements s3;
The statement else is always associated with an if.
If the condition is true, then statements s1 will be executed. After executing
them, the program will skip the else block and control goes to statement s3
that follows the else block.
If the condition is false, then the statements in the else block, i.e., s2 will
be executed followed by statement s3.
Statements s1 will not be executed at all when the condition becomes
false. The usage of braces clearly brings out which statements belong to the if
block and which to the else block.
Example 5.2 brings out the usage of if... else.
/*Example 5.2
To demonstrate the use of if.. else*/
#include <stdio.h>
main()
{
unsigned int a,b;
Self-Instructional
Material 59
Decision Making and printf (“enter two integers\n”);
Branching
scanf(“%u%u”, &a, &b);
if (a==b)
{
NOTES
printf(“you typed equal numbers\n”);
}
else
{
printf(“numbers not equal\n”);
}
}
The output of the program when unequal numbers were keyed in is as
follows.
Result of the program
enter two integers
17 13
numbers not equal
5.2.3 Nesting of the if...else Statements
We witnessed the usage of a single if statement in Example 5.1. We saw if
followed by else in Example 5.2. There is no restriction to the number of if,
which can be used in a program. This applies to else as well, but else can
only follow an if statement.
We can have the following in a program:
{
if (condition1)
{
if (condition2)
{statements–s1}
else
if (condition3)
{statements–s2,}
}
else
{statements–s4}
statements–s5
}
This is called a nested if and else statement. As the level of nesting
increases, it will be difficult to analyse and logical mistakes will be made more
easily.
Self-Instructional
60 Material
In the above example, when condition1 is false, statements– Decision Making and
Branching
s4 will be executed. If condition1 is true and condition2 is also true,
then statements–s1 will be executed.
If condition1 is true and condition2 and condition3 are
NOTES
false, statements–s5 will be executed directly.
To execute statements–s2
Condition1 has to be true;
Condition2 has to be false,
And condition3 has to be true.
Try to analyse this yourself. There are better methods to solve the above
problem, which will be discussed later.
For example, three unequal integers are keyed in and are called x, y and z.
Write a program to find the greatest of the three numbers.
Before writing a program, we must write the algorithm. We should not straight
away get down to programming.
Algorithm 1
Algorithm for finding the largest of 3 integers.
Step 1. Print a message to enter 3 integers.
Step 2. Get three numbers and store them at &x, &y and &z.
Step 3. Check if x > y
Step 4. If false, go to step 9
Step 5. If true
Step 6. Check if x > z
Step 7. If true, write x is the largest; End
Step 8. If false, write z is the largest; End
Step 9. Check if y>z
Step 10. If true, write y is the largest; End
Step 11. If not, write z is the largest.
End
Let us now code these steps into a ‘C’ program, which is shown in Example
5.3.
/*Example 5.3
To demonstrate the use of the nested if.. else*/
#include <stdio.h>
main()
{
Self-Instructional
Material 61
Decision Making and int x,y,z;
Branching
printf (“enter three unequal integers\n”);
scanf(“%d%d%d”, &x, &y, &z);
if(x>y)
NOTES
{
if(x>z)
{
printf(“x is largest\n”);
}
else
{
printf(“z is largest\n”);
}
}
else
{
if(y>z)
{
printf(“y is largest”);
}
else
{
printf(“z is largest”);
}
}
}
Test the correctness of the program by giving a different set of values for x,
y and z.
Result of the program
enter three unequal integers
908 231 907
x is largest
Look at the example. It uses multiple nesting of if ... else.
Take care to see that every opening brace has a corresponding closing
brace. It is better to indent the braces as shown in the example so that no mistake
is committed. Take care to see that else matches with the corresponding if
and each opening brace {matches with a corresponding closing brace}; if either
an opening {or closing} is extra, then an error will result.
Self-Instructional
62 Material
5.2.4 Logical Operators and Branching Decision Making and
Branching
In the above examples we have been checking one condition at a time. It would
be nice if we could check more than one condition at a time. ‘C’ provides three
logical operators for combining more than one condition. These are as follows: NOTES
Logical and represented as &&
Logical or represented as ||
Negation or not represented as ! (exclamation).
Let us see some examples of usage of the logical operators. In Example 5.3
we concluded that,
if x > y and if x > z, then x is the largest.
We will represent the same as,
if ((x > y) && (x > y))
printf (“x is the largest”);
You will see that the program has become much more elegant.
The syntax for && is,
if ((condition1) && (condition2))
{
statements–s1
}
Statements–s1 will be executed only if both the conditions are true.
The syntax for ‘or’ is as follows:
if ((condition 1 ) ||(condition 2))
{
statements–s2
}
In this case, even if one of the conditions is true, the statements–s2
will be executed. At least one condition has to be true for the execution of s2.
However, if both are false, s2 will not be executed.
The NOT operator with symbol ! can be used along with any other relational
or logical operator or as a stand-alone operator. It simply negates the operator
following it. The syntax of ‘!’ is as follows:
if ! (condition) statement s3;
s3 will be executed only when the condition is not true or the condition is
false.
Let us rewrite Algorithm 1 by using the logical operators. The revised
Algorithm 2 is given below:
Self-Instructional
Material 63
Decision Making and Algorithm 2
Branching
Step 1: If (x > y) and (x > z), x is the largest.
Step 2: Else if (x<y) and (y>z), y is the largest.
NOTES Step 3: Else print z is the greatest.
The complete program is given in Example 5.4.
/*Example 5.4
To demonstrate the use of logical operators*/
#include <stdio.h>
main()
{
int x,y,z;
printf (“enter three unequal integers\n”);
scanf(“%d%d%d”, &x, &y, &z);
if ((x>y) && (x>z))
printf(“x is largest\n”);
else
{
if((x<y) && (y>z))
printf(“y is largest\n”);
else
printf(“z is largest\n”);
}
}
Result of the program
enter three unequal integers
12 23 78
z is greatest
Let us now write a program to convert a lower case letter typed into an
upper case letter. For this purpose you may have to refer to the ASCII table in
Annexure 2.
It is obvious that if we subtract 32 from the ASCII value of a lower case
alphabet we will get the ASCII value of the corresponding upper case letter. Let
us write an algorithm for the conversion of lower case to an upper case letter. It is
given in Algorithm 3.
Algorithm 3
Step 1: Send a message for getting a character
Step 2: Get a character
Step 3: Check whether the character typed is >=a and <=z
Self-Instructional
64 Material
(This is essential since we can only convert a lower case alphabet into upper Decision Making and
Branching
case.)
Step 4: If so, subtract 32 from the value of the character; if not, go to step
6
NOTES
Step 5: Output the character with the revised ASCII value; END
Step 6: Print “an invalid character” END
The algorithm is implemented in Example 5.5.
/*Example 5.5
Conversion of lower case letter to upper case*/
#include <stdio.h>
main()
{
char alpha;
printf (“enter lower case alphabet\n”);
alpha=getchar();
if (( alpha >=’a’)&& (alpha<=’z’))
{
alpha= (alpha-32);
putchar (alpha);
}
else
printf(“invalid entry; retry”);
}
Now you can test the program by giving both the valid and invalid inputs;
valid inputs are the lower case letters and invalid inputs are all other characters.
Result of the program
The result for the invalid input is given below:
enter lower case alphabet
8
invalid entry; retry
The result when tried with a valid input is given below:
enter lower case alphabet
n
N
The programs should be executed, i.e., tested with both the valid and invalid
inputs.
Self-Instructional
Material 65
Decision Making and 5.2.5 Conditional Operator and if...else
Branching
The syntax for the conditional operator is given below:
(Condition)? statement1: statement2;
NOTES What does it mean? If the condition is true, execute statement1; else,
execute statement2. Here nesting is not possible. The if...else statement
is more readable than the conditional(?) operator. However, the
conditional operator is quite handy in simple situations as given below:
(a > b) ? print a greater
: print b greater;
Thus, the operator has to be used in simple situations. If nothing is written in
the position corresponding to else, then it means nothing is to be done when
the condition is false.
Example 5.2 is rewritten using the ? operator in Example 5.6.
/*Example 5.6
To demonstrate the use of the ? operator*/
#include <stdio.h>
main()
{
unsigned int a,b;
printf (“enter two integers\n”);
scanf(“%u%u”, &a, &b);
(a==b)?printf(“you typed equal numbers\n”):
printf(“numbers not equal\n”);
}
Result of the program
enter two integers
123 456
numbers not equal
Self-Instructional
70 Material
Unless the program is made to exit by statements such as break after Decision Making and
Branching
executing the group of statements corresponding to a particular case, the program
will execute all the statements in the program from then on. This should be noted.
Therefore, the programmer has to specify where to end. In the case of
if...else, where to begin and where to end is clear as also in the case of NOTES
switch. The program starts at the beginning of the case that meets the condition,
but ends at the bottom of the switch unless otherwise specified. It will also
execute the statements following default. It will of course not bother about the
keywords. That is the reason for the break statement, since we do not want the
program to execute irrelevant statements.
It is a good programming practice to include a break statement after the
default as well. If this is not done at the inception, at a later stage when more case
statements are added after default, this would lead to problems. Whenever default
is executed all the statements following it, even if they belong to some other case,
will also be executed if break is not included after default.
Now the program can be extended to print the value of the number up to 99
in words. This makes it more complicated since the words are unique up to nineteen.
A program is given below for achieving the task. This is made to loop using
do...while.
/*Example 5.9
to print out in words the value
of a number typed in the range 1-99*/
#include <stdio.h>
#include<conio.h>
main()
{
int num,m,ch=’y’;
do
{
printf(“Type a number 1 to 99\n”);
scanf(“%d”,&num);
if ((num >0)&&(num <100))
/*only if the number is within the valid range 0 to 99
the following will be executed*/
{
if (num >= 20)
{
m=num/10;
switch(m)
{
case 2:printf(“TWENTY “);
Self-Instructional
Material 71
Decision Making and break;
Branching
case 3:printf(“THIRTY “);
break;
case 4:printf(“FORTY “);
NOTES
break;
case 5:printf(“FIFTY “);
break;
case 6:printf(“SIXTY “);
break;
case 7:printf(“SEVENTY “);
break;
case 8:printf(“EIGHTY “);
break;
case 9:printf(“NINETY “);
break;
}
}
if (num >20)
num= num%10;
switch(num)
{
case 1:printf(“ONE\n”);
break;
case 2:printf(“TWO\n”);
break;
case 3:printf(“THREE\n”);
break;
case 4:printf(“FOUR\n”);
break;
case 5:printf(“FIVE\n”);
break;
case 6:printf(“SIX\n”);
break;
case 7:printf(“SEVEN\n”);
break;
case 8:printf(“EIGHT\n”);
break;
case 9:printf(“NINE\n”);
break;
case 10:printf(“TEN\n”);
Self-Instructional
break;
72 Material
case 11:printf(“ELEVEN\n”); Decision Making and
Branching
break;
case 12:printf(“TWELVE\n”);
break;
NOTES
case 13:printf(“THIRTEEN\n”);
break;
case 14:printf(“FOURTEEN\n”);
break;
case 15:printf(“FIFTEEN\n”);
break;
case 16:printf(“SIXTEEN\n”);
break;
case 17:printf(“SEVENTEEN\n”);
break;
case 18:printf(“EIGHTEEN\n”);
break;
case 19:printf(“NINETEEN\n”);
break;
}
}
else
printf(“number outside range\n”);
printf(“\nenter y if you want to continue\n”);
ch=getche();
if (ch!=’y’)
printf(“End of session”);
}
while (ch==’y’);
}
Result of the program
Type a number 1 to 99
123
number outside range
enter y if you want to continue
yType a number 1 to 99
78
SEVENTY EIGHT
enter y if you want to continue
yType a number 1 to 99
6
SIX Self-Instructional
Material 73
Decision Making and enter y if you want to continue
Branching
nEnd of session
How does it work ?
NOTES The entered number is checked. If it is 20 or above, the following action takes
place. For example, assume that a number 64 is entered. It is > = 20.
Therefore, m = num/10 will give m as 6. Hence, SIXTY will be printed
(with a space at the end), corresponding to case 6.
Now since num > 20, the second if condition will be true.
Num = num % 10 will assign the remainder equal to 4 to num. Therefore,
case 4 in the second switch will be true and four will be printed.
Assume you have expressed your desire to continue and enter 16.
Since num > = 20 will be false and switch (m) will be ignored. Hence,
switch (num) will be executed. Case 16 matches with switch (16).
Therefore, SIXTEEN will be printed. The correctness of the program can be
checked for any number in the range of 0 – 99.
The expression associated with the switch can be of type char since
char can also be considered an integer. For example, the switch statement
can be of the form,
char m ;
switch (m)
{
case ‘a’ : s1 ;
break ;
case ‘b’ : s2 ;
break ;
}
If m evaluates to ‘a’, s1 will be executed and if it is ‘b’, s2 will be
executed. Remember the label of case has to be a constant expression.
Other characters such as +, –, etc. can be used as case labels since
their integer values are known from the ASCII table.
Int op ;
switch (op)
{
case ‘+’ : s1; break;
case ‘/’ : s2 ; break;
}
Here when op is +, s1 will be executed and when it is /, s2 will be
executed.
You can try these by writing programs.
Self-Instructional
74 Material
Decision Making and
5.4 BREAK, CONTINUE, GOTO STATEMENTS Branching
The keywords while, for and switch test the condition on top, while
do...while checks at the bottom for quitting the loop. The break statement NOTES
helps immediate exit from any part of the loop as demonstrated with the switch
statement. It can be used with any other loop construct or anywhere in the program.
When the break statement is executed it goes to the bottom of the block. Recall
that a block is a group of statements enclosed between an opening brace and the
corresponding closing brace.
The continue statement is related to break. When continue is
executed, it causes the next iteration of the corresponding for, do...while
or while loop to begin. Therefore, continue takes the program to the top
of the block and in the for loop, it will cause the next increment operation,
followed by checking whether the condition is true or false in order to decide the
next course of action. This is similar to skipping the current execution and continuing
with the next operation after incrementing. The statement continue skips the
rest of the statements in the loop for that iteration, whereas break terminates the
loop.
Write a program to check whether a given number is positive or negative. If
it is zero, the program should terminate after printing the value. If it is a positive
integer above zero and <=20000, the value will be printed; if negative, it will go
to fetch the next number. If the number is >20000, the program terminates. The
program is given below:
/*Example 5.10
/*program to demonstrate continue*/
#include <stdio.h>
main()
{
int a;
do
{
printf(“enter a number-enter 0 to end session\n”);
scanf(“%d”, &a);
if(a > 20000)
{
printf(“you entered a high value-going out of
range\n”);
break;
}
else
if(a>=0)
Self-Instructional
Material 75
Decision Making and printf(“you entered %d\n”, a);
Branching
if (a <0)
{
printf(“you entered a negative number\n”);
NOTES
continue;
}
}
while(a !=0);
printf(“ End of session\n”);
}
Result of the program
enter a number-enter 0 to end session
33
you entered 33
enter a number-enter 0 to end session
-60
you entered a negative number
enter a number-enter 0 to end session
45
you entered 45
enter a number-enter 0 to end session
25000
you entered a high value-going out of range
End of session
If the number typed > 20000, or if it is equal to zero, the program comes
out of the loop and prints “End of session”. If the number is negative, a <
0 and hence, continue will be executed. It will go to the top of the loop. The
next integer will be received. The program, therefore, terminates when a = 0 as
well as a > 20000, but there is a difference. If the number entered is zero, the
program checks whether a > 20000. Since the condition fails, it checks whether
a > = 0 and since it is true, 0 will be printed and then the while condition is
checked. The program terminates after the while condition is checked.
However, if the number entered is >20000, the loop terminates instantly
without transacting any business except printing messages as given above.
The return statement can appear anywhere in a function and when it is
encountered a value is returned to the called function. The return may also not
return a value in statements as given below:
return ;
return (0) ;
The return statement may appear anywhere in the function and not
Self-Instructional necessarily at the end of the function. Whenever return is executed, the program
76 Material
returns to the function called the current function. The program returns to the place Decision Making and
Branching
from where it called the function. Thus return is also used to suddenly exit
from a function or a loop in a function.
Exit Function NOTES
The library function exit()causes the termination of the current program. Note
that, exit() terminates the execution of the program itself, and not the block.
The statement break enables coming out of the block or loop in which it is
executed but exit terminates the program at whatever stage the program may
be. exit is a powerful function.
Quite often we have to perform the same operation a number of times. We may
also have to repeat the same operation with one or more of the values changed,
which is known as loop or iteration. It is definitely possible to write a program for
such situations with the concepts we have learnt so far. However, there are special
constructs in any programming language for carrying out repeated calculations.
5.5.1 Iteration Using if
Before we look at loop constructs, let us consider an example to see the need for
repetitive calculations. Assume that we want to find the sum of the first ten natural
numbers, 1 – 10. This can be achieved through successive addition, i.e., first we
initialize the sum to 0 and then add 1 to the sum. Next we add 2 to the sum, then
3, and so on till we add 10 to the sum. Thus, by repeated addition 10 times, we
have found the sum of first ten natural numbers.
The following algorithm summarizes what we have done.
Step 1: Sum = 0
Step 2: I = 1
Step 3: If I < = 10 perform the following operations:
sum = sum + I; I = I + 1;
Self-Instructional
Material 77
Decision Making and Step 4: Print the sum
Branching
Let us analyse the algorithm.
At the beginning, steps 1 and 2 are entered with sum = 0 and I = 1
NOTES since I < = 10
Sum will be equal to sum + I,
i.e., sum = 0 + 1 = 1
I = I + 1, i.e., I = 2
Now the program goes to Step 3.
with I = 2 and sum = 1
Since I < = 10
sum = sum + I
sum was 1 and I is 2
sum = 1 + 2 = 3
Next I will be incremented to 3.
Third iteration:
Step 3 is approached with I = 3 and sum = 3.
since I < = 10
sum = sum + I = (1 + 2) + 3
I=4
Ninth iteration:
Step 3 is approached with I = 9.
since I < = 10
sum = (1 + 2 + 3 +............+ 8) + 9
I is incremented to 10.
Tenth iteration:
Step 3 is approached with I = 10.
since I < = 10
sum = sum + I
= (1 + 2 + 3 +........+ 8 + 9) + 10
Now I is incremented to 11.
since I <= 10 is not true, the program does not execute the statements
following the if and jumps to Step 4.
In Step 4 the sum is printed.
This algorithm is implemented in Example 5.11.
Self-Instructional
78 Material
/*Example 5.11 Decision Making and
Branching
Demonstrates the use of if for iteration*/
#include <stdio.h>
main()
NOTES
{
int sum=0, i=1; /*declaration and initialization
combined*/
step3: /*label- loop starts here*/
if (i <=10)
{
Sum = sum + i;
i = i + 1;
goto step3;
}
printf(“sum of first 10 natural numbers=%d\n”, sum);
}
Result of the program
sum of first 10 natural numbers = 55
The program uses if and goto keywords. According to the algorithm,
the program has to go to Step3. Step3 in this program is called a label, which is
followed by a colon. The rules for coining a label name are the same as for an
identifier. The label can be placed anywhere in the same function where the goto
statement is found. Usage of goto is considered to be bad programming practice
since it leads to errors when changes are made in the program and also affects the
readability. It is always possible to write a program without using goto. This can
be done by using a for statement.
5.5.2 For Statement
The for statement is meant for easy implementation of iterations unlike if. The
syntax of for is as follows:
for (exp1; exp2; exp3)
{statements;}
Note the keyword, the parentheses and semicolons. There is no semicolon
after exp3. exp1, exp2 and exp3 are expressions. The usage of the for
loop is given below:
exp1– Contains the initial value of an index or a variable.
exp3– Contains the alteration to the index after each iteration of the body
of the for statement. The body of the statement is either a single statement or a
group of statements enclosed within braces.
If a single statement has to be executed, then braces are not required.
Self-Instructional
Material 79
Decision Making and exp2– Condition that must be satisfied if the body of statements is to be
Branching
executed.
An example of a for loop is given below:
NOTES for (i = 0; i < 5; i++)
printf(“%d”, i);
The loop will start with an initial value of i = 0. Since i < 5, the body of
the for loop will be executed and it will print 0. Now the exp3 will be executed
and i will be incremented to 1. Since i is less than 5, body of the loop will again
be executed to print 1. This will continue till 4 is printed. i will now be incremented
to 5 and since i is not less than 5, the for loop will be terminated. This is how
for is used to carry out repetitive operations.
Let us now write a program for finding the sum of the first ten natural
numbers using the for statement.
The program is given in Example 5.12
/*Example 5.12
Demonstrates the use of the for statement to find the sum of
the first 10 natural numbers*/
#include <stdio.h>
main()
{
int sum=0, i; /*declaration and initialization combined*/
for (i=1; i<=10; i++) /*loop starts here*/
{
Sum = sum + i;
}
printf(“sum of the first 10 natural numbers=%d\n”, sum);
}
Result of the program
sum of first 10 natural numbers = 55
Note the difference between Example 5.11 and Example 5.12.
We have eliminated the label Step 3 and the goto statement.
The initialization of i = 1 is carried out as part of the for statement.
The incrementing of i is also carried out as part of the for statement. The
program has, therefore, been simplified.
How does the program work?
Step 1: i = 1
Self-Instructional
80 Material
i is checked with i <= 10 Decision Making and
Branching
Since i is less than 10, the for loop is executed.
sum = sum + i = 0 + 1 = 1
Step 2: i is incremented to 2 NOTES
2 is <=10
Therefore, the for loop is executed.
sum = sum + i = (1) + 2
Steps 3 to 8: Same logic applies till the condition is met.
Step 9: i is incremented to 9
9 is < = 10
Therefore, the for loop is executed.
sum = sum + i = (1 + 2 +........+ 8) + 9
Step 10: i is incremented to 10
10 is < = 10
sum = sum + I = (1 + 2 +..........+ 9) + 10
Step 11: i is incremented to 11.
11 is not < = 10.
Therefore, the for loop is now terminated.
The printf() function is now executed automatically.
Let us summarize the operation of the for loop.
When a program encounters a for loop, it first checks the condition through
the expression in the middle. If the condition is satisfied it executes the group of
statements. After executing the statements in the body of the loop, the program
transfers the execution to the for statement and the third expression is executed,
which is usually incrementing or decrementing. Then the condition is checked. If
the condition is not satisfied, the group of statements will not be executed and the
program will skip to the next statement after the statements pertaining to the for
statement.
By chance if the initial value was typed as 11 instead of 1 in the program,
the condition will turn out to be false and the group of statements will not be
executed at all.
Three Components of for
The three components of a for statement are as follows:
exp1 and exp3 are assignments or function calls. We will discuss function
calls at a later stage; exp2 is a relational expression. The three expressions may
not always be present. However, even if an expression is not present, the associated
semicolon should be present.
Self-Instructional
Material 81
Decision Making and For example,
Branching
for (; exp2 ;)
{s1}
NOTES Here the initial value is not specified and the incrementing does not take
place after every iteration. Presumably, the initial value is assigned elsewhere and
incrementing or a similar operation takes place as part of the group of statements
following the for. However, since exp2 is present, the loop will terminate.
However, if all three expressions are omitted as given below,
for ( ; ; )
the loop will never terminate because the conditional statement is absent. If
exp2 is not present, it is assumed that the condition is true always. Such a
statement should not be used.
Instead of incrementing, we can use i + = 2 as exp3 when i will be
incremented by 2 every time.
Let us try to print the list of even numbers up to 50. The program is given
below:
/*Example 5.13
variation in for statement - to print even numbers*/
#include <stdio.h>
main()
{
int i=2;
for (; i<50; i+=2) /*loop starts here*/
{
printf(“%i is an even number\n”,i);
}
}
Here we initialize i = 2 before the for loop itself. However, the
corresponding semicolon is present at the right place.
Result of the program
2 is an even number
4 is an even number
6 is an even number
8 is an even number
10 is an even number
12 is an even number
14 is an even number
16 is an even number
18 is an even number
Self-Instructional
82 Material
20 is an even number Decision Making and
Branching
22 is an even number
24 is an even number
26 is an even number
NOTES
28 is an even number
30 is an even number
32 is an even number
34 is an even number
36 is an even number
38 is an even number
40 is an even number
42 is an even number
44 is an even number
46 is an even number
48 is an even number
5.5.3 Other forms of for Loop
The for loops can be nested as follows:
for (i = 1; i <= 10; i++)
{
for (j = 1; j <= 5; j++)
{
for (k = 1; k <= 2; k++)
{
s1
}
}
}
The statement s1 will be executed as follows:
First time i = 1, j = 1, k=1
Second time i = 1, j = 1, k=2
Third time i = 1, j = 2, k=1
i = 1, j = 2, k=2
i = 1, j = 3, k=1
i = 1, j = 3, k=2
Lastly i = 10, j = 5, k=2
s1 will be executed 2*5*10 = 100 times.
Any level of nesting is acceptable; however, the higher the level of nesting is,
the more easy it will be to commit mistakes and more difficult to understand.
Self-Instructional
Material 83
Decision Making and Let us look at some more for loops.
Branching
For ( x = –5; – –x >= –10; )
{
}
NOTES
Here the decrement and conditional statements are combined in exp2.
Since decrement is a prefix, the decrement of x is carried out first. The
condition is then checked in order to decide whether to continue or not. Then the
loop is executed. Therefore, the first iteration will be carried out with x = –6 and
the last with x = –10.
Another variation of the statement is given as follows:
for (y = 100; y ++<= 200;)
{
s2
}
Here too exp2 and exp3 are combined. This is a postfix notation. The
following sequence is carried out: condition check, increment and execute the
loop. Therefore, the statement s2 following the for loop will be executed the
first time with y = 101 and finally with y = 201 as well.
The for loop is a popular iteration construct not only in ‘C’ but also in
other languages. Here the initial value, the step and the final value are clear and
unambiguous and simple to write. There are other loop statements also. In the
next section, we will study the while loop.
5.5.4 The while Loop
The while loop is a subset of the for loop. The syntax for the while loop is
given as follows:
while (expression)
{statements;}
This means that the statement(s), which is a single statement or multiple
statements, will be executed while the expression is true. When it becomes false,
the execution will stop.
The while loop is similar to the for loop without exp1 and exp3.
The for loop can be simulated or replaced with the while loop as follows.
exp1;
while (exp2)
{
statements
exp3;
}
Self-Instructional
84 Material
The programmer can use while or for at his discretion. The for loop Decision Making and
Branching
is preferred when the initialization and incrementation are simpler.
Let us look at some examples.
Let us write a program for the generation of any multiplication table. NOTES
The program is as follows:
/*Example 5.14
use of while - You can generate multiplication
tables of your choice using this program.
caution: Don’t exceed maximum limits of integer */
#include <stdio.h>
main()
{
int a,b,product;
a=1;
b=0;
product=0;
printf(“Enter which table you want”);
scanf(“%d”,&b);
while (a <=10)
{
product = a*b;
printf(“%2d X %d= %3d\n”,a,b,product);
a++;
}
}
When the program asks you to enter a table and you type 12, you will get
the 12th table. This is shown as follows:
Result of the program
Enter which table you want 12
1 X 12 = 12
2 X 12= 24
3 X 12= 36
4 X 12= 48
5 X 12= 60
6 X 12= 72
7 X 12= 84
8 X 12= 96
Self-Instructional
Material 85
Decision Making and 9 X 12= 108
Branching
10 X 12= 120
Note here that the condition is (a < =10); incrementing is done within the
loop in a++. Variable a is initialized as 1 before entering the while loop.
NOTES
If you want to print the table up to 16*12 = 192 then simply change the
condition to while (a < =16). Simple, isn’t it?
Let us now write a program to reverse a given number. For example, if 345
is the given number, we should get the reversed number as 543. The program is
given below.
/*Example 5.15
/*Program to reverse a number*/
#include<stdio.h>
main()
{
long unsigned n, reverse;
printf(“enter the number to be reversed\n”);
scanf(“%lu”, &n);
reverse=0;
while (n>0)
{
reverse=reverse*10+(n%10);
n=n/10;
}
printf(“Reversed number=%lu”, reverse);
}
Result of the program:
enter the number to be reversed
4562
Reversed number=2654
How does the program work? Let us discuss for n = 345.
Before entering the while loop, n = 345
reverse = 0
Since 345 > 0, the condition is true and the loop is entered.
Iteration 1
reverse = 0 *10 + (345 % 10)
=0+5=5
n = 345 / 10 = 34
Self-Instructional
86 Material
Iteration 2 Decision Making and
Branching
reverse = 5 * 10 + (34 % 10) because n = 34 now
= 50 + 4 = 54
n = 34 / 10 =3
NOTES
Iteration 3
reverse = 54 * 10 + (3 % 10)
= 540 + 3 = 543
n = 3 / 10 = 0
Now since n is not greater than 0, the program will come out of the loop
and will, print.
Reversed number = 543
5.5.5 Do ... While Loop
The Do ... While loop is a modification of the while statement. In the
while statement, before the group of statements following the while are
executed, the condition associated with the while is checked. If the condition is
true or fulfilled, then the associated statements are executed. If not, the program
skips the statements associated with the while loop. This is depicted in Figure
5.1.
After execution of the statements, the program will check again whether the
condition is true and then continue to execute or skip the statements depending on
the condition. The statements may not be executed even once if the condition was
false at the entry point.
However, the do...while loop works differently as shown in Figure
5.2.
Self-Instructional
Material 87
Decision Making and
Branching
do
STATEMENTS
NOTES
TRUE
FALSE
Here the statements following do will be executed once before the condition
is checked. If it is true, then the statements will be executed again. If not, the
program will skip the statements and proceed further. Thus, whatever be the
condition, the statements following do will be executed once before checking the
condition. This is the essential difference between do...while and while.
The while loop tests the condition on top of the loop; but do...while
tests at the bottom after executing the statements. The while loop executes the
statements after checking the condition; but do...while executes the statements
before testing the condition. The syntax of do...while is as follows:
do
{
statements
}
while (expression);
The statement do...while is not used as frequently as the while
loop.
Example 5.16 converts upper case alphabets to lower case. In case you
want to convert more alphabets you will have to execute the program again and
again. This can be avoided by the while loop. The program will continue to run
as long as you want to convert more and more alphabets. The program has been
rewritten with while for converting upper case to lower case. You can convert
as long as you want. When you want to stop, enter 1. The program, which uses
while for converting an upper case character to a lower case is given in Example
5.16.
/*Example 5.16
Conversion of upper case to lower case alphabet*/
#include <stdio.h>
#include<conio.h>
Self-Instructional
main()
88 Material
{ Decision Making and
Branching
int alpha=0;
while (alpha!=’1')
{ NOTES
printf (“\nenter upper case alphabet- enter 1 to
quit\n”);
alpha=getche();
if ( alpha >=’A’&& alpha<=’Z’)
{
alpha= (alpha+32);
putch(alpha);
}
else
{
if(alpha!=’1')
printf(“\ninvalid entry; retry”);
else
printf(“End of session”);
}
}
}
Result of the program
enter upper case alphabet- enter 1 to quit
Pp
enter upper case alphabet- enter 1 to quit
p
invalid entry; retry
enter upper case alphabet- enter 1 to quit
Qq
enter upper case alphabet- enter 1 to quit
1End of session
This program works till 1 is pressed. It continues to convert upper case to
lower case till 1 is pressed. The program has been designed in such a manner that
it will perform at least one iteration of the statements following while. This can
be rewritten using do...while. The rewritten program is given below:
/*Example 5.17
Conversion of upper case to a lower case alphabet*/
#include <stdio.h>
#include<conio.h> Self-Instructional
Material 89
Decision Making and main()
Branching
{
int alpha=0;
NOTES do
{
printf (“\nenter upper case alphabet- enter 1 to
quit\n”);
alpha=getche();
if ( alpha >=’A’&& alpha<=’Z’)
{
alpha=(alpha+32);
putch(alpha);
}
else
{
if(alpha==’1')
printf(“End of Session”);
else
printf(“\ninvalid entry; retry”);
}
}while(alpha!=’1');
}
Result of the program
enter upper case alphabet- enter 1 to quit
Gg
enter upper case alphabet- enter 1 to quit
o
invalid entry; retry
enter upper case alphabet- enter 1 to quit
Dd
enter upper case alphabet- enter 1 to quit
1End of Session
How does it differ? Here too, the program will attempt to convert one
character before it can be terminated. Assuming that the first character was 1, the
program will still attempt to convert it and print the message “End of
Session” before it quits.
Self-Instructional
90 Material
Suppose the first character is a valid one and a number of characters are Decision Making and
Branching
converted in succession; when you want to terminate the program, 1 has to be
pressed and even then the program will not stop immediately. It will stop only after
the statements are executed. Since the problem is the same, a detailed look at
both the examples will bring out the similarity in operation between both the NOTES
constructs. However, there are occasions when it is quite suitable as given in the
next section.
5.7 SUMMARY
Self-Instructional
92 Material
The while loop will be executed so long as the associated condition is Decision Making and
Branching
true.
The for loop is an improvement of the while loop containing three
expressions on the header of the statement. The condition appears in the
NOTES
middle followed by a semicolon.
The first expression usually initializes a variable and the last expression
increments it.
for and while loops should be constructed so that they terminate after
execution; otherwise, an endless loop will be made, which will halt the
computer.
A variation of the while loop is the do...while loop, which checks
the condition after the loop has been executed once. Therefore,
do...while will execute the body of the loop at least once. This is
because the do...while loop starts with do and has the condition
checked only at the end of the loop. The loop body starts after do and
ends just before the while.
switch ... case is a multi-way branching construct. The switch
is followed by an expression in parentheses, which is evaluated as an integer
at the time of program execution.
The statements following the switch begin with case labels where each
case label has a unique integer, like case 10, case 9, etc. Therefore,
the program, after executing the switch, goes to the label corresponding
to the switch expression.
At the end of all the case statements, a default statement can be
included, which will also contain a group of statements. If the switch
expression does not match with any of the case expressions, then the
default statement will be executed.
A switch statement need not have a default statement and in such a case the
program will come out of the switch if no match is found.
continue statement serves to skip the rest of the statements in the loop
and execute the loop after incrementing or decrementing and checking the
condition.
The return statement enables the function to instantly return program
execution to the called function.
NOTES
5.9 SELF ASSESSMENT QUESTIONS AND
EXERCISES
Self-Instructional
94 Material
Arrays
UNIT 6 ARRAYS
Structure NOTES
6.0 Introduction
6.1 Objectives
6.2 Basic Concept of Arrays
6.2.1 Array Declaration
6.2.2 Array Initialisation
6.2.3 Multi-Dimensional Arrays
6.2.4 Variable Length Array/ Dynamic array
6.3 Answers to Check Your Progress Questions
6.4 Summary
6.5 Key Words
6.6 Self Assessment Questions and Exercises
6.7 Further Readings
6.0 INTRODUCTION
C facilitates the arrangement of same data types in the memory as an array. Arrays
are also used in other computer languages, such as Pascal and BASIC. However,
in C, it is very popular to make a larger unit of same data types. It makes repetitive
tasks easy if elements of the same data type need to be processed repetitively. In
essence, an array holds a fixed number of same data elements. Data items can be
grouped in an array, which temporarily stores the data. In C array declaration is
done by using int and char keywords, such as int a[5]; and char
Student_Name[]= “Student”; respectively. In daily life, similar objects are grouped
into units; for example, in a library, all English fiction and non-fiction works are
kept in separate shelves. The same concept is used in C arrays. Subscripts or
indices are arranged in square brackets in arrays for addressing in the memory
location. Each indexed value is called an element. The types of arrays used in C
are one-dimensional, two-dimensional and multi-dimensional arrays.
6.1 OBJECTIVES
Self-Instructional
Material 95
Arrays
6.2 BASIC CONCEPT OF ARRAYS
Self-Instructional
96 Material
6.2.1 Array Declaration Arrays
Assuming that there are 40 employees in an office and we want to store their ages,
we would have to create 40 variables of type integer or float and store their ages.
While such a definition seems alright, it would cause complications while NOTES
programming. Instead, this can be declared as an array of size 40.
For instance,
short emp_age [40];
Here, we have declared an integer variable known as emp_age with a
dimension of 40. A single variable has been declared to store the ages of 40
employees. But for this feature, we would have to write 40 lines to declare the
same with 40 different names.
An array is also variable and hence must be declared like any other variable.
The naming convention is the same as in the case of other variables. The array
name cannot be a reserved word and must be unique in the program. An array
variable name and another ordinary variable name cannot be identical. Since there
is no limit to variable names, do not use similar names for a basic variable and an
array. What distinguishes an array variable from a single variable in their declaration
is the dimension within the square brackets.
What does variable declaration do? It allots memory space for the variable. If
we declare an array variable of type integer and dimension 40, then the computer
will allot a memory size of 40 words for the variable contiguously. The last word is
important. The elements in an array will be stored in consecutive memory locations.
Since an integer of type short needs two bytes for storage and if the memory is
organized and addressed in terms of bytes, the following allocation would be carried
out for emp_age elements.
emp_age [0] 1000
emp_age [1] 1002
emp_age [2] 1004
If emp_age [0] is stored at the location with address 1000, emp_age [1] will
be at 1002. It is enough for us to indicate the starting address to find the address of
any of the elements of the array. The emp_age [2] will be stored at 1004. The
formula for finding the address of element emp_age [n] = starting address + n * 2.
If emp_age had been defined as a float variable and if emp_age [0] starts at
the location 1000, then emp_age [10] would be found at location 1040. The
formula is: address of nth element = starting address + n * (size of variable). The
important point to be noted is that if the starting address is known and the type of
variable is known, the exact location where an element of the array is stored can
be computed. An array has to contain elements of the same type. A float array
cannot have integers or characters.
We must always specify the array size. We would normally expect to get an
error message if the array size is exceeded; but, this does not happen in C language. Self-Instructional
Material 97
Arrays In the above example, if we try to read the value of emp_age [50] nothing will
happen. No error message will be printed. Therefore, it is the responsibility of the
programmer not to exceed the array size. Since we have a single subscript, the
arrays declared so far are known as one-dimensional arrays.
NOTES
Examples of one-dimensional arrays are given below:
int emp_age[100];/* no space between variable name & dimension */
float mark[100];
char name[25]; /* name contains 25 characters */
6.2.2 Array Initialisation
If the array elements are known beforehand, they can be declared right at the
beginning. If the employees’ ages are known beforehand, they can be declared
as:
int emp_age [5] = {40, 32, 45, 22, 27};
The data elements are written within braces separated by commas. In this
case, when data elements are declared, there is no need to declare the size; we
can write:
int emp_age [] = { 40, 32, 45, 22, 27 };
The latter is advantageous. If the size is not declared, the compiler will count
the number of elements and automatically allot the size. On the other hand, if we
specify the size and give lesser number of elements, then the compiler will assume
the other elements to be zero.
For instance, if we declare
int Marks [ 5 ] = { 100, 70, 80 };
In this case, Marks [0] = 100
Marks [1] = 70
Marks [2] = 80
What happens to the other elements? The computer will assign 0 to them.
Marks [3] = 0
Marks [4] = 0
If we declare size 5 and give 7 elements then there will be an error. Therefore,
if we know the data elements in advance, we can allow the compiler to calculate
the size.
Now let us try some programs.
Example 6.1
We want to get 10 integers, one at a time, and print them after they are collected.
The program is given below:
Self-Instructional
98 Material
Ten integers of an array are scanned the Arrays
scan function and printed */
#include <stdio.h>
int main()
{
int s1[10]; NOTES
int i;
printf(“Enter 10 integers \n”);
for (i=0; i<=9; i++)
{
scanf(“%d”,&s1[i]);
}
printf(“you have entered:\n”);
for (i=0; i<=9; i++)
{
printf (“%d\n”, s1[i]);
}
}
Result of the program
Enter 10 integers
1 2 3 4 5 6 7 8 9 0
you have entered:
1
2
3
4
5
6
7
8
9
0
1 5 9
2 6 10
3 7 11
4 8 12
Notice that we had entered a 3x4 matrix. After transpose it has become a 4x3
matrix. Essentially, each row of matrix A has become a column of B. Finding the
transpose of a matrix is required in many applications.
Self-Instructional
Material 105
Arrays The input in the above program was a rectangular matrix. What will happen if
we input a square matrix in the above program? Let us execute the program and
see.
Enter number of rows of given matrix
NOTES 3
Enter number of columns of given matrix
3
Enter row number 1 of given matrix
1 2 3
Enter row number 2 of given matrix
4 5 6
Enter row number 3 of given matrix
7 8 9
Elements of transpose matrix are:
1 4 7
2 5 8
3 6 9
During the second time, we wanted to transpose a square matrix. So a 3x3
matrix was given as input. The output is a perfect transpose of a given matrix. The
columns and rows have interchanged. Thus, the program works correctly, both
for square matrix as well as the rectangular matrix.
Triangular Matrices
Upper Triangular Matrix
We may recall that a principal diagonal or leading diagonal of a square matrix A
contains the elements whose row index and column index are same, i.e., it includes
the elements A[1] [1], A[2] [2], A[3] [3], etc. A square matrix in which all the
elements below the leading diagonal are zero is called an upper triangular matrix.
For instance, the following is an upper triangular matrix.
{10, 20, 30}
{ 0, 50, 60}
{ 0, 0, 40}
Notice that all the elements below the leading diagonal are zero. This can be
expressed mathematically as A [i] [j] = 0 for i>j.
Now let us write an algorithm to print the elements of an upper triangular
matrix. Essentially, we need not print those elements, which we know will be zero
in an upper triangular matrix.
Algorithm for printing elements of upper triangular matrix
Matrix_Upper_Triangular (int A[i][j])
Step 1: int i,j, row;
Step 2: int A[10][10];
Step 3: read row
Self-Instructional
106 Material
Step 4: /*getting given matrix row by row*/ Arrays
Self-Instructional
108 Material
Let matrix Arrays
[10 20 30]
A [2] [3] = [40 50 60]
[1 2] NOTES
B [3] [2] = [3 4]
[5 6]
Number of columns in matrix A = 3
Number of columns in matrix B = 3
Hence, multiplication A x B is possible.
Let P be the product matrix. Let us use C notation for subscript, i.e., the first
element will have a subscript of zero.
P [0] [0] = [10×1 + 20×3 + 30×5] = 220
P [0] [1] = [10×2 + 20×4 + 30×6] = 280
P [1] [0] = [40×1 + 50×3 + 60×5] = 490
P [1] [1] = [40×2 + 50×4 + 60×6] = 640
Thus, multiplication of 2x3 matrix by 3x2 matrix results in a 2x2 matrix as
given below:
[220 280]
P [2] [2] = [490 640]
We can generalize the calculation of each element as given below:
n 1
where n is the number of columns of the first matrix as well as the number of rows
of the second matrix.
i is the number of rows of the first matrix and the product matrix
j is the number of columns of first matrix and the product matrix.
Let us confirm this through an example. For the sake of simplicity, the values
are given in the program itself.
Example 6.5
/* To demonstrate matrix multiplication*/
#include<stdio.h>
int main()
{
int i,j,k;
int A[2][3]={
{10, 20, 30},
{40, 50, 60}
};
Self-Instructional
Material 109
Arrays int B[3][2]={
{1, 2},
{3, 4},
{5, 6}
};
NOTES int P[2][2];
/*Matrix multiplication*/
for(i=0; i<2; i++)
for(j=0; j<2; j++)
{
P[i][j]=0; /*Initializing product matrix*/
for(k=0; k<3; k++)
P[i][j]=P[i][j]+A[i][k]*B[k][j];/*calculating elements*/
}
/*Printing values of Product matrix*/
printf(“Elements of Product matrix are:\n”);
for(i=0; i<2; i++)
for(j=0; j<2; j++)
{
printf(“P[%d][%d]=%d\n”, i,j, P[i][j]);
}
}
We initialize matrices A & B with actual values. Then, we declare a product
matrix P [2] [2]. The dimension of the matrix requires a little explanation.
We have A [2] [3] &
B [3] [2]
Since the number of columns of the first matrix is the same as the number of
rows of the second matrix, we can multiply them. The dimensions of the resultant
matrix are as given below:
P [number of rows of first matrix] [number of columns of second matrix]
Assume A [3] [2] & B [2] [4]
The product matrix in this case will be P [3] [4]. This has to be understood
clearly.
The number of rows of product matrix will be equal to the number of rows of
the first matrix and number columns of the product matrix will be equal to the
number of columns of the second matrix. Now, look at the section where we
carry out matrix multiplication. We initialize the elements of the product matrix.
Then each element value is calculated. We are using a nested for loops and inside
them, another for loop. Finally, we print the values. The result of the program is
given below:
Result of Example 6.5
Elements of Product matrix are:
P[0][0]=220
P[0][1]=280
P[1][0]=490
Self-Instructional P[1][1]=640
110 Material
Let us now formulate an algorithm for multiplication of matrices. The algorithm Arrays
shall be such that it shall be able to accept different sizes of matrices for multiplication.
However, multiplication is possible only if the number of columns in the first matrix
is equal to the number of columns in the second matrix. The algorithm is given
below: NOTES
Self-Instructional
Material 111
Arrays for (I=0; I<row; I++)
for (j=0; j<column; j++)
print P[I] [j];
NOTES
Step 8: End
Let us now generalize the program to carry out matrix multiplication. The
generalized program implementing the above algorithm for matrix multiplication is
given below:
Example 6.6
/* Matrix multiplication generalized*/
#include<stdio.h>
int main()
{
int i,j,k;
int row, colrow, column;
/*the first matrix subscripts are first two and
the second matrix subscripts are the last two.
colrow gives the number of columns of first matrix and
and number of rows of second matrix*/
int A[10][10], B[10][10], P[10][10];
printf(“Enter number of rows of first matrix\n”);
scanf(“%d”, &row);
printf(“Enter number of columns of first matrix\n”);
scanf(“%d”, &colrow);
printf(“Enter number of columns of second matrix\n”);
scanf(“%d”, &column);
/*getting first matrix row by row*/
for(i=0; i<row; i++)
{
printf(“Enter row number %d of first matrix\n”, i+1);
for(j=0; j<colrow; j++)
scanf(“%d”, &A[i][j]);
}
/*Matrix multiplication*/
Self-Instructional
for(i=0; i<row; i++)
112 Material
for(j=0; j<column; j++) Arrays
{
P[i][j]=0; /*Initializing product matrix*/
for(k=0; k<colrow; k++)
P[i][j]=P[i][j]+A[i][k]*B[k][j];/*calculating elements*/
NOTES
}
/*Printing values of Product matrix*/
Look at the program. Since the number of columns of first matrix is same as
the number of rows of the second, we call the number as colrow. The row refers
to the number of rows in the first matrix and column refers to the number of columns
in the second matrix. Thus, we are going to compute
P [row] [column] = A [row] [colrow] x
B [colrow] [column]
After declaration of the three variables, we also declare the three matrices.
Since we have to give a constant as the dimension of the matrix, size of 10 has
been given. Any large size can also be given. Then, we get the values for the
variables row, colrow and column at runtime.
The next section gets the elements of the first matrix A row by row. Thereafter,
we get the values of elements of the second matrix B. Then each element of the
product matrix is computed. Then the elements of the product matrix are printed.
The interactions with the system and result of first execution follow:
Result of first execution
Enter number of rows of first matrix
2
Enter number of columns of first matrix
3
Enter number of columns of second matrix
2
Enter row number 1 of first matrix
10 20 30
Enter row number 2 of first matrix
40 50 60
Enter row number 1 of second matrix
1 2
Enter row number 2 of second matrix
3 4
Enter row number 3 of second matrix
5 6
Elements of Product matrix are:
Self-Instructional
Material 113
Arrays P[0][0]=220
P[0][1]=280
P[1][0]=490
P[1][1]=640
NOTES The matrices multiplied are same as in the previous program. The result
confirms that our generalized algorithm and the corresponding program work
correctly. Now, let us try two different matrices for confirming the correctness of
the program.
Result of second execution
Enter number of rows of first matrix
4
Enter number of columns of first matrix
3
Enter number of columns of second matrix
2
Enter row number 1 of first matrix
1 2 3
Enter row number 2 of first matrix
4 5 6
Enter row number 3 of first matrix
7 8 9
Enter row number 4 of first matrix
10 20 30
Enter row number 1 of second matrix
40 50
Enter row number 2 of second matrix
60 70
Enter row number 3 of second matrix
80 90
Elements of Product matrix are:
P[0][0]=400
P[0][1]=460
P[1][0]=940
P[1][1]=1090
P[2][0]=1480
P[2][1]=1720
P[3][0]=4000
P[3][1]=4600
Let us confirm the correctness of the results manually.
[1 2 3]
A = [4 5 6]
[7 8 9]
[10 20 30]
[40 50]
B = [60 70]
[80 90]
P [0] [0]= [1×40 + 2×60 + 3×80]
= 400
Self-Instructional
114 Material
P [0] [1] = [1×50 + 2×70 + 3×90] Arrays
= 460
P [3] [1] = [10×50 + 2×70 + 3×90]
= 4600 NOTES
Thus, the generalized program for matrix multiplication works correctly.
Designated Initializers
The ANSI/ISO standard issued in the year 1990 permitted assignment of values to array
elements directly as given in the following program.
Example 6.7
#include<stdio.h>
int main()
{
int i;
int m[5];
m[0] = 10;
m[4] = 20;
for(i=1;i<4;i++)
{
m[i] = 0;
}
printf(“the elements of the array array follow \n”);
for(i=0;i<5;i++)
{
printf(“%d\n”,m[i]);
}
}
In the above program, we assign the values for 0th element and 4th element
directly as 10 and 20 respectively. The values of the other elements (1st, 2nd and
3rd) are assigned as zero in the for loop.
The output of the program is given below:
the elements of the array array follow
10
0
0
0
20
In the next example, we show the program again but rather than assigning
values to the first and last elements of the array directly as in the above program,
we initialize them explicitly by subscript, using designated initializers.
Example 6.8
#include<stdio.h>
int main()
{ int i;
int m[5]=
{ [0]=10, // initialize elements with designated
initializers
[4]=20
Self-Instructional
Material 115
Arrays };
printf(“The elements of the array follow \n”);
for(i=0;i<5;i++)
printf(“%d\n”,m[i]);
NOTES }
The result of the program follows
The elements of the array follow
10
0
0
0
20
Look at the above program carefully. We assign values to the array elements
explicitly using designated initializers [0] and [4]. Note, there is no comma after
the last assignment. The initialization is carried out within braces and the closing
brace is followed by a semicolon. Any element which is not explicitly initialized is
implicitly initialized to zero. This type of syntax was not allowed in earlier versions
of C90.
The designated initializers are supported for user defined data types, such as
arrays, structures, and unions. A designated initializer, or designator, points to a
particular element to be initialized. A designator list is a comma-separated list of
one or more designators. A designator list followed by an equal sign constitutes
a designation.
Designated initializers allow for the following flexibility:
Elements within a user defined data type can be initialized in any order.
The initializer list can omit elements that are declared anywhere in the data
type. Elements that are omitted are initialized as if they are static objects: arithmetic
types are initialized to 0; pointers are initialized to NULL.
6.2.4 Variable Length Array/ Dynamic array
In C90, arrays are of constant and predetermined size. Suppose we do not know
an array size at compilation time then how to handle this situation without using
dynamic memory allocation? C99 allows us to handle array of unknown size by
using variable length array. A variable length array is that whose length or size is
defined at execution time. The following example shows a method of using variable
length arrays. In the example we are declaring an array called printarray which
takes as arguments an integer for size of the array and another integer array. We
get arraysize at run time. In the for loop we generate the values for array elements
as square of the array index i for the sake of simplicity. We could have obtained
different values through scanf function in the for loop, if needed. Then we call the
function printarray and pass the array size and all the elements of the array. See
the simplicity of the statement
Self-Instructional
116 Material
printarray (arraysize, array); Arrays
Binary Search
There are a number of search methods. Here we look at Binary search. An
important pre-condition for binary search is that the data is ordered or arranged in
ascending or descending order in an array, like names are arranged alphabetically
in a telephone directory.
Let us now study the algorithm for binary search to understand the concept.
We will assume that the array of numbers is arranged in increasing order.
Self-Instructional
Material 117
Arrays Algorithm for Binary Search(a[n], x, left, right)
{
int a[n]; /* subscript of left most element will be 0
and right most n–1 */
left = 0
NOTES right = n–1
found = false;
while (left < right)
{
mid = (left + right)/2;
if (a (mid) = =x) found = true;
else
if (a (mid) < x) left = mid + 1;
else right = (mid-1);
}
if (found) print (“found”); else print (“Not
found”);
}
A program implementing binary search algorithm is given below:
/*Example 6.10*/
/*Binary search- The numbers are ordered*/
#include <stdio.h>
#define UPPER 5
#define TRUE 1
#define FALSE 0
int main ()
{
int left =0, mid=0, right=UPPER, found=FALSE;
int x;
int a [] = {10, 20, 30, 40, 50, 60};
printf(“ENTER THE NUMBER TO SEARCH\n”);
scanf(“%d”, &x);
while ((left <= right) && (!found))
{
mid = (left+right)/2;
if (a[mid]==x) found = TRUE;
else
if (a[mid] < x)
left = (mid +1);
else
right = (mid-1);
}
if (found)
printf(“found the number %d in position %d\n”, x,
mid+1);
else
printf(“NOT found the number %d”, x);
}
1. An array is one of the user defined of data types. An array can hold a
number of data of the same type. In a program we can declare arrays of
integers, arrays of characters and arrays of floating point numbers, etc.
depending on the need.
2. Variable declaration allots memory space for the variable. If we declare an
array variable of type integer and dimension 40, then the computer will allot
a memory size of 40 words for the variable contiguously.
3. A variable length array/dynamic array is that whose length or size is defined
at execution time.
6.4 SUMMARY
An array is one of the user defined of data types. An array can hold a
number of data of the same type. In a program we can declare arrays of
integers, arrays of characters and arrays of floating point numbers, etc.
depending on the need.
We can use an index with the name of the array to indicate the elements.
An array is also variable and hence must be declared like any other variable.
The naming convention is the same as in the case of other variables. The
array name cannot be a reserved word and must be unique in the program.
Variable declaration allots memory space for the variable. If we declare an
array variable of type integer and dimension 40, then the computer will allot
a memory size of 40 words for the variable contiguously.
If the array elements are known beforehand, they can be declared right at
the beginning.
Self-Instructional
Material 119
Arrays Multi-dimensional arrays operate on the same principle as single dimensional
arrays.
A variable length array is that whose length or size is defined at execution
time.
NOTES
Self-Instructional
120 Material
Strings
UNIT 7 STRINGS
Structure NOTES
7.0 Introduction
7.1 Objectives
7.2 Basic Concept of Strings
7.2.1 Use of scanf() and printf() with Strings
7.2.2 Reading and Writing Strings: gets and puts
7.2.3 Library Functions for String Handling
7.2.4 Two-dimensional Character Arrays
7.3 Answers to Check Your Progress Questions
7.4 Summary
7.5 Key Words
7.6 Self Assessment Questions and Exercises
7.7 Further Readings
7.0 INTRODUCTION
We know that arrays are user-defined data types containing same data type such
as integers or real numbers. We also discussed one-dimensional and multi-
dimensional arrays. We know how to address each element. In C language, string
is a special type of array. When a data item, constant or variable consists of array
of characters, such arrays are known as strings. We will study more operations
using strings in this unit.
7.1 OBJECTIVES
S e v e n \0
Actually, we do not place the null character at the end of a string constant.
The C compiler automatically places the ‘\0’ at the end of the string when it initializes
the array. Note that the ASCII value of NULL, i.e., ‘\0’ is zero, whereas the
ASCII value of number zero is 48.
7.2.1 Use of scanf() and printf() with Strings
One can use scanf() to receive strings from the screen. The code for using scanf
for reading a name is given below:
char name [25];
scanf (“ %s ”, str);
Strings can be declared as an array of characters as shown above. In the
scanf function when we get the array of characters as a string, it is enough to
indicate the name of the array without a subscript. In this case the identifier or the
name of the string is str, When we get a string, there is no need for writing ‘&’
before str in this case in the scanf argument list. We can indicate the name of the
string variable itself. Let us now write a program to read a string with scanf() and
write with printf().
Self-Instructional
122 Material
The program is given below: Strings
Example 7.1
/* Reading and writing with formatted I/O functions*/
#include<stdio.h>
int main () NOTES
{
char str [10];
printf (“Enter your name\n”);
scanf (“%s”, str);
printf (“You Entered: %s\n”);
}
Look at the program. We are declaring a string str as a character array of
size 10. Look at the way we receive the array. We do not prefix ampersand (&)
to the variable name str when we use the scanf function. We do not even suffix it
with square brackets. Then, we print the contents of variable str. The format
specifier in both the cases is %s. Look at the result of the program.
Result of Example 7.1
Enter your name
Rama Krishnan
You Entered: Rama
We typed ‘Rama Krishnan’. But we got ‘Rama’ since the white space following
the first word was considered to be end of character array. Hence, the computer
stopped reading thereafter. This is because we used a formatted input function,
namely scanf ().
It is to be noted carefully that we cannot exceed the dimension of the character
array which is 10 in this case. Also, it cannot receive a multi-word string as the
above example demonstrated.
7.2.2 Reading and Writing Strings: gets and puts
Strings may contain blanks in between. If we use a scanf() function to get the
string with a space in between such as “Rama Krishnan”, Krishnan will not be
taken note of since space is an indicator of the end of entry of the input as indicated
by the result of the previous example. But gets will take all that is entered till the
enter key is pressed. Therefore, after entering the full name, the enter key can be
pressed. Thus, using gets is a better way for strings. We can get a string in a much
simpler way using gets (). The syntax for gets is: gets (name);
Similarly, puts () can be used for printing a variable or a constant as given
below:
puts (name);
puts (“Enter the word”);
However, there is a limitation. printf can be used to print more than one
variable and scanf to get more than one variable at a time, in a single statement.
However, puts can output only one variable and gets can input only one variable
in one statement. In order to input or output more than one variable, separate Self-Instructional
Material 123
Strings statements have to be written for each variable. As we know that gets and puts
are unformatted I/O functions, there are no format specifications associated with
them.
The example below gives the modified version of the above program.
NOTES Example 7.2
/* Reading and writing with unformatted I/O functions*/
#include<stdio.h>
int main ()
{
char str [10];
printf (“Enter your name\n”);
gets (str);
printf (“You Entered :”);
puts (str);
}
Look at the program. We have declared str as a one-dimensional character
array. We read the string as shown below:
gets (str);
No format needs to be specified. Writing also is similar. The argument to
puts () as well as gets () are str of type string. Look at the result of the program.
Result of Example 7.2
Enter your name
Rama Krishnan
You Entered:Rama Krishnan
The entire string has been received although there is white space in between.
Thus, gets() is more suitable for handling strings. But, if we have to receive two
strings, we need to call gets() twice. Though any number of strings can be received
with one scanf() statement, it will treat white space as a string terminator as in
Example 7.1. Similarly, puts() can display only one string at a time. Whereas
printf() can print any number of strings with one statement.
String COPY
Let us write a program to copy one string to another.
Example 7.3
/*String copy*/
#include<stdio.h>
int main()
{
char str1[10], str2[10];
int i;
printf(“Enter a string\n”);
gets (str1);
for(i=0; i<10; i++)
str2[i]=str1[i];
printf(“you Entered:\n”);
puts(str1);
Self-Instructional
124 Material
printf(“copied string is:\n”); Strings
puts(str2);
}
Let us analyze the program. Two strings str1 and str2 are declared with size NOTES
10. Then we get str1. In the for loop, we assign str1 to str2, one character at a
time. Finally, we print both the strings.
The result of the program is given below:
Result of Example 7.3
Enter a string
Vinayagar
you Entered:
Vinayagar
copied string is:
Vinayagar
We have written a program for copying one string to another. But a library
function strcpy() is available for this purpose. Let us write a program for copying
a string to another using the library function. The program is given below:
Example 7.4
/*String copy using library function*/
#include<stdio.h>
#include<string.h>
int main()
{
char str1[]=”Subramaniar”, str2[11];
strcpy(str2,str1);
printf(“you Entered:\n”);
puts(str1);
printf(“copied string is:\n”);
puts(str2);
}
Look at the declaration statement. We have declared and initialized str1 and
declared str2 in one statement. There is no need to give the dimension when we
initialize the array as given in the program. The compiler will count the number of
elements and add the dimension by itself. Look at the string copy statement,
reproduced below:
strcpy (str2, str1) ;
Contents of the second named string will be copied to first named string.
strcpy() is a library function and it receives two string variables, the first one is the
destination string and the last one the source string. Look at the result of execution
of the program.
Result of Example 7.4
you Entered:
Subramaniar
copied string is:
Subramaniar
Self-Instructional
Material 125
Strings The program works correctly. Thus, we can use the library function easily
without writing a program for copying strings.
The library function is part of header file<string.h>. Therefore, some compilers
may require us to include <string.h> in the program for using the function.
NOTES
Finding String Length
Many times we may need to find the length of a given string. Let us now write a
program to find the length of a string.
Example 7.5
/*Finding length of a string*/
#include<stdio.h>
int main()
{
char str1[]=”Shri Rama Jeyam”;
int length;
for(length=0; str1[length]!=’\0’; length++);
printf(“you Entered: “);
puts(str1);
printf(“\nits length=% d “, length);
}
Look at the program. Look at the following statement carefully.
for(length=0; str1[length]!=’\0’; length++);
The length of the string is computed in this statement only. In the first iteration
of the for statement, str1 [0] will be compared with NULL (‘/0’). Since it is not
NULL, length will be incremented to 1. This continues till the last character of the
string is compared. After that, we would have reached the end of the string or
NULL. Hence, execution of the for loop will be terminated. The variable length
will thus contain the actual length of the string. It is then printed. Thus, the program
works correctly as the result below indicates.
Result of Example 7.5
you Entered: Shri Rama Jeyam
its length= 15
Even for finding the length of the string there is a library function called strlen().
Let us use it and modify the above program. The modified program is given
below:
Example 7.6
/*String length using library function strlen()*/
#include<stdio.h>
#include<string.h>
int main()
{
char str1[]=”Shri Rama Jeyam”;
printf(“you Entered: “);
puts(str1);
printf(“\nits length=%d”, strlen(str1));
Self-Instructional }
126 Material
Look at the program. We find the length and print it in the last statement Strings
reproduced below:
printf(“\nits length=%d”, strlen(str1));
When the program execution reaches the line, the cursor will go to the beginning NOTES
of the next line because of the appearance of \n. Then the text “its length = ” will
be printed. Then, it will look for an integer specified outside the quote, to print
because of the appearance of %d. Here the integer will come out of executing the
library function strlen(str1). Thus, we get identical result as given below.
Result of Example 7.6
you Entered: Shri Rama Jeyam
its length=15
From the above examples, it will be clear that the use of library functions
conserves the effort and also shortens the program. We have used a few library
functions, which facilitate string manipulation.
7.2.3 Library Functions for String Handling
There are a number of library functions to handle strings. A list of such functions
available for string manipulation is given in Table 7.1.
Table 7.1 String Library Functions
Function nameApplication
/*displaying strings*/
for (i=0; i<5; i++)
{
printf(“name[%d]: %s\n”, i+1, name[i]);
}
}
Look at the program. We declare a two-dimensional character array, called
name[5][10].
Then we receive the names. Look at the ease with which we receive it.
scanf(“%s”, name[i]);
We do not even give the second dimension. This is possible only in the case of
Self-Instructional strings. Recall that when str was a one-dimensional array, we read it in the scanf()
128 Material
function by simply specifying str and not its address. But since we are specifying Strings
1. puts can output only one variable and gets can input only one variable
in one statement.
2. Strlen () function provides the length of a given string.
7.4 SUMMARY
A string is formed using an array of the basic data type char. We can define
a string variable as well as string literal. String literals are words surrounded
by double quotation marks.
A string is an array of characters, which means that it may contain zero to
many characters.
One can use scanf () to receive strings from the screen.
Strings may contain blanks in between. If we use a scanf () function to
get the string with a space in between such as “Rama Krishnan”, Krishnan
will not be taken note of since space is an indicator of the end of entry of the
input.
printf can be used to print more than one variable and scanf to get
more than one variable at a time, in a single statement. However, puts can
output only one variable and gets can input only one variable in one statement.
Self-Instructional
132 Material
Strings
7.5 KEY WORDS
gets: This function is used to scan or read a line of text from a standard
input (stdin) device, and store it in the string variable. NOTES
Strrev ():It is a function that reverse the given string.
Self-Instructional
Material 133
Functions Basics
BLOCK - III
USER DEFINED FUNCTIONS
NOTES
UNIT 8 FUNCTIONS BASICS
Structure
8.0 Introduction
8.1 Objectives
8.2 General Forms of Functions
8.2.1 Function Prototype
8.2.2 Function Call – Passing Arguments to a Function
8.2.3 Function Definition
8.2.4 Function Arguments
8.2.5 Scope: Rules for Functions
8.2.6 Return Values
8.2.7 Arrays and Functions
8.2.8 Call by Value
8.2.9 Call by Reference
8.3 Formal and Actual Parameters
8.4 Recursive Function
8.4.1 Basic Concepts
8.4.2 Implementation of Euclid’s gcd Algorithm
8.5 Answers to Check Your Progress Questions
8.6 Summary
8.7 Key Words
8.8 Self Assessment Questions and Exercises
8.9 Further Readings
8.0 INTRODUCTION
In this unit, you will learn about user-defined functions, and about function
declaration, function call and how to define a function. A function, when declared
in a program, is a function prototype which may be declared at the beginning of a
main program. A function, on execution, is supposed to do something: either return
a value as integer, character or float; or perform some operation. A function consists
of two parts, declarator and declaration. A function declaration has the format in
which the type of data returned, name of the function and arguments on which the
function is to operate, are mentioned. Arguments declared as part of the function
prototype are called formal parameters, which are enclosed in a pair of parentheses.
A function may not contain any parameter, in which case an empty pair of
parentheses should follow the name of the function. A function may not return a
value, in which case void is written as the return data type.
Self-Instructional
134 Material
A function may be called directly or indirectly by another function. For this, Functions Basics
8.1 OBJECTIVES
Self-Instructional
Material 135
Functions Basics If no arguments are passed into a function, an empty pair of parentheses
must follow the function name. For example,
char fun4( );
NOTES The arguments declared as part of the prototype are also known as formal
parameters. The formal arguments indicate the type of data to be transferred from
the calling function.
8.2.2 Function Call – Passing Arguments to a Function
We may call a function either directly or indirectly. When we call the function, we
pass the actual arguments or values. Calling a function is also known as function
reference.
There must be a one-to-one correspondence between formal arguments
declared and the actual arguments sent. They should be of the same data type and
in the same order. For example,
sum=f1 (20.5, 10); fun4( );
8.2.3 Function Definition
Function definition can be written anywhere in the file with a proper declarator,
followed by the declaration of local variables and statements. Function definition
consists of two parts, namely function declarator or heading and function
declarations. The function heading is similar to function declaration but will not
terminate with a semicolon.
The use of functions will be demonstrated with simple programs in this unit.
Suppose you wish to get two integers. Pass them to a function add. Add
them in the add function. Return the value to the main function and print it. The
algorithm for solving the problem will be as follows:
Main Function
Step 1: Define function add
Step 2: Get 2 integers
Step 3: Call add and pass the 2 values
Step 4: Get the sum
Step 5: Print the value
function add
Step 1: Get the value
Step 2: Add them
Step 3: Return the value to main
Thus, you have divided the problem. The program is as follows:
/*Example 8.1*
/* use of function*/
#include <stdio.h>
Self-Instructional
136 Material
int main() Functions Basics
{
int a=0, b=0, sum=0;
int add(int a, int b); /*function declaration*/ NOTES
printf(“enter 2 integers\n”);
scanf(“%d%d”, &a, &b);
sum =add(a, b); /*function call*/
printf(“sum of %d and %d =%d”, a, b, sum);
}
/*function definition*/
int add (int c, int d) /*function declarator*/
{
int e;
e= c+d;
return e;
}
Result of the program
enter 2 integers
6667 4445
sum of 6667 and 4445 =11112
The explanation as to how the program works is given below:
On the fifth statement (seventh line), the declaration of the function add is
given. Note that the function will return an integer. Hence, the return type is defined
as int. The formal arguments are defined as int a and int b. The function
name is add. You cannot use a variable without declaring it, as also a function
without telling the compiler about it. Note also that function declaration ends with
a semicolon, similar to the declaration of any other variable. Function declaration
should appear at the beginning of the calling function. It hints to the compiler that
the function is going to call the function add, later in the program. If the calling
function is not going to pass any arguments, then empty parentheses are to be
written after the function name. The parentheses must be present in the function
declaration. This happens when the function is called to perform an operation
without passing arguments. In this case, if a and b are part of the called
function(add) itself, then we need not pass any parameters. In such a case, the
function declaration will be as follows assuming that the called function returns an
integer:
int add ( ) ;
In Example 8.1, you get the values of a and b. After that you call the function
add and assign the value returned by the function to an already defined int
variable sum as follows:
Self-Instructional
Material 137
Functions Basics sum = add ( a , b );
Note that add(a, b) is the function call or function reference. Here, the
return type is not to be given. The type of arguments are also not to be given. It is
a simple statement without all the elements of the function declaration. However,
NOTES the function name and the names of the arguments passed, if any, should be present
in the function call. When the program sees a function reference or function call, it
looks for and calls the function and transfers the arguments.
The function definition consists of two parts, i.e., the function declarator
and function declarations.
The function declarator is a replica of the function declaration. The only
difference is that while the declaration in the calling function will end with a semicolon,
the declarator in the called function will not end with a semicolon. As in main(),
the entire functions body will be enclosed within braces. The whole function can
be assumed to be one program statement. This means that all the statements within
the body will be executed one after another before the program execution returns
to the place in the main function from where it was called.
The important points to be noted are:
(a) The declarator must agree totally with the declaration in the called
function, i.e., the return data type, the function name, the argument
type should all appear in the same order. The declarator will not end
with a semicolon.
(b) You can also give the same name as in the calling function—in
declaration statement or function call—or different names to the
arguments in the function declarator. Here, we have given the names
c and d. What is important; however, is that the type of arguments
should appear, as it is in the declaration in the calling program. They
must also appear in the same order.
(c) At the time of execution, when the function encounters the closing
brace }, it returns control to the calling program and returns to the
same place at which the function was called.
In this program, you have a specific statement return (e) before the
closing brace. Therefore, the program will go back to the main function with the
value of e. This value will be substituted as
sum = (returned value)
Therefore, sum gets the value which is printed in the next statement. This is
how the function works.
Assume now that the program gets a and b values, gets their sum1, gets
c and d and gets their sum2 and then both the sums are passed to the function to
get their total. The program for doing this is as follows:
/*Example 8.2*
/* A function called many times */
Self-Instructional
138 Material
#include <stdio.h> Functions Basics
int main()
{
float a, b, c, d, sum1, sum2, sum3;
NOTES
float add(float a, float b); /*function declaration*/
printf(“enter 2 float numbers\n”);
scanf(“%f%f”, &a, &b);
sum1 =add(a, b); /*function call*/
printf(“enter 2 more float numbers\n”);
scanf(“%f%f”, &c, &d);
sum2 =add(c, d); /*function call*/
sum3 =add(sum1, sum2); /*function call*/
printf(“sum of %f and %f =%f\n”, a, b, sum1);
printf(“sum of %f and %f =%f\n”, c, d, sum2);
printf(“sum of %f and %f =%f\n”, sum1,sum2, sum3);
}
/*function definition*/
float add (float c, float d) /*function declarator*/
{
float e;
e= c+d;
return e;
}
Result of the program
enter 2 float numbers
1.5 3.7
enter 2 more float numbers
5.6 8.9
sum of 1.500000 and 3.700000 =5.200000
sum of 5.600000 and 8.900000 =14.500000
sum of 5.200000 and 14.500000 =19.70000
You have defined sum1, sum2 and sum3 as float variables.
You are calling the function add three times with the following assignment
statements:
sum1 = add( a, b );
sum2 = add( c, d);
sum3 = add( sum1 , sum2 );
Thus, the program goes back and forth between main() and add as
given below:
Self-Instructional
Material 139
Functions Basics int main()
add (a, b)
int main()
add (c, d)
NOTES
int main()
add (sum 1, sum 2)
int main()
Had you not used the function add, you would have to write statements
pertaining to add 3 times in the main program. Such a program would be large
and difficult to read. In this method, you have to code for add only once and
hence, the program size is small. This is one of the reasons for the usage of functions.
In Example 8.2, you could add another function call by add (10.005,
3.1125); This statement will also work perfectly. After the function is executed,
the sum will be returned to the main() function. Therefore, both variables and
constants can be passed to a function by making use of the same function declaration.
You have seen a program, which calls a function thrice. You will now discuss
a problem, which calls three functions.
Problem
The user gives a four-digit number. If the number is odd, then the number has to
be reversed. If it is even, then the number is to be doubled. If it is evenly divisible
by three, then the digits are to be added. Now, let us write the algorithm for
solving the problem.
Step 1: Get the number.
Step 2: If the number is odd call, the reverse function.
Step 3: Else multiply the number by 2 and hence call multiply.
Step 4: If the number is evenly divisible by 3, call add–digits.
These are the steps. The first one, namely writing a function to multiply by 2
is simple. We will look at the other two steps now.
Reverse
The following steps show the reversing of number.
Step 1: reverse = 0
step 2: while ( number > 0 )
reverse = reverse * 10 + (number % 10 )
number = number/10
Step 3: return (reverse).
add–digits function
Step 1: sum = 0
Step 2: while number > 0
Self-Instructional
140 Material
sum = sum + (number % 10) Functions Basics
number = number / 10
Step 3: return (sum)
Let us see how the above algorithm add–digits works.
NOTES
Let us give 4321 as the number.
Step 1: sum = 0
Step 2: Iteration 1
sum = 0 + modulus of (4321/10)
= 0 + 1 = 1
number = 4321/10 = 432
Iteration 2
sum = 1 + modulus of (432/10)
= 1 + 2
After 4 iterations:
sum =1+2+3+4
Step 3: sum is returned.
The program is given below:
/*Example 8.3*/
/*program to demonstrate calling
multiple functions*/
#include<stdio.h>
int main()
{
long nummul=0;
long num=0, rev=0, add_digit=0;
/*good practice to inialize all variables*/
long reverse(long num);
long mult(long num);
int sum_digit(long num);
printf(“enter unsigned number\n”);
scanf(“%lu”, &num);
if (num%2) /*remainder 1*/
{
rev = reverse(num);
printf(“number is odd\n”);
printf(“number entered=%lu\n number reversed=%lu\n”,
num, rev);
}
else
{
Self-Instructional
Material 141
Functions Basics nummul=mult(num);
printf(“number is even\n”);
printf(“number=%lu\n its multiple=%lu\n”, num,
nummul);
NOTES }
if (num%3 ==0)
{
add_digit= sum_digit(num);
printf(“number evenly divisible by 3\n”);
printf(“sum of digits =%lu”, add_digit);
}
}
long reverse(long n)
{
long r=0;
while (n>0)
{
r=r*10+(n%10);
n=n/10;
}
return r;
}
long mult(long p)
{
long sq;
sq=2*p;
return sq;
}
int sum_digit(long num)
{
long sum=0;
while (num >0)
{
sum=sum+(num%10);
num=num/10;
}
return sum;
}
Result of the program
enter unsigned number
Self-Instructional
4321
142 Material
number is odd Functions Basics
number entered=4321
number reversed=1234
Look at the program. After getting the number from the user, it evaluates if
NOTES
the remainder of (num/2) = true; i.e., if the remainder is 1, then it is true.
If the remainder = 1, then the number is odd and hence the reverse function
is called. The returned value is assigned to rev and printed.
If the number is even, the number is doubled. Since the doubled value may
exceed the maximum of the unsigned integer, we have declared it as a long
integer.
Next, we check if the number is evenly divisible by 3.
If it is so, then we add the digits. Thus, the main function of Example 8.3
calls three functions for carrying out specific tasks. All the three functions are
supplied with the same arguments but return different values.
8.2.4 Function Arguments
You know now that an argument is a parameter or value. It could be of any of the
valid types, such as all forms of integers or a float or char. You come across two
types of arguments when you deal with functions:
formal arguments
actual arguments
Formal arguments are defined in the function declaration in the calling
function. What is actual argument? Data, which is passed from the calling function
to the called function, is called the actual argument. The actual arguments are
passed to the called function through a function call.
Each actual argument supplied by the calling function should correspond to
the formal arguments in the same order. The new ANSI standard permits declaration
of the data types within the function declaration to be followed by the argument
name. You have used only this type of declaration as it will help students follow the
C++ program easily. This helps in understanding one to one correspondence
between the actual arguments supplied and those received in the function and
facilitates the compiler to verify that one to one correspondence exists and that the
right number of parameters have been passed. It may be noted that formal
arguments cannot be used for any other purposes. They only give a prototype for
the function. Thus, the names of the formal arguments are dummy and will not be
recognized elsewhere, even in the functions in which they are defined.
Although, the types of variables in the function declaration, also known as
prototype and function call are to be the same, the names need not be the same. You
have already used this concept in Example 8.2 after defining float a and float
b in the functions prototype, you first called add (a, b), add (c, d) and
then add (sum1, sum2). Thus, the formal arguments defined in the prototype
and the actual arguments were not the same in two of the above cases. Self-Instructional
Material 143
Functions Basics When the actual arguments are passed to a function, the function notes the
order in which they are received and appropriately stores them in different locations.
You must note that even if you use a and b in the add function, they will be
stored in different locations. They will have no relationship with a and b of the
NOTES main function. Therefore, even if a and b are assigned different values in the
called function, the corresponding values in the calling function would not have
changed. You will verify this point in the program in the next section.
8.2.5 Scope: Rules for Functions
The scope of the variable is local to the function, unless it is a global variable. For
instance,
int function1(int I )
{ int j=100;
double function2 (int j) ;
function2 (j) ;
}
double function2 (int p)
{ double m;
return m;
}
The variable j in function1 is not known to function2. You pass
it to function2 through the argument j. This will be assigned as equal to
int p. Similarly, m in function2 is not known to function1. It can be
made known to function1 through the return statement. This makes the
scope rules of variables in function quite clear. The scope of variables is local to
the function where defined. However, global variables are accessible by all the
functions in the program if they are defined above all functions.
/*Example 8.4*
/* To demonstrate that the scope of a
variable is local to the function*/
#include <stdio.h>
int main()
{
float a=100.250, b=200.50;
void change (float a, float b);
change(a, b);
printf(“a= %f b= %f\n “, a, b);
printf(“these are the original values”);
}
Self-Instructional
144 Material
/*function definition*/ Functions Basics
Self-Instructional
Material 145
Functions Basics The return statement can be any of the following types:
return (sum) ;
return V1;
return “ true” ;
NOTES
return ‘ Z ’ ;
return 0;
return 4.0 + 3.0;
In some examples, you have returned variables whose values are known
when they are returned and in other examples, you return constants. You can even
return expressions. If the return statement is not present, it means the return data
type is void.
You can also have multiple return statements in a function. However, for
every call, only one of the return statements will be active and only one value will
be returned.
8.2.7 Arrays and Functions
There is no restriction in passing any number of values to a function; the restriction
is only in the return of values from a function. Therefore, arrays can be passed to
a function without any difficulty, one element at a time, as follows:
#include <stdio.h>
int main()
{
int a[]={1,2,3,4,5};
int j;
int func(int a);
for (j=0; j<=4; j++)
func (a[j]);
..........
}
int func(int c)
{
......
}
Here, func has been declared as a function passing a single integer. Note
here that the declaration or the prototype gives only the format of the parameters
passed. The values are only indicative and are not actual values. They are the
formal values. Therefore, the parameters declared inside the parentheses act only
as a checklist. They cannot be used in the main function elsewhere without actually
declaring them on top of the function. But, for this rule, there would have been a
conflict between a[] which is an array and a which is a simple variable. Here, no
conflict arises because a is not recognized in the main function. It is only a checklist
Self-Instructional
146 Material
to see that whenever the function calls func, an integer has to be passed. If we Functions Basics
try to pass a float, the compiler will detect an error. This is not so in the case of
variables defined in the function declarator above the functions body, as they are
recognized as actual names. In this case, int c is declared as a variable in
func. The initial value will be the same as passed by the calling function. Thus, NOTES
since a is used in the function declaration, only one integer can be passed to the
function func. Actually, the entire array can be passed to a function irrespective
of its size, by suitable declaration, as the following example indicates.
/*Example 8.5*/
/* To find the greatest number in an array*/
#include <stdio.h>
int main()
{
int array[]= {8, 45, 5, 911, 2};
int size=5, max;
int fung(int array[], int size);
max=fung(array, size);
printf(“%d\n”, max);
}
int fung(int a1[], int size)
{
int i, j, maxp=0;
for (j=0; j<size; j++)
{
if (a1[j] > maxp)
{
maxp=a1[j];
}
}
return maxp;
}
Result of the program
911
The objective of Example 8.5 is to find the greatest number in an array. In
the program, an array called array is initialized with 5 values as given below:
int array[]= {8, 45, 5, 911, 2}; size is declared as 5 and
a function called fung has been declared. It will pass an array and an integer to
the called function. The array size has been kept open and the called function will
return an integer. The next statement calls fung and passes all elements of the
array and an integer 5 equal to size. The function gets the actual values and
size=5. The maximum value in the array is found in the for loop and stored in
Self-Instructional
Material 147
Functions Basics maxp. The value maxp is returned to the main function and printed there. Thus,
the function is called by value.
8.2.8 Call by Value
NOTES In this section, you have been calling functions by passing values. For example,
function calls in some of the above programs are as follows:
change(a, b);
rev = reverse(num);
The values passed to the function change are a & b which are known.
Similarly, while calling function reverse, we pass num. This is called call by
value. When you call functions by value, the called functions can return only one
value.
8.2.9 Call by Reference
The call by reference method of parring agreements to a function copies the address
of an argument into the formal parameter. So, it results into the modification in the
values of actual parameters.
Formal parameters are always variables; this does not mean that they are always
variable parameters. You can use numbers, expressions or function calls as actual
parameters. Here are some examples of valid actual parameters in the function
call calc_consumer_bill:
bill = calc_consumer_bill (25, 32, 27);
bill = calc_consumer_bill (50+60, 25*2, 100-75);
bill = calc_consumer_bill (a, b, (int) sqrt(25));
The last line in this example code will use math.h header file because sqrt is the
square root function and returns double value, so it must be cast into an int to
be passed to cal_consumer_bill.
pop. You have not defined any stack and therefore, you can assume that the
system does this for you. After pushing the intermediate result into stack, the program
calls fact(1), which returns 1. Now, the intermediate result is popped and the
value of fact 1 is substituted to get the factorial of 2 as 2. NOTES
Now call factorial 5. You call fact and get back,
result = 5 * fact(4) [1]
Now, fact(4) is called to get 4 * fact(3.) Substituting this in
equation [1], we get
result = 5 * 4 * fact(3)
fact(3) again is called to get 3 * fact(2) and so on till we get fact(1)
which will be returned as 1. Therefore, we get factorial 5 as 5 x 4 x
3 x 2 x 1. Such repetitive calling of the same function is called recursion. The
calls are recursive calls. The result and function fact has been declared to
be of type long so as to take care of large numbers. If the fact function were
not called repeatedly, the program size would have become very large. Thus,
recursion keeps the program size small but understanding recursion is not easy. If
the program can be visualized as recursive, it will result in compact code. Recursive
functions can easily become infinite loops. Therefore, the functions should have a
statement with if so that the program will definitely terminate. In the factorial
program, assume for a moment that the first statement in fact function is absent.
Then we have to end the program only when n becomes 1. What will happen, if
by chance, n is entered as a negative number? The program will get into an endless
loop. Therefore, to avoid such eventualities, you can either have a statement as
follows:
If (n<1) exit().
Or you could do this by the statement if (n<1) return 0, as has
been done here.
This will ensure that if either 0 or a negative number is entered, you get the
factorial as 0 and the program will terminate gracefully.
You should also note that recursive programs simulate the use of stack. You
write to the stack and retrieve information from the stack. Writing to stack is
called push and retrieving or reading or getting value from the stack is known as
pop. The feature of stack is last in, first out and therefore, you get the value of the
data entered last first, as illustrated in the following example.
You push or pop only through the top of the stack. Assume that you
want to push a, b & c, one at a time. You push ‘a’. It will be on top
of the stack. When you push b, a will be pushed to the next lower location and
b will occupy the top of the stack. Next, when you push ‘c’, ‘c’ will
occupy the top of the stack, ‘b’ one location before and ‘a’ one location
before ‘b’. Thus, you can push data till the stack becomes full. If you pop the
stack now, it will eject ‘c’, then ‘b’ and so on. Thus, you pop on a last-in-
first-out basis. Self-Instructional
Material 151
Functions Basics Reconsider the factorial program in which you were storing intermediate
results in a stack-like manner and popping LIFO. Take the example of finding the
factorial of 4. On the first call, you get 4 * fact(3). You push this into the
stack and in the next call, you get 3 * fact(2). Again, you push the intermediate
NOTES result to stack and evaluate fact(2) to get 2 * fact(1). This is also
put to stack. Now, you pass fact 1 and get fact(1) as 1, after which
you get the value of fact(2) by popping fact(2) as 2 * fact(1).
The popping continues till the result is obtained. Such a conceptualization will help
you to understand recursion easily.
8.4.2 Implementation of Euclid’s gcd Algorithm
Euclid’s gcd algorithm is quite suitable for recursion. The modified algorithm,
which uses recursion, is as follows:
Algorithm using recursion
Main function
Step 1 Read two integers m and n
Step 2 Call function gcd (m, n)
Step 3 Print gcd
Function gcd (m, n)
Step 1 if (n==0) return m;
else
return (gcd(n, m%n));
Step 3 End
When two integers are received, the main function calls gcd function. In
the gcd function, it is checked whether n equals zero. If so, m is the gcd if not,
the function calls gcd again by changing the arguments as follows:
m=n
n=m%n
See the clarity in the above function.
You can easily observe that by using recursion, even the number of steps in
the program has gone down. But, it requires a little skill to convert the program
into a recursive function. The program implementing the above algorithm is as
follows:
/*Example 8.8*
Euclid’s GCD*/
#include<stdio.h>
int main()
{
int m, n;
int gcd(int m, int n);
Self-Instructional
152 Material
printf(“Enter 2 integers\n”); Functions Basics
scanf(“%d %d”, &m,&n);
printf(“GCD of %d and %d=%d”, m, n, gcd(m,n));
}
NOTES
int gcd(int m, int n)
{
if (n==0) return m;
else
return (gcd(n, m%n));
}
The program was executed twice and the result of the program is as follows:
Result of the program
First Time
Enter 2 integers
12 256
GCD of 12 and 256=4
Second Time
Enter 2 integers
1225 625
GCD of 1225 and 625=25
You can even enter the first number to be lower than the second number as
executed during the first time. The program works all right because in one iteration,
the numbers get reversed namely the first number is larger than the second number
after iteration. Thus, recursion is quite suitable for solving this problem.
Actual parameters: These are the parameters that appear in function calls.
Formal parameters: These are the parameters that appear in function
declarations.
1. Find the output of the following program and then confirm your findings by
executing the same.
#include <stdio.h> NOTES
int main()
{
float z=0.0;
int y;
` float div(int x);
for (y=0; y<=10; y++)
{
z=div(y+2);
printf(“result=%f\n”, z);
}
}
float div(int n)
{
float b, c=2.0;
b=n/c;
return b;
}
2. Explain the following:
(a) Function
(b) Formal vs actual parameters
(c) Return statement
(d) A function calling multiple functions
3. Explain the recursive factorial algorithm for finding the factorial of 7.
4. Describe what the following programs do:
(a)
#include <stdio.h>
int main()
{
int j, k=100;
int functn(int m);
functn(k);
printf(“%d”,k);
}
int functn(int k) Self-Instructional
Material 155
Functions Basics {
if (k<=0) return 0;
if(k==1) return 1;
else
NOTES
return functn(k-1);
}
(b)
#include <stdio.h>
int main()
{
int j, k=100;
int functn(int m);
j=functn(k);
printf(“%d”, j);
}
int functn(int k)
{
if (k<=0) return 0;
if(k==1) return 1;
else
return (k+functn(k-1));
}
Self-Instructional
156 Material
Structure and Union
9.0 INTRODUCTION
In this unit, you will learn about structures and union. A structure is a user-defined
data type like an array. While an array contains elements of the same data type, a
structure contains members of varying data types. A structure declaration ends
with a semicolon and the keyword is struct. The tag for structure is optional.
Structures can be passed by reference and can be nested. Unions help in conserving
memory as only one of the many variables will be used at a time. The syntax of a
union is similar to that of structure.
9.1 OBJECTIVES
For example, int I means that I is an integer variable. Similarly, the following
is a structure variable declaration:
struct book s1;
NOTES
Here s1 is a variable of type structure book. Suppose, you define,
struct book s1, s2 ;
This means that there are two variables s1 and s2 of type struct
book. These variables can hold different values for their members.
Another point to be noted is that the structure declaration appears above all
other declarations. An example which does nothing but defines structure and
declares structure variables is as follows:
main ( )
{
struct book
{
char title [25];
char author [15];
char publisher [25];
float price;
unsigned year;
};
struct book s1, s2, s3 ;
}
If you want to define a large number of books, then how will you modify the
structure variable declaration? It will be as follows:
struct book s[1000];
This will allocate space for storing 1000 structures or records of books.
However, how much storage space will be allocated for each element of the array?
It will be the sum of storage spaces required for each member. In struct book,
the storage space required will be as follows:
title 25 + 1 (for NULL to indicate end of string)
author 15 + 1
publisher 25 + 1
price 4
year 2
Therefore, the system allots space for 1000 structure variables each with
the above requirement. Space is allocated only after seeing the structure variable
declaration.
Self-Instructional
Material 159
Structure and Union Look at another example to make the concept clear. You know that the
bank account of each account holder is a record. Now, define a structure for it.
struct account
{
NOTES
unsigned number;
char name [15];
int balance ;
} a1, a2;
Instead of declaring separate structure variables, such as struct
account a1, a2; we can use coding as in the example given above. Here,
the variables are declared just after the closing brace of the structure declaration
and terminated with a semicolon. This is perfectly correct. The declaration of the
members of the structure is clear; the balance has been declared as an integer
instead of a float to make it simple. This means that the minimum transaction is
a rupee.
9.2.2 Processing a Structure
The structure variable declaration is of no use unless the variables are assigned
values. Here, each member has to be specifically accessed for each structure
variable. For example, to assign the account number for variable a1, you have to
specify as follows:
a1. number = 0001 ;
There is a dot operator between the structure variable name and the member
name or tag.
Suppose, you then want to assign account no.2 to a2, it can be assigned as
follows:
a2. number = 2;
If you want to know the address where a2 number is stored, you can use
printf (“ %u “ , & a2 . number) ;
This is similar to other data types. The structure is a complex data type and
therefore, you have to indicate which structure variable to which the member
belongs as; otherwise, the number is common to all the structure variables, such
as a1, a2, a3, etc., Therefore, it is necessary to be specific. Assuming that
you want to get the value from the keyboard, you can use scanf() as follows:
scanf ( “ % u “, & a1 . number ) ;
You can also assign initial values directly as follows:
struct account a1 = { 0001, “Vasu”, 1000};
struct account a2 = { 0002, “Ram”, 1500 };
Self-Instructional
160 Material
All the members are specified. This is similar to the declaration of initial Structure and Union
values for arrays. However, note the semicolon after the closing brace. The
struct a1 will, therefore, receive the values for the members in the order in
which they appear. Therefore, you must give the values in the right order and they
will be accepted automatically as follows: NOTES
a1 . number = 0001
a1 . name = Vasu
a1 . balance = 1000
Note too that if the initial values are assigned as above, inside a function,
they will be treated as static variables. If they are declared before main, they
will be treated as global variables.
Let us write a program to create a structure account, open 2 accounts with
initial deposits in the accounts. Deposit Rs 1000 to Vasu’s account, withdraw 500
from Ram’s account and print the balance. The following example demonstrates
the above.
/*Example 9.1 - structures*
#include<stdio.h>
int main()
{
struct account
{
unsigned number;
char name[15];
int balance;
};
static struct account a1= {001, “VASU”, 1000};
static struct account a2= {002, “RAM”, 2000};
a1.balance+=1000;
a2.balance-=500;
printf(“A/c No:=%u\t Name:=%s\t Balance:=%d\n”,
a1.number, a1.name, a1.balance);
printf(“A/c No:=%u\t Name:=%s\t balance:=%d\n”,
a2.number, a2.name, a2.balance);
}
Result of the program
A/c No:=1 Name:=VASU Balance:=2000
A/c No:=2 Name:=RAM balance:=1500
A simple program was written for a bank transaction. For a deposit, we
write
a1 . balance = a1 . balance + 1000 ;
Self-Instructional
Material 161
Structure and Union Therefore, the balance is updated. Similarly, when an amount is withdrawn,
the balance is adjusted. However, in practice, the user cannot write a program for
each credit and deposit. You will develop a program soon which will not require
the user to do programming.
NOTES
9.2.3 User-Defined Data Type
A structure is also a data type. It is not a basic type defined in C language like
int, float, etc. But, it is defined by the programmer. Hence, it is called as
user-defined data type.
Array of Structures
Let us now create an array of structures for the account. This is nothing but an
array of accounts, declared with size. Let us restrict the size to 5. The records will
be created by using keyboard entry. The program is given below:
/*Example 9.2 - to demonstrate structures*
#include<stdio.h>
int main()
{
struct account
{
unsigned number;
char name[15];
int balance;
}a[5];
int i;
for(i=0; i<=4; i++)
{
printf(“A/c No:=\t Name:=\t Balance:=\n”);
scanf(“%u%s%d”, &a[i].number, a[i].name,
&a[i].balance);
}
for(i=0; i<=4; i++)
{
printf(“A/c No:=%u\t Name:=%s\t Balance:=%d\n”,
a[i].number, a[i].name, a[i].balance);
}
}
Self-Instructional
162 Material
Result of the program Structure and Union
{
printf(“name does not match\n”);
return b; NOTES
}
}
else
{
printf(“account number does not match\n”);
return b;
}
}
Result of the program
A/c No:=1 Name:=VASU Balance:=1000
Enter account number
1
Enter name in caps
VASU
enter deposit made
4600
A/c No:=1 Name:=VASU new balance:=5600
Now, look at the program carefully. A function prototype has been declared
in main() as given below:
int credit(unsigned a, char *n, int d);
Here, there is no reference to structure at all. A structure a1 is passed to
function credit by passing individual elements of a structure. In function
credit, these values are received. Then, the deposit is entered and added to
the balance after checking the correctness of the details of the account. The new
balance is returned to main and stored in a1.
9.2.5 Structure Passing to Functions
Passing each member of the structure is a tedious job. The entire structure can
instead be passed to the function making for easy handling. The above example
can be altered by passing an entire structure, as follows:
/*Example 9.4 - passing entire structure to function*/
#include<stdio.h>
struct account
{
unsigned number; Self-Instructional
Material 165
Structure and Union char name[15];
int balance;
};
int main()
NOTES
{
static struct account a1= {001, “Vasu”, 1000};
struct account credit(struct account x);
printf(“A/c No:=%u\t Name:=%s\t Balance:=%d\n”,
a1.number, a1.name, a1.balance);
a1=credit(a1);
printf(“A/c No:=%u\t Name:=%s\t Balance:=%d\n”,
a1.number, a1.name, a1.balance);
}
struct account credit(struct account y)
{
int x;
printf(“enter deposit made”);
scanf(“%d”, &x);
y.balance+=x;
return y;
}
Result of the program
A/c No:=1 Name:=Vasu Balance:=1000
enter deposit made 6700
A/c No:=1 Name:=Vasu Balance:=7700
If you want to pass a structure, the called function should also know the
structure and hence, the structure has to be declared before the main function.
Therefore, structure account has been declared as a global structure. The
function credit is declared with return data type structure as follows:
struct account credit(struct account x);
Thus, you pass and return struct account. Then, credit is
called by simply passing structure a1. In the called program, the deposit is added
to the balance and updated. This is returned to the main() where the updated
record is printed.
9.2.6 Structure Within Structure
You have been nesting if statement and loops so far. You can now create structures
within structures. Here, a structure defined earlier can become a member of another
structure. For example, you can create a structure called deposit using other data
Self-Instructional
166 Material
types and structure account. The declaration of the basic structure should precede Structure and Union
Self-Instructional
168 Material
Now, to access loan amount, we have to specify: Structure and Union
loan1 . amount
To access deposit amount, we have to specify:
oan1 . dep . amount NOTES
To access the balance, we have to specify:
loan1 . dep . ac . balance
Therefore, usage of the same variable name amount has not resulted in a
conflict since it has to be seen in which context it is defined. Thus, structures can
be used within structures without difficulty.
Structure containing arrays
You saw some members of structures being arrays. You used them to represent an
array of characters. You can also have integer, float arrays as members of
structures. For example,
struct fixed_deposit
{
unsigned Ac_Number;
char name[25];
double deposit[4];
}rama;
Here, you have defined a structure fixed_deposit and declared a
variable rama of the same type. In the structure definition, you have a member
deposit as an array of double of size 4. This means, you can store 4 deposits
of rama. This is called array within structure.
You can access the first deposit of rama by the following:
rama.deposit[0]
The last deposit of rama can be accessed by:
rama.deposit[3]
Application of structures
Structures, as you know, can be used for database management. They can be
used in several applications, such as libraries, departmental stores, banking, etc.
Structures are also used in C++. The syntax of structures is similar to classes in
C++. Structures contain data but classes contain data and functions.
Structures are also used in a variety of other applications, such as:
Graphics
Formatting floppy discs
Mouse movement
Payroll
Thus, structure is a very useful construct. Self-Instructional
Material 169
Structure and Union
Self-Instructional
170 Material
However, the difference is: Structure and Union
(i) The memory size of the structure variable is the sum of the sizes of its
members, whereas in union, it is the largest size of its members.
(ii) It is the programmer’s responsibility to keep track of which type is
NOTES
currently in use unlike in structure where no member is lost.
(iii) In structures, all members can be initialized, whereas a union can
only be initialized with a value of the type of its first member.
A program using union to store either an int value or float value is
given as follows:
/* Example 9.6 – Demonstrate union */
#include <stdio.h>
#include <conio.h>
union sel
{ int n;
float f;
};
int main()
{ union sel m1;
void printval(union sel *m1,char type);
char type =’p’;
char cont =’y’;
while(cont==’y’)
{
printf(“\nWant to enter Integer Or Float (i/
f):”);
type=getche();
if(type==’i’)
{
printf(“\nEnter Integer Value :”);
scanf(“%d”,&m1.n);
}
else
{
printf(“\nEnter Float Value :”);
scanf(“%f”,&m1.f);
}
printval(&m1,type);
printf(“\nWant to continue- enter (y/n):”);
cont=getche();
Self-Instructional
Material 171
Structure and Union }
}
void printval(union sel *m1,char type)
{
NOTES
if(type==’i’)
printf(“Integer Value Is %d\n”,m1->n);
else
printf(“Float Value Is %f\n”,m1->f);
}
Result of the program
Want to enter Integer Or Float (i/f):i
Enter Integer Value :456
Integer Value Is 456
Want to continue- enter (y/n):y
Want to enter Integer Or Float (i/f):3
Enter Float Value :300.30
Float Value Is 300.299988
Want to continue- enter (y/n):n
The union sel is declared before main, with two members int
n and float f. A function printval is also declared. Depending upon
whether the user wants an integer value or float value, type is set to i or
f. If type is i, integer value is received and if it is f, a float value is received.
The value received is printed in the function printval. Note carefully how the
pointer to union is declared in the function prototype and header. You have to
declare union whenever you pass a union to a function. It is declared as
union sel * m1. As you would have declared int * i, the type here is
union sel.
If you have perused the result, you would find that the program asks for
float value, although 3 has been typed instead of f. It is because of the design
of the program. It will ask for float value when a character other than i is
typed. You can take this as an exercise to correct the program to ask for float
value only when ‘f’ is typed.
Now, consider another example.
In the case of an employee database, you would like to store either the
father’s name (in the case of men and unmarried women), the husband’s name in
the case of married women or the guardian’s name. This can be represented as a
union as shown below:
Union guardian
{
Self-Instructional char father [10];
172 Material
char husband [10]; Structure and Union
printf(“Name:%s\nbirthdate:%s\nguardian:%s\n”,
emp[i].name, emp[i]. birthdate,
emp[i].u.husband);
}
}
Result of the program
Name:SITA
birthdate:19/11/1958
guardian:RAM
The employee details are given in the form of struct emp which also
contains union for guardian. All the string variables have been given as
pointers to char. The struct is defined as an array of size 2 and the initial
values of emp[0] and emp[1] are assigned for each member. Next, the data
of employees whose basic equals 12000 are printed. Note how the union is
handled. You will note that in such cases when only one of the three will be entered,
there is no need to reserve memory for storing 3 variables. It is enough to store
only one of them. A union provides a methodology for achieving this.
1. A structure contains different data elements whereas an array contains same NOTES
data elements.
2. Keyword struct is used to declare a structure.
3. A structure is like a record that contains fields as name of variables. These
variables are known as members.
4. A structure is created with the keyword struct followed by a name
which is optional. The beginning of a structure is denoted by an opening
brace in which members of the structure are declared. These members can
be of different data types. Declaration of structure is completed by a closing
brace followed by a semicolon.
5. A union is a variable that holds a common assigned area for different
data types but only one is used at a time. It is declared with a keyword
union followed by a name (which is optional) above the opening brace
and defining members as done in case of structure.
6. In structures, all members can be initialized, whereas a union can only
be initialized with a value of the type of its first member.
9.5 SUMMARY
Self-Instructional
176 Material
Pointers
BLOCK - IV
POINTERS
NOTES
UNIT 10 POINTERS
Structure
10.0 Introduction
10.1 Objectives
10.2 Concept of Pointer
10.2.1 Pointer Arithmetic
10.3 Answers to Check Your Progress Questions
10.4 Summary
10.5 Key Words
10.6 Self Assessment Questions and Exercises
10.7 Further Readings
10.0 INTRODUCTION
In this unit, you will learn about the pointers. The pointer is a powerful concept of
C and is closely associated with memory addressing. It is an integer variable,
which contains the address of a variable. These variables are stored in the memory
and each location in the memory has an address. It can point to any data type. The
storage capacity varies from machine to machine. Pointer arithmetic will make the
concept of pointers clear and unambiguous. You can call a function and pass actual
values to them. The function call using pointers is known as call by reference
where the address of the variable is passed. Functions can also return reference or
pointers.
10.1 OBJECTIVES
Pointer is a one of the unique concepts of C since it facilitates direct access to the
hardware and results in compact coding. It also facilitates returning more than one
value from a function. Pointers are closely associated with memory addressing.
Self-Instructional
Material 177
Pointers We know that constants and variables are stored in memory, and that each location
in memory has an address just as a person has an address. The memory locations
are available in groups of 8 bits or a byte. Each byte in memory has an address.
Therefore, each location has an address and stores a value. The value stored can
NOTES correspond to any data type such as float or char or int and their type modifiers.
However, the addresses themselves will be of type integers. All these data types
are stored in terms of 1s and 0s. We will not go into further details of storage
except to state that each memory location stores a value and has an address. The
memory locations are arranged in increasing order of addresses, starting from
0000, and increases one by one. We may have the address of the last location as
FFFF. What does F denote? The addresses are denoted in terms of hexadecimal
numbers. We can calculate the decimal equivalent of this and find the decimal
address of the last location. The storage capacity varies from machine to machine.
The & operator has been used to denote the address of the variable in the
scanf function. If var is the name of a data type, &var denotes the address of the
location where it is stored. Whenever a data type is declared, a memory location
needs to be allocated depending on the data type. The allocation of memory
space takes place at the time of execution of the program, and therefore the address
of a variable may be different at different times of execution, since the computer
allots it at random depending upon the availability of memory locations. However,
memory locations for each data type will be contiguous so as to make for easy
handling. For instance, a double needs 8 bytes of storage and therefore all the 8
bytes will be stored continuously or contiguously. Each byte of the value of the
variable will be stored one after the other in continuous locations.
For, instance, the following is declared:
float ft =100.52;
Here ft is the name of the variable. Its value is 100.52. This number will be
stored in 4 bytes in the memory in sequentially numbered storage locations. When
we print the value of the address of a variable, it will always print the starting
address. If the starting address and the data type are known it is easy to find out
the locations which are occupied by the variable. For instance, if the starting address
of the float ft is 0011, then the variable will occupy up to memory location 0014.
However, if we print the address of ft, i.e., &ft, we will get 0011.
A similar concept can be extended to a string. A string is an array of characters,
with each character occupying a byte of memory. If Peter is stored in string w, and
if w[o], i.e., p is stored in location 0020, then ‘e’ will be stored in 0021, ‘t’ in 0022
and so on. Every element of an array will also be stored contiguously. The formula
for finding out the location of an element or address of pth element in an array is
given below:
address of pth element= starting address of array + p * (storage space for the
data type)
Self-Instructional
178 Material
Example 10.1 Pointers
If an integer array ia is stored from location 992 onwards, find out the location
of the 10 the element.
Address of 10th element = 992 + 10*4 = 1032. It is the starting point. However, NOTES
the second byte of the integer will be stored in location 1033.
Note: The 10th element will have the subscript 9, since the 1st element has the
subscript 0.
Note: We know that int data type is allocated 2 bytes in some systems and 4
bytes in some systems. For the sake of simplicity we assume that int occupies 2
bytes in this chapter.
Example 10.2
If the 10th element of a long double is stored from location 2000 onwards,
find the location of the 15th element and the first element assuming that long double
occupies 10 bytes.
The 1st element will be stored at location 2000-10*10=1900.
The 15th element will be stored at 1900+15*10=2050.
Let us now consider a pointer to an integer. Let the integer be mark. Then the
address will be denoted as &mark. Note that all addresses will be in integers for
all data types. In the case of pointers, the address of mark will be stored in
another location. The pointer is a variable that contains the address of the variable.
We can assign the address of the integer to an integer pointer. Usually we declare:
int mark; mark=75; we can also declare int *ip; This means ip is a pointer
to the integer. We can assign ip = &mark; i.e. we have assigned the address of
mark to ip. Let us pictorially explain this.
ip*fp; /*invalid*/
ip*2; /*invalid*/
fp/10; /*invalid*/ NOTES
ip = ip*10; /*invalid*/
If we say ip = fp; then both fp and ip will point to the same location, and
hence fp will point to the same variable pointed to by ip.
Pointer is variable too
A pointer is a variable that contains the address of another variable. As you know,
any variable has the following four properties:
(a) name
(b) value
(c) address
(d) data type
For instance, consider the following declaration of a simple integer.
int var = 10;
Here, the name is var, and its value is 10. Its address is not declared here
since we want to give flexibility to the compiler to store it wherever it wants. If we
specify an address, then the compiler must store the value at the same address.
Specifying actual address is carried out during machine language programming.
However, this is not required in High-Level Language (HLL) programming, and
by printing the value of &var, we can find out the address of the variable. When
the statement to find the address is executed at different times, different addresses
will be printed. What is important is that the compiler allocates an address at run
time for each variable and retains this till program execution is completed. This is
not strictly so, in the case of auto variables. The compiler forgets the address of a
variable when the program comes out of the block in which the variable is declared.
At this point you may also recall that in the case of function declarations in the
calling function, the compiler does not allocate memory to the variables in the
declaration. That is the reason why the parameters in the declaration part are not
recognized in the calling function. It is only a prototype.
The fourth feature of a variable is its data type. In the above example, var is
an integer. A pointer has all the four properties of variables. However, the data
type of every pointer is always an integer because it is the value of the memory
address. Memory addresses are integers. They cannot be floats or any other data
types. They may point to an integer or a float or a character or a function, etc.
They have a name. They have a value. For instance the following is a valid
declaration of a pointer to an integer.
int * ip;
Self-Instructional
Material 181
Pointers Here, ip is the name of a pointer. It points to or it contains the address of an
integer, which is the value. It will also be stored in another location in memory like
any other variables. The pointer itself is an integer even though it is not declared as
such.
NOTES
10.2.1 Pointer Arithmetic
Let us look at some examples involving pointers:
Example 10.3
int dat = 100;
int * var;
var = &dat;
Here, dat is an integer variable. Its value is 100; its name is dat; it will be
stored in memory in a location with an address.
The next declaration means that var is a pointer to an integer, and is a variable.
It is an integer, and will be stored at a location in memory with an address. The
value of var is the address of the integer variable it points to. We do not know as
yet which integer it points to. It can, however, be made to point to any integer we
like, by a proper assignment.
Now look at the next assignment. The variable var is assigned the value of
&dat. This means var has the same value as the address of dat. By taking into
consideration the previous statements we can conclude that var is a pointer and it
points to dat.
Now if we specify dat or * var, they point to the same value 100. Similarly, if
we specify &dat or var it is the address or to be precise, the starting address of
dat or * var.
Example 10.4
int * var
* var = 100
The above statements declare var as a pointer to an integer, and later propose
to assign 100 to the integer variable. We do not know or do not want to make
public the name of the variable. However, we can always access the variable as
* var. This works well in Borland C++ compilers, but could lead to run time
errors in other compilers.
Both the statements cannot be combined into one as int * var = 100. This will
be flagged as an error even in the Borland C++ compiler. Therefore it is not
possible to combine both the declaration and assignment insofar as a pointer variable
and integer constant are concerned. It would be safer to make var point to another
variable as given in Example 10.3.
Self-Instructional
182 Material
Example 10.5 Pointers
int * var;
* var = 100;
Note: If this gives an error while compiling or while running the program, NOTES
modify this as in Example 10.3 above.
What will be the value of the output of the following statements after the
execution of the following statements?
printf (“%d”, * var);
printf (“%d”, (* var) ++);
printf (“%d”, * var);
printf (“%d”, var);
We can easily guess that the first printf will give the value of * var as 100.
What is the significance of the parentheses and the increment operation, in the
second statement? As the bracket or parentheses has precedence over other
operators, the value of * var will be printed as 100. After printing, it will be
incremented as 101, because the increment is postfix the value of * var after
execution of the statement will be 101. The next statement will confirm this when
it prints 101.
The fourth printf case prints the address of var. It printed 1192 at one of the
attempts. We are unlikely to get the same address on execution. The location
where the variable is stored will not vary till the execution of the program is
completed. If we try the program again, we will get a different address.. It does
not affect our work. However, we may note down the value and substitute it for
the values mentioned here for understanding the concept of pointers.
Remember to enclose the pointer variable within parenthesis as given in the
example. The postfix of the increment operator, enables increment of the variable
after printing.
Note: In the examples we are assuming that int occupies 2 bytes.
Example 10.6
After execution of the above 4-printf statements, we execute the following
statements:
printf (“%d”, * var ++);
printf (“%d”, * case);
What happens? The value of * var, i.e., 101 is the first to be printed out and
then var will be incremented, i.e., instead of incrementing the value as desired, the
address is incremented, and therefore var now points to the next location.
Remember, var was pointing to 1192! Will it go to 1193? No. Since var is an
integer, 1192 and 1193 (2 bytes) are already occupied and hence var points to
1194. The next statement prints the value of * var. We had stored 101 in location
Self-Instructional
Material 183
Pointers 1192. We don’t know what is contained in 1194. Hence the next printf will print
garbage value. Note carefully what happened. We wanted to increment * var in
the first statement of example 4. However, the compiler has assumed that we
wanted to increment the pointer which underlines the importance of parenthesis.
NOTES Also note that whenever we use postfix notation, the postfix operation is effective
only after execution of the statement.
Is everything lost now? Can we not go back to address 1192? Yes, we can as
the following indicates. Note that the following statements are executed in
continuation of all the above statements.
Example 10.7
printf (“%d”, var) ;
printf (“%d”, – – var) ;
printf (“%d”, * var) ;
The first statement in this example prints the address of the location in memory
pointed to by var. As expected the pointer is at the location 1194. The second
statement carries out two operations in the sequence given below:
(a) decrement the pointer
(b) print the new address.
Decrementing takes place before printing because it is a prefix operator. Now
it prints 1192, the original address is restored. Now the third statement prints the
value of * var or the value stored in location 1192, i.e., 101.
Note that prefix, carries out the increment or decrement before printing or any
desired operation, whereas postfix does that after printing. Note that we are
discussing the fundamentals of pointers, and that they should be understood clearly
before you proceed further.
We now have 101 stored in address 1192 and pointed to by var. Let us see
what happens on execution of the following statements, in continuation.
Example 10.8
printf (“%d”, ++ (* var));
printf (“%d”, var);
These statements are perfectly correct. * var is incremented and the new
value printed in the first statement. Therefore 102 will be printed. Has the address
been changed? No. Hence the second statement will print the address as 1192.
Can we increment and decrement addresses? Yes, as the following indicates.
Example 10.9
printf (“%d”, var ++);
printf (“%d”, var) ;
Self-Instructional
184 Material
What will be printed in the first statement above, 1192, or 1194? It will be Pointers
1192, because incrementing var will take place after the first printf. Obviously the
second statement will print the address incremented after the previous printf, viz.,
1194. Let us not lose track, but get back to the old address, and try prefixing
increment / decrement operators to the address. NOTES
Example 10.10
var – –; (a)
printf (“%d”, var) ; (b)
printf (“% d”, ++ var) ; (c)
printf (“% d”, – – var) ; (d)
printf (“% d”, var) ; (e)
printf (“% d”, * var) (f)
Before execution of the first statement in this example, we have:
var = 1194
location 1192 contains 102
Let us now analyze the execution statement-wise.
(a) decrements var to 1192
(b) confirms that var is 1192 indeed.
(c) ++ var, increments var and then prints as 1194.
(d) – – var decrements var and then prints as 1192
(e) confirms var is 1192
(f) The value in var is 102.
Now the concepts are becoming clearer. Let us carry out one more exercise
as in Example 10.11 Assume that all the above statements were executed and the
following are now executed.
Example 10.11
printf (“%d”, * (var ++)) ; (g)
printf (“%d”, * (– – var)) ; (h)
printf (“%d”, var) ; (i)
printf (“%d”, * var) ; (j)
(g)Here, * var is printed as 102 because of the postfix operator. Then var,
i.e., the address is incremented to 1194.
(h)Here because of the prefix, var is decremented to 1192 and then the
value at 1192, i.e., 102 is printed.
The next 2 statements confirm this.
Self-Instructional
Material 185
Pointers Now you would be familiar with intricacies of pointers, prefix, suffix and
parenthesis. To gain more confidence do the exercise at the end of the chapter
before proceeding further. In order to confirm our discussions regarding the basic
principles of pointers a program involving all these statements and the output are
NOTES given below.
Example 10.12
/* pointers*/
#include <stdio.h>
int main()
{
int * var;
int a =100;
var = &a;
printf(“value of * var=%d\n”, *var);
printf(“value of (*var)++=%d\n”, (*var)++);
printf(“value of * var=%d\n”, *var);
printf(“address var=%d\n”, var);
printf(“value of *var++=%d\n”, *var++);
printf(“value of * var=%d\n”, *var);
printf(“address var=%d\n”, var);
printf(“original address var again=%d\n”, —var);
/*original address restored*/
printf(“value of * var=%d\n”, *var);
printf(“value of ++(*var)=%d\n”, ++(*var));
printf(“address var=%d\n”, var);
printf(“address var++=%d\n”, var++);
printf(“address var=%d\n”, var);
var—;
printf(“address var after decrementing=%d\n”, var);
printf(“address ++var=%d\n”, ++var);
printf(“address – –var=%d\n”, – –var);
printf(“address var=%d\n”, var);
printf(“value of * var=%d\n”, *var);
printf(“value of *(var++)=%d\n”, *(var++));
printf(“value of *(– –var) = %d\n”, *(– –var));
printf(“address var=%d\n”, var);
printf(“value of * var=%d\n”, *var);
}
Result of program when executed subsequently
value of * var=100
value of (*var)++=100
value of * var=101
address var=9106
value of *var++=101
Self-Instructional
186 Material
value of * var=9108 Pointers
address var=9108
original address var again=9106
value of * var=101
value of ++(*var)=102 NOTES
address var=9106
address var++=9106
address var=9108
address var after decrementing=9106
address ++var=9108
address – –var=9106
address var=9106
value of * var=102
value of * (var++)=102
value of *(– –var) = 102
address var=9106
value of * var=102
function ‘Call by Reference’
We have been calling functions and passing actual values to them. When we call
functions, we pass actual arguments as per the list provided in the declaration.
These are all values, which are passed to a function, and this method is called call
by value. In call by value, we can return only one value from a function, and
therefore it puts restrictions on the usage of functions. This can be overcome by
using call by reference, where any number of values can be indirectly returned.
Call by reference can be implemented by using pointers as in the example 10.13:
Assume that we want to pass a and b to a function, divide a by b and return
both the quotient and remainder to the main function. It is not possible to do this
by call by value. Call by value can return only a single value, either the quotient or
remainder, but not both. This can be achieved by call by reference as the following
example demonstrates.
Example 10.13
/* to demonstrate function call by reference*/
#include <stdio.h>
int main()
{
int a=100, b=13;
void div(int *p, int *q);/*indicates call by reference*/
div(&a, &b);/*addresses of a and b are passed*/
printf(“quotient= %d remainder= %d\n “, a, b);
}
/*function definition*/
void div(int *px, int *py) /*function declarator*/
{
Self-Instructional
Material 187
Pointers int temp1, temp2;
temp1=*px;
temp2=*py;
*px=temp1/temp2;
NOTES *py=temp1%temp2;
}
Result of program
quotient= 7 remainder= 9
How does the program work?
In the declaration part, we have declared div as a function passing two pointer
variables and getting back void or none. We call div(&a, &b). We don’t pass the
values, but reference to the values. We actually pass the address of a and b to
function div.
The function div receives the reference, i.e., addresses of a & b.
px = &a;
py = &b;
px points to a and py points to b. Hence *px gets the value of a and *py gets
the value of b. Now the contents of *px and *py, i.e., a and b are copied to
temp1 and temp2.
We divide temp1 by temp2 and place the result in variable *px whose address
is known to both main and the function div. In the main function the address
corresponds to a and in the function it corresponds to *px. Therefore the address
of the quotient is returned to the main function indirectly. Similarly *py contains the
remainder. It will be stored in b through the reference. Thus, the values of the
quotient and remainder are stored in locations &a and &b, and we have indirectly
returned 2 values to main through call by reference. The concept, though, may
seem hazy at this point, will become clear as we see more examples. Some more
points are to be noted carefully;
The function declaration indicates that there is a function div, which returns
nothing. It passes two pointers to integers. The pointers are declared as int*p and
int*q. You will notice that they are not declared in the main function and therefore
p and q have no significance except to indicate that they are pointers to integers.
They also indicate that the addresses of two integers are to be passed while calling
the function.
Self-Instructional
188 Material
Pointers
10.3 ANSWERS TO CHECK YOUR PROGRESS
QUESTIONS
1. The & operator has been used to denote the address of the variable in the NOTES
scanf function. If var is the name of a data type, &var denotes the address
of the location where it is stored.
2. A pointer is a variable that contains the address of another variable.
3. The following is a valid declaration of a pointer to an integer.
int *ip;
10.4 SUMMARY
Pointer: A variable that contains the address (not the value) of another
variable or a literal.
& operator: It provides the address of the pointer variable where it is
stored in the memory.
Self-Instructional
190 Material
Pointers as Functions
11.0 INTRODUCTION
In this unit, you will learn about the pointer as function, array of pointers and
pointer scale factors. Pointer as a function parameter is used to hold addresses of
arguments passed during function call. This is also known as call by reference.
When a function is called by reference any change made to the reference variable
will effect the original variable. Array of pointers is the array that holds memory
locations.
11.1 OBJECTIVES
The function call using pointers is known as ‘call by reference’. Here, the address
of the variable is passed. Note that calling by reference has to be indicated in the
function declaration such as these:
fun (int *p, char *cp, float *fp, int *array);
Self-Instructional
Material 191
Pointer as Functions This is an indication that the function is to be called by reference for those
parameters which are pointers. A mixed declaration could also be used as given
below:
fun1(int a, char *cp);
NOTES
Here, we are indicating that an integer is passed by value and a character
variable is passed by reference. In the above example, while we can either pass a
character array (string) or a character through the second declaration, we can
only pass one integer variable through the first parameter.
The function declarator above the function body has to match the declaration.
Hence when fun1 is called, an integer followed by an address of character will be
passed. In the function fun1 we may have a declarator as follows:
fun1(int d, char * ch)
Here, the value of the integer variable will be automatically get assigned d, and
the ch will be assigned the address of the character variable. This means both ch
and the address of the character variable in the calling function will point to the
same location. Thus, both in the calling function and in the called function, the
variable is accessible, although under different names. Any modification made to
the character variable either in the calling function or the called function affects
both.
While calling by reference, we have to pass the address of the variable. If the
variable is declared by value such as int a, then we have to pass &a. If it was
declared as a pointer to say, an integer such as int * ip, then ip has to be passed.
Function ‘Return by Reference’
So far we have seen functions returning only a value, irrespective of whether they
were called by value or by reference. Functions can also return reference or pointers.
Whenever a function is to return a pointer, this has to be indicated by the
following:
Function Declaration
Declare the function as returning pointers. For instance,
int * fun1() ;
char * fun2() ;
float * fun3 (int a, float * b, char * c) ;
The difference is the insertion of pointer(*) between the return data type and
the function name.
Function Declarator
This will be in the same format as the prototype or function declaration. For
instance,
Self-Instructional
192 Material
float * fun3 (int a, float * b, char * c) Pointers as Functions
Result of program
131
The called function returns the address of the greatest number in the array.
Look at the function declaration. The function returning a pointer is indicated by
the following (a starmark between the return data type and function name).
Self-Instructional
Material 193
Pointer as Functions int * fung(...)
The address of array [0] is received by fung() and stored in *p2. In other
words, p2 points to the 0th location of the array.
NOTES Pointer Notations for Arrays
At this point we must note another way of representing the elements of the array.
The address of the 0th element is stored at the location p2 or address p2 +0.
The element with a subscript 1 of the array will be at one location above or at p2
+ 1. Thus the address of the nth element of this array *p2 will be at address p2 +
n. If we know the value of the pointer variable, i.e., the address of the pointer,
then it would be easy to express its value. The value of the integer stored at the nth
location can be represented as * (p2 + n) just as the value at address (p2+0) is
*(p2 + 0) or * p2. This notation is, therefore, quite handy.
The if statement compares maxp with *(p2 + j) or p2 [j] or array [j]. You
will easily understand the logic of getting the maximum or greatest number in * (p2
+ j). At the end of the iterations, * (p2 + j) which is stored at location p2 + j
contains the maximum value in the array, and therefore we are returning an address
or reference to the called function. In this example (p2 + 3) is the address of the
greatest number in the array. After return from the function, max gets the value of
p2 + j. In the printf *max which is the value stored in max is printed. We have
already defined max as a pointer to an integer in the main function. Thus, the
function fung returns the address of a value or a pointer, and by returning the
address, the value is retrieved automatically by the main function.
Arrays and Pointers
Example 11.1 involved arrays and pointers. Use of a pointer made the passing of
an array to a function a simple task. We define array as an integer. However, in
order to pass an address, the prototype was defined with a pointer argument int *
p1. This means an address will be passed to the function while calling it. No
distinction was made between a simple integer variable and an integer array. int *
p1 can be a single valued integer or an array. This is possible because arrays are
stored contiguously in memory. If the address of the 0th element is known, and the
data type is known, it would not be difficult to calculate the address of any element
in the array. Therefore, it is enough if the address of the 0th element is passed to a
function. *p1 refers to the address of a variable or to the 0th element of an array.
Note the flexibility of arrays in “C” and how intelligently the language uses pointers.
While calling, a function, the address has to be passed, and this is achieved in
the above example by passing & array[0].
In the called program *p2 is treated as an array without any additional efforts.
By adding the index to p2 we get the address of the various elements in the array.
Getting value is achieved by placing * before the address. Let us look at another
example using arrays and pointers, as given below:
Self-Instructional
194 Material
Example 11.2 Passing an array of integers to function. Pointers as Functions
*method2*/
#include<stdio.h>
int main()
{ NOTES
int array[]={10, 20, 30, 40, 50};
int *a;
void pass(int *a, int k);
a=&array[0];
pass(a, 4);
}
void pass(int *b, int j)
{
int k=0;
while (k <= j)
{
(*b)=(*b)/2;
printf(“value %d @ address %d\n”, *b, b);
k++;
b++;
}
}
Result of program
value 5 @ address 8694
value 10 @ address 8696
value 15 @ address 8698
value 20 @ address 8700
value 25 @ address 8702
Here, * a has been declared as a pointer to integer. The variable a has been
assigned the address of the 0th element of the array. Now the function call is made
using pass (a, 4); Again a is the address of the variable array [0].
In the function pass, b received the address of a, and the next element of the
array is accessed each time by incrementing the address b. Note that the values of
the elements in the array are divided by 2 in the called function. As we become
familiar with pointers we can write programs very easily.
11.2.2 Pointer Notation for Multi-dimensional Arrays
We may represent a two-dimensional array conventionally as a[i][j].
The elements of a two-dimensional array of size 3x3 can be represented
symbolically as given below:
a00 a01 a02
a10 a11 a12
a20 a21 a22
Self-Instructional
Material 195
Pointer as Functions We can then visualize this as an array of arrays. Do not get puzzled. Each row
is an array, and we have three such arrays. Thus, a two-dimensional array can be
considered as an array of one-dimensional arrays. Therefore, we can expect the
following type of memory allocation by the system:
NOTES
0 1 2 0 1 2 0 1 2
a[0][0] a[1][0] a[2][0]
This means all the elements of the 0 row are stored contiguously. a[0][0] is
th
stored first, followed by all elements of the 0th row. Next, the first row starts with
the first element a[1][0]. At the end of the first row, the second row starts with
a[2][0]. Try to visualize how the elements of a two-dimensional array are stored
contiguously.
You know that
a[i] = * (air)
where a + i is the address of the element.
You also know that
a [0] = * a and its address is stored in location a.
You can now transform a two dimensional array into this convenient form.
You can visualize **b[0], **b[1] and **b[2] to represent the values of row
first elements which are stored at locations *b[0], *b[1] and *b[2] as given
below:
0 1 2 0 1 2 0 1 2
Address *b[0] *b[1] *b[2]
** indicates pointer to pointer. This is acceptable since the row pointers in
turn point to column pointers. If you assume the first row elements as pointers,
then the addresses of elements of the two-dimensional arrays can be addressed
by simple arithmetic.
*b points to the value in the one-dimensional array. Then **b refers to the
value in the two-dimensional array. All elements of the two dimensional array are
stored contiguously. From the storage pattern we declare the following:
**b refers to the value at the 0th row of a two-dimensional array. Naturally,
the address of the 0th row will be *b.
**(b+1) refers to the value of the 0th element in the 1st row. Its address will be
*(b+1)
In general the 0th element in ith row contains the value **(b+i) and its address
is *(b+i).
We have only talked about the 0th element in each row, i.e., where the row
starts conceptually. How do we address the other elements? You know that an
element b[i][j] is the jth element in the ith row,
Self-Instructional
196 Material
We know the address of the 0th element. It is * (b+i). Therefore, the address Pointers as Functions
of the jth element in ith row will be (* (b+i) + j). Note, j is the offset. Therefore, the
value at this location can be expressed as * ( * ( b + i ) + j ). We have just added
a star outside the address.
NOTES
Now the address of the 2nd element in the 2nd row will be
(*( b + 2 ) + 2)
Its value will be
*( * ( b + 2 ) + 2 )
What will be the address of the 0th element in the second row
(*(b + 2 ))
What will the value be?
*( * ( b + 2 ))
Note the parentheses and *. To understand this clearly, execute the following
program.
Example 11.3 To understand pointers to 2 dimensional array.
#include<stdio.h>
int main()
{
int i,j;
int a[3][3];
printf(“Enter the values of 3x3 matrix\n”);
for (i=0; i<=2; i++)
for(j=0; j<=2; j++)
scanf(“%d”, (*(a+i)+j));
for (i=0; i<=2; i++)
{
for (j=0; j<=2; j++)
{
printf(“address=%d\n”, (*(a+i)+j));
printf(“value=%d\n”, *(*(a+i)+j));
}
}
}
Result of program
Enter the values of 3x3 matrix
00 01 02
10 11 12
20 21 22
address=9098
value=0
address=9100
value=1
address=9102
value=2
Self-Instructional
Material 197
Pointer as Functions address=9104
value=10
address=9106
value=11
address=9108
NOTES value=12
address=9110
value=20
address=9112
value=21
address=9114
value=22
This example helps us to understand how a two-dimensional array is stored in
the memory. The array has been declared in the normal way without pointers, but
the array elements have been received, stored and printed using pointer notation.
When we execute the above program, we can type the numbers in any one of the
ways given below:
Enter one integer at a time followed by Return
Enter all integers in a row with spaces between them and finally hit Return
Enter three integers in a row as the result of the program indicates.
Since it is a two-dimensional array we would like to input the value in the form
of rows and columns and get the output in the same form. It would be better if the
computer accepts the inputs at the given places and prompts us to do so, as in the
example 11.4
Case Study: Receiving Inputs at Chosen Points
Example 11.4- To accept and print in matrix form.
#include <stdio.h>
#include <conio.h>
int main()
{
int a[3][2];
int i,j;
printf(“Enter values of 3x2 matrix-\n”);
printf(“Press Enter after each value”);
for (i=0; i<=2; i++)
{
for (j=0; j<=1; j++)
{
gotoxy (j*10+10,4+i*2);
scanf(“%d”,(*(a+i)+j));
}
}
for (i=0; i<=2; i++)
{
for (j=0; j<=1; j++)
{
gotoxy (j*10+40, 4+i*2);
Self-Instructional
198 Material
printf(“%d”, *(*(a+i)+j)); Pointers as Functions
}
}
}
Result of program NOTES
Enter values of 3x2 matrix-
Press Enter after each value
00 01 0 1
10 11 10 11
20 21 20 21
A library function gotoxy(x, y) has been used in the program. This function
makes the cursor go to the point (x, y) on the screen. At the first iteration when
both j and i are 0, we will call goto(10,4) while scanning the values and call
goto(40, 4) while printing the values. Therefore, the first value will be scanned on
the 4th line from the top and at the 10th character position. The first value will be
printed at the same line and 40th character position as the result of the program
indicates. Therefore, we can direct the cursor to any position as we like. Thus,
gotoxy() will be quite useful in advanced programming.
This has been used both for scanf() and printf(). The system will scan inputs
from those points and print outputs at the points specified. We can specify any
point on the screen to take inputs and print outputs. When we execute the program
the cursor will go to the specified position. After we have typed one value and
entered the return key, the cursor will blink at the next point, giving the impression
of inputting a matrix. After the values are given, the output also appears in the form
of a matrix. The left pair of numbers is what were entered. Since the same vertical
position, but a different horizontal position has been specified in the program, the
printout appears on the same lines, but to the right of the input values. Try the
program and see for yourself.
Look at the address specification along with the scanf(). It is
( * ( a + i ) + j ) which is equivalent to &a [i][j].
Putting a star before this converts this to the value a [i][j].
This program clearly illustrates the way to handle a two-dimensional array
with pointers.
Although the array could have been declared as **a, it has been declared
with the dimensions of the array. Since it does not know exactly the total number
of elements in the former definition, garbage values may be stored in some more
locations adjacent to the array elements, which can create problems. Some compilers
will cause a run time error, if the array has been declared as **a. Therefore, it
would be better to specify the dimension of the array as given in the above two
examples.
Self-Instructional
Material 199
Pointer as Functions
11.3 CHAIN OF POINTERS/ARRAY OF POINTERS
Result of program
Enter name size NOTES
5
Enter name
Raman
Enter name size
5
Enter name
Gopal
Enter name size
6
Enter name
Sharma
Enter name size
7
Enter name
Ramanan
Enter name size
4
Enter name
Basu
Sorted Names Are :
Basu
Gopal
Raman
Ramanan
Sharma
Here, the user is asked to first enter the number of characters in a name to be
entered. After that the name is entered. This helps in allocating the right size to
each name, no space more, no space less.
We call strcmp and pass references to names being compared. The function
strcmp returns 0 if strings are equal; <0 if string 1 is less than string 2 in ASCII
value; >0 if string 1 is greater than string 2. Thus, names will be exchanged if
*name[j] is less than *name[i]. The string comparison starts from the first character
of each word. If they are equal it will go to the next character and so on, till they
are unequal or NULL is reached in either of them. Then the difference in the
ASCII values of the characters compared last is returned. This is what we wanted
in arranging the names alphabetically. Key in the program and you will find that it
works correctly.
Pointers to functions
We have discussed various aspects of pointers such as pointers to variables,
functions returning pointers, etc. What then, is a pointer to a function? Consider
the following programs.
Self-Instructional
Material 201
Pointer as Functions #include <stdio.h>
int main()
{ char y=’a’;
void func ( char z);
void (*fp) ( char x);
NOTES fp = func ;
(*fp) (y) ;
}
void func ( char x)
{ ...
}
A perusal of the above program indicates that the address of func is assigned
to the function pointer fp. While calling the function, (*fp) (y) is used. Thus fp gets
the address of func, indicating that functions also have addresses. Such function
pointers are used in searching and memory resident programs.
Self-Instructional
202 Material
Pointers as Functions
11.5 ANSWERS TO CHECK YOUR PROGRESS
QUESTIONS
1. The function call using pointers is known as call by reference. Here the NOTES
address of the variable is passed. Note that calling by reference has to be
indicated in the function declaration such as these:
fun (int *p, char *cp, float *fp, int
*array);
2. ** indicates pointer to pointer. This is acceptable since the row pointers in
turn point to the column pointers.
3. The function goto xy (x, y) makes the cursor go to the point (x,
y) on the screen.
11.6 SUMMARY
The function call using pointers is known as ‘call by reference’. Here, the
address of the variable is passed.
While calling by reference, we have to pass the address of the variable. If
the variable is declared by value such as int a, then we have to pass &a. If
it was declared as a pointer to say, an integer such as int * ip, then ip has to
be passed.
We had discussed that a pointer to a one-dimensional array can be denoted
as*b and two-dimensional array can be denoted as **b.
The addresses or pointers can be stepped up or stepped down.
When we say we are comparing pointers, we are comparing their addresses.
Null pointer: It is a type of pointer of any data type and generally takes a
value as zero. It can also take any pointer type, but do not point to any valid
reference or memory address. It is different from a pointer that is not
initialized.
gotoxy(x,y): It is a library function and is used in advanced
programming to direct the cursor to go to the point (x,y) on the screen.
Self-Instructional
Material 203
Pointer as Functions
11.8 SELF ASSESSMENT QUESTIONS AND
EXERCISES
Self-Instructional
204 Material
Strings with Pointer
12.0 INTRODUCTION
In this unit, you will learn about the pointer and character strings. A String is a
sequence of characters stored in an array. Strings can also be declared
using pointers. You will learn about dynamic memory allocation and structures
pointers. Static allocation of memory in case of arrays through dimension leads
either to excessive allocation or short allocation. This can be managed by dynamically
allocating memory at run-time through the functions namely malloc() and
calloc(). The memory allocated using these functions can be freed, when it is
not required using the function free().
12.1 OBJECTIVES
Result of program
length of the word=19
We have a library function strlen() to find the length of the string. This program
carries out the same task although strlen() could be used to find the length of any
string. The program serves to illustrate the concept of strings and pointers easily. It
prints the length of the string in terms of the number of characters. The white
spaces in between will also be counted.
We have initialized *wp while declaring it as a pointer to a character. The
compiler will not normally accept such initialization, but makes an exception for
strings, since there is no anomaly as to whether the initialization is for the value or
the address, as a string cannot be an address, unlike an integer.
Note the statements in the function. The address as well as n are incremented
when the *w is not NULL. NULL indicates the end of string since NULL will be
appended to all the strings. When w points to NULL, there will be no further
increment of w as well as n. Therefore, n indicates the length of the string wp; n is
returned to the main function. You will notice that just by incrementing the address,
we can scan the string.
The same program to find length of string is modified and shown below:
Example 12.2- Alternate method to find the length of a string.
#include <stdio.h>
int main()
{
int wlength;
char *wp=”shri durgaya namaha”;
int wlen(char *wp);
wlength=wlen(wp);
Self-Instructional
206 Material
printf(“length of the word=%d”,wlength); Strings with Pointer
}
/*function to find length*/
int wlen(char *w)
{
char *p = w; NOTES
while (*p!=’\0’)
p++;
return p-w;
}
You get the same result.
Here, the address w is assigned to p through the assignment and declaration
statement in the called function. Hence, p also points to the same string that is p
points to the first character in the word. When p points to the first character or 0th
element p is incremented to the 1st location. When p points to the (n-1)th element,
p is incremented to nth location. Here, only p is incremented, not w. It continues to
point to the 0th location. Therefore at the time of termination of while loop, p will
point to the location corresponding to NULL. Thus p - w, i.e., the difference in the
addresses that is equal to the number of characters in wp, is returned to the main
function and printed there.
Case Study: To Print a Substring
Let us write a function to print a substring of given length and starting position. This
is illustrated in Example 12.3.
Example 12.3 Gets substring beginning with specified character
position.
#include <stdio.h>
#include <string.h>
void substring(char *str,char *substr,int len);
int main()
{
char text[80],substr[20];
int len,pos;
printf(“Enter any Text :”);
gets(text);
printf(“Enter the Length of Substring Required :”);
scanf(“%d”,&len);
printf(“Enter the Position From which Required :”);
scanf(“%d”,&pos);
substring(text+(pos-1),substr,len);
printf(“Substring Is %s \n”,substr);
}
void substring(char *str,char *substr,int len)
{
int cnt=0;
while(*str &&cnt <len)
{
*(substr++)=*(str++);
cnt++;
} Self-Instructional
Material 207
Strings with Pointer *(substr)=0;
}
Result of program
NOTES Enter any Text :This is a program to get a substring
Enter the Length of Substring Required :7
Enter the Position From which Required :11
Substring Is program
Try to understand how the program works. The following statement, which is
a call to the function, needs explanation.
substring(text+(pos-1),substr,len);
Usually we count the first character of a word as the 1st position, whereas C
will recognize it as the 0th position. text points to the address of the 0th position of
the text. Therefore, text+(pos-1) points to the address of the character in text
from which the substring starts.
Although substr is empty, we are passing the address of the 0th location of
the substring as the next argument. We will store the substring in substr, which is
empty when it is passed to the called function.
The third argument is the length of the substring.
Now look at the called function:
In the while loop we carry out the following operations:
Copy (str) to substr, i.e., from the starting position indicated by the user,
copy one character of text to substring
Increment str
Increment substr
Increment local counter cnt
Copying will terminate either on finding no characters in str or when the required
number of characters have been copied
Thus, the program works correctly.
Note the following features:
Since the strings are passed by reference, there is no need to return the
addresses or values, as the addresses of strings are known to the main function.
In the former case, garbage values will be stored in the empty spaces in the array
misleading the user. In the latter case, the elements will be lost. To avoid this
problem, you may think that you can specify marks [n] and give the value of n
later at run-time. However, this will not work, and the compiler will force you to NOTES
give the actual dimension. Hence, dynamic memory allocation is useful. malloc
and calloc serve to specify the actual dimension at run-time and hence, enable
memory allocation dynamically. Next time when you execute the program, you
can specify any value for n. It will definitely work.
The functions malloc() and calloc() allot memory dynamically.
The specifications are given below in the following statement.
void * malloc (n*size n );
It returns the pointer to n bytes of the memory or NULL if allotment is not possible.
Since it returns a pointer you have to specify the array as a pointer variable as
given below:
int *b ; / * array declared * /
b = (int *) malloc (x * 2) ; / * x is the array size * /
Similarly the calloc is defined as void * calloc (sizen,
size_size). Here the number of arguments is two. The first one is the array
size and the second one is the bytes occupied per element, i.e., the storage space
required for the data type. The function returns a pointer allocating space for an
array of size sizen, of data type size size, but the array contents will be
initialized to zero. In malloc, the initial contents will be garbage values. You can
use it as follows:
int * b;
b = (int *) calloc (x, 4);
Here 4 indicates the array is of type float and space is allocated to store
x floats. When you use calloc or malloc, you must include alloc.h.
A program to demonstrate malloc and calloc is as follows:
Program 12.4 To do string concatenation by using dynamic
allocation of memory.
#include <stdio.h>
#include <alloc.h>
#include <string.h>
main()
{
char *newstrcat(char *dest, char *src);
char *name1, *name2;
int n1, n2;
printf(“Enter size of 2 names:\n”);
Self-Instructional
Material 209
Strings with Pointer scanf(“%d%d”, &n1, &n2);
name1 = (char *) calloc(n1, 1);
name2 = (char *) calloc(n2, 1);
printf(“Enter 2 names\n”);
NOTES
scanf(“%s%s”, name1, name2);
printf(“New name:%s\n”,newstrcat(name1,name2));
}
char *newstrcat(char *dest, char *src)
{
char *w;
int i,len,len1,cnt=0;
len=strlen(dest);
len1=strlen(src);
w=(char *)malloc(len+len1+1);
for(i=0;i<len;i++)
w[cnt++]=dest[i];
for(i=0;i<len1;i++)
w[cnt++]=src[i];
w[cnt]=0;
return(w);
}
Result of the program
Enter size of 2 names:
44
Enter 2 names
Rama samy
New name:Ramasamy
calloc is used to allot memory to name1 and name2. The function
newstrcat is called while printing. In the called function, malloc is used to
allot space equal to the size of name1, name2 +1. The additional space is for
placing NULL. The string is concatenated by copying one character at a time
using two for statements. Finally, the concatenated string is returned to the main
function where it is printed.
The memory allocated using malloc, calloc can also be freed, when
it is no longer necessary by using the function free(). For example, in the
main ( ) of the above example, after the last statement you can add the following
statements:
free(name1);
free(name2);
These statements will deallocate the memory space allocated to them after
Self-Instructional
the job of printing the concatenated string is over. Thus, dynamic allocation of the
210 Material
memory according to the exact need and freeing it after use is quite useful for Strings with Pointer
You know how to declare pointers to various datatypes and arrays. Similarly,
pointers to structures can also be declared. For instance, in the case of the structure
account, you can declare a pointer as follows:
struct account a1 = { 1, “Vasu”, 1000 };
struct account * sp;
struct sp = &a1 ;
Now, sp is a pointer to structure. Therefore, if you assume structure as
another basic datatype, declaring it as an array and declaring it as a pointer, etc.
follow the same rules. Structure is in fact, a user defined datatype.
Access to individual elements of a structure defined in the form of a pointer
is similar but instead of dot, we use an arrow pointer - >. Arrow pointer is formed
by typing minus followed by the greater sign. However, on to the left of the arrow
operator, there must be a pointer to a structure. The following example will clarify
the point:
/*Example 12.5- structure pointers */
#include<stdio.h>
int main()
{
struct account
{
unsigned number;
char name[15];
int balance;
}a5;
static struct account a1= {001, “VASU”, 1000};
struct account *sp;
sp=&a1;
printf(“A/c No:=%u\t Name:=%s\t Balance:=%d\n”,
sp->number, sp->name, sp->balance);
a5=*sp;
printf(“A/c No:=%u\t Name:=%s\t Balance:=%d\n”,
a5.number, a5.name, a5.balance);
}
Self-Instructional
Material 211
Strings with Pointer Result of the program
A/c No:=1 Name:=VASU Balance:=1000
A/c No:=1 Name:=VASU Balance:=1000
the balance.
Now, look at some more examples to understand structure pointers but
before that you must know now to allocate dynamic memory allocation for
NOTES
structures.
Let us say, struct cycle * cp; then to allocate memory dynamically,
we can write:
cp = (struct cycle * ) malloc (size of (struct cycle ) * n)) ;
- n is the number of structure variables of type struct cycle.
In the above, you have treated structure similar to other datatype. The size
of the structure is not fixed like basic datatype. However, you can use the sizeof
operator to get the size of the structure variable.
12.6 SUMMARY
Strlen (): It is a function that returns the length of the given string.
Calloc () : It is a function that allocate the multiple blocks of memory
dynamically.
(e) np = np – 2
(f) *np ++
(g) np++ NOTES
(h) *np++
(i) ++np
(j) *np
Long Answer Questions
1. Describe the following with the help of examples:
(a) Pointer arithmetic.
(b) Pointers and two-dimensional arrays.
(c) Advantage and operation of:
(i) malloc
(ii) calloc
(d) String functions.
(e) Call by reference and similarity with global variables.
2. Write programs for the following:
(a) A function nstrcmp to compare string cs to string ct; return <0
if cs <ct, 0 if cs = = c or >0 if cs > ct.
(b) A function to check whether characters +, –, *, / present in a
string.
(c) To find the kth smallest element in an array using pointers.
(d) To check whether a string is palindrome.
(e) To reverse a number using pointers.
13.0 INTRODUCTION
In this unit, you will learn about data files. In C programming, you include
<stdio.h>: a file essential for any program to read from a standard input
device or to write to a standard output device. It has declaration pointers to three
files, namely stdin, stdout and stderr which means that the contents of
these files are added to the program, when the program executes. In this unit, you
will learn how to use either the hard disk drive or the floppy disk drive as the input/
output medium. In day-to-day usage of large applications, the standard input/
output is neither convenient nor adequate to handle large volumes of data and
hence, the disk drives only serve as Input/Output (I/O) devices. You will also
learn about the usage of files for storing data, popularly known as data files. Data
files stored in the secondary or auxiliary storage devices, such as hard disk drives
or floppy disks, are permanent unless deleted. In contrast, what is written to the
monitor is only for immediate use. The data stored in disk drives can be accessed
later and modified, if necessary. Further, in this unit, you will learn about file pointers,
binary mode and text mode operations, reading a data file and processing a data
file.
13.1 OBJECTIVES
What is a file pointer? It is a pointer to a file, just like other pointers to arrays,
structures etc. It points to a structure that contains information about the file. The
information connected with a file is as given below:
location of the buffer.
the position in the file of the character currently being pointed to.
whether the file is being read or written.
whether an error has occurred or the end of the file has been reached.
We don’t need to know the details of these because stdio.h handles it
elegantly. There is a structure with typedef FILE in stdio.h which handles all file
Self-Instructional
218 Material
related tasks as above, whether it is in the floppy or the hard disk drive. Therefore Introduction to Files
in order to use a file without difficulty, we have to include stdio.h and declare a file
pointer which points to FILE as given below:
FILE * fp;
NOTES
Therefore the file pointer points to a structure which contains information
about the file management functions. When we open a file, and the opening of the
file is successful, the file pointer will point to the first character in the file. In other
words, the file gets opened and loaded to the buffer. NULL is a macro defined in
stdio.h which indicates that file open has failed. Therefore, when file open is
successful the file pointer will point to the address of the buffer which will be a
non-zero integer value. If not, the file pointer will get a value of NULL which is 0.
The file pointer will point to the next character after the first one is fetched
or copied on to the system. The structure FILE keeps track of where the pointer
remains at any point in time after opening the file. It keeps track of which files are
being used. It also knows whether the file is empty, the end of the file has been
reached or an error has occurred. We don’t have to worry about file management
tasks once a file pointer has been declared in our program to point to FILE. Since
FILE is known to <stdio.h>, we do not have to bother about it. This declaration
of structure FILE has relieved the programmer from most of the mundane jobs.
Files are formats that save data for future use. Any file has to be opened for any
further processing, such as reading, writing or appending, i.e., writing at the end of
the file. The characters will be written or read one after another from the beginning
to the end, unless otherwise specified. You have to open the file and assign the file
pointer to take care of further operations. Hence, you can declare,
FILE * fp;
fp = fopen (“filename”, “r”);
Filename is the name of the file, which you want to open. You must give the
path name correctly so that the file can be opened. ‘r’ indicates that the file has
to be opened for reading purposes.
fp = fopen (“Ex1.C”, “r”); will enable opening file Ex1.C.
Therefore, the arguments to fopen() are the name of the file and the
mode character. Obviously w is for write, a for append, i.e., adding at the end of
the file. If these characters are specified, the operations as indicated can be
performed after opening the file. It is, therefore, essential to indicate the operations
to be performed before opening the file. When the file is opened in the ‘w’ mode,
the data will be written to the file from the beginning. This means that if the named
file is already in existence, the previous contents will be lost due to overwriting. If
Self-Instructional
Material 219
Introduction to Files the file does not exist, then a file with the assigned name will be opened. When the
append mode is specified, the writing will start after the last entry, or in other
words, previous contents of the file will be preserved.
FILE provides the link between the operating system and the program
NOTES
currently being executed. FILE is a structure containing information about the
corresponding files, including information such as:
The location of the file
The location of the buffer
The size of the file
After the command is executed in the read mode, the file will be loaded into
the buffer if it is present. If the file is absent, or the file specification is not correct,
then the file will not be opened. If the opening of the file is successful, the pointer
will point to the first character in the file, and if not, NULL is returned, meaning
that the access is not successful. The fopen() function returns a pointer to the
starting address of the buffer area associated with the file and assigns it to the file
pointer, fp in this case.
After the operations are completed, the file has to be closed. The syntax for
closing file is given below:
fclose(filepointer);
fclose() also flushes or empties the buffer. The function fputc() performs
putting one character into a file. If for every fputc(), the computer prints a
character to a file, then it will get tired. Therefore, it collects all the characters to
be written onto a file in the buffer. When the buffer is full or when fclose() is
executed, the buffer is emptied by writing to the hard disc drive in the assigned file
name.
Concept of Binary Files
You can open files in the text mode or the binary mode. In the binary, data will be
stored in the binary form and the storage space will be equal to the number of
bytes required for the storage of various data types. In the text mode, they will be
stored as alphanumeric characters. If you require to use the file in the binary mode,
you must use ‘rb’ for reading, ‘wb’ for writing, and ‘ab’ for appending. If
you want to store data in the text mode, you have to append t to the mode character
as ‘rt’, ‘wt’, ‘at’, etc. Since the default is in the text mode, t will be
assumed if nothing is specified after the mode character. Therefore, mode ‘w’
means opening a text file for writing.
The difference between opening files in the binary mode and the text mode
are given in Table 13.1.
Self-Instructional
220 Material
Table 13.1 Difference between Binary Mode and Text Mode Operations Introduction to Files
Text mode needs more than the 2 In binary mode the numbers will be
bytes for storing an integer, since it stored in the specified width. 30000
treats each digit as a character. e.g., needs 2 bytes only.
30,000 needs 5 bytes.
Therefore, binary files and text files are to be processed taking into account
their properties as above, although the file could be opened in any mode. The file
I/O functions, such as fgetc, fputc, fscanf, fprintf, fgets, fputs,
are applicable to the operations in any of the modes.
The files can be used to store employee records using structures in a payroll
program. Book records can be stored in a file in a library database. Inventories
can be stored in a file. However, storing all these in the text mode will consume
more space on the file. Hence, the binary mode can be used to create the files.
Some files cannot be stored in the text mode at all, such as executable files.
You are familiar with reading and writing. So far you were reading from and writing
to standard input/output. Therefore, you used functions for the formatted I/O with
stdio such as scanf() and printf(). We also used unformatted I/O
such as getch(), putch() and other statements. When dealing with files,
there are similar functions for I/O. The functions getc(), fgetc(), fputc()
and putc() are unformatted file I/O functions similar to getch() and
putch(). You will consider the formatted file operations in this section. When it
pertains to standard input or output, you use scanf() and printf(). To
handle formatted I/O with files, you have to use fscanf() and fprintf().
You can write numbers, characters, etc. to the file using fprintf().
This helps in writing to the file neatly with a proper format. In fact, any output can
be directed to a file instead of the monitor. However, you have to indicate which
file you are writing to by giving the file pointer. The following syntax has to be
followed for fprintf():
Self-Instructional
Material 221
Introduction to Files fprintf (filepointer, “format specifier”, variable names);
You are only adding the file pointer as one of the parameters before the
format specifier. This is similar to sprintf(), which helps in writing to a buffer.
In the case of sprintf(), buffer was a pointer to a string variable. Here,
NOTES
instead of a pointer to a string variable, a pointer to a file is given in the
fprintf() statement. Like the string pointer in sprintf(), the file pointer
should have been declared in the function and should be pointing to the file.
Before writing to a file, the file must be opened in the write mode. You can
declare the following:
FILE * fp ;
fp = fopen (“filename”, “wb”);
You have to write wb within double quotes for opening a file for writing in
the binary mode. Therefore, fopen() searches the named file. If the file is
found, it starts writing. Obviously the previous contents will be lost. If a file is not
found, a new file will be created. If unable to open a file for writing, NULL will be
returned.
You can also append data to the file after the existing contents. In this manner,
we will be able to preserve the contents of a file. However, when you open the file
in the append mode, and the file is not present, a new file will be opened. If a file
is present, then writing is carried out from the current end of the file. After writing
is completed either in the write mode or the append mode, a special character will
be automatically included at the end of the text in case of text files. In case of
binary files, no special character will be appended. This can be read back as
EOF. Usually it is – 1, but it is implementation-dependent. Hence, it is safer to use
EOF to check the end of the text files.
Reading and Writing
Let us look at a program to write numbers to a binary file using fprintf()
and then read from the file using fscanf().
Example 13.1 - Writing digits to a binary file and then reading.
#include <stdio.h>
int main()
{
int alpha,i;
FILE *fp;
fp=fopen(“ss.doc”, “wb”);
if(fp==NULL)
printf(“could not open file\n”);
else
{
for (i=0; i<=99; i++)
Self-Instructional
222 Material
fprintf(fp,” %d”, i); Introduction to Files
fclose(fp);
/*now read the contents*/
fp=fopen(“ss.doc”, “rb”);
for (i=0; i<100; i++) NOTES
{
fscanf(fp,”%d”, &alpha);
printf(“ %d”, alpha);
}
fclose (fp);
}
}
Self-Instructional
Material 223
Introduction to Files Example 13.2 - writing, then appending digits to a file and then
reading.
#include <stdio.h>
int main()
NOTES {
int alpha,i;
FILE *fp;
fp=fopen(“ss.doc”, “wb”);
for (i=0; i<20; i++)
fprintf(fp,” %d”, i);
fclose(fp);
fp=fopen(“ss.doc”, “ab”);
for (i=20; i<100; i++)
fprintf(fp,” %d”, i);
fclose(fp);
/*now read the contents*/
fp=fopen(“ss.doc”, “rb”);
for (i=0; i<100; i++)
{
fscanf(fp,”%d”, &alpha);
printf(“ %d”, alpha);
}
fclose (fp);
}
can go to the help screen of the ‘C’ language system to get more details as well
as search for help on any of the library functions. The help screen gives the syntax
of the functions and also provides examples in which the function or command is
used. Even after reading this book or any other book on ‘C’, you will not be able NOTES
to use all the functions. Hence, the best way is to take the help from the help
screen whenever other functions are to be used.
fgetc() reads the character pointed to by fp. It then increments fp so
that fp points to the next character. We can keep on incrementing fp till the end
of file, i.e., end of data is reached. When a file is created in the text mode, the
system inserts a special character at the end of the text. Therefore, while reading a
file, when the last character has been read and the end of the file is reached, EOF
is returned by the file pointer. The following program reads one character at a time
till EOF is reached from an already created text file, ss.doc. The program is
implemented using the do...while statement.
Example 13.3 - reading characters from a file.
#include <stdio.h>
int main()
{
int alpha;
FILE *fp;
fp=fopen(“ss.doc”, “r”);
do
{
alpha=fgetc(fp);
putchar(alpha);
} while(alpha!=EOF);
fclose (fp);
}
File Copy
File copy can be achieved by reading one character at a time and writing to another
file either in the write mode or the append mode. Here it is proposed to read from
Self-Instructional
Material 225
Introduction to Files a file and write to two different files, one in the write mode and another in the
append mode. This means you have to open three files in the following manner:
FILE * fr, *fw; *fa;
NOTES You can assign three file pointers as given above. Three files are then opened. You
can use any name for the file pointers and there may be as many file pointers as the
number of files to be used. The program is as follows:
Example 13.4 - reading from file ss,writing to file ws and appending
to file as, all at a time.
#include <stdio.h>
int main()
{
int alpha;
FILE *fr,*fw, *fa;
fr=fopen(“ss.doc”, “r”);
fw=fopen(“ws.doc”, “w”);
fa=fopen(“as.doc”, “a”);
do
{
alpha=fgetc(fr);
fputc(alpha, fw);
fputc(alpha, fa);
putchar(alpha);
}while(alpha!=EOF);
fclose (fr);
fclose (fw);
fclose (fa);
}
After opening the three files, alpha() gets the character, which is written to
both the files using fputc(), and the character is also displayed on the screen.
This is continued till EOF is received in alpha from ss.doc, the source file.
Finally, the files are closed. Verify that your program has worked alright.
Since, you are also writing to the monitor, in addition to writing and appending
to files, the program output appears as follows.
Result of the program
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
93 94 95 96 97 98 99
Self-Instructional
226 Material
There are some more mode specifiers with fopen like r+, w+ and a+, Introduction to Files
Line Input/Output
You have discussed writing to and reading from a file, one character at a time,
using both the unformatted and formatted I/O for the purpose. You can also read
one line at a time. This is enabled by the fgets() function. This is a standard
library function with the following syntax:
Char * fgets (char * buf, int max line, FILE * fp);
fgets() reads the next line from the file pointed to by fp into the character
array buf. The line means characters up to maxline –1, i.e., if maxline is
80, each execution of the function will permit reading of up to 79 characters in the
next line. Here 79 is the maximum, but you can even read 10 characters at a time,
if it is specified.
fgets(alpha, 10, fr);
Here alpha is the name of the buffer from where 10 characters are to be read at
a time. The file pointer fr points to the file from which the line is read, and the line
read is terminated with NULL. Therefore, it returns a line if available and NULL if
the file is empty or an error occurs in opening the file or reading the file.
The complementary function to fgets() is fputs(). Obviously
fputs() will write a line of text into the file. The syntax is as follows:
int fputs (char * buf , file * fp );
The contents of array buf are written onto the file pointed to by fp. It returns
EOF on error and zero otherwise. Note that the execution of fgets() returns
a line and fputs() returns zero after a normal operation.
The functions gets() and puts() were used with stdio, whereas
fgets() and fputs() operate on files.
We can write a program to transfer two lines of text from the buffer to a file
and then read the contents of the file to the monitor. This is shown in Example
13.5.
Example 13.5 - writing and reading lines on files.
#include <stdio.h>
#include<string.h>
Self-Instructional
Material 227
Introduction to Files int main()
{
int i;
char alpha[80];
NOTES
FILE *fr,*fw;
fw=fopen(“ws.doc”, “wb”);
for(i=0; i<2; i++)
{
printf(“Enter a line up to 80 characters\n”);
gets(alpha);
fputs(alpha, fw);
}
fclose(fw);
fr=fopen(“ws.doc”, “rb”);
while
( fgets(alpha,20, fr)!=NULL)
puts(alpha);
fclose (fr);
}
Note carefully the fgets() statement. Here, alpha is the buffer with a width
of 80 characters. Each line can be up to 80 characters and two lines are entered
through alpha to ws.doc. Later on, 20 characters are read into alpha at a
time from same file till NULL is returned.
Result of the program
Enter a line upto 80 characters
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Enter a line upto 80 characters
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
aaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaabbbb
bbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbb
bb
More than 20 numbers of a & b were written on to the file. However, since we
have specified reading 20 characters at a time. The output appears in 6 lines. Had
we specified reading more characters at a time, the number of reads would have
reduced. You can try this yourself.
Thus, you can read and write one line at a time.
Self-Instructional
228 Material
Introduction to Files
13.6 SUMMARY
In real life, a large volume of data will be generated and requires the use of
files.
C provides an easy way to access files. A pointer to the file has to be
assigned for each file, which is to be opened, to facilitate their handling.
Files are to be opened specifically in one of the modes such as read, write
or append.
After the operation is complete, the file has to be closed using fclose().
Self-Instructional
Material 229
Introduction to Files Opening and closing of files cannot be assumed to take place correctly at
all times. Hence, suitable error statements are to be included in the program
and the file can be read one character at a time using the fgetc() and
fscanf() commands.
NOTES
13.7 KEY WORDS
14.0 INTRODUCTION
In this unit, you will learn about the error handling methods during I/O operations
and command line arguments. ferror () function is used to detect any error
during file accessing. It is possible to pass some values from the command line to
your C programs when they are executed. These values are called command line
arguments and many times they are important for your program especially when
you want to control your program from outside instead of hard coding those values
inside the code. The command line arguments are handled using main () function
arguments.
14.1 OBJECTIVES
When an error is encountered during file processing, the program execution will
be terminated and error messages will be displayed. Following measures may be
adopted to identify or avoid errors during file processing.
(i) ferror() function can be used to detect any error during file accessing.
This function will return a zero when there is no error, otherwise it will return
Self-Instructional
Material 231
Error Handling Methods a non-zero number.
FILE *fptr;
if(ferror(fptr) == 0)
printf(“\n The file is available for processing”);
NOTES else
printf(“\n Error in accessing the file!!!”);
(ii) To verify whether a file exists in the disk, the following definitions will help.
if(fptr == NULL)
printf(“\n No content or file does not exist”);
(iii) When data in a file may be exhausted, end of file condition will be
encountered. Use the following definition to display end of file condition.
if(feof(fptr) == EOF)
printf(“\n End of file is reached”);
Note that EOF is a macro which specifies the end of file condition.
Entering an invalid file name or trying to write data to a write protected disk
are some of the other reasons for errors during file processing.
This can be used to copy a file to another file. Assume that the first named file is to
be copied to the second named file. You may write a program and convert it into
an executable file, specifying the argument in the DOS command line.
You may specify as follows at the C> prompt:
C > prgname . exe f1.cpp f2.cpp.
This means that you want to copy the contents of f1.cpp to f2.cpp. Here,
the number of arguments are 3, and therefore argc will contain 3.
*agrv[0] = prgname.exe
*agrv[1] = f1.cpp - source to copy from
*agrv[2] = f2.cpp - file where to be copied
Files are the formats that are required for saving data for future use. Random
Access Memory (RAM) holds data temporarily. File structures are used to
save data permanently. The C program files can be stored at the user specified
location. Figure 14.1 shows the file sequence hierarchy in C language.
Files
True random access file handling only accesses the file at the point at which the
data should be read or written rather than having to process it sequentially. A
different approach is also possible whereby a part of the file is used for sequential
access to locate something in the random access portion of the file in the same
way as a File Allocation Table (FAT) works. The three main functions that seek
Self-Instructional
236 Material
forward and backward with file handling are as follows: Error Handling Methods
(i) rewind() – This function returns the file pointer to the beginning.
(ii) fseek() – This function returns the position of the file pointer.
(iii) ftell() – This function returns the current offset of the file pointer. NOTES
Each of these functions operates on the C file pointer, which is just the offset from
the start of the file, and can be positioned at will. All read/write operations take
place at the current position of the file pointer.
The rewind() Function
The rewind()function can be used in sequential or random access C file
programming. It simply tells the file system to position the file pointer at the start of
the file. Any error flags are also cleared and no value is returned.
Using fseek() and ftell() to Process Files
The fseek()function is very useful in random access files where either the
record or block size is known or there is an allocation system that denotes the
start and end positions of records in an index portion of the file. The
fseek()function takes three parameters:
(i) FILE * f – It represents the file pointer;
(ii) long offset – It represents the position offset;
(iii) int origin – It represents the point from which the offset is applied.
The origin parameter can be one of the following three values:
(i) SEEK_SET – It works from the start.
(ii) SEEK_CUR – It works from the current position.
(iii) SEEK_END – It works from the end of the file.
There are two fundamental types of files, text and binary. Of these, binary is generally
simpler to deal with. Random access means you can move to any part of a file and
read or write data from it without having to read through the entire file. Basically,
seeking forward and backward pointer in file handling is done with fseek function.
The general format of fseek function is as follows:
fseek(file * Fileptr, offset, position);
This function is used to move the file position to a desired location within the
file. Fileptr is a pointer to the file concerned. offset is a number or variable
of type long and position is an integer number. offset specifies the number
of positions (in bytes) to be moved from the location specified at the position.
Input and output are normally sequential in which each read or write takes
place at a position in the file right after the previous one. When necessary, however,
a file can be read or written in any arbitrary order. The system call lseek provides
a way to move around in a file without reading or writing any data:
long lseek(int fd, long offset, int origin);
Self-Instructional
Material 237
Error Handling Methods This function sets the current position in the file whose descriptor is fd to
offset which is taken relative to the location specified by origin. Subsequent
reading or writing will begin at that position. The origin can be 0,1 or 2 to
specify that offset is to be measured from the beginning, from the current
NOTES position or from the end of the file, respectively. With lseek it is possible to
treat files more or less like arrays at the price of slower access. For example, the
following function reads any number of bytes from any arbitrary place in a file. It
returns the number read or -1 on error.
#include “syscalls.h”
/*get: read n bytes from position pos */
int get(int fd, long pos, char *buf, int n)
{
if (lseek(fd, pos, 0) >= 0) /* get to pos */
return read(fd, buf, n);
else
return -1;
}
The return value from lseek is a long integer type that gives the new position
in the file which depend on the setting conditions, such as seeking forward or
seeking backward or -1 if an error occurs. The standard library function fseek
is similar to lseek except that the first argument is a FILE * and the return
value is non-zero if an error occurs. To determine whether the functions fseek()
or lseek() operates correctly check its return value.
14.6 SUMMARY
Self-Instructional
238 Material
ferror () function can be used to detect any error during file accessing. Error Handling Methods
This function will return a zero when there is no error, otherwise it will return
a non-zero number.
Entering an invalid file name or trying to write data to a write protected disk
NOTES
are some of the other reasons for errors during file processing.
The rewind()function can be used in sequential or random access C
file programming. It simply tells the file system to position the file pointer at
the start of the file.
There are two fundamental types of files, text and binary. Of these, binary is
generally simpler to deal with. Random access means you can move to any
part of a file and read or write data from it without having to read through
the entire file.
Self-Instructional
Material 239
Error Handling Methods Jeyapoovan T. 2006. Computer Programming - Theory & Practice. New Delhi:
Vikas Publishing.
Khurana, Rohit. 2005. Object Oriented Programming. New Delhi: Vikas
Publishing.
NOTES
Kanetkar, Yashwant. 2003. Let Us C. New Delhi: BPB Publication.
Saxena, Sanjay. 2003. A First Course In Computers. New Delhi: Vikas
Publishing.
Subburaj, R. 2000. Programming In C. New Delhi: Vikas Publishing.
Self-Instructional
240 Material
.emaN e1.sruIncrease
oC eht fothe
ezifont
s tnosize
f ehof
t esthe
aerCourse
cnI .1 Name.
.egaP revoC e2.ht nuse
i rethe
daefollowing
h a sa gniwasolaloheader
f eht esin
u the
.2 Cover Page.
YTISREVINUALAGAPPA
APPAGALAUNIVERSITY
B.Sc. [Computer Science]
elcyC drihT eht ni )46.3:APGC( CA[Accredited
AN yb edarGwith
’+A’’A+’
htiwGrade
detidby
ercNAAC
cA[ (CGPA:3.64) in the Third Cycle
]CGU-DRHM yb ytisrevinU I–yrogeand
taC Graded
sa dedarasG Category–I
dna University by MHRD-UGC]
300 036 – IDUKIARA
KARAIKUDI
K – 630 003
130 13 NOITACUDE ECNATSIDDIRECTORATE
FO ETAROTCEOF
RIDDISTANCE EDUCATION
PROGRAMMING IN C
I - Semester
PROGRAMMING IN C
B.Sc. [Computer Science]
130 13
itnem sYou
a egaare
p reinstructed
voc eht etatodpupdate
u ot dethe
tcurcover
tsni erpage
a uoYas mentioned below:
.emaN e1.sruIncrease
oC eht fothe
ezifont
s tnosize
f ehof
t esthe
aerCourse
cnI .1 Name.
aP revoC e2.ht nuse
i rethe
daefollowing
h a sa gniwasolaloheader
f eht esin
u the
.2 Cover Page.
ISREVINUALAGAPPA
APPAGALAUNIVERSITY
B.Sc. [Computer Science]
rihT eht ni )46.3:APGC( CA[Accredited
AN yb edarGwith
’+A’’A+’
htiwGrade
detidby
ercNAAC
cA[ (CGPA:3.64) in the Third Cycle
]CGU-DRHM yb ytisrevinU I–yrogeand
taC Graded
sa dedarasG Category–I
dna University by MHRD-UGC]
300 036 – IDUKIARA
KARAIKUDI
K
ITACUDE ECNATSIDDIRECTORATE
FO ETAROTCEOF
– 630 003
RIDDISTANCE EDUCATION
PROGRAMMING IN C
I - Semester