You are on page 1of 819

SYSTEMATIC APPROACH TO

USING

* Do not buy the old book - you will -r=:=====t-


, not get the latest updated version.
* Helpful for placement. Purchase
Book with
Hologram
Only

A. M. PADMA REDDY

.----'--
l' 1C?30b~

Systematic Approach
To
Data structures
(with C)
aoot< sTO
Nt-fCE
B~ -~ Avaltab1a
BUY seOlRights are vritb us
Re~:~aU.ham. aeftgaluna

A.M. Padma Reddy B.E., M. Tech., MISTE


Professor and Head, Department of Computer Science
&
Information Science
Sri Nandi Publications

#256, 2nd main, 10th cross


Padmanabhanagar (B.S.K. 2nd stage)
Bangalore - 560 070

Phone: 080 - 26698274,·26694533


9845070827, 99001 70827

E-mail id of author: padmareddy_am@y


Mobile: 98450 70827

,.
FIRST EDITION SEP-1999
SECOND EDITION OCT -2002
THIRD EDITION AUG - 2003
FOURTH EDITION AUG - 2004
FIFTH EDITION AUG - 2005
SIXTH EDITION SEP - 2006
SEVENTH EDITION AUG,- 2007
EIGTH REVISED EDITION AUG - 2008
NINTH REVISED EDITION AUG - 2009

Copyright © 1999 by Author

Caution No part of this book should be copied, reproduced or adapted, abridged


or translated or stored in a retrieval system or transmitted in any form by any
device. Resale of the book is strictly prohibited. Breach of the above, will entail in
civil and criminal action.

Note Due care and diligence has been taken while editing and printing this book.'
Neither the author nor the publishers of the book hold any responsibility for any
mistakes that may have inadvertently crept in and are not responsible for any
consequential damages caused. The book acts as just a reference to move forward
and understand the concepts.

PRICE Rs. 295.00


Dedicated

to
Nly children

P. Mona1iJca
&
P.Mithil
Acknowledgements

This gives me a heavenly delighted pleasure to write an acknowledgement t? this


book. Because, this book is the contribution of a large number of people, I wish to
list only few contributors. '. .. .
I am grateful to Prof. M.R Holla, President of Sn Sa! Vidya Vikas
Shikshana Samiti for encouraging me to write the book.
Here I would like to thank and remember those who have encouraged me
for writing flus textbook and those who have give sU'E,'E,estiol\s. PIoL R. Snm'J"dSan.
r nner HO • Dept. of Computet: Science RNSIT. Y. Iayasimna HOD, Dept. of
Electronics & Communication, R.C Shanmukha Swamy HOD, Dept. of Electrical
& Electronics and Mr. Narayana Raju of Sai Vidya Institute of Technology, Mr. R.
Srinivas Raju and Mr. M.K. Manohar of Sri Sai Vidya Vikas Shikshana Samithi.
I thank our parents, in-laws, brothers, and sisters for their constant
encouragement with moral support.
Finally, most important contributions from the beginning to till the end
have come from Mr. M. Rajashekara Reddy, Executive Committee Member-B.E.S
Colleges., My wife R. Nirmala and my children P. Monalika, P. Mithil. The
constant encouragement, support, patience and endurance shown during the
preparation of this manuscript were remarkable. My wife and my children gave
me inspiration throughout.

-,
A.M. Padma Reddy
To Readers

I thank all the readers for providing encouragement by providing the feedback and
suggestions to improve the quality of the book. In this re-revised version, pointers,
structures, union file-handling chapters have been updated. The chapters on stacks,
queues, linked lists, trees, sorting and searching techniques have been updated and
most of the errors identified by readers are' corrected. The book has been updated
and completely modified so that it is easy to read and understand the concepts. 1
thank all those who gave me suggestions by reading this book and pinpointing the
mistakes. This time too I request all the readers to come with suggestions t(
improve the quality of this book thereby making this a best book on Datr
structures (with C).

Any suggestions,clarifIcations required please mail me a


padmareddy_am@yahoo.com or 080-26698274 or 98450-70827. Thank yoi
once again readers.

A.M. Padma Reddy


Syllabus
Data Structures with C .
(Common to CSE & ISE)

III SEMESTER

Sub Code IAMARKS:25


Hours/W eek : 4 Exam Hours: 3
Total Hours : 52 Marks :100
PART-A
(C Language features)

Unit I
1. Pointers: Concepts, Pointer variables, Accessing variables through pointers,
Pointer declaration and definition, Initialization of pointer variables, Pointers
and functions, Pointer to pointers, Compatibility, Lvalue and Rvalue, Arrays
and pointers, Pointer arithmetic and arrays, Passing an array to a function,
Understanding complex declarations, Memory allocation functions, Array of
pointers. - 7 hours

Unit II
2.' Strings: String Concepts, C strings, String I/O functions, Array of strings,
String manipulation functions, Memory formatting - 2 hours

3. Derived types - Enumerated, Structure, and Union: The type definition,


Enumerated types, Structure, Accessing structures, Complex structures, Array
of structures, Structures and functions, Unions - 3 hours

4. Binary files: Classification of Files, Using Binary Files, Standard Library


Functions for Files - 2 hours

PART-B
(Data structures with C)

Unit III
5. The Stack: Defmition and Examples, Representing Stacks in C, An Example-
Infix, Postfix and Prefix - 7 hours
Unit IV
6. Recursion: Recursive Definition and Processes, Recursion in C, Writing
Recursive Programs, Simulating Recursion, Efficiency of Recursion
- 4 hours - 4 hours

7. Queue: The Queue and its Sequential Representation - 2 hours

Unit V
8. Lists: Linked Lists, Lists in C, An Example - Simulation using Linked Lists
- 6 Hours
Unit VI
9. Lists: Other List structures - 6 Hours

Unit VII
10. Trees: Binary Trees, Binary Tree Representations - 6 Hours

Unit VIII
11. Trees: Representing Lists as Binary Trees, Trees and their applications
- 7 Hours

Text Books
1. Behrouz A. Foruzan and Richard F. Gilberg, Computer Science A Structured
Programming Approach Using C, Second Edition, Thomson, 2003
(Chapter 9.1 to 9.9, Chapter 10.1 to 10.6, Chapter 11.1 to 11.6, Chapter 12.1 to
12.8, Chapter 13.1 to 13.3)
2. Data Structures using C, Aaron M. Tenenbaum, Yedidyah Langsam & Moshe
J. Augenstein, Pearson EducationIPHI, 2006
(Chapter 2, 3, 4, 5.1, 5.2, 5.4, 5.5)

Reference Books
3.. Richard F. Gilberg and Behrouz A, Forouzam, Data Structures A
pseudocode apparoach with C, Thomson 2005
4. Robert Kruse & Bruce Leung, Data Structures and Program Design in C,
Peason Education, 2007

Question paper pattern


Note: The question paper consists of two parts A and B containing 2 and 6
questions respectively. The student is required to answer any 5 questions
selecting at least one question from Part A
Unit IV
6. Recursion: Recursive Definition and Processes, Recursion in C, Writing
Recursive Programs, Simulating Recursion, Efficiency of Recursion
- 4 hours - 4 hours

7. Queue: The Queue and its Sequential Representation - 2 hours

Unit V
8. Lists: Linked Lists, Lists in C, An Example - Simulation using Linked Lists
- 6 Hours
Unit VI
9. Lists: Other List structures - 6 Hours

Unit VII
10. Trees: Binary Trees, Binary Tree Representations - 6 Hours

Unit VIII
11. Trees: Representing Lists as Binary Trees, Trees and their applications
- 7 Hours

Text Books
1. Behrouz A. Foruzan and Richard F. Gilberg, Computer Science A Structured
Programming Approach Using C, Second Edition, Thomson, 2003
(Chapter 9.1 to 9.9, Chapter 10.1 to 10.6, Chapter 11.1 to 11.6, Chapter 12.1 to
12.8, Chapter 13.1 to 13.3)
2. Data Structures using C, Aaron M. Tenenbaum, Yedidyah Langsam & Moshe
J. Augenstein, Pearson EducationJPHI, 2006
(Chapter 2, 3, 4, 5.1, 5.2, 5.4, 5.5)

Reference Books
3.. Richard F. Gilberg and Behrouz A, Forouzam, Data Structures A
pseudocode apparoach with C, Thomson 2005
4. Robert Kruse & Bruce Leung, Data Structures and Program Design in C,
Peason Education, 2007

Question paper pattern

Note: The question paper consists of two parts A and B containing 2 and 6
questions respectively. The student is required to answer any 5 questions
selecting at least one question from Part A
Contents
Part 1· Advanced C Concepts
Chapter 1

Introducing to C
1.1 Introduction : 1.1
1.1.1 Character set (Alphabets of C) 1.2
1.1.2 C tokens : 1.3
1.1.3 Keywords 1.3
1.1.4 Identifiers 1.4
1.1.5 Constants 1.5
1.2 Meaning of variables 1.10
1.3 Basic/SimplelPrimitive Data types 1.10
1.3.1 int 1.10
1.3.2 float 1.11
1.3.3 double 1.11
1.3.4 char : 1.11
1.3.5 void : 1.11
1.4 User defined data types 1.12
1.5 Declaration of variables 1.13
1.6 Operators ' .' 1.13
1.6.1 Classification based on the number of operands 1.14
1.6.2 Classification based on the type of the operation 1.15
1.7 Arithmetic operators 1.15
1.7.1 Arithmetic expressions : 1.16
1.7.2 Modes of expressions 1.17
1.7.3 Arithmetic operator's precedence (Precedence of operators) 1.17
1.7.4 Relational operators 1.20
1.7.5 Logical operators 1.21
1.7.6 Relational and Logical expressions ~..1.22
1.7.7 Assignment operator 1.22
1.7.8 Increment and decrement operators 1.23
1.7.8.1 increment operator , 1.23
1.7.8.2 decrement operator 1.25
1.7.9 Conditional operator 1.26
1.7.] 0 Bitwise operators 1.27
1.7.11 Special operators (comma, sizeof operators) : 1.28
1.8 The precedence of operators (Hierarchy of operators) 1.29
1.8.1 Left associative operator 1.29
1.8.2 Right associative orerator.. 1.30
1.9 Sequential statements 1.31
1.10. Branching statements 1.33
1.10..1 The if statement/simple-if statement... 1.33
1.10..2 The if-else statement 1.34
1.10..3 The nested if-statement : 1.36
1.10..4 The else-if-ladder statement... · 1.37
1.10..5 The switch statement 1.38
1.10..6 The for statement 1.41
1.10..7 The while statement.. 1.42
1.10..8 do-while statement., ..: 1.44
1.11 Arrays 1.45
1.12 Insertion sort ..: 1.50.
1.13 Why functions : 1.53
1.14 Memory organization in C l.68
1.15 Storage classes (Local/globallregister/static ) 1.69

PART-A
UNIT-l

Chapter 2
Pointers

2.1 Introduction : 2.1


2.2 Pointer concepts 2.1
2.2.1 Pointer constants 2.2
2'.2.2 Pointer values : 2.3
2.2.3 Pointer variable : 2.4
2.3 Accessing variables through pointers 2.6
2.3.1 Pointer declaration and definition 2.6
2.3.2 Dangling pointers 2.8
2.3.3 Initializing a pointer variable ' 2.9
2.3.4 NULL Pointer 2.12
2.3.5 Accessing variables through pointers 2.13
2.4 Pointers and functions : 2.18
2.4.1 Pass by value (Call by value) ~ 2.19
2.4.2 Pass by reference(Call by reference) - Pointer as formal parameter. 2.2Q
2.4.3 Functions returning pointers 2.22
2.4.4 Pointers to pointers 2.25
2.4.5 , Compatibility and void pointer. 2.36
2.4.6 L-value and R-value : 2.39
2.4.7 Answers to selected problems 2.42
-2.5 Pointer applications 2.51
2.5.1 • Arrays and pointers 2.51
2.5.2 Pointer arithmetic and arrays 2.54
2.5.2.1 Pointers and I-dimensional arrays 2.54
2.5.2.2 Largest ofn numbers 2.56
2.5.2.3 Pointers and other operators 2.58
2.5.2.4 Adding an integer to a pointer 2.59
2.5.2.5 Display array elements using pointers 2.61
2.5.2.6 Sum ofN numbers using pointers 2.63
2.5.2.7 Subtracting an integer from a pointer 2.63
2.5.2.8 Subtracting two pointers 2.65
2.5.2.9 Comparing two pointers 2.66
2.6--Passing an array to a function 2.68
2.7 Pointers and two dimensional arrays/Pointer to l-dimensional arrays 2.71
2.8 Understanding complex declarations : 2.77
2.9 Memory allocation functions 2.80
2.9.1 Memory map ofC program 2.82
2.9.2 Memory management functions 2.84
2.9.2.1 malloc(size) ~ 2.85
2.9.2.2 calloc(n, size) 2.89
2.9.2.3 realloc(ptr, size) : 2.31
2.9.2.4 free(ptr) 2.98·
2.10 Array of pointers 2.100
2.11 Pointers to functions 2.106
2.12 Advantages and disadvantages of pointers 2.110

UNIT-2
.Chapter 3
Strings

3.1 String concepts 3.1


3.1.1 Fixed length format.. 3.2
3.1.2 Variable length format., 3.2
3.1.2.1 Length controlled string 3.3-
3.1.2.2 Delimited string 3.4
3.2 C strings 3.4
3.2.1 String. literal 3.5
3.2.2 Referencing string literal 3.5
3.2.3 Character vs string containing single character 3.6
3.3 String variable : 3.7
3.3.1 String as variable 3.8
3.3.2 Initializing strings 3.9
3.3.3 Strings and the assignment operator 3.12
3.4 String input/output functions 3.12
3.4.1 Formatted input functions - scanf .3.13
3.4.2 Formatted output functions - printf 3.19
3.4.3 Unfonnatted input functions - getst) 3.23
3.4.4 Unfonnatted output functions - puts 3.23
3.5 Arrays of strings 3.24
3.6 String handling functions : 3.26
3.6.1 strlen - string length : 3.27
3.6.2 strcpy - string copy : 3.29
3.6.3 strncpy - string number copy 3.33
3.6.4 string concatenate 3.35
3.6.5 string number concatenate 3.37
3.6.6 strcmp - string compare 3.38
3.6.7 strncmp - string number compare 3.42
3.6.8 strchr - string containing character.. 3.42
3.6.9 strrchr - string rear character 3.44
3.6.10 strstr - string in string 3.46
3.6.11 strspn - string span 3.49
3.6.12 strcspn - string number span 3.50
3.6.13 strpbrk - variation of string span 3.53
3.7 Memory formatting 3.53
3.7.1 sscanf- string scan fonnat... 3.54
3.7.2 sprintf - string print fonnat.. 3.56
3.8 Programming examples
3.8.1 strrev - string reverse 3.58
3.8.2 Check for palindrome ~ 3.58
3.8.3 Count vowels and consonants 3.61
3.8.4 String sorting 3.62
3.8.5 Upper case to lowercase and viceversa 3.63

Chapter 4
Derived types-Enumerated, Structure, and Union

4.1 Introduction 4.1


4.2 The type definition 4.2
4.3 Enumerated data types 4.3
4.4 Why structures? 4.6
4.4.1 Structure and its definition .4.6
4.4.2 Structure declaration .4.8
4.4.2.1 Tagged structure 4.8
4.4.2.2 Structure variables .4.11
4.4.2.3 Type-defined structure .4:13
4.4.3 Structure initialization ..~ .4.15
4.5 Accessing structures 4.20
4.5.1 sizeof a structure (Concept of slack bytes) ~ .4.22
4.5.2 Structure operations 4.26
4.5.3 Pointer to structures ~ .4.28
- 4.6 Complex structures 4.32
4.6.1 Nested structures 4.33
4.6.2 Structures containing arrays .4.35
4.6.3 Structures containing pointers .4.38
4.7 Array of structures : : 4.39
4.8 Structures and functions .4.41
4.8.1 Sending individual members .4.42
4.8.2 Sending the whole structure .4.43
4.8.3 Passing structures through pointers .4.8.3
4.8.4 Uses of structures 4.46
4.9 Operation on complex numbers(add, sub, multiply, divide) .4.47
4.10 Union and its definition .4.53
4.12 Bit-field : 4.58

Chapter 5
Binary files

5.1 Files and classification of files 5.1


~.1.1 Text file 5.2
5.1.2 Binary file 5.3
5.2 Using binary files 5.4
5.2.1 Declare a file pointer variable : 5.5
5.2.2 States and modes of a file 5.6
5.3 Standard library functions for files 5.9
: 5.3.1 File open and close functions 5.9
5.3.2 Block read and write (i/o) functions 5.11
5:3.2.1 file read - fread :- 5.11
5.3.2.2 file write - fwrite 5.15
5.3.3 File status functions 5.20
5.3.4 File positioning functions 5.23
5.3.5 System file operations 5.27
5.4 Using text files ': :..5.30
5.4.1 getc, putc 5.30
5.4.2 fscanf, fprintf 5.35
5.5 Command line arguments 5.41
5.5.1 Display contents of file 5.42
5.5.2 Obtain text and create a file (use only command -line arguments) 5.44
5.5.3 Implementing copy command : _ 5.46
UNIT-3
DATA STRUCTURES
Chapter 6
The Stack

6.1 Introduction 6.1


6.2 Stacks 6.2
·6.2.1 Insert/Push operation 6.3
6.2.2 Delete/pop operation 6.6
6.2.3 Display 6.9
6.2.4 Stack implementation using arrays 6.11
6.3 Applications of stack 6.14
6.4 Conversion of expressions 6.14
6.4.1 Precedence and associativity of the operators 6.16
6.4.2 Conversion from infix to postfix 6.19
6.4.3 Conversion from infix to prefix 6.26
6.4.4 Evaluation of Postfix expression 6.32
6.4.5 Postfix to prefix 6.35
. 6.4.6 Postfix to infix : 6.38
6.4.7 Prefix to POStfiX 6.40
6.4.8 Prefix to infix 6.43
6.4.9 Other useful algorithms and solutions 6.45
6.5 Stacks using structures : 6.53

UNIT-4
Chapter 7
Recursion

7.1 Introduction 7.1


7.1.1 Iterative version to compute factorial of n 7.2
vn.2 Recursive version to compute factorial of n 7.4
7.1.3 How recursion works :. 7.5
";?I.4 ' Fibonocci series 7.9
7.2 GCD of two numbers(Euclid's algorithm) 7.12
';;.3 Tower ofHanoi ~ 7.14
./7.4 Multiplication of natural numbers 7.16
.}0 Binary search 7.18
7.6 Maximum ofn elements 7.20
7.7 Minimum ofn elements 7.22
7.8 Sumofnelementsofarray 7.23
7.9 Product ofn elements of array : 7.24
7.10 Print a given number in reverse order : 7.24
7.11 Print array elements, in reverse order.. 7.25
7.12 Efficiency of recursion 7.26
"J13 Properties of r~cursive functions 7.28

Chapter 8
Queues

8.1 Introduction .., , "., : , 8.1


8.2 Different types of queues 8.2
J2.1 Queue (Ordinary queue) 8.3
/8.2.1.1 Insert at the rear end 8.3
/8.2.1.2 Delete from the front end 8.6
8.2.1.3 Display queue contents 8.8
8.2.2 Double ended queue(Deque) 8.12
8.2.2.1 Insert at the front end : 8.13
8.2.2.2 Delete from the rear end 8.15
8.2.2.3 Disadvantage of queue (ordinary queue) 8.20
~2.3 Circular queue 8.21
-: 8.2.3.1 To insert from the rear end 8.23
1"'8.2.3.2 To delete from front end : 8.24
8.2.3.3 To display queue contents 8.25
v'S.2.4 Priority queue 8.27
8.3 Dequeue using structures 8.31
8.4 Circular queue using structures 8.36
8.5 Priority queue using structures 8.40
8.6 Input restricted queue 8.44
8.7 Output restricted queue 8.46

UNIT-5

Chapter 9
Lists

9.1 Introduction : ~9.1


9.2 Linked list 9.2
~ .2.1 Singly linked list 9.3
9.2.2 Operations on singly linked lists 9.14
.....-9.2.2.1Insert a node at the front end 9.14
..f7 9.2.2.2 Display singly linked list... 9.17
y.3 Other operations of lists 9.20
9.3.1 Delete a node from the front end 9.21
9.3.2 Insert a node at the rear end 9.23
9.3.3 Delete a node from the rear end 9.25
...)}.3,4 Implementation of queues using linked lists 9.29
/9.3.5 Implementation of stacks 9.30
9.3.6 Implementation ofdeques using linked lists 9.30
9.3.7 Creating an ordered linked list... 9.34
,/9.3.8 Search for an item in a list 9.38
....-9:3.9 Delete a node whose information field is specified 9.39
~.1 0 Delete a node at the specified position 9.43
9.3.11 Concatenate two lists 9.46
9.3.12 Reverse a list without creating new nodes 9.48
~.3.13 Insert a node at the specified position · 9.49
9.3.14 Priority queue using linked lists 9.50
9.3.15 Non-homogeneous lists .' 9.50
, 9.3.16 Implementation oflists using arrays 9.60
9.4 Static allocation Vs Linked allocation 9.69

UNIT-6

Chapter 9 continued
)

UiGer List structures


9.5 Circular singly linked list... 9.73
9.5.1 Insert a node at the front end : 9.75
9.5.2 Insert a node at the rear end 9.77
9.5.3 Delete a node from front end 9.79
9.5.4 Delete a node from rear end 9.81
9.6 Header node 9.85
9.7 Circular list with a header node 9.87
9.7.1 Insert a node at the front end 9.88
9.7.2 Insert a node at the rear end 9.89
9.7.3 Delete a node whose info field is specified 9.91
9.7.4 Insert a node at the specified position 9.92
9.7.5 Delete a node at the specified position 9.94
9.8 Doubly linked lists 9.100
9.8.1 Insert a node at the front end 9.102
9.8.2 Insert a node at the rear end 9.103
9.8.3 Delete a node from the front end 9.104
9.8.4 Delete a node from the rear end 9.106
9.8.5 Delete a node whose info field is specified 9.107
9.8.6 .Delete all nodes whose info field is specified as key : 9.109
9.8.7 Insert a node after the key/before the key · 9.110
9.8.8 Singly Vs Doubly linked lists 9.116
9.9 Application of linked lists : 9.117
9.9.1 Addition of two long positive numbers 9.117
9.9.2 Evaluation ofapolynomial 9.123
9.9.3 Addition of two polynomials 9.129
UNIT-7 and 8
Chapterl0
Trees
10.1 Introduction ~ :......................................................•.... 10.1
10.2 Types of binary trees ' 10.6
10.3 Storage representation ofa binary tree 10.9
10.4 Various operations on binary trees using linked representation 10.12
10.4.1 Insertion : 10.12
10.4.2 Traversals 10.14
10.4.3 Searching 10.21
10.4.4 Copying a tree ; 10.27
10.5 Binary search tree : 10.27
10.5.1 Insertion · 10.28
10.5.2 Searching 10.31
10.5.3 Other operations · 10.33
10.5.3.1 To fmd maximum value in a tree(BST) 10.33
10.5.3.2 To find minimum value in a BST 10.33
10.5.3.3 Height of tree 10.34
10.5.3.4 Count nodes in a tree 10.35
10.5.3.5 Count leaves in a tree : 10.35
10.5.3.6 Delete a node from the tree 10.36
10.5.3.7 Binary search tree as apriority queue 10.42
10.6 Applications 10.44
10.6.1 Searching ~ 10.44
10.6.2 Sorting ~ 10.44
. 10.6.3 Expression trees :10.45

hapter 11
Sorting and searching
11.1 Introduction 11.1
11.2 Bubble sort ~ 11.2
11.3 Selection sort : r: 11.5

11.4 Merge sort .. .. 11.7


11.5 Quick sort · 11.13
11.6 Tree sorts (Heap sort) : 11.17
11.6.3 Priority queue using heap , 11.26
11.7 Insertion sorts , 11.26
11.8.2 Shell sort 11.26
11.8 Address calculation sort : 11.30
11.9 Radix sort 11.33
11.10 Searching ..: :................................................•.... 11.37
11.10.1 Linear search (Sequential search) 11.38
11.10.2 Binary search : 11.40
11.10.3 Searching an ordered table 11.40
11.10.4 Indexed sequential search 11.41
11.10.5 Interpolation search : : 11.43
Data Structures (with C) LAB Programs
III SEMESTER

Sub Code IAMARKS:25


Hours/Week : 3 Exam Hours: 3
Marks: 50

stions listed in the syllabus have to be included in the lots. The


tion has to be considered, provided the request is made for the
same, wit half an hour from the start of the examination. The allotment of
s detailed below:

Sl. Activity Max.


No. Marks
.
1. Procedure 10
Writing program & procedure for the assigned
problems along with algorithms / flowchart

2. Conduction 30
Execution of the program, and showing the
results in proper format
3. Viva-voce** ) 10
.
Total Max. Marks 50
I

Minimum passing Marks (40% of Max. Marks) 20


1Arite a C program to create a sequential file with at least 5 records, each record
having the s sown
h b eow:
1 ~
-..............
USN Name Marksl Maf~l \ Marks3
+ve integer 25 characters +ve +ve I +ve
integer integer I integer., I

Write ~ecessary functions:


• To display all the records in the file
• To search for a specific record based on the USN. In case the record is not
found, suitable message should be displayed. Both the options in l~ltiscase
must be demonstrated

Solution: Example 5.4.2.7, Page 5.38


YWrite and demonstrate the following C functions:
• newStrCpy that does the same job as the strcpy
• newStrCat that does the same job as strcat without using any library
functions.

Solution:: Example 3.6.2.3, Page 3.32 (strcpy)


Example 3.6.4.2, Page 3.37 (strcat):

3/'Write a C program, which accepts the Internet Protocol (IP) address in decimal
dot format (ex: 153.18.8.105) and converts it into 32-bit long integer
(ex:2568095849) using strtok library function and unions.

Solution: Page 10.74

4/'Write a C Program to construct a stack of integers and to perform the following


operations on it:
• Push
• Pop
• Display
The program should print appropriate messages for stack overflow, stack
underflow, and stack empty.

Solution: Example 6.2.9, Page 6.11 (using global variables)


Example 6.2.10, Page 6.12 (by passing parameters)
Example 6.5.8, Page 6.57 (Using structures) ,
5 <Write a C Program to convert and print a given valid parenthesized infix
arithmetic expression to postfix expression. The expression consists of single
character operands and the binary operators + (Plus), - (minus), * (multiply) and /
(divide).

olution: Example 6.4.2.5, Page 6.24

6 Write a C Program to evaluate a valid suffix/postfIx expression using stack.


Assume that the suffix/postfix expression is read as a single line consisting of
non-negative single digit operands and binary arithmetic operators. The ~~Uunetic
operators are + (add), - (subtract), * (multiply) and / (divide).
-----.
Solution: Example 6.4.4.2, Page 6.33--
7/'Write a C Program to simulate the working of a queue of integers using an array.
Provide the following operations:
• Insert
• Delete
• Display

Solution: Example 8.2.1.3.3, Page 8.10 (using global variables)

Note: .There is a mistake in maim),


Use insertreart), instead of insertrearfitem, q, &r)
Use delete_fronu), instead of delete_front(q, &f, &r) i

8/Write a C Program to simula.~ the working of Ii drcular qlJ~'!~ vf integers using


an array. Provide the following- operations:
• Insert
• Delete
• Display

Solution: Example 8.2.3.3.2, Page 8.26


9. Write a C Program using dynamic variables and pointers, to construct a singf
linked list consisting of the following information in each node: student ic
(integer), student name (character string) and semester (integer). The operations tc
be supported are:
• The insertion operation
i. At the front of a list
ii. At the back of the list
iii. At any position in the list
• Deleting a node based on student id. If the specified node is not present in the
list an error message should be displayed. Both the options should be
demonstrated .
• Searching a node based on student id and update the information content. 1
the specified node is not present in the list an error message should be
displayed. Both situations should be displayed .
• Displaying all the nodes in the list.

Solution: Example 9.3.15.9, Page 9.57

Note: Only one set of operations among a, band c with d may be asked in the
examination

lO;Write a C Program using dynamic variables and pointers to construct a stack 01

·
integers using singly linked list and to perform the following operations: - ./
·-Push ~
~ /
• Display ~
The program should print appropriate messages for stack o,vrflo~ a;d stack
empty.

Solution: Example 9.3.5, Page 9.31

11 ~rtte aerogram using d amic vari~bles and pointers tc construct a queue of


integers using singly link list and to perform the followirg operations:
• Insert
•.... Delete
• Display
The program should print appropriate messages for c;tIeuefull and queue empty.

Solutiouz Same as example 9.3.5, Page 9.31, lXlt; instead of insert_frontO call
insert-rean) given in example 9.3.2
12.Write a C Program to support the following operations on a doubly linked list
where each node consists of integers: .
• Create a doubly linked list by adding each node at the front.
• Insert a new node to the left of the node whose key value is read as an input
• Delete the node of a given data, if it is found, otherwise display appropriate
message.
• Display the contents of the list.

Solution: Same as example 9.8.7.3, Page 9.113

Note: Only either (a,b and d) or (a, c and d) may be asked in the examination

13.Write a C Program
• To construct a binary search tree of integers.
• To traverse the tree using all the methods i.e., inorder, preorder and postorder.
• To display the elements in the tree.

Solution: Example 10.5.3.6.2, Page 10.40

141Writerecursive C Programs for


• Searching an element on a given list of integers using the Binary Search
method.
• Solving the Towers of Hanoi problem.

Solution: Example 7.5.2, Page 7.20 (binary search)


Example 7.3.2, Page 7.16 (Tower of Hanoi)

Note: In the examination all questions must be given on lots.


Chapter 1: Introduction to C
I What are we studying in this chapter? I
• Keywords, identifiers, Constants
• Various data types
• Operators in C
• Variables
• Control statements
• Arrays
• Functions

1.1Introduction
Thischapter gives a brief description of various types of constants, data types,
operatorsand control statements available in C language. This chapter also gives a
briefdescription on arrays, functions and and memory organization of C language.

ote: The author assumes that the reader has fair knowledge of C language. In case,
thereader wants to know more fundamentals and the method of writing C programs
stepby step in a systematic manner before proceeding to Advanced C and data-
structures,he/she can refer the book "Computer Concepts and C Programming
Techniques" by Padma Reddy A.M

Thesequence of steps to learn any language including C language is shown below:

Step1: As a first step, before learning any language (such as English), we learn the
alphabets of a language. Here, we learn the alphabets of C language.
Step2: In the second step, we learn how one or more alphabets can be grouped
together to form meaningful words. In C language, these meaningful words
are called tokens.
Step3: In the third step, we learn how one or more words (called tokens) are
grouped together to form meaningful sentences. In C language, the sentences
are called instructions or statements.
Step 4: In the final step, we learn how one or more sentences can be grouped
together to form paragraphs. In C language, these collections of paragraphs
(group of statements) constitute a complete program.
1.2 Q Introduction to C

Steps to learn Steps to learn


English language C Language

Ex: Letters from A to Z, a to z


Alphabets Alphabets Digits from 0 to 9
,"

Symbols such as +, -, *, <, > etc.


1 1 Ex: Keywords: for, if, int, float, .....
Words Tokens Variables: sum, area, first, marks, .
Constants: 10, 10.5, -5.9999,'a', .
1 1 Ex: 1. area = length * breadth;
Sentences Statements/
2. si = p * t * r / 100;
Instructions

1 1 #include <stdio.h>
void maim)
Paragraphs Program {
int si, p = 1000, t = 2, r = 5;

Fig. 1.1 Steps to learn a si = p * t * r /100;


programming language
printf("simple interest = %d" ,si);
}

Now, let us follow these steps one by one to learn C language.


L

1.1.1 Character set (Alphabets of C)


The first step in learning C language is to learn alphabets of C language. As English
language has alphabets such as 'A' to 'Z', C language also has its own alphabets.
Now let us see" What are the alphabets of C language? or What are the characters
that are used while writing C programs?"

Definition: The characters that are used while wntmg C programs are called
alphabets or character set. Using these alphabets, we can obtain meaningful numbers,
meaningful expressions and statements. For example, the alphabets of C language are
shown below:
• Letters: Upper case letters from 'A' to 'Z' and lower case letters from 'a' to 'z'
• Digits: from 0 to 9
1.2 .Q Introduction to C

Steps to learn Steps to learn


English language C Language

Ex: Letters from A to Z, a to z


Alphabets Alphabets Digits from 0 to 9
Symbols such as +, -, *, <, > etc.
! 1 Ex: Keywords: for, if, int, float, .....
Words Tokens Variables: sum, area, first, marks, .
Constants: 10,10.5, -5.9999,'a', .
! 1 Ex: 1. area = length * breadth;
Sentences Statements/
2. si = p * t * r / 100;
Instructions

1 1 #inc1ude <stdio.h>
void mairu)
Paragraphs Program {
int si, p = 1000, t = 2, r = 5;

Fig. 1.1 Steps to learn a si = p * t * r / 100;


programming language
printf("simple interest = %d",si);
}

Now, let us follow these steps one by one to learn C language.

1.1.1 Character set (Alphabets of C)


The first step in learning C language is to learn alphabets of C language. As English
language has alphabets such as 'A' to 'Z', C language also has its own alphabets.
Now let us see "What are the alphabets of C language? or What are the characters
that are used while writing C programs?"

Definition: The characters that are used while writing C programs are called
alphabets or character set. Using these alphabets, we can obtain meaningful numbers,
meaningful expressions and statements. For example, the alphabets of C language are
shown below:
• Letters: Upper case letters from 'A' to 'Z' and lower case letters from 'a' to 'z'
• Digits: from 0 to 9
Q Systematic Approach to Data Structures using C 1.3

• Symbols such as
- tilde # hash % percent
A caret ( left parentheses = assignment
- rmnus srgn ) right parentheses underscore
+ plus sign -' {left brace I vertical bar
/ division symbol } right brace ' single quote or apostrophe
* asterisk (or star) [left bracket dot
; semicolon ] right bracket " double quotation
: colon < less than ? question mark
, comma > greater than \ back slash
• White spaces: Characters such as space, tab(\t), new line(\n), carriage return(\r)
etc. are also the alphabets of C language and are called white spaces.

1.1.2 C Tokens
Oncewe know the alphabets of C language, the second step in learning C language is
"How these alphabets are combined to get meaningful words called tokens?" Now,
letus see "what are C tokens?"

DcfinitionA token is a smallest or basic unit of any program. One or more characters
are grouped in sequence to form meaningful words. These meaningful words are
called tokens. The tokens in C language are broadly classified as shown below:
Keywords Ex: if, for, while etc.
Identifiers Ex:sum, length, i etc.
Tokens __ -+---:~Constants Ex)O, 10.5, 'a', "padrna" etc.

Operators Ex:+, -, *, / etc.

Special symbols Ex: [], {}, () etc.

1.1.3Keywords
In this section, let use see "What are keywords? What are the various keywords
available ill C?"
Dcfinition: The words which have predefined meaning in C language are called
.f words.Since they are reserved for specific purpose in C language, they are also
cal ed reserved words. The keywords have some specific purpose in C language and
1..4 Q Introduction to C

~ence can not be used as variable names, function names etc. The different keywords
available in C language are shown b~low:

Keywords
auto double int struct
break else long switch
case enum register typedef
char extern return umon
canst float short unsigned
continue for signed void
default go to sizeof volatile
do if static while

Note: The meaning of the keywords can not be changed by the user. One more
important thing to remember is that all keywords should be written, in lower case
letters. We should never use capital letters while using keywords. If 'we use capital
letters they are treated as just identifiers.
1.1.4 Identifiers
In this 'Section, let use see" What are identifiers?"
De nition: An identifier is the fancy term used in place of 'name '. An identifier is a
word consisting of sequence of one or more letters or digits along with "_" (read as
underscore). The rules to be followed to frame an identifier are:
• The first character in the identifier should be a letter or "_" (read as underscore)
and can be followed by any number of letters or digits or underscores.
• No extra symbols are allowed other than letters, digits and "_".
• The length of an identifier can be up to a maximum of 31 characters.
if'" fA'~.(~a'"~Id~ •• ~~ "<. ;,L • .~". ...d: s •• • Y ••

",\'ahd/l!1Vahd , bl; ~easons for !~v~tl,d~ty.!:.Jj'l '; :"'",'


1'!deq!!fierS.;';;~:i~";"_<,,! .
principle amount valid -
a valid -
a
- --- 1 valid One or more underscores is valid
- I--- b valid

---
a--- 1 valid
Sum1 valid -
~ Systematic Approach to Data Structures using C 1.5

for invalid It is a keyword


forl valid -
3 factorial invalid Should not start with digit
Sum, 1 invalid Comma should not be there
sum-of-digits invalid Minus sign should not be there
sum of digits invalid No spaces are allowed
$sum invalid . $ sign should not be there
if invalid It is a keyword
valid But, do not use

Note: Do not use only underscores as an identifier, even though it is valid identifier.
Trythis program:
void maim)
{
int -= 10', /* Note: Underscore is used as a variable *1
printf("%d",-.J; /* Output: 10*/
}

1.1.5 Constants
In this section let us see "What are constants? What are the different types oJ
constants?"along with examples of valid and invalid constants.
Definition: A constantis a data item which will not change during the execution of a
program.The constants in C language are classified as shown below:

Integer

Floating point
Constants
Character constant

String constant

1.1.5.1 Integer constant


Now,let us answer the question "What is an integer? Explain with example"

Definition: An integer constant is a whole number without any decimal point. No


extra characters are allowed other than + and - sign. If + and - are present, they
1.6 Q Introduction to C

should precede the number. An integer constant can be classified into three types as
shown below:

Decimal -For example, 10, 140, -140 etc.

Integer
constantst Octal For example, 010, 0140, -0140 etc.

Hexadecimal For example, Ox8A, OXAB, OXAl23 etc.

Now, let us answer the question "What is a decimal number? Explain with example"
Definition: A decimal integer constant can be any combination of digits from '0' to
'9'. No extra characters are allowed other than + and - sign. If + and - are present,
they should precede the number. For example, 100, -67, +989 etc. are valid. The
following are invalid:

Integers valid/invalid Reasons for invalidity


10,000 ' invalid Comma not allowed f'

0.5 invalid Decimal point not allowed


10 20 invalid Space is not allowed
085 invalid Should not have a prefix 0
32768 invalid Out of range for 16 bit machine
-32769 invalid Out of range for 16 bit machine

Now, let us answer the question "What is an octal number? Explain with example"

Definition: An octal integer constant can be any combination of digits from '0' to '7'
with a prefix 0 (digit zero). No extra characters are allowed other than + and - sign.
If + and - are present, they should precede the number. For example, 010, 0777, -065
etc. are valid. The following are invalid:

Integers valid/invalid Reasons for invalidity ,


. , -
,
10,000 invalid Comma not allowed
0.5 invalid Decimal point not allowed
10 20 invalid Space is not allowed
085 invalid 8 is invalid in octal ,
777 invalid Should have a prefix 0

Now, let us answer the question "What is a hexadecimal number? Explain with
example"
Q Systematic Approach to Data Structures using C 1.7

Definition: A hexadecimal integer constant can be any combinations of digits from


'0' through '9' along with the letters 'A' to 'F' or 'a' to 'f. This constant has to be
preceded by Ox or Ox. For example, Ox8A, OXAB, OXA123 etc. are valid. The
followingare invalid constants.
. .
!~tegers.)!~~valid/invalid . Reasons for invalidity . . .
'

10,000 invalid .Comma not allowed


OxABGH invalid G and H are invalid characters
Ox123.45 invalid Decimal point not allowed
..

01234 invalid Should precede with Ox or OX

Note: A number starting with 0 is an octal number and should have digits from 0 to 7.
Usuallydecimal integer constants are used in programming. Octal and hexadecimal
constantsare rarely used.

1.1.5.2Floating point constant

Definition: The numeric quantities having fractional part are called floating point
constants.All negative 'numbers should have a prefix '-'. A positive number can have
an optional '+' sign. No other extra characters are allowed. The floating point
constantscan be represented using two forms as shown below:
~ Fractional form
Floating point
notations ~ Scientific notation
(Exponent notation)

Fractional form: Now, the question is "How to represent floating point numbers
usingfractional form? Give examples" A floating point number represented using
fractionalform has an integer part followed by a decimal point and a fractional part.
We can omit the digits before the decimal point or after the decimal point.
For example,0.5, -0.99, -.6, -9., +.9 etc are all valid floating point
numbers.

Exponent form (Scientific notation): Now, the question is "How to represent


floating point numbers in. scientific notation? Give examples "The floating point
number represented using scientific notation (also called exponential notation) has
threeparts namely: .
(Partl) (Part2) (Part 3)
mantissa e or E exponent.
Q Systematic Approach to Data Structures using C 1.7

Definition: A hexadecimal integer constant can be any combinations of digits from


'0' through '9' along with the letters 'A' to 'F' or 'a' to 'f. This constant has to be
preceded by Ox or Ox. For example, Ox8A, OXAB, OXA123 etc. are valid. The
followingare invalid constants.

o ~Rt~ger(:!~
~yalid/invalid iReasons for invalidity
10,000 invalid .Comma not allowed
OxABGH invalid G and H are invalid characters
Ox123.45 invalid Decimal point not allowed
- -
01234 invalid Should precede with Ox or OX

Note: A number starting with 0 is an octal number and should have digits from 0 to 7.
Usuallydecimal integer constants are used in programming. Octal and hexadecimal
constantsare rarely used.

1.1.5.2 Floating point constant

Definition: The numeric quantities having fractional part are called floating point
constants.All negative 'numbers should have a prefix '-'. A positive number can have
an optional '+' sign. No other extra characters are allowed. The floating point
constantscan be represented using two forms as shown below:
~ Fractional form
Floating point
notations ~ Scientific notation
(Exponent notation)

Fractional form: Now, the question is "How to represent floating point numbers
usingfractional form? Give examples" A floating point number represented using
fractionalform lias an integer part followed by a decimal point and a fractional part.
We can omit the digits before the decimal point or after the decimal point.
For example, 0.5, -0.99, -.6, -9., +.9 etc are all valid floating point
numbers.

Exponent form (Scientific notation): Now, the question is "How to represent


floating point numbers in scientific notation? Give examples "The floating point
number represented using scientific notation (also called exponential notation) has
threeparts namely: .
(PartI) (Part2) (Part 3)
mantissa e or E exponent.
1.8 Q Introduction to C
t
where
• The mantissa can be an integer or a floating point number represented using
fractional notation.
• The letter e or E should follow mantissa.
• The exponent should follow e or E. The exponent has to be an integer with
optional '+' or '-' sign.
The following examples gives invalid floating point numbers. The reasons for
invalidity are also shown.
• >

,Floating point/ valid/invalid . Reasons for invalidity


.Real constant.
22.0/7 invalid / is not allowed
120 invalid No decimal point
6.5e 8 invalid White space not allowed between e and 8
1.2.3 invalid More than one decimal point is not allowed
2,123.4 invalid Comma is not allowed
10.5e-6.9 invalid Fractional part 6.9 is not allowed in exponent part

1.1.5.3 Character constant

Definition: A character enclosed within a pair of single quotes (apostrophe denoted


by') is called a character constant. Each character is associated with a unique value
c led an ASCII(American §.tandard Code for ,!nformation Interchange) value. The
following example gives valid and invalid character constants. The reasons for
invalidity are also shown.

'character /"f'?'''' fvalid/invalid 'Reasons for invalidity- ", . . '..


c~nstant .'_ '. . :-..
'9' valid
'a' valid
'$' valid
'\nO valid Escape character (see section 8.6.4)
'\t' valid Escape character (see section 8.6.4)
"9" invalid Double quotes not allowed
'99' invalid Two characters are not allowed
Now, let us see "What are backslash constants? or What are escape sequence
characters?"
Q Systematic Approach to Data Structures using C}~
Definition: An escape sequence character begins with a backslash and is followed by
one character. A backslash(\) along with some characters give rise to special print
effects by changing( escaping) the meaning of some characters. Since an escape
sequence character starts with backslash, they are also called backs lash constants.
The commonly used escape sequences are shown below:

Character Escape" "~ ".". Meaning ,


"', , " character ',' ""1; ,r , '., ,
Bell \a Beep sound
backspace \b Cursor moves towards left one position
horizontal tab \t Cursor moves towards right by 8 positions
vertical tab \v This is usually not supported
newline \n Cursor moves to the next line
form feed \f Cursor moves to the next page
carriage return \r Cursor moves to the start of current line
quotation mark \" "
apostrophe \'
question mark \? ?
backslash \\ \
NULL \0 Null character

Note: The backslash characters such as \a, \b, \t, \v, \n, \f, \r and \0 are non-printable
characters.

1.1.5.4 String constant

Dcfinition:A sequence of characters (i.e., one or more characters) enclosed within a


pair of double quotes is called a string constant. The string always ends with NULL
(denoted by \0) character. The following example gives valid and invalid string
constants. The reasons for invalidity are also ~.,.Jwn.

character1'q'):',/; :'valid/invalid' Reasons


l' for,invalidit:\F"'iif ;"~" )~!~~~'0Ii;;;:
co~sta'iit'M::et~ij~:i~;;
:.:::','~~ ' ',' :, r>,"':,:;::;.
no,' ,.:/ :~~'" '-:L.' ,:}:: j'li~:~~
:'-:~ ~~;
'9' invalid Should be enclosed between " "
"9" valid -
"Padma" valid -
"\n." valid -
'Padma' invalid Should be enclosed between " "
"padma reddy" valid -
1.10 Q Introduction to C

1.Z"Meaning of variables

Definition: A variable is defined as the name given to a memory location where the
data can be stored, accessed or manipulated. In short, an identifier which is used to
store a value is called variable. The value stored in the variable may change during
execution of the program.

Note: A variable name should not be a C keyword such as if, lor, else, while etc. See
section 1.1.4 for valid and invalid variables (identifiers).

Note: Always it is better to use the variables with meaningful names for easy
understanding of the program. Do not use only underscore as variable name, even
though it is valid.

1.3 Basic/Simple/Primitive Data types


Definition: We know that variables can have different values in memory during
execution of a program. The type of the value that a variable can store in the memory
can be defined using data type. The various primitive data types of C language are
classified as shown below:

int
char
Primitive
Data types --+--. float
double
void

Note: The primitive data types are also called basic data types or simple data types or
fundamental data types.

1.3:1 int
It is a keyword which is used to define integer numbers. Normally they are
associated with the variables to store signed integer values in memory locations. That
is, using this data type both positive and negative numbers can be stored in the
memory. To represent only unsigned numbers it is normally associated with a
qualifier unsigned.

,!;lSystematic Approach to Data Structures using C 1.11

For example, unsigned int is used to define only positive numbers. Negative
numberscan not be stored if a variable is associated with unsigned int. The size of
integer and range of integer varies from machine to machine as shown below:

or
o to 65535
32-bit machine 4 bytes o to 2 -1
or or
o to 4294967295 2147483648 to 2147483647

1.3.2 float
It is a keyword which is used to define floating point numbers. The floating point
numbersare also called real numbers. Normally they are associated with the variables
(alsocalled identifiers) to store floating point numbers in memory locations. That is,
usingthis data type both positive and negative floating point numbers can be stored in
thememory.

1.3.3 double
It is a keyword which is used to define BIG floating point numbers with much higher
precision.Normally they are associated with the variables to store BIG floating point
numbersin memory locations. That is, using this data type both positive and negative
BIG floatingpoint numbers can be stored in the memory.

1.3.4 char
It is a keyword which is used to define single character or a sequence of characters
calledstring. Normally, they are associated with the variables to store a character or a
stringin memory locations. Each character stored in the memory is associated with a
unique value called an ASCII (American Standard Code For Information
Interchange)value.

1.3.5 void
It is an empty data type. It is normally used in functions to indicate that the function
doesnot return any value. Since no value is associated with this data type, it does not
occupyany space in the memory. Normally, it is not associated with any variable
(exceptpointers).

1.12 Q Introduction to C

1.4 User defined data types


Now, let us see "What are user defined data types?"

Definition: The programmer can define his/her own identifiers to represent a data
type using primitive data types or derived data types. These data types that are
renamed or defmed by the programmer for his/her convenience are called user
defined data types. The user defined data types car. also be used to declare the
variables. Consider the syntax shown below:

typcdcf data_type identifier;

where
• typedef is the keyword.
• data_type can be basic or derived or another user defined data type.
• identifier is the new name given to the ~ata_type.

Consider the type definition statement shown below:

typcdcf f1oatAMOUNT~

Here, the identifier AMOUNT can be considered as a new data type, derived from the
basi data type float. For example, in the declaration

AMOUNT a;

a is variable of type AMOUNT i.e., of type float. Some of the points to be


remembered at this point are:
• Using typedef more meaningful data type names with short names can be created
and used for declaring the variables. Thus, increasing the readability of the
program.
• The rules used for defining the identifier can be used to obtain a new data type
such as AMOUNT.
• If the typedef statement is situated within a function, the scope of this typedef is
limited only to that function and the new data type thus obtained can not be used
outside this function. If the typedef is in the beginning of all the functions, then it
will be global and can be used by any function.
Q Systematic Approach to Data Structures using C 1.1~

1.5 Declaration of variables


Now, let us answer the question "What is type declaration or How to declare the
variables?What is the use oj declaration of variables?"

Definition: The compiler reserves the memory for the variables so that the data can
be accessed, manipulated and stored using these variables. For this to happen, all the
variablesshould be declared in the beginning of the program. This way of declaring
all the variables in the beginning of the program is called. type declaration or
declarationoj variables. The. purpose of declaring the variable is to know the type of
datato be stored and to reserve the required amount of memory for the variables. The
reservingmemory for the variables based on the data type is done by the compiler.

Thesyntax to declare a variable is shown below;

data_type vl,v2, ..... vn;


where
• data_type is any of the basic data type such as int, float, char, double etc.
• vI,v2, .. vn are the variables. All the variables should be separated by commas and
finally should end with semicolon;

Forexample,
int number, choice, flag;
float amount;

In this example, the variables such as number, choice and flag are integer variables.
This declaration indicates that these variables contain only integer values. The
variable amount should contain only floating point number since it is declared as
float.

Note: Always it is better to use the identifiers with meaningful names for easy
understandingof the program.

Now, we will see how these variables and constants are joined together usmg
operatorsto obtain the expressions and how to evaluate the expressions.

1.6 Operators

Now, let us see "What is an operator?" An operator is a symbol that specifies the
operation/activity to be performed. For example, + means add, - means subtract, *
1.14 Q Introduction to C

means multiply and so on. Here, + , -, * , I etc., are some of the operators in C. C
language includes large number of operators. The operators in C can be classified
based on
• The number of operands an operator has.
• The type of operation being performed.

1.6.1 Classification based on the number of operands

A mathematical expression consists of numbers and variables joined by operators


such as +, -, *, I and % to perform meaningful computations. For example,

10 + 20 II Here, 10 and 20 are called operands and + is an operator.


II Since there are two operands, the operator + is called
II a binary operator

-100 II Here 100 is an operand and '-' is an operator. Since the


II operator '-' is associated with only operand it is called
II unary operator
-
Now, let us "Classify the operators in C language based on the number oj
operands and Give suitable examples" The operators are classified into four major
categories based on the number of operands as shown below:

Unary operators
Binary operators
Operators
Ternary (?:)

Special: comma, sizeof etc.

Now, let us "Define the unary operator giving examples"

Definition: An operator which acts on only one operand to produce the result is
called unary operator. In the expressions involving unary operators, the operators
precede the operand. For example, -10, -a, *b, &c, -d etc., are all the expressions
with unary operators.

Now, let us "Define the binary operators giving examples"


.Q Systematic Approach to Data Structures using C 1.15

Definition: An operator which acts on two operands to produce the result is called a
binary operator. In an expression involving a bi~ary operator, the operator is in
between two operands.
For example, a + b, a * b, 10/5, 10/a etc., are all expressions with binary
operators.

ow, let us "Define the ternary operator giving examples"

Definition: An operator which acts on three operands to produce a result is called a


ternary operator. Ternary operator is also called conditional operator. For example,
a? b: c

In this example, there an, three operands a, band c (hence the name ternary). The two
operators are? and :

1.6.2Classification based on the type of the operation


Since C has more number of operators, instead of classifying the operators based on
the number of operands on which the operator acts, it is better to classify them based
on the type of operation being performed as shown below:

Arithmetic operators (+, *, - etc.)


Assignment operators ( =, += etc., )
IncrementlDecrement operators ( ++, --)

Types of Relational operators ( <, <=, etc., )


Operators Logical operators ( &&, II etc., )
Conditional operator ( ?:)
Bitwise operators ( &, A, etc., )
Special operators ( , . [] etc.,)

E
comma operator (,)
size of operator
Address operator (&)
etc.,
Now, let us discuss each of these operators one by one in detail.

1.7Arithmetic Operators
In this section, let us see ••What are arithmetic operators? What are the operations
performed by these operators? Explain with examples"
1.16 Q Introduction to C

Definition: The operators that are used to perform arithmetic operations such as
addition, subtraction, multiplication etc., are called arithmetic operators. Arithmetic
operators can be classified into two types based on the number of operands as:
• Arithmetic binary operators
• Arithmetic unary operators

The meaning of all the operators along with examples is shown below:
Description Symbols Meaning Example result

Addition + add 4+2 6


Arithmetic Subtraction subtract 4-2 2
Binary Multiplication * multiply 4*2 8
Operators Division I divide 4/2 2

/"
Mod % remainder 4%2 0

Note: Modulus operation denoted by % is used only for integer values and not for
floating point numbers. This operator returns the remainder after division. Some other
examples involving modulus operations are shown below:

Example Result
3%2 1 [Divide 3 by 2. The remainder is 1]
5%3 2 [Divide 5 by 3. The remainder is 2]
2%5 2 [Divide 2 by 5. The remainder is 2]
-5%3 -2 [Divide -5 by 3. The remainder is -2]

1.7.1 Ar ithmctic expressions


Once we know various arithmetic operators, let us see "What are arithmetic
expressions r:

Definition: An expression consisting of constants and variables along with arithmetic


operators such as +, -, *, I and % to perform meaningful computation is called an
arithmetic expression. The constants and variables in an expression are called
operands.

For example
10 + 2 * 5 II Here, 10,2 and 5 are operands whereas +, * are operators
(a + b - c) 12 II Here, a, band c are operands and +, - are operators.
are arithmetic expressions.
Q Systematic Approach to Data Structures using C 1.17

1.7.2 Modes of expressions


In the expression a + b, a and b are called operands and + is the operator. The
operandsin an expression can hold integer, floating point or double values. Based on
thetypeof the operands in the expression, there are 3 modes of expressions namely:
• Integer expressions
• Floating point expressions
• Mixed mode expressions

Integer expression: If all the operands such as constants and variables are of type int,
theresult obtained will be of type integer. The resulting expression is called integer
expression. For example,
4/2 = 2 (In 412,4 and 2 are operands and / is an operator)
4/3 = 1 (Note: Answer is not 1.3333 because both operands are integer
and hence the result should be in integer format)
3/4= 0 (Note: It is not 0.75 because both operands are integer and
hence the result should be integer. The value after dot .',<,
should be discarded)

floating point expression: If all the operands such as constants and variables are of
typefloat or double, the result obtained will be of type float or double. The resulting
expressionis called floating point expression. For example,
4.0/2.0 = 2.'0 .
4.0/3.0 = 1.333
3.0/4.0 = 0.75

fixed mode expressions: If the operands such as constants and variables are of
differentdata types such as int.float, double etc .., the expression is called mixed mode
expression. DUring evaluation, all the values should be of same data type. So, data
conversion takes place from one data type to another data type (implicit type .
conversion).This is done normally done by converting/promoting lower data type to
higherdata type. For example,
4.0/3 = 1.333 ( Note:Here, the integer 3 is converted into float, then
4. / 3 = 1.333 (evaluation is carried out and hence, the result is float)

1.7.3 Arithmetic operator's precedence (Prece~ence of operators)


In this section, let us See the rules that are to be followed during evaluation of an
arithmeticexpression. We have studied in high school to evaluate a mathematical
expressionusing BODMAS rulepuring evaluation:
1.18 Q Introduction to C

• Brackets will have the first precedence


• 0f operator will have the second precedence
• Division operator will have the third precedence
• 1\1ultiplication operator will have the fourth precedence
• A ddition operator will have the fifth precedence
• Subtraction operator will have the sixth precedence.

Exa mple 1.7.3.1: What is the result of 6 x (2 + 3) / 5? Based .on the BODMAS rule,
in this example, the following operations have to be carried out in sequence:
• First preference is to evaluate within Brackets
.• Second preference for Division .
• Third preference for Multiplication

Based on the BODMAS rule (priority), we evaluate -the given expression as shown
below:-
6x~/5
Brackets have the first precedence
6 x '---y--J
5 / 5
Division has the second precedence
6 x 1
'---.r---'
Multiplication has the third precedence
6
Thus, based on the priority given to each operation in the BODMAS rule, the
expressions are evaluated. These rules are called precedence rules or precedence of
operators or hierarchy of operators Before worrying about precedence of operators
in C, let us see the evaluation of an expression with two or more operators having the
same priority.

Example 1.7.3.2: What is the result of8 + 4 + 3? All of us evaluate the expression as
shown below:
8 + 4 + 3
'-y-' [First add 8 and 4 to get 12] /

12 + 3
'---y-U
[Next add 12 and 3 to get 15]
15
Observation: In the above expression, same operator "+".is used twice and hence
both operators have the same priority and the precedence rules are not applicable.
Q Systematic Approach to Data Structures using C 1.19

Thenthe question is "How to evaluate?" Normally, we do the evaluation as shown


below:
First we compute 8 + 4 to get 12
Next we compute 12 + 3 to get 15 thus moving from Left to Right.

Sinceevaluation is done from left to right one after the other, we say that the operator
"+" is left-to-right associative (also called left associative). Now, let us "Define left-
to-right associative. Give examples"

I finition: In an expression, if there are two or more operators having the same
priorityand are evaluated from left-to-right, then the operators are called Left to Right
ciauve operators. We normally denote using L ~ R. They are also called left
associativeoperators. This process of evaluating from left to right is called left
associativity.
For example,
8+4+3=15
8-4-3=1
Inthisexample, the operators ,"+" and "-" are left associative operators.

Now,let us see "What is precedence of operators or hierarchy of operations in C


guage?"

finition: In C language, each operator is associated with a priority value. Based on


thepriority, the expressions are evaluated. A part of the expression with priority 1 is
evaluatedfirst; part of the expression with priority value 2 is evaluated next and so
on. These priority values that are associated with various operators are called
, ecedence of operators. The operations that are carried out based on the precedence
ofoperatorsare called hierarchy of operations. ,
For example, the table below shows arithmetic operators along with priority
andassociativity:
Description Operator Priority Associativity

Multiplication (*) 1 Left to Right


Division (I) 1 Left to Right
Arithmetic
Operators Mod (%) 1 Left to Right
Addition (+) 2 Left to Right
Subtraction (-) 2 Left to Right
1.29 Q Introduction to C

From the table the following observations are made:


• First preference is given to the operators *, / and % because all of them have the
priority values 1.
• Second preference is given to the operators + and - because all of them have the
priority values 2. _
• If an expression consists of only the operators *, / and % then the evaluation is
done from left to right because they are left-to-right associative
• Similarly, if an expression consists of only the operators + and -, then the
evaluation is done from left to right because they are left-to-right associative. For
example, consider the evaluation of two expressions shown below:
8 / 4 * 16 8 *4 / 16'
~ ~
.2 * 16 32 / 16
'---v--' '---v--'
32 2
Note: Observe that in both the expressions, evaluation is done from left to right
whether the first operator is / or *. This. is because both of these operators have the
same priority values and they are left associative. Let us take some more examples:

1.7.4 Relational operators


In this section, let us see another Important type of operator in C called relational
operator. Now, the question is "What are relational operator
Definition: The relational operators also called compare operators are used to
compare two operands. They are used to find the relationship between two operands
and hence are called relational operators. The two operands may be constants,
variables or expressions. The relationship between these two operands results in true
(always 1) or false (always 0). The relational operators and the meaning associated
with them are shown in the table below.
Description Operator Priority Associativity
Less than < 1 Left to right
Lesser/equal <= 1 Left to right

Relational Greater > 1 Left to right

Operators Greater/equal >= 1 Left to right


Equal 2 Left to right
Not equal != 2 Left to right
Q Systematic Approach to Data Structures using C 1.21-

Oncewe know various relational operators, the next question is "What are relational
pressions ?"

Definition: An expression that contains. relational operators is called relational


expression. For example, the following are relational expressions:
a+b>c
b*b - 4*a*c = 0

Now,the question is "What are the rules to be followed while evaluating relational
ressiolls?"The rules to be followed while evaluating the expression consisting of
arithmeticoperators and relational operators are shown below: .
• Evaluate the expression within brackets
• Evaluate unary operators
• Evaluate arithmetic expressions
• Evaluate relational expressions

1.7.5 Logical operators


Inthissection, let us see "What are logical operators?"

fmition:As we have logic gates such as AND, OR and NOT whose output is 1 or
0, we also have logical operators. After evaluation, expression consisting of logical
operatorsresults in either true or false and hence such expressions are called a logical
expressions.The logical operators and the meaning associated with them are shown
below:
Description Operator Priority Associativity

Logical
Operators -E not (unary operator)
and (binary operator) &&
or (binary operator)
!

II
1

2
3
Left to right
Left to right
Left to right

otePuring evaluation, the ! operator has highest priority, the operator && has the
nexthighestpriority and the operator II has the least priority.

Nowthe question is "When logical operators are used?"'fhe logical operators are
usedto combine two or more relational expressions. Since the output of relational
expressionsis true or false, the output of logical expression is also true or false.
For examplejf a = b && b = c, then the triangle is equilateral triangle.
Here,two relational expressions are combined together by a logical && operator.
~1.22 Q Introduction to C

1.7.6 Relational and Logical expressions


The logical operators are used to combine two or more relational expressions. Thl
rules to be followed while evaluating the expression consisting of logical expressiu
is shown below:
• Brackets
• Unary expressions
• Evaluate arithmetic expressions
• Evaluate relational expressions
• Evaluate logical expressions

1.7.7 Assignment operator


Before manipulating the data, the data has to be stored in memory. Now, the question
is "How to store the data in memory?" This is where the assignment operator is
used. The data can be stored in the memory only using the assignment operator. Now,
let us see" What is an assignment operator? How to store the. data ill memory usin
assignment operator? "

Definition: An operator which is used to copy the data or result of an expression into
a memory location (which is identified by a variable name) is called an assignmen
operator. Copying or storing into a memory location is called assigning and hence the
name. The assignment operator is denoted by '='...sign. The syntax is shown below:

Syntax (General rule)


variable = expression; II expression can be a constant/expression! variable
II ; is must at the end

For example, the following statements are valid


a = b; II Store the value of b into a
area = L * B; II Compute the product and store in varlable area
pi = ~.1416; II Store the number 3.1416 using the variable pi

Normal mistakes during typing the program:


a = = b; II Error: "=" is relational operator. This can be used only to
II compare. Not for copying
a = b*10; II Error: After digit 1, the character O(pronounced as oh) is
II . typed. It is not zero.
a = b*10 II Error: No semicolon at the end
• 10 + b = c; II Error: Expression not allowed on LHS of assignment operator
~ Systematic Approach to Data Structures using C 1.2~_

horthand assignment operators We have observed that parents call their children
byshorthandnames. We also use shorthand names to call our friends. Likewise, we
canalsouse shorthand notations for assignment operator. For example, short hand
assignmentoperators such as +=, - =, *=, /= etc., can be used to assign values. The
tablebelow shows short hand operators, short hand statements and the meaning
associatedwith them.

t= a+=2 a=a+2 Perform a + 2 and store the result in a


a-=2 a= a- 2 Perform a - 2 and store the result in a
*= a *=2 a=a *2 Perform a * 2 and store the result in a
/= a/=2 a= a/ 2 Perform a / 2 and store the result in a

Observethat in all these cases the value of the variable a changes. In fact, the value of
a variablemay change during the execution of the program.

1.7.8 Increment and decrement operators.


Incrementand decrement operators are very compact and powerful operators
availableespecially in C language. These two operators are unary operators and have
onlyoneoperand. First we shall concentrate on increment operator.

1 7.8.1 increment operator


In this section, let us see "What is an increment operator? What are the different
'ypes of increment operators?" . . .
cfinition:++ IS an Increment operator. This IS an unary operator. It Increments the
valueof the operand by one. The increment operator is classified into two categories
asshownbelow:
..!YJ:!£ Operator Example result
ost increment ++ a++ 21
Increment
Operator
re increment ++ ++a 21

If initialvalue of a is 20, in both cases after executing, the value of a willbe 21. If
finalvalues are same using both the types of operators, then "What is post increment?
What is pre increment?
1.24 Q Introduction to C
Post increment If the increment operator + Pre increment If the increme
++ is placed after (post) the operand, then operator ++ is placed before (pre) tht c
the operator is called post increment. As operand, then the operator is calla v
the name indicates, post increment means pre increment. As the name indicates.
increment after (post) the operand value pre increment means increment befon
is used. So, operand value is used first (pre) the operand value is used. So.
and then the operand value is the operand value is incremented by
incremented by 1. and this incremented value is used. I

PROGRAM TRACING PROGRAM TRACING


void maint) void maim)
{ I Initialization { I Initialization
int a = 20; I a=20, int a = 20; I a=20
a++; I a= 21 ++a;
I 21
I Output I.Output
printf("%d", a) I 21 printf("%d", a)1 21 '
I I

} }

Note: Observe that the outputs of both the programs are same. In this context, there s
no difference between the two. In fact, if post increment or pre increment appear
alone along with the operand and are not part of any expression, then there is no
difference in the final value. But, the difference comes into picture, if they are part of
the expression or part of the assignment statement. Now, let us see "What is III
difference between post increment and pre increment?" by taking an example.
Post increment Pre increment
PROGRAM I Tracing I>ROGRAM Tracing
VOl mam void maim) I.
{ I Initialization { I Initialization
int a = 20; I a = 20 int a = 20; a=20
int b; I b =? intb; I b=?
I
b = a++; 1* b = a *11 b = 20 b=++a; 1* a=a+ 1 *1 I a = 21
1* a=a+l */1 a = 21 1* b = a *11 b = 21
IOlltput I Output
printf("%d" ,a); I 21 printf("%d" ,a); 21
I 21
printf("%d",b ); I 20· printf("%d" ,b);
} } I
I I
Note:b=a++ ~ b=a; Note:b=++a ~ a=a+l;
a= a + 1; b =a;
Q Systematic Approach to Data Structures using C 1.25

~nt OIl': Post increment means increment after (post) the value of a is used. So, first a is
he copied into b, then a is updated by 1. Pre increment means increment before (pre) the
ed valueof a is used. So, firs a is updated by 1 and then updated value is copied into b.
:s, Oncewe know what increment operator is, let us discuss about decrement operator.
re
1.7.8.2 decrement operator

In this section, let us see" What is a decrement operator? What are the different type»
1" innent operator?" .
Dctlnition: -- is a decrement
operator. This is an unary operator: It decrements the
valueof the operand by one. The decrement operator is classified into two categories
as shown below:
..!Yl!£ Operator Example result

Decrement
Operator
-+[ Post decre~ent a-- 19

Pre decrement . ·--a 19

If initial value of a is 20, in both cases after executing, the value of a will be 19. If
final values are same using both the types of operators, then" What is post decrement?
II, .. IS pre decrement?"

Post decrement If the decrement • Pre decrement If the decrement


operator -- is placed after (post) the operator -- is placed before (pre) the
operand, then the operator is called post operand, then the operator is called
decrement. So, operand value is used first pre decrement. So, the operand value
and then the operand value is is decremented by 1 first and this
decremented by 1. decremented value is used.
I
OGRAM I TRACING PROGRAM I TR\(,1. (;
void maint) void mainO I
{ I II Initialization { I II Initialization
int a = 20; I II a = 20 int a = 20; I II a = 2
I
a--', Illa=19 --a' I II 19
I II Output , I II Output
printf("%d", a)1 1119 printf("%d", a} II 19
} I
1.26 Q Introduction to C

l'ote: Observe that there is no difference between the post decrement or


decrement since they are not part of any expression. But, the difference comes in
picture, if they are part of the expression or part of the assignment statement
shown:

Post decrement Pre decrement


PROGRAM 11 T racmg
. PROGRAM 1 Tracing .
void maim) void maim) 1
{ 1 Initialization { 1 Initialization
int a = 20; 1 a=20 int a = 20; 1a=20
int b; Ib=? intb; 1b=?

b = a--; 1* b = a *1 1 b = 20 b = --a; 1* a=a-l *1 1 a = 19


l*a=a-1*/1 a=19 1* b = a */1 b = 19
1 Output 1 Output
printf("%d",a); printf("%d" ,a);
119
119
printf("%d",b);
120 p rintf("%d" ,b); I 19
1 1
Note: b = a-- ~ b = a; Note:b=--a ~ a=a-1;
a = a-I; b =a;
Post decrement means decrement after Pre decrement means decrement bef(
(post) the value of a is used. So, first a is (pre) the value of a is used. So, first a
copied into b, then a is decremented by 1. decremented by 1 and then updated valu
copied into b.

1.7.9 Conditional operator


In this section, let us see another important operator called conditional operata
Now, let us see "What is a conditional operator?"

Definition: The conditional operator is also called ternary operator. As the narn
indicates, an operator that operates on three operands is called ternary operator.' Th
ternary operators are? and: The syntax is shown below:
(expl) ? exp2 : exp3;
where
• expl is an expression evaluated to true orfalse
.• if expl is evaluated to true, exp2 is executed
• if expl is evaluated to false, exp3 is executed

For example, max = (a > b) ? a : b;


~ Systematic Approach to Data Structures using C 1.27

Here,whenever a is greater than b, the value of a is assigned to max. Otherwise, the


valueof b is assigned to max. The program to find the larger of two numbers using
ternaryoperator is shown below:
Example1.7.9.1: Program to find the larger of two numbers using ternary operator.

PROGRAM TRACE-l I TRACE-2


"inclue <stdlO.h>
I
voidmaim) I
(
int a,b,big;
I
I
printf("Enter the value of a and b\n"); hnter
nput
a, b I ~put
nter a, b
scanf("%d %d",&a, &b); 10 20 I 25 10
I
/* The larger of a and b is stored in big */ a=10, b=20 I a=25, b=10
big = ( a> b ) ? a : b; big = 20 I big = 25
Output I Output
printf("Big = %d\n",big); BIg - 2.0 I Big - 25 .

1.7.10Bitwise operators

In thissection let us see "What are bitwise operators?"


Definition:The data is stored in the memory in terms of binary digits i.e., O's and 1'So
Sometimes, it may be necessary to manipulate these bits. The operators that are used
tomanipulatethe bits are called bit wise operators. .
The various symbols used and the associated meanings are shown in the table
below:
Description Operator Precedence Associativitv
Bit-wise Negate 1 L~R
left shift « - 2 L~R
Bitwise right shift » 2 L~R
Operators Bit-wise and & /
3 L~R
Bit-wise xor /\
4 L~R
Bit-wise or 5 L~R
1.28 Q Introduction to C

1.7.11 Special operators

Let us discuss some special operators that are supported in C language.

1.7.1 J.l Comma operator (, operator)

ow, let us see "What is a comma operator and what is its advantage?"

Definition: The comma operator represented as a comma ( , ) accepts two operant


and it is used to combine two or more statements into a single statement. Th
compact statements can be written using comma operator. The statements
executed one by one from left to right and hence it is Ieft associative operator. It ill
the least precedence during evaluation of an expression.

Example 1.7.11.1: Consider the set of statements shown below:


temp = a;
a=b;
b = temp;

These three different statements can be written as a single statement using cornm
operator as shown below:

temp = a, a = b, b = temp; 1* Exchange the values of a and b */

Example 1.7.11.2: Consider the statements shown below:


a = 5 + 5, 6 * 5; II Output a = 30
b = 3, 25; . II Output b = 25

1.7.11.2 sizeof operator

This operator is used to fmd the number of bytes occupied by a variable or a constan
in the computer memory. The syntax is shown below:

sizeof (operand);

For example,
sizeof( char) 1 byte
sizeof(int) 2 bytes
sizeof(float) 4 bytes
Q Systematic Approach to Data Structures using C 1...22-

1.8The precedence of operators (Hierarchy of operators)


Sofarwe have discussed various types of operators. To evaluate any expression, we
shouldknow the hierarchy or precedence of all types of operators. Now, let us see
. II'ha/is precedence of operators or hierarchy of operations ;11 C language?"

Definition:In C language, each operator is associated with priority value. Based on


thepriority,the expressions are evaluated. The priority of each operator is pre-defined
in C language. The pre-defined priority or precedence order given to each of the
operatoris called precedence of operator. The operations that are carried out based
ontheprecedence of operators are called hierarchy of operations.

Operator category ~perators in order of precedence. Associativity


(highest to lowest)
0 Innermost brackets/function calls L~R
[] Array element reference (Left to right)
unaryoperators ++, --, l, sizeof, -, +, -, &, * R~L
(Right to left)
Memberaccess * or-> L~R
arithmeticoperators *, /, % L~R
arithmeticoperators -, + L~R
Shiftoperator «,» L~R
Relationaloperators <, <=, >, >= L~R
equalityoperators = , ,=
. L~R
Bitwiseand & L~R
Bitwisexor /\
L~R
,
Bitwiseor I L~R
logicaland && L~R
logicalor II L~R
conditionaloperator ?: R~L
assignmentoperator =, +=, -=, /=, *=, %=, &=, «= etc R~L
commaoperator , L~R

1.8.1Left associative operator

ow, let us see "What is associativity of operators? What are the different
elt fica/ions based 011 assosciativity? ..
1.30 Q Introduction to C

Definition: If all the operators in an expression have equal priority, then the directs
order chosen (left to right evaluation or right to evaluation) to evaluate an expressi
is calledassociativity of operators. They are classified into two categories based lY.
the direction of evaluation chosen as shown below:
• Left associative (Left to right associative)
• Right associative (Right to left associative)

1.8.2 Right associative operator

Now, let us see "What is left to right associative? Give examples"

Definition: In an expression, if there are two or more operators having the sam
priority and are evaluated from left-to-right, then the operators are called Left to Rig
associative operators. We normally denote using L ---+R. They are also called s
associative operators. This process of evaluating from left to right is called

For example,
8+4+3=15 A- Here, + and - are left associative operators
8-4-3=1 J
Now, let us see" What is right to left associative? Give examples"
,
Definition: In an expression, if there are two or more operators having the sam
priority and are evaluated from right-to-left, then the operators are calledRight to le
associative operators. We normally denote using R---+L.They are also called rig
associative operators. This process of evaluating from right to left is called rig
associativity.
For example,
i = j = k = 10; f/ The operator is right associative operator and
// assignment will be done from right to left

Note: All unary operators are right associative operators.

Now, we should see"What are control statel~ents? What are the types of contt
statements?"
Definition: The order in which the statements are executed is calledcolltroljlow. 11:
statements that are used to control the flow of execution of the program are calk
control statements. These statements alter the sequence of execution of the progra
Based on the order in which the statements are executed, the various con
statements are classified as shown below:
Q Systematic Approach to Data Structures using C l.l~Jl
Sequential
simple-if
statements
if-else
Conditional
branch statements Nested-if

Control else-if-ladder
Branching
Statements -+-~ statements switch

goto

Un conditional break
branch statements continue

Loop
Statements -f
.
or
wh'lIe
o-while
Now,let us concentrate on each of the control statement one by one.
return

1 9 Sequential statements
First,we shall see "What are ~eqllential statements? Why they are considered as
quential control statements?"
efinltionThe programmer writes a sequence of statements to do a specific activity.
Allthese statements in a program are executed in the order in which they appear in
the program. These programming statements that are executed sequentially, that is
one after the other, are called sequential control statements. Here, no separate
statementsare required to make these statements executed in sequence. The flowchart
andthe equivalent programming statements are shown below:

void maim)
{
( sti ft)

Statement-I; Statement -1 I
~
Statement-2; Statemen~2.1
I .
I
I

Statement-n;
}
1.32 Q Introduction to C

Here, statement-l is executed first followed by statement-2 followed by statement)


and so on. In short, we say that execution of a program is normally sequential (one
after the other). For example, let us write a program to convert degrees in Fahrenhei
to degrees in Celsius which is given by the following relation:

C = (5/9)(F-32)

The sequence of steps to be followed are:


• Input degrees in Fahrenheit
• Compute Celsius using C = (5/9)(F-32)
• Display the result
• Stop execution
The C program to convert Fahrenheit to Celsius is shown below:

Example 1.9.1: C Program to convert Fahrenheit to Celsius


TRACING

void mainO Execution starts from main


{
float f, c;
}rput .
printf("Enter degree in Fahrenheit\n"); nter degree in Fahrenheit
scanf("%f' ,&f); 40
/*Convert into Celsius */ Compute the degrees in Celsius
c = (float) 5 / 9 * (f - 32); c-4.4444
Out ut
printf'(rResult = o/c
. 0
f\n" "c), esu t = 4.4444
}

Advantage No separate control statements are required to execute the sequential


statements one after the other.
•..•.
u!-- ..•
-·-- ••••
~I'
l~aUV.lInnF>_
The sequence in which the statements are executed can not be
changed. .

Now, "flow 10 O\'C/'COlllC this advantage?" This is where branching statements will
make their existence. .
Q Systematic Approach to Data Structures using C \.33

1.10Branching statements
Now,thequestion is "What are branching statements? What are the different types of
'wenching statements?"
Definition:In sequential control, we know that all the statements are executed in the
orderspecifiedin the program one after the other. However, computer can skip the
executionof some statements. This skipping facility is provided by a group of
instructionscalled skip instructions. These skip instructions are also called branching
instructions/statements. Thus, the statements that alter the sequence of execution of
theprogramare called branching statements. The branching instructions are classified
asshownbelow:
simple-if
if-else
Conditional ----i
branch statements Nested-if
else- if-ladder
Branching . switch
statements
goto
Un conditional break
branch statements continue
return

Now,let us see" What are conditional and unconditional branch statements? Wliat
ire the various types?"
Definition: Normally, all the statements are executed one after the other. The
computercan skip the execution of some statements based on some condition. These
statementsthat alter the sequence of execution of the program based on some
conditionare called conditional branch statements. They are also called selection
statements or decision statements.
For example, if, if-else, else-if-ladder and switch statement.

1.10.1The if statement/simple-if statement


Inthissection, we concentrate on an important selection statement called if-statement.
Now,let us see" What is if-statement/simple-if? When if-statement call be used?"
J.34 Q Introduction to C

Definition: The simple-if or if-statement is a simple selection/decision stateme


When a set of statements have to be executed or skipped when the condition is true
h
false, then if-statement is used. The syntax of if statement is shown below:
b

Stat-Al';
~
Stat-A2;
I
I Stat-A21
,
I
I
't'
Stat-An;
If statement
false
if ( condition)
{

Stat_Bl;}
:
The statements
B 1 to Bn are
{I Stat-Bl
I
true
I The statements
Bl to Bn are
skipped if the
~ executed if the t condition is
Stat-Bn; condition is true Stat-Bn false
}

Stat-Cl;

Stat-C2;
I
I
T
I Stat-C21
I
I I
't' {t
Stat-Cn; I Stat-Cn I
After executing the statements AI, A2 An one after the other, the condition ii
checked. If the condition is true, the block of statements B 1, B2, ..... Bn are executed
otherwise they are skipped. After executing the statements B 1 to Bn or after skipping
the statements Cl, C2, .... Cn are executed.

1.10.2 The if-else statement


In this section, let us see a variation of if-statement called if-else statement and see
, What is if-else statement? When if-else-statement can be used?"
~ Systematic Approach to Data Structures using C 1.35

Definition: The if-else-statement is a simple selection/decision statement. It is a two- C

way decision statement which does one thing or does another. If one set of activities
haveto be performed when the condition is true and another set of activities have to
beperformedwhen the condition isfalse, then if-else-statement is used. The syntax of
ifelse statement along with equivalent flowchart is shown below:
Syntax of if-else Equivalent flowchart
Stat-BI; ~

Stat-B2;
I
I
I Stat-B21
I
I
I
Y '+'
Stat-Bn;
If-else- statement 1----.1 •...•
-------------.
false
if ( condition)
{
Stat-TI;
. Execute T I to
Sta\-T2;
I
T2 if condition
I
'(
is true
Stat-Tn;
}
else
Stat-El ;
Execute E 1 to
Stat'jE2; E2 if condition
I
I is false I
'( '+'

}
Stat-En; I Stat-En I
I
<
Stat-Al:
I
I
I Stat-~
I
I
'f
Y
Stat-An;
I Stat-An I
Note: Stat-Bl , B2, ... Bn appear before if-else, Stat-Al , A2, ... An appear after if-else,
Stat-T1,T2,... Tn are executed if the condition is true, else Stat-El , E2, ..... En are
executed.
1.36 Q Introduction to C

After executing the statements B I, B2, .... Bn one after the other, the condition
checked. If the condition is true, the statements TI, T2, .... Tn are executed follow
by AI, A2, An. If the condition is false the statements EI, E2, En a;
executed followed by A I, A2, An. So, whether the condition is true or false,
statements A I, A2, ..... An following if-else-statement will be executed.

1.] 0.3 The nested if-statement

In this section, let us see a variation of if or if-else statement called nesteu


statement. "What is a nested-if-statement? Why is it used?"
~
Definition: An if or if-else statement within another if or if-else statement is calla
"nested ifstatement". When an action has to be performed based on many decisioru
then this statement is used. So, it is called multi-way decision statement. There can
many variations of nested-if-statements. Here, only two variations are shown below:
if (condition)
{ if (condition)
if or if-else statement {
} OR if or if-else statement
else }
{
if or if-else statement

The nested if-statements shown above are executed as shown below:


• The statements Stat-Bl , B2, ... Bn are executed one after the other
• Then, the outermost if-statement is executed.
• If the Condl is true, the innermost if-statement is executed. In case if tht
condition fails, the statements Stat-El , E2, .... En are executed. After executin
these statements, the control comes out of the if-statement and the statements Al
A2, .... An are executed
• When executing the innermost if-statement, the Cond2 is checked for true or
false. If the condition Cond2 is true, then the statements Stat-Cl , Stat-C2 .... Sta
Cn are executed otherwise, the statements Stat-DL, Stat-Z .... Stat-Dn are executed
After executing the innermost loop(whether the condition is true or false), control
comes out of the entire if-statement and the statements Stat-Al , A2 .... An are
executed.
,Q Systematic Approach to Data Structures using C 1.37

For example, consider the statement:


if ( salary >= 10000)
{
if (sex = 'M')
print "Pay Tax"
else
print "No tax"
}
,
Inthisprogram segment, the if-else statement is inside the if-statement and hence the
abovestatement is called nested-if statement. Here, if salary >= 10000 and sex is
malethen the output "Pay Tax" is obtained. If salary is >= 10000 and if sex is female,
theoutput will be "No tax". Now, let us write a program along with algorithm to fmd
thelargestof 3 numbers using nested-if statement

Advantages
• There are situations involving series of decisions where we are forced to use an if
or if-else in another if or if-else statement. In such situations, nested-if-statements
are used.
• Each and every condition may be evaluated to true or false and may involve
expressions of various data types.

Disadvantages
• The nested ifs are difficult to understand and modify
• As depth of nesting increases, the readability of the program decreases.

1.10.4The else-if-ladder statement

In this section, we discuss a variation of nested-if called else-if ladder. Now, let us see
,.H1wtis else-if ladder statement?"

Definition: When an action has to be performed based on many decisions, then this
statementis used. So, it is called multi-way decision statement. The else-if-ladder is a
formof nested if-statement. Here, nesting is allowed only in the else part. The orderly
nestingof if-statement only in the else part is called else-if-ladder.

The following points are observed from the above flowchart: .


• The statements before the else-if-ladder Bl, B2, .... Bn are executed one after the
other. Then, the conditions cond-l, cond-2 etc., of else-if-ladder are evaluated one
after the other as long as the conditions are false. Once the condition is evaluated
1.38 Q Introduction to C

10 true, the corresponding statement is executed and control comes out of


entire else-if-Iadder executing the statements AI, A2 .... An which comes after
else-if-ladder.
• If all the conditions are evaluated to false, the last statement stat-n is execute:
Then control comes out of else-if-ladder and the statements AI, A2 ... An whi
comes after the else-if-Iadder a~e executed.

Advantages In situations involving series of decisions one after the other, ea


decision/condition may involve expressions of various data types such as jlo
integer, char and dc:uble. In these situations the else-if-ladder is used

Disadvantages
• The nested ifs are difficult to understand and modify
• As depth of nesting' increases, the readability of the 'program decreases.
• In situations involving series of decisions one after the other, ea
"-
decision/condition may involve expressions which results in integer value,
these situations the usage of else-if-ladder is not recommended. Instead, we go £
switch statement.

1.10.5 The switch statement


In this section, let us see another important branching statement called swit
statement. Now, we shall see" When switch statement is used?" We know that, '
situati ons involving series of decisions one after the other, the else-if-Iadder can
used. Each and every decision/condition may involve expressions which results'
various data types such as float, double, integer, character etc. Here, else-i
ladder/nested-if can be used. But, in situations involving series of decisions one aft
the other, each decision/condition may involve expressions which results in integ
value. This integer value may be used for comparison using equality operator =.
In these situations, where the result is of integer data type and series of integ
values are used in decisions, the usage of switch statement is recommended, becau
it improves readability of the program. "What is a switch statement?"
Definition: The switch statement provides a way to select an alternative out of sever
alternatives based on the choice. The choice can either be any integer value or
character. The choice can also be an expression which results in an integer value
Based on this integer value, the control is tr?nsferred to a particular case value.

Advantages
• Improves readability of the program
• More structured way of writing the program
Q Systematic Approach to Data Structures usin C 1.39·

Disadvantages
• Usedonly if the expressions used for checking the conditions results in integer
value(char is also allowed). If the result of expression is not integer value, switch
statementcan not be used.
Thesyntax of switch statement is (same as else-if-Iadder. Both structures are
considered
as multiple selection statements) shown below:
Syntax' ~
Statement-B1; ~

Statement-B2; I Stat-B21
Statement-Bn;
Switch statement
switch (choice / expression)
{
case value 1: true I.BloCk-I; .~
Block-I; no-break in:Block-I
I
break; I

case value2:
Block-2;
break;

case valuen:

Block-n;.
no-break in'Block-n
break; ~-- .JI

default:
Block-d

Statement-AI;
~
Statement-A2;
I Stat-A21
o
I
I
'i'
Statement-An;
I Stat-An I
1.40 Q Introduction to C

After executing the statements B 1, B2, .... Bn, the expression in switch is evaluated
an integer value. The integer value thus obtained if it matches with any of the valu
value1, value2, ..... valuen, the control is transferred to the appropriate block. Duris
execution, if break statement is executed, then the control comes out of the swit
statement and the statements AI, A2, ... An which comes after the switch statem
are executed. During execution of a particular case, if break is not encountered, th
control goes to the subsequent cases and the statements under those cases will
executed till the break statement is encountered. If the value of the expression d
not match with any of the case values value1, value2, .... valuen then, control corn
out of the switch statement in the absence of default. If default case is part of tIK
switch, then the statements in default block will be executed. Some valid and inval'
ways of writing switch expressions and case constants are shown below by assumin
the following declarations:
int i:,
char c',
float f,
double d',

User input Valid! Reasons for invalidity


invalid
switch(i + 5.5) invalid Floating point numbers not allowed
switch (c + d) invalid d is double. doublelfloat variables are not allows
case ~ invalid : missing after 4
case4: invalid Space must be present between case and 4
Case 4: invalid Keyword case should be lower .case lette
Capital letter C is not allowed
case + invalid + should be enclosed between two single quotes
case "+" invalid Strings are not allowed. + should be enclos
between two single quotes
case 'A' valid
case 'A'-'B' valid Integer expressions with constants are allowed'
case:
case i + 2 invalid Variables are not allowed in case 'I
I
case "A" . invalid Strings are not allowed in case
case 'choice' invalid Only one character is allowed between two singk
quotes.
case 1:2:3 invalid There should be separate case for each of 1, 2, 3
Q Systematic Approach to Data Structures using C 1.41

ormally,the statements in a program are executed one after the other. Now, let us
see What are looping/repetitive constructs? What are tile types oj looping
nstructs? "
Drill tion The statements that enable the programmer to execute a set of statements
repeatedly till the required activity is completed are called looping constructs or 1001'
( ·01 statements. These statements are also called repetitive constructs/statements
I'

r.: itive constructs/statements. The statements within a loop may be executed for a
fixed numberof times or until a certain condition is reached. The various types of
loopingconstructsthat are supported in C language are discussed below:

1.10.6 The for statement


First,let us see" What is a Jor loop? Explain with syntax, flowchart and example
I ,IC working oj the Jor-loop"

Deli ition: A set of statements may have to be repeatedly executed for a specified
numberof times. In such situations, we use for loop. Thus, a Jar loop is defined as an
iterativestatement that causes a set of statements to be executed repeatedly for a fixed
numberof times. If we know well in advance as how many times a set of statements
havetobe repeatedly executed, then Jar l.oop is the best choice. The syntax of the Jar
loop alongwith equivalent flowchart is shown below: . ~
Stat-BI; ~
I
I
Stat-B2; I

•••
Stat-Bn; Syntax I I Stat-Bn I flowchart
r----------~I
for (expl; exp2; exp3)
for loop
--::-!.--_------"'I'----~
L-. false
{ ~ for exp 1 to exp2 step exp3
Stat-I"'" ±true
Stat-2 ~
~ Body of the for-loop I Stat-2
I
I
I
'M
Stat-n...•
I Stat-n I
I

Stat-AI; I Stat-AI I
I
1'.42 Q Introduction to C

where
• for is a keyword (reserved word)
• expl- stands for initialization expression. It should end with semicol
denoted by the symbol ';'.
• exp2 - stands for terminal condition. Basically, it is an expression
should be terminated semicolon (;)
• exp3 - normally stands for step size. The expression exp3 may
. increment/decrement (updation)
• body of the loop - consists of various statements. All the statements Stat
Stat-2, .... Stan-n within the body of the loop ends with semicolon.

Note: The statements Stat-B'l , Stat-B2, ... Stat-Bn appear before the for-loop and tb
statements Stat-A I, Stat-A2, ..... Stat-An appear after while loop.

Working of for loop The following sequences of operations are carried out afte
executing the statements B I, B2, ... Bn that appear just before the for-loop.
• The expression expl is executed first It is always executed only once when th
execution of the for-loop begins.
• The expression exp2 is executed next. If the expression exp2 is evaluated to falSI
the control comes out of the loop without executing the body of the loop. Lata
the statements AI, A2, ... An are executed.
• If the expression exp2 is evaluated to TRUE, the body of the loop is execut
Alter executing the body of the loop, the expression exp3 is executed. It
normally updated by the specified step size. Then exp2 is executed and the proc
is repeated.
• Once the expression exp2 is evaluated to FALSE, the control comes out of
loop and the statements AI, A2 .... ~ are executed.

1.10.7 The while statement

In this section, let us see "What is a while loop? When it is used? What is the sym
ofwhile loop?"
Definition: A set of statements may have to be repeatedly executed till a certai
condition is reached. In such situations, we do not know exactly how many times a s~
of statements have to be repeated. So, naturally we need to have a condition-
controlled loop. In C language, the condition-controlling is done generally by a whil
loop. That is why the while-loop is generally called condition-controlled loop. Th
syntax of the while-loop along with equivalent flowchart is shown below:


Q Systematic Approach to Data Structures using C 1.43

Stat-BI;
I Sta;-BI I
I
I
Stat-B2; I
'+'
Stat-Bn;
while loop
while (exp) false
{
Stat-I;
Stat-2;
Body of the while-loop

Stat-n;

Stat-Al; I Stat-AI I
I
I
I
Stat-An; , '+'

where
I
Stat-An I
• while is a keyword (reserved word)
• expis the expression which is evaluated to TRUE or FALSE. The expression exp
mustbe enclosed within "(" and ")".

· otl The statements BI, B2, ... Bn appear before while loop and the statements AI,
A2, ..... Anappear after while loop.

\\ orking of while 100pThe following sequences of operations are carried out after
executing the statements B I, B2, ... Bn that appear just before the while-loop.
• If the expression exp is evaluated to false at the time of entry into the loop, the
controlcomes out of the loop without executing the body of the loop. Later, the
statementsA I, A2; ... An are executed.
• Iftheexpression exp is evaluated to TRUE, the body of the loop is executed. After
executingthe body of the loop, control goes back to beginning of the while-
statementand exp is again evaluated to true or false.
1.44 Q Introduction to C

• Thus, the body of the loop is repeatedly executed as long as exp is evaluated
TRUE. Once the expression exp is evaluated to FALSE, the control comes out
the loop and the statements AI, A2 .... An are executed.

1.10.8 do-while statement

In this section, let us see" What is a do-while loop? When is it -used? What is I
svntax of do-while loop?"

Deflnition: do-while loop is similar to a while-loop and used when a set of stateme
may have to be repeatedly executed until a certain condition is reached. When we
not know exactly how many times a set of statements have to be repeated do-w
can be used. The syntax of the do-while loop along with equivalent flowchart
shown below:

Stat-BI;
I Stat-BI I
I
I
Stat-B2; I
'+'
Stat-Bn;
do-while loop
do
{ .I
,
Stat-I
I
I
Stat-I I
I
Stat-2 Body of do-while loop
I Stit-n I
Stat-n
} while (exp)

Stat-Al ; I Stat-AI I
I
I
I

Stat-An; '+'
I Stat-An I
where
• do and while are keywords (also called reserved word)
• exp is the expression which is evaluated to TRUE or FALSE. The expression
must be enclosed within "(" and ")",
Q Systematic Approach to Data Structures using C 1.45

Working of do-while loop The following sequences of operations are carried out
afterexecutingthe statements B I, B2, ... Bn that appear just before the do-while-loop .
• The body of the do-while loop consisting of statements Stat-I, Stat-Z,..... Stat-n
areexecuted one after the other.
• Then,the exp is evaluated. If the expression exp is evaluated to TRUE, the body of
the loop is executed again and, the process is repeated. The moment exp is
evaluatedto false; control comes out of the 'do-while and the ,statements AI,
A2, ... An which appear after the do-while loop are executed.
Sincethe expression exp is evaluated to TRUE or FALSE at the bottom of the do-
while loop, the do-while-loop is called bottom testing loop or exit-coil trolled loop.
Here,thebody of the loop is executed at least once.

Now, let us discuss about "What is an array? How array can be used and
manipulated?"
1.11Arrays
DefinitionAn array is defined as an ordered set of similar data items. All the data
itemsof an array are stored in consecutive memory locations -in RAM. The elements
ofanarrayare of same data type and each item can be accessed using the same name.
Forexample,consider an array of marks of 5 students as shown below:

aO I 90 I 45 I 99 I €>O I,
marks[O] marks[l] marks[2] marks[3] marks [4] ,
Toreferan item in the array, we specify the name of the array along with position of
theitem.The position of the item must be written within square brackets (m. The
positionof the item enclosed within square brackets is called "subscript" or "index".

1.11.1Single-dimensional arrays

Dcfinition:Asingle-dimensional array (also called one-dimensional array) is a linear


list consistingof related and similar data items. In memory all the data items are
storedin contiguous memory locations one after the other. Pictorial representation of
a singledimensional array is shown below:
array name+-e- marks [0] marks[I] marks[2] marks [3] marks [4]
data ~
address ~
I I @O I ~ I 9.9 I ,7:9 I 9.0 I
, 1000~1001 I , 1002~1O03 1\ 1004.;1005 I , 1006~1O07 I ,1 008-~009 /
2 bytes 2 bytes 2 bytes 2 bytes 2 bytes
1.46 Q Introduction to C

1.1-1.2Initialization of single dimensional arrays

Now, we shall answer the question "What is initialization? How arrays can
initialized?"

Definition: Assigning the required information to a variable before processing


called initialization. As we initialize a variable to some initial value (for exam
°
sum = before the loop), we can initialize the individual elements of an array. Am
elements can be initialized at the time of declaration. Now, let us see "HOI
initialize all the specified memory locations?"

1.11.3 Initializing 'all specified memory locations


Arrays can be initialized at the time of declaration when theirinitial values are knee
in advance. Array elements can be initialized with data items of type intege
character, float etc.

Example 1.11.3.1: Consider integer initialization shown below:

int a[5] = {10, 15,20,25, 30};

~uring compilation, 5 contiguous memory locations are reserved by the compiler ~


the variable a and all these locations are initialized as shown below:

If the size of integer is 2 bytes, 10 bytes will be allocated for the variable a.

Other examples,
int a[5] = {1O, 15,20,25,30,40, 50}; Ilerror: Number of initial values
Ilare more than the size of array
Example 1.11.3.2: Consider character initialization shown below:
char b[8] = {'C', '0' , 'M' , 'P' , 'U' , 'T' , 'E' , 'R'}·,

During compilation, 8 contiguous memory locations are reserved by the compiler for
the variable b and all these locations are initialized as shown below:
Q Systematic Approach to Data Structures usin C 1.47

In fact, instead of characters, ASCII values are stored in the memory. Since a
characteroccupies 1 byte, 8 bytes will be allocated for the variable b.

Other examples,
charb[5] = {'M', '0', 'N', '1', 'K', 'A'}; //error: Number of initial values
/Iare more than the size of array
) .11.4 Partial array initialization
Partialarray initialization is possible in C language. If the number of values to be
initializedis less than the size of the array, then the elements are initialized in the
order from oth location. The remaining locations will be initialized to zero
automatically.For example, consider the partial initialization shown below:
int a[5] = { 10, 15};

Eventhough compiler allocates 5 memory locations, using this declaration statement,


thecompiler initializes first two locations with 10 and 15. The next set of memory
locationsare automatically initialized to O's by the compiler as shown below:

1.11 Ii Initialization without size

Considerthe declaration along with initialization shown below:


char b[] = {'C' , '0' , 'M' , 'P' , 'U' , 'T' , 'E' , 'R'}'
.,
In this declaration, even though we have not specified exact number of
elementsto be used in array b, the. array size will be set to the total number of initial
valuesspecified. So, the array size will be set to 8 automatically. The array b is
initializedas shown below.
I

1.11.6 rray initialization with a string

Considerthe declaration with string initialization:


char b[] = "COMPUTER";

Thearray b is initialized as shown below.


1.48 Q Introduction to C

Even though the string "COMPUTER" contains 8 characters, because it is a string,


always ends with null character. So, the array size is 9 bytes (i.e., string length +
byte for null character).

char b[9] = "COMPUTER"; 1* Correct. Tll~ size of the array is string length + 1 *
char b[8] = "COMPUTER"; I*Wrong. Size of the array should be minimum 9*
For string initialization, usually the programmers prefer the following declaration:
char b[] = "COMPUTER";
1.11.7 Reading/writing single dimensional arrays
In this section, let us concentrate on how to read the data from the keyboard and ho
to display data Items stored in the array. Consider the declaration shown below:
int a[5];
Here, 5 memory locations are reserved and each item in the memory location can~
accessed by specifying the index as shown below:
Using a[O] through a[4] we can access 5 data items.
~ ~ ~
Note: III general, Using a[Oj through a[n-lJ we call access n data items.
Once we know how to access each location in the memory, next question is "How
store the data items ill these locations?" This is achieved by reading the n data ite
fro the keyboard using scanfO function as shown below:

scanf("%d", &a[O]);
scanf("%d", &a[I]);
scanf("%d", &a[2]);

scanf("%d",&a[n-l ]);
, I I
Y ..,
In general, scanf("%d",&a[i)) where i = 0, 1, 2, 3, n-I. So, in C language,'
we want to reap n data items from the keyboard, the following statement can be used:
for fi==Oi i c=n-It if+) li=O 1 2 n-I
{ I a[O] a[l] a[2] a[n-l]
scanf("%d", &a[i]); I 10 20 30 50
}

The above for loop can also be written by replacing '<=' relation by '< 'relation 3!
shown below:
~ Systematic Approach to Data Structures using C 1.49

for (i = 0; i < n; i++) Ii = 0 1 2 n-I


{ I a[O] a[l] a[2] a[n-1]
scanf("%d", &a[iD; I 10 20 30 50
}

Similarly
to display n data items stored in the array, replace scanfO by printfO
statement
as shown below: ,
for (i= 0; i < n; i++)
{
printf("%d", ajij);
}
ow,let us write a small program to read n elements from the keyboard and to
display
n elements on to the screen.
Example1.11.7.1:To read n elements from the keyboard and display the numbers on
themonitor ".

TRACING'

voidmain/) IExecution starts from here


{
I .
int n, a[101, i; [non-executable statement
I Input
printf("Enter the no. of items"); IEnter the no. of items
scanf("%d",&n); 15
printf("Enter n elements"); IIEntern elements
for (i = 0; i < n; i++) i=O 1 2 3 4
{ I a[O] a[l] a[2] a[3] a[4]
scanf("%d",&a[iD; I 10 20 30 40 50
I
I Output
printf("The N elements are"); IThe N elements are
for (i = 0; i < n; i++) i=O 1 2 3 4
{ I a[O]a[l] a[2] a[3] a[4]
printf("%d\n", ariD; I 10 20 30 40 50
I
I
1.50 Q Introduction to C

f.12 Insertion sort

As we can arrange numbers in ascending order using bubble sort, using insertion sort
also we can arrange numbers in ascending order. Now, let us see "How insertion sort
works?" -

Procedure: The sorting procedure is similar to the way we play cards. After shuffling
the cards, we pick each card and insert it into the proper place so that cards in hand
are arranged in ascending order. The same technique is being followed while
arranging the elements in ascending order. The given list is divided into two parts:
sorted part and unsorted part as shown below:

( n elements -----3)~1

O .j i +1 - n-1
~ sorted -7 ~ un sorted )
'V
boundary

Note that all the elements from 0 to j are sorted and elements from i to n-1 are not
sorted. The ith item can be inserted into any of the positions from 0 to j so that
clements towards left of boundary are sorted. As each item is inserted towards the
sorted left part, the boundary moves to the right decreasing the unsorted list. Finally,
once the boundary moves to the right most position, the elements towards the left of
boundary represent the sorted list. -

Example 1.12.1: Sort the elements 25, 75, 40, 10,20 using insertion sort

Step 1: Item to be inserted is 75. i.e., item = a[l]

75 is inserted after 25

Step 2: Item to be inserted is 40 i.e., item = a[2]


,-- ...

40 is inserted between 25 and 75


Q Systematic Approach to Data Structures using C 1.51

Step 3: Item to be inserted is 10 i.e., item ~ a[3]

10 is inserted before 25

Step 4: Item to be inserted is 20 i.e., item = a[4]

~ '"
~ 20 is inserted between 10 and 25
~unsorted

Output
~
~ Final sorted list

Design: Consider an array of n elements to sort. The item to be inserted can be


accessedas shown below:
in step 1: item = a[l]}
in step 2: item = a[2]
in step 3: item = a[3]
in step 4: item = a[ 4]
t
i.e., item = a[i].where i = 1 to n-1

In general, item = a[i] where


i = 1 to 4 i.e.,
i.e., i = 1 to 5 - 1
i.e., i = 1 to n - 1

ow, item has to be compared with a[j] with initial value of j = i -1. Now, as long as
item < a[j] and j >=0 it is required to perform following activities:
• copy a[j] to a[j+ lJ
• decrement j by 1.
1.5...2· Q Introduction to C

The equivalent statements can be written as shown below:

j=i-1;
while (item < a[j] && j >= 0
{
a[j+ 1] = a[j]; These statement should be executed for
j=j-1; each item = a[i], where i = 1 to n-1
{
}

Once the condition fails copy item into a[j+ 1] using the statement:
a[j+l] = item .

The function to sort elements using insertion sort is shown below:

Example 1.12.2: Function to sort the numbers using insertion sort

void insertion_ sort(int n, int am


{
int i, j, item;

for (i = 1; i <= n-l; i++)


{
1* Insert the item from unsorted part *1
item = a[i];
j=i-l;

1* Find the appropriate place to insert *1


while (item < a[j] && j >= 0)
{
a[j+ 1] = a[j];
j=j-l;
}

. 1* Insert at the appropriate place *1


a[j+ 1] = item;
}
}

The complete program to arrange numbers in ascending order using insertion sort
shown below:
Q Systematic Approach to Data Structures using C 1.51

Example 1.12.3 : Arrange numbers in ascending order using insertion sort

#include <stdio.h>

/* Include: Example 1.12.2: Function to sort using insertion sort */

void mairu)
{
int i, n, j, item, a[lO];
priritf("Enter the number of elementsm'');
scanf("%d" ,&n);

/* Read n elements */
printf("Enter n elements\n");
for (i = 0; i < n; i++)
{
scanf("%d", &a[i]);
-}

/* Sort the elements using insertion sort */


insertion_ sort( a, n);

/* Dis lay the sorted elements */


printf "The sorted elements are\n");
for (i = 0; i < n; i++)
{
printf("%d\n", a[i]);

1.13 Why functions?


The programs that we study or read from books are very small when compared to the
programsthat we write for a complex problem. If the program is very big, there are
toomany disadvantages:
• It is very difficult for the programmer to write a large program
• Very difficult to identify the logical errors and correct
• Very difficult to read and understand
• Large programs are more prone to errors and ~o on. These disadvantages can
be overcome usingfunctions. So, let us see "What is afunction?"
1.54 Q Introduction to C

Definition: In C language, a large program can be divided into a series of individud


- related programs called modules. These modules are called functions. Thus afunction
(also called subprogram) is a program segment that carries out some specific an~
well-defined tasks. The functions can be developed and tested separately. For
example,
• The function sqru) is used to find square root of il given number
• The function scanfO is used to read data from the keyboard
• The function printfO is used to print the result on to the display unit and so on.
Once we know the definition of a function, let us know the answer for the next
question" What are the different types of functions?" The functions can be classified
into two categories as shown below:
Library functions
. -{ (Built in functions)
F unctions
User Defined Functions
(UDFs)
Now, let us see"What are library functions?"
Definition: As library. is a collection of various types of books, magazines, journals
etc., we have C library. The standard C . library is a collection various types of
functions which perform some standard/and pre-defined tasks. These functions which
are part of the C compiler that have been written for general purpose are called
library functions. They are also called built infunctions. For example,
• sqrtt) - finds the square root of a given number
• sint) - computes the sine of an angle
• cost) - computes the cosine of an angle etc.
• scanfi) - accept the data from the keyboard
• printfi) - send the data to output unit
,

Since the standard library functions are limited, programmercan not completely rely
on these library functions. The programmer has to write his/her own programs called
user-defined functions. Now, let us see" What are User Defined E.l~llctiolls(fjDFs)?"
Definition: In most cases, the programmers need other than library functions' to
achieve some specific tasks. These functions which are written by the
programmer/user to do some specific tasks are called user defined functions (UDFs).
For example,
Suppose, we want to add two matrices a and b. There is no standard library
function in C to add two matrices like a library function sqrtt) which finds the square
Q Systematic Approach to Data Structures using C 1.55,

root of a number. So, we can write a function add _matrixt). This function is written
by the user and it is used by the user. So, it is called user-defined function. Now,
consider the program shown below:

PROGRAM I TRACING
#inc1ude <stdio.h> I
#inc1ude <math.h> I
void maim) : Execution starts from here
{
float n, s; I
I
n= 36; In = 36
s = sqrt(n); Is = 6.000000
printf("squareJoot(%d) = %t\n", n, s); ~squareroot/Jti) = 6.000000
}

The various points to note here are:


• Execution starts from the function maim)
• The value 36 is copied into n.
• .Invoke the function sqrtt) and obtain the square root of n and store it in the
variable s.
• Display the square root using the function printtt).

Now, let us see "What will happen when a function sqrtt) is invoked?"For the
explanation purpose consider the program shown below:

r#;c;de<~i~h;---------l· ._' _
I #include <math.h> I r float sqrt(int n) I
II~oid maint) I { I
{ I stat-l ; I
I float n, s; JI stat-2; I
I' 1" I
I n = 36; II I
I s = sqrt(n);
II
~ return result· I
I
I} prlntfrvsquareroou'zsd) = %t\n", n, s);
;r;-'
III~ _I ~I _. J
I

I
----i calling function t- - - - J
. called function
1.56 Q Introduction to C

Here, we have not written the function sqru] which is shown on the right hand side.
Because, it is library function it is written by the compiler developers. We do not
know what statements they have used to compute square-root. But, we know that by
invoking the function sqrtt), we can get the result. Now, some points to remember
are:
• Invoking the function sqrtt) is done by simply writing the name of the function
as shown in function maint) using '=' operator. We say that the function sqrtt)
is called. So, the function sqrtt) is often .called "called function ",
• Who is calling the function sqrtt)? It is clear from the above program that the
function maini) is calling. So, the function maint) is called "calling function ",
• When a function is called, control is transferred as shown using the arrow from
maint) to sqrtt). Each statement in the function sqrtt) is executed and square
root of given number is computed.
• After executing the last statement i.e., return result, the control will be
transferred to the function maini) along with the result. This is shown by
drawing the line from sqrtt) to maint).
• The result obtained from sqru) is copied into variable s.
• The result is displayed on the screen.

Note: Execution always starts from the function maini). The way the function maini)
gets the job done from various functions can be explained using the following
analogy:

• A boss in the organization calls his


subordinates and asks them to
• The function maint) calls other
functions to do the designated job
perform a specific task and return and get the result from those
the results back to him. functions.

• The boss does not know how his


subordinates perform their
• The function maint) does not know
how the functions performs their
designated tasks. designated tasks.

• The subordinates might call their


co-subordinates to achieve the task
• The' functions might call some other
sub- functions to achieve the task
without the knowledge of boss without the knowledge of maint).

Now, using all these concepts, let us write some simple functions. Consider the
program shown below:
,!;lSystematic Approach to Data Structures using C L57

PROGRAM TRACING
#include <stdio.h> I
void maint)
I
{
I
int a, b, sum; I
I Input
printf("Enter the values for a and b\n"); IEnter the values for a and b
scanf("%d %d" ,&a, &b); 11020
sum = a + b; : sum = 10 ~ 20 = 30
Output
printf("%d", sum); I 30
t
"What does this program do?" It is very simple. It accepts two numbers, adds these
numbers and displays the result. Now, "Can we write a function to add two
numbers? " Yes, we can!!! The above program itself is a function. But, the name of
the function is maim). If we want to write our own function, then just change the
name of the function main to add as shown below:

#inc1ude<stdio.h>

void addt)
{
int a, b, sum;

printf("Enter the values for a and b\n");


scanf("%d %d",&a, &b);

sum = a + b;

printf("%d", sum);

Yes,we have written one function. In other words, we say we have defined a function
whose name is addt). This is called function definition. Since we have written this
function, it is called "user-defined function ".But, it is not complete. We know that
1.58 Q Introduction to C

- execution always starts from the function main. But, there is no main. So, we have to
write one function main which calls the function add as shown below:

void addt)
#inc1ude <stdio.h> {
int : a, b, sum;
void mainr) printf("Enter the values for a and b\n");
{
scanf("%d %d" ,&a, &b);
addt);
} sum=a+b;
printf("%d", sum);
}

The sequence operations that are performed when above program is executed ate:
• Execution of the program starts from maim)
• The function addt) is invoked
• Control is transferred from function maint) to function addi) as shown using
arrow mark.
• The function addt) accepts two numbers, adds those numbers and print the result
• Then, control is transferred from function addi) to function maint) as shown using
the arrow mark from right to left
• In the function maint), there is no other function/statement to be executed and
~ hence execution of the function maint) is terminated.
Note: we formally write above set of functions in one file as shown below:
~--~---------------
#inc1ude <stdio.h> I
void addt) I
{ .I
int a, b, sum; I
printf("Enter the values for a and b\n"); I
scanf("%d %d" ,&a, &b); ,...----------.
File name: add.e
sum = a+b;
printf("%d", sum); I
} I
void mairu)
I
{ I
addt); I
} I
------------------~
Q Systematic Approach to Data Structures using C l.S.~
1.13.1 Elements of user-defined functions
In this section, let us see "What are the elements of user-defined functions? ..The
elements of user-defined functions are shown below:

Elements of ~ser
defined functions -f Function definition
Function call i -

Function declaration

Function definition: The program module that is written to achieve a specific task is
calledfunction definition. For example, consider the function shown below:

void addt)
{ This function accepts two numbers,
int a, b, sum; adds those two numbers and prints
the result. Here, instead of giving
scanf("%d %d",&a, &b); main as the name of the function,
sum=a+b; we have given add as name of the
printf("%d\n", sum); function.
}

Function call: We know that execution always starts from function maint). If we '
want to use the function addt) that we have just discussed, it has to be invoked. This
is called function call. In general, a function callis nothing but invoking a function at
the required place in the program. For example, the function addi) that we have
written earlier can be invoked as shown below:
void maim)
{
addt); /* This statement transfers the control to addi) function */
}

Function declaration: Functions are like variables. As variables are declared before
they are used, we normally declare the functions before they are defmed and end with
semicolon. This is called function declarationvt function prototype.For example, the
function declaration for the function addi) can be written as: .

void addt);
l'
- I
Note the semicolon at the end. This is must for the function declaration. So, the
complete program usingfunction declaration,function call and function definition is
shown below: .
1.60 Q Introduction to C

_____ ~ File name: add.c


#include <stdio.h>
~-----.,
void add/); .c---.....:.-.....;..---:...----I FUDCti0t::J
declaration
void addf) I
{ I
int a, b, sum; I
printf("Enter the values for a and b\n"); "'-- Function
scanf("%d %d",&a, &b); ~ definition
sum = a+b; I
printf("%d", sum); I
} I
I
void mainO I
{
addt); +4------------1 Function
call
}

j.
------------------~
Once we know the functional elements, let us discuss each of these in detail, in th
coming sections.

1.13.2 Definition of functions (Function definition)

This is most important topic and hence, let us discuss in detail. Now, let us answer th
question "What isfunction definition? Explain in detail"

Definition: The program module that is written to achieve a specific task is calle
function definition. The various elements of the function definition are shown below:

Function header -E :~~e


parameters

-E
Function definition
Declaration statements
Function body Executable statements
return statement
.!;l Systematic Approach to Data Structures using C 1.61.

The general format of function definition along with example is shown below:

General format Example


function header r function.A. header "
r~------~~~-------,
arameters int add (int m. int n
{
declaration part; int sum;

executable part; sum=m+n;

return exp; return sum;


}

T
Function body Function body

It is clear from the above figure that Function Header= type + name + (parameters)
where

type e:::> can be int, float, double, void etc. This is the type of the value
that the function is expected to return. If the function is not
returning any value, then we need to specify the return type as
void. In the example, the function is expected to return an
integer value and hence the type is specified as int.
name e:::> can be any valid identifier. Therefore, the rules that are followed
to frame variables are followed to frame function name.
Normally, the name of the function itself should indicate the
activity being performed by the function .. In the example. add is
the name of the function and perform addition operation.
parameters e:::> Parameters are list of variables. All the variables should be
separately declared and each declaration should be separated by
by comma. All the parameters should be enclosed with in '(' and
')': These variables accept the values when the function is
invoked. These variables are often called formal parameters or"
dummy parameters. In the example, the variables m and n are
called formal parameters. .
m tiC

fum:ti defiDition, first part is the function header and second part is the
hotly. The rela1ion between jim-ction body and its elements is shown below:

Function body =declaration part + execution part + return statement

declaration c:::) Apart from the parameters, whatever variables are used in
thefun£tion should be declared. These variables are called local
mri.oble. (auto variables). In the example, the variable sum is
declared as a local variable.
execution c:) This part contains the statements that 'perform the actual job of
e function. In the example, sum = m + n is the execution
statement.
return c::> Using this statement" the function returns the evaluated result. If
a fimdion 0 not retum any value, the return statement can be
omitted In the example, the function returns sum of two
numbers.
Example 1.13.2.1 Function to accept two values a and b using formal parameters,
to these 0 numbers and return the result is shown below:

Function header = type + name + parameters


Function body =
1
. declaration part +

=a+b; executable part +

return statement
end of the function body
"

Example 1.13.2.2: FWldion to accept two values a and b, add these two numbers,
. res.Wt. d 00 Tetum any value i shown below:

to) I accept two values


I
smn; I declare the variables used here

s:mn=a+b; : Add the two accepted values

I Display the result


I
Q Systematic Appro

1.13.3 Return values and their type


As discussed earlier, a function may not send the value or may send the
calling function. This is possible only using the returnstatement as bel
• return; 1* This statement is used when function ~ sending
any value to the callingfunctimt *1
• 'retum expression; 1* This statement is used wh~ function is sending
a value to the calling fimctio *~
Now, let us see how to write a function which computes the gest of 0 DlImbreIE
and sends the larger value. Since the function has to find largest of 0 DUllnbelS
• It requires two values and hence two variables ace required in the :fi.ulCtiiLn
• It is expected to return a value and hence the type of e
specified.

The complete function to return the larger of two numbers is shown be

1* Function definition to return larger of two numbers *1


int maximum(int in, int n)
{
if (m > n) return In; 1* Return m as largest *1
return n; 1* Return n as largest *1
}

1.13.4Function calls
After writing the functions, appropriate functions have to be invo ell to ge j b
done from those functions. This invocation of a function is caIled.fiuwtio raJll For
example, in the previous section, we have written a function maximumO 110 !the
larger of two numbers. This function can be invoked using e ion I'TJlliin(j
shown below:
void maim)
{
int m, n, res;

printf("Enter the values for m and n\n"');


seanCe %d o/od",&m, &n);

res = maximum(m, n); 1* Function call which calls function maximum */


printf("Maximum (%d, %d) = %d ••, m, II, res);

}
1.64 Q Introduction to C

Execution starts from the function maint}. After reading the values of m and n, the
function is invoked using the statement:

nr----~-~)Actual parameters
res = maximum(m, n);
The variables that are used while calling the function are called actual parameters.
Next, control is transferred to the function maximums). The function fmds the larger
of two items and control is returned back to the function maint} along with the result.
The value returned is copied into the variable res and is displayed on the screen in
function mainO. This isillustrated in the figure shown below:

I-void ~ain() - - - - - - -I Formal parameters


I
{
I r:-----}--t-,
int maximum(int rn, int n) 1
I int m, n, res I {
1 I I if (m > n) I
I prtntf(t'Enter m and n\n")·, 1 return m; 1
I scanf("%d %d",&m, &n)· I 1 else 1
I _.-l'_.22 _--+1-;----
Q..o return n; I
res = maximum(m, n); <} I
I
:1 }
printf("%d", res)~

Calling function
. ~
l- - - - - -I
I
I 1
1
Called function r- - .J

I Actual parameters
Now, let us see the difference between actual parameters and formal parameters.

Actual parameters Formal parameters

1. Actual parameters are used in calling 1. Formal parameters are used in the
function when a function is invoked. function header of a called function
Example: Example:
c = sum(a, b); int sum(int m, int n)
{
Here, a and b are actual parameters.
}
Here, m and n are called formal
parameters
~ Systematic Approach to Data Structures using C 1.65

2. Actual parameters can be constants, 2. Formal parameters should be only


variables or expressions variables. Expressions and constants
Example: are not allowed
c = sum (a+4, b); Example:
int sum(int rn, int n) II Correct
int sum(int m+n, int n) II wrong
int sum(int m, 10) II wrong
3. Actual parameters sends values to the 3. Formal parameters receive values
formal parameters from the actual parameters.
Example:
c = sum( 4, 5);
. Example: int sum(int m, int n)
{
.. < .
}
Here, m will have the value 4 and n
will have the value 5.
4. Addresses of actual parameters can be 4. If formal parameters contains
sent to formal parameters. addresses, they should be declared as
pointers.

1.13.5 Categories of functions


Based on the parameters and return value, the functions are categorized as shown
below:
Functions with no parameters and no return values
Functions with no parameters and return values
Categories of functions --t--. Functions with parameters and no return values
Functions with parameters and return values
Functions that return multiple values.

Now, let us discuss each of the categories one by one.

1.13.5.1 Functions with no parameters and no return values


In this category, there is no data transfer between the calling function and called
function. But, there is flow of control from calling function to the called function and
back as shown using the arrow marks. When no parameters are there, the function can
not receive any values from the calling function. When the function does not return a
value, the calling function can not receive any value from the called function. For
example, consider the program shown below:
,- - - - -
1.66 ~ Introduction to C

- - - - - - - - -.....,
#include <stdio.h> void surm) /* No parameters */ 1
void sumt); /* declaration */
: { int a, b, c; :
r ~Oid ;;;;'inO- - - - I 1 printf("Enter the values of a and b"); 1
I scanf("%d %d",&a, &b); 1
I sumt); I
I } I 1 c = a + b; 1
L
[calling function I J
Il _I
printf("Sum = %d", c);
/* No return valu~ *.L - - J
1

Called function I
Observe from the above program that the function sumO do not receive any values
from the function main/) and it does not return any value to the function maint). But,
still we can input two numbers from the keyboard and perform addition of two
numbers.

1.13.5.2 Functions with no parameters and return values


In this category, there is no data transfer from the calling function to the called
function. But, there is data transfer from called function to the calling function. When
no parameters are there, the function can not receive any values from the calling
l function. When the function returns a value, the calling function receives one value
from the called function. For example, consider the program shown below:
#include <stdio.h>
int surru); /* declaration */ ,- - - - - - - - - - - - - -.....,
int sumt) /* No parameters */ 1
r ~oid ;ainO- - - - --,
I { : { int a, b, c; :
1 int c; 1 1 printf("Enter the values of a and b"); 1
I 1 1 scanf("%d %d",&a, &b); I
I c = sum/); 1
1 c = a + b; 1
I printf("Sum = %d", c);,
I. } return c; 1
I} !
Il 1--
Calling function --I 1 /* returns a value */ _ _ _
. Called function r-
I -
----------------
Q Systematic Approach to Data Structures using C 1.67,

Observe from the above program that the function sumO do not receive any values
from the function mairu). But, it accepts data from the keyboard, find the sum of
those numbers and returns the result to the calling function.

1.13.5.3 Functions with parameters and no return values


In this category, there is data transfer from the calling function to the called function
using parameters. But, there is no data transfer from called function to the calling
function. When parameters are passed, the function can receive values from the
calling function. When the function does not return a value, the calling function can
not receive any value from the called function. For example, consider the program
shown below:

#include <stdio.h>

void sum(int a, int b); 1* declaration *1

I-;oid
I{
~inO - - - - - - - - - - -'1---------
, void sum(int a, int b)
-1
,
I int m, n; " { /* With parameters */ ,
I , int c;
I printf("Enter m and n"); I' I
I scanf("%d %d",&m, &n . I' c = a + b; I
I sum(m, n); I~ printf("Sum = %d", c); :
I}
t., - -I Calling function r--- _..J
'( }
l
I*Noreturnvalue*f
Called function 1--
I

Observe from the above program that the function sumO receives two values from the
functionmaim), finds the sum of these numbers and display the result there itself. The
result is not passed to the calling function, but only control is transferred.

1.13.5.4 Functions with parameters and return values


In this category, there is data transfer between the calling function and called
function. When parameters are passed, the called function can receive values from
the calling function. When the function returns a value, the calling function can
receive a value from the called function. For example, consider the program shown
below:
1.68 Q Introduction to C

#incIude <stdio.h>

int sum(int a, int b); /* declaration */


r------------·---1
void maint) 1-- - - - - - - --1
I { 1 1 int sum(int a, int b) 1
I int m, n, c; 1 {
I 1 int c; 1
I printf("Enter m and n"); I 1 I
I scanf("%d %d",&m, &n . I I c = a + b; 1
I II I
I ~ return c; 1

I l } r------~I--I
I
I }
printf("Sum = %d", c);
1 l Called function
I----- J
l
L--
Calling function

Observe from the above program that the function sumO receives two values from the
function maint), finds the sum of these numbers and sends the result back to the
calling function.
l
Note: Now we are aware that the called function receives the information from the
calling function through the parameters. The variables used while invoking the called
function are called actual parameters and the variables used in the function header of
the called function are called formal parameters.

1.14 Memory organization in C

Now, let us see "What is the memory organization in C?" Here, let us assume the
size of the memory is 1MB = 1024 x 1024 bytes = 1048576 bytes of memory. All
these locations are numbered sequentially from 0 to 1048575 as shown in figure 1.14.

ote: It is observed from the above figure that the addresses for program, data, global
•and static variables along with memory reserved for dynamic allocation will be in
..ncreasing order of the addresses. But, for the local variables, the memory is allocated
10 decreasing order of their addresses.
Q Systematic Approach to Data Structures using C 1.69
. -
Addresses
00000
Program Code 00001
Reserved for the program

Data

Reserved for global and static


Global and static variables variables defined in program

Heap memory }. F~r dynamic memory allocation


I I
't
"
t
I
t
I

Stack .......... }For local variables in the functions


1048574
1048575
Fig 1.14. Memory organization in C

i.rs Storage classes (Local/Global/register and static var~ables)


The variables may be declared within the function or they may be declared outside the
functions. Based on where the variables are declared, the scope and lifetime of
variables change. Now, let us see "What is the scope and lifespan oj a variable?"
Definition: Scopeof a variable is defined as the region or a boundary of the program
over which a vanable can be accessed during execution of the program. Normally, the
scope is related to a block of C code. The lifes anof a variable is defined as the
period during which a variable retains a given va ue during execution of a program.
The various storage classes have different scope and lifetime. Now, let us see "What
are various storage classes available in c·;rhe various storage classes in C language
are classified as sliown below:
Global variables
Local variables
Storage classes in C ---f
Static variables
Register variables
1.70 Q lntroduction to C

1.15.1 Global variable

Now, let us see "Wlat are global variables? Giving examples"

Definition: Global variables are the variables which are defined before all functions.
The global variables have the following features:
• These variables are declared before the functions.
• . Memory is allocated for these variables only once and all the allocated
memory is initialized to zero.
• These variables can be accessed by any functiori and are alive and active
throughout the program.
• Any function can use a global variable and change its value.
• Memory is de-allocated once the execution of the program is over.

Consider the program shown below:

#include <stdio.h>

int a= lO'}
int b = 20~ Stored in r:nemory area reserved for
int c:, global vanables.

. void addt)
h Stored in Program code area normally
c = a+ b; at the beginning of the memory
}
void subtracu)
{ Stored in Program code
c = a- b;
}
void maint)
{ Stored in Program code
addt);
Output
printf("a = %d\nb= %d\n", a, b); a= 10
printf("a + b = %d\n", c); b=20
a + b = 30
subtractt); a-b=-10
printf("a - b = %d\n",c);
.'
}
~ Systematic Approach to Data Structures using C 1.71_

In this program, the variables a, band c are defined before all the functions. So, these
variables can be accessed and modified by any function without passing them as
function arguments. We should remember that global variables are visible only from
the point of declaration to the end of the program. Now, let us see "How the addresses
are assigned to each of the global variable in the following program?" The memory
organization for global variables is shown on the right hand side of the program.

Memory organization for


global variables
#ioclude <stdio.h> Addresses
....... I

int i = 10; 1* 2 bytes *1 i 50000 io
50002 I
float f= 1.15; 1* 4 bytes *1 f
50004 ,
1.150000

50006 I
I
double d = 1.12345678 1* 8 bytes *1 dO< 50008
1.12~5678
50010
50012 I,
iot j =20; 1* 2 bytes *1 J -I 50014 !o
char
char
c1 = 'A';
c2= 'B';
1* 1 byte *1
1* 1 byte *1
ct. c2 50016 A .,
I B
....... I

void maint)
{
printf("&i = %u i = %d\n", &i, i); &i = 50000 i = 10
printf("&f= %u f= %d\n", &f, f); &f = 50002 f= 1.150000
printf("&d = %u d = %If\n'',&d,d); &d = 50006 d = 1.123457
printf("&j = %uj = %d\n", &j,j); &j = 50014 j =20
printf("&c1 = %u c1 = %c\n", &c1, c1); &c1 = 50016 c1=A
. ~c2=~ c2=B

Increasing order
Note: Using & followed by variable name, we get the address of the variable. All the
addresses are assigned to variables one by one in the order in which they are declared.
So, the variables declared in the beginning will have lower addresses when compared
to the variables declared at the end. That is, the addresses of all global variables and
static variables will be in increasing orderas shown below:
&i < &f < &d < &j < &ct < &ct
50000 < 50002 < 50006 < 50014 < 50016 < 50017
1. 72 Q Introduction to C

1.15.2 Local variable (Automatic variable)

Now, let us see "What are, local variables? Giving examples"

Definition: Local variables are the variables which are defined within a function.
These variables are also called automatic variables. As and when control enters into
the function, memory is allocated for these variables and when control goes out of the
function, memory will be de-allocated. That is the reason, the local variables can not
be accessed by any other function. The local variables have the following features:
• These variables are declared inside the function.
• Memory is allocated for these variables when the control enters into the
function and memory is de-allocated for local variables when the control goes
out of the function. But, memory contents are not initialized to zero.
• These variables can not be accessed by any function and are alive and active
within the function. The scope of these variables is limited only to the function
in which they are declared and cannot be accessed outside the function.
• No other function Can use a local variable and change its value.

Note: A local variable is accessible only within the function or block in which it is
defined.

For example, consider the program shown below:


#include <stdio.h>
void add(int a, int b)
{
int c;

c = a + b;
printf("Result = %d\n", c);
}
void maint)
{
int a = 10, b = 20;

add(a,b);
}
Q Systematic Approach to Data Structures using C 1.73.
)

The variable c used in function addt) is a local variable as it is defined only in that
function. Even though the variable c holds the result, when the control goes out of the
function, the variable c can not be accessed. If we use the variable c outside the
function an error "undefined symbol c" is displayed by the compiler. Note that the
variables a and b are defined within the function maint) and are also local variables.
Now, let us see "What is the memory organization for local variables?" or
"How the addresses are assigned to each of the local variable in the following
program?" The memory organization for local variables is' opposite to that of global
variables. For local variables, memory is allocated only in the stack area. In stack
area, memory is allocated from higher address to lower address as shown in following
program:

Memory organization for


#include <stdio.h>
local variables
void maim) Addresses
{
int i = 10;
f=1.15;
1* 2 bytes *1 IIT~---
50016
50014
.......
1

10
.1
1.190000
. 500.1.1.
..J001
. ......

lj
float 1* 4 bytes:" I f
50012 I 50011
50010A i - 50009 I
I
double d = 1.12345678 1* 8 bytes *1 .50008 1.123~S678 _5000_~
d
50006 I 500051
I,
50004
int j = 20; 1* 2 bytes *1 i 50002 20 ~50001 .
char
char
cl = 'A".,
c2 = 'B'; 1* 1 byte *1
=
1* 1 byte *1 cl. c2 50000
I~~
A I
,
!
8

.
4::9j
... ,. .....

Output
printf("&i = %u i = %d\n", &i, i); &i = 50016 i = 10
printf("&f= %u f= %d\n", &f, f); &f = 50014 f= 1.150000
printf("&d = %u d = %If\n'',&d,d); &d = 50010 d = 1.123457
printf("&j = %uj = %d\n", &j,j); &j = 50002 j = 20
printf("&cl = %u cl ::;:%c\n", &cl, cl); &c1 = 50000 c1=A
} &c2 = 49999 c2 =B

Note: Using & followed by variable name, we get the address of the variable.
1. 74 Q Introduction to C

Note: All the addresses are assigned to variables one by one in the order in which
they are declared. So, the variables declared in the beginning will have higher
addresses when compared to the variables declared at the end. That is, the addresses
of all local variables will be indecreasing order as shown below:

&i . > &f > &d > &j > &c1 > &c1
50016> 50014 > 50010 > 50002> 50000> 49999

1.15.3 Static variable

Now, let us see "What are static variables? Giving examples"

Definition: Static variables can be declared outside the function or within the
function. They have the characteristics of both local and global variables. The'
declaration of a static variable should begin with {he keyword static.

For example,
static int a, b;
static float c;

The static variables have the following features:


• These variables are declared inside the function or out side the function
• Memory is allocated for these variables only once and memory contents are not
initialized to zero.
• If these variables are defined inside a function, they can not be accessed by any
function and are alive and active throughout the execution of the program. The
scope of these variables is limited only to the function in which they are declared
and cannot be accessed outside the function.
• No other function can use a static variable and change its value if it is declared
inside a function.
• Memory is de-allocated for static variables when the execution of the program
stops.

Note: The static variable have some features of local variable and some features of
global variable.

For example, consider the program shown below:


Q Systematic Approach to Data Structures using C 1.75

#include <stdio.h>

void displayt)
{
static int i =0;
i++;
printf("%d ",i);
}

void maim)
{
intj;
Output
for (j = 0; j < 5; j++) displayt); 12345
}

Note: Memory organization for static variables is same as that of global variables.

1.15.4 Register variable

Now, let us see "What are register variables? Giving example"

Definition: Any variable declared 'with the qualifier register is called a register
variable. This declaration instructs the compiler that the variable under use is to be
stored in one of the registers but, not in main memory. Register accessing is much
faster compared to the memory access and hence, frequently accessed variables such
as loop variables are usually stored in register variables. This leads to faster execution
of the program. If the register is not free, the compiler can ignore this and the memory
is allocated as it is done for other variables. The register declaration is shown below:

register int x;

This declaration is allowed only for the local (automatic) variables and to the formal
parameters. So, all register variables are automatic. The registers are allocated for
these variables as the control enters into the function and registers are freed
immediately once the control comes out of the function. Their definitions are valid
only to the function in which they are defmed. .
1.76 Q Introduction to C

-Now, let us see "What are the differences between local and global variables?"

Global variables Local variables


1. These variables are declared outside 1. These variables are declared inside
all the functions but, inside the the function
program

2. Global variables are alive and holds 2. Local variables are alive when control
the values as long as the program is .enters into the function during
being executed. execution and are destroyed when the
control comes out of the function.

3. The global variables are accessible 3. The local variables are accessible
throughout the program only in the function inside which they
have been created.

4. Global variables are allocated 4. Local variables are allocated memory


memory on the permanent storage on the stack

5. Global variables are always initialized 5. Local variables are not initialized
to zero automatically in some compilers.

6. Addresses are assigned in the order in 6. Addresses are assigned in the order in
." which the global variables are present which the local variables are present
in the program but in increasing order in the program but in decreasing order

\ .
Chapter 2: Pointers
I What are we studying in this chapter? I
• Pointer Concepts
• Pointer variables
• Accessing variables through pointers
• Pointer declaration and definition
• Initialization of pointer variables
• Pointers and functions
• Pointer to pointers
• Compatibility
• L-value and R-value
• Arrays and pointers
• Pointer arithmetic and arrays
• Passing an array to a function
• Understanding complex declarations
• Memory allocation functions
• Array of pointers
• Programming examples. - 7 hours

2.1 Introduction

Pointer is the one of the important feature available in C language. Almost all the
programs in the software industry are written only using pointers. But, many people
think that pointers concept is difficult. The correct understanding and use of pointers
is very much required for successful C programming. Pointers are one of the strongest
and also one of the most dangerous feature (if not used properly) available in C. Due
to its importance and dangerous feature, the concept of pointers is dealt in detail.
Now, let us understand the concept of pointers.

2.2 Pointer concepts

In this section, let us see "What is a pointer?" and "Explain the concept of pointer"
2.2 Q Pointers

Definition: The basic data types in C language are int, float, char, double and void.
l
Pointer is a special data type which is derived from these basic data types) So, pointer
is called derived data type. The pointer takes the values from 0 to 65535 if the size of
the RAM is 64K. The pointers are always associated with the following three
concepts:

Pointer
concept -E Pointer constants
.
Pomter values

Pointer variables

2.2.1 Pointer constants

Now, let us see "What are pointer constants?"

Definition: As we store any information in our memory, the computer stores


information in computer memory. The computer memory is divided into a number of
locations called storage cells. Each location can hold one byte of information and
each location is associated with address. Let us assume size of memory is 64K where
1K = 1024 bytes. So, total number of memory locations = 64K = 64 x 1K
= 64 x 1024 bytes
= 65536 locations

Logically, all 65536 locations in computer memory are numbered sequentially from 0
to 65535 but, physically they are divided into even bank and odd bank. Even bank is
set of memory locations with even addresses and odd bank is set of memory locations
with odd addresses as shown below:

Address Memory locations Address


o I
1
2 I 3
4 I 5
6 I 7
I
I
65530 65531
65532 I 65533
65534 I 65535
./" I <,
even bank . odd bank
Q Systematic Approach to Data Structures using C 2.3

These memory addresses are called pointer constants. We can not change them; but,
we can only use themto store data values.
For example, in the above memory organization, the addresses ranging from 0
to 65535 are pointer constants.

Note: The address of a memory location is a pointer constant and can not be changed.

2.2.2 Pointer values


Suppose, we have the following declaration:

int i = 100, j = 200, k = 300;

This declaration tells the compiler to perform the following activities:


• Reserve space for three integer values in memory
• Associate the variables i, j and k with these memory locations
• Store 100, 200 and 300 at the locations i, j and k respectively as shown below:

Variable Address Memory locations Address


0 I 1
2 I 3
4 I 5
6 I 7,
I
65530 100 65531
J 65532 2bo 65533
k 65534 300 65535
t t t t
variables address Values address

The address of the variable can not be accessed directly. The address of the variable
can be obtained using address operator (denoted by &) in C language.

Note: The address operator can be used with any variable that can be placed on the
left side of an assignment operator. Since constants, expressions and array names can
not be used on the left hand side of the assignment and hence accessing address is
invalid for constants, expressions and array names. The following are invalid:
2.4 Q Pointers

Usage Valid/Invalid Reasons for invalidity


&100 Invalid Address of a constant can not be obtained
&(p + 10) Invalid Address of an expression can not be obtained
&(p + q) Invalid Address of an expression can not be obtained
int a[10]; Address of entire array can not be obtained
&a Invalid
register a;
b Invalid Address of a register variable can not be
obtained

Note: If a is an array, then address of the first location of the array is obtained either
usmg:
&a[O] or a.

Assume that the compiler has chosen the address 65530 for the variable i, the address
65532 for the variable j and 65534 for the variable k. These addresses assigned to
variables i, j and k are called pointer values. Now, let us "Define pointer values"

Definition: Memory is divided into number of storage cells called locations. All the
locations in computer memory are numbered sequentially from 0 to 65535 (with
memory size of 64K). Out of these addresses, the system assigns some addresses of
the memory locations to the variables. These memory addresses assigned to variables
by the system are called pointer values.
For example, the addresses 65530, 65532 and 65534 which are assigned to the
variables i, j and k are pointer values. These pointer values can be obtained using
address operator (&). Using &i, &j and &k we can obtain pointer values 65530,
65532 and 65534.

Note: Without address operator (&), it is not possible to obtain the pointer value of a
variable.

Note: The pointer values (i.e., the addresses assigned to variables) may vary each
time the program is executed. That is, the address of the variable may change from
one run of the program to another.

2.2.3 Pointer variable

Now, let us see "What are pointer variables?"


Q Systematic Approach to Data Structures using c..2 5
Definition: A variable which holds address of another variable is called <pointer
variable. In other words, pointer variable is a variable which holds pointer value (i.e.,
address of a variable). For example, if i is a variable and address of i is stored in a
variable p as shown below:
p=&i;

then the variable p is called apointer variable. The memory organization after
executing the above statement is shown below:

Variable Address Memory locations


0 I
2 t
4 I
t

P 50000 651;34
I
:
65534 300
t t t
variables address Values
Physical representation Logical representation

ate that the address of variable i which is 65534 is assigned to variable p. So,
even though address of p is 50000 ( pointer value), the value stored in that location is
65534. Since p is a variable which contains address of a variable, the variable p is
called pointer variable. In the logical representation, the variable p points to the
variable i. So, we say that the variable p points to i and hence the name pointer. The
relationship between p and i is pictorially represented as shown below:

L....-__ =jr----.~1
p
__ 3-:-0_0_

If we use the statement:


p=&j;
the variable p contains the address of variable j.
Note: A pointer variable should contain only the address (i.e., pointer value).
2.6 Q Pointers

Note: Note the difference between pointer value and value stored in memory location.
Pointer value is 50000 and value stored in memory location is 65534.

2.3 Accessing variables through pointers


Once we know the concept of pointers, let us see "What are the steps to be
followed to use pointers?" The following sequence of operations have to be
performed by the programmer:

Declare a data variable Ex: int a·,


Steps to be Declare a pointer variable Ex: int *p;
followed while
using pointers Initialize a pointer variable Ex: p = &a;
Access data using pointer variable Ex: printf("%d", *p);

2.3.1 Pointer declaration and Definition

In C language, we know that all the variables should be declared before they are used.
Pointer variables also should be declared before they are used. In this section, let us
see "How to declare pointer variables?" The syntax to declare a pointer variable is
shown below: .
~
type * identifier ; .

I L~
..
Name given to the pointer variable
~ The asterisk (*) in between type and identifier
tells that the identifier is a pointer variable
'-------+ type can be any data type such as int, float,
char etc. It can be derived/user-defined data
type also.

Example 2.3.1.1: Consider the following declaration

int *p;

The above declaration can be read as ''p is pointer to integer variable" and this
declaration informs the following points:
Q Systematic Approach to Data Structures using C 2.7

• The variable p is a pointer variable. So, it should contain the address of


variable during execution.
• The type int refers to the type of the variable stored in pointer variable p
i.e., the pointer variable p should contain address of an integer variable.

Example 2.3.1.2: Consider the following declaration:

double *pd;
.
This declaration informs the compiler that pd is a pointer variable and can hold the
address of a variable of type double.

Example 2.3.1.3: In the declaration, the position of * is immaterial. For example, all
the following declarations are same:
int ' *pa;
int * pa;
int* pa;

Any of the above declaration informs that the variable pa is a pointer variable and it
should contain address of integer variable.

Example 2.3.1.4: Consider the multiple declarations as shown below:


int* pa, pb, pc;

otc: Here, most of the readers wrongly assume that the variables pa, pb and pc are
pointer variables. This is because * is attached to int. This assumption is wrong. Only
pa is a pointer variable, where as the variables pb and pc are ordinary integer
variables. For better readability, the above declaration can be written as shown below:
int *pa, pb, pc;
Now, we can easily say that pa is pointer variable because of * operator, whereas pb
and pc are integer variables and are not pointer variables. It is still better if the
variables are declared in separate lines as. shown below:
int *pa;
int . pb;
int pc;
2.8 Q Pointers

2.3.2 Dangling pointers

In the previous section, we have seen the method of declaring a pointer variable. For
example, consider the following declaration:

int *p;

This indicates that p is a pointer variable and the corresponding memory location
should contain address of an integer variable. But, the declaration will not initialize
the memory location and memory contains garbage value as shown below:

p I ~arbage value

Here, the pointer variable p does not contain a valid address and we say that it is' a
dangling pointer. Now, let us see "What is a dangling pointer?"

Deflnitione e, pointer variable should contain a valid address. A pointer variable


which does not contain a valid address is called dangling pointer.

Example Z.3.2.1:Consider the following declarations and assume all are global
variables.

int *pi; 1* Pointer to an integer *1


float *pf; 1* Pointer to a float number *1
char *pc; 1* Pointer to a character *1
~ho~ the memory organization for these variables ..

Solutiomaj] global variables are initialized by the compiler during compilation. The
pointer variables are initialized to NULL indicating they do not point to any memory
ocations as shown below:

pi
pf ~
pc
Q Systematic Approach to Data Structures using C 2.9

Example 2.3.2.2: Consider the following declarations and assume all are local
variables.

int *pi; 1* Pointer to an integer *1


float *pf; 1* Pointer to a float number *1
char *pc; 1* Pointer to a character *1

Show the memory organization for these variables.

Solution:The local variables are not initialized by the compiler during compilation.
[This is because, the local variables are created and used only during
untimelexecution time. The pointer variables also will not be initializedand hence
hey normally contain some garbage values and hence are called dangling pointers.
Irhe memory organization is shown below:

pi ~ Garbage value
pf Garbage value
pc Garbage value

Note:The pointer variables pi, pf and pc does not contain valid addresses and hence
they are dangling pointers.

Note:Most of the errors in programming are due to un-initialized pointers. These


errors are very difficult to debug. So, it is the responsibility of the programmer to
avoid dangling pointers. Hence, it is necessary to initialize the pointer variables so
that they always contain valid addresses. Only then, the pointer variables can be used
to access the data.

2.3.3 Initializing a pointer variable

Now, the question is "How to initialize a pointer variable?"


2.10 Q Pointers

- Initialization of a pointer variable is the process of assigning the 'address of a variable


to a pointer variable. The initialization of a pointer variable can be done using
following three steps:

Step. 1: Declare a data variable

Step 2: Declare a pointer variable

Step 3: Assign address of a data variable to pointer variable


using & operator and assignment operator

Note that the steps 1 and 2 can be interchanged i.e., we can first declare a pointer
variable, then declare a data variable and then initialize the pointer variable.

Example 2.3.3.1: Consider the following three statements:


int : x; /* Step 1: x is declared as a data variable */

int' *px; /* ep 2: px is declared as a poiriter variable */

px = & x; /* , _. copy address of data variable to pointer variable */

Here, the variable x is declared as integer data variable. Since px is a pointer variable
~of type integer, it should contain address of integer variable. So, using the statement:
px=&x

the valid address is stored in the pointer variable and hence the pointer variable px is
initialized.

Example 2.3.3.2: Consider the following three statements:


int x;
iot *px;
px=&x;

The above three statements can also be written as shown below:


iot x;
int *px = &x;
~ Systematic Approach to Data Structures using C 2.11

Note: It is also possible to combine the declaration of data variable, pointer variable
and initialization of pointer variable in one step as shown below:

int x, *px = &x;

Here, x is declared as a data variable, px is declared as pointer variable and px is


initialized to address of data variable x.

Example 2.3.3.3: Consider the following statements:


int p, *ip;
.float .: d, f;

ip = &p; 1* Correct initialization *1

ip = &d; 1* Wrong initialization *1

Note: First initialization is correct. In the second initialization, ip is a pointer to


integer. So, it should contain address of integer variable. But, address of floating point
variable d is stored in ip and hence it-is wrong.

Example 2.3.3.4: Pointers are flexible i.e., a pointer can point to different data
variables by storing the address of appropriate variables. Consider the following
declaration:
int x = 10, Y = 20, z = 30;
int *p;
x
p=&x;

p y
p=&y;

z
p=&z;

ote: It is observed from above example that the pointer variable p points to Jifferent
memory locations by storing the addresses of different variables. Thus, same pointe
can be pointed to different data variables.
2.12 Q Pointers

2~3.4NULL Pointer

Now, let us see"What is a NULL pointer?"

Definition: A NULL pointer is defined as a special pointer value that points to


nowhere in the memory. If it is too early in the code to assign a value to the pointer,
then it is better to assign NULL (i.e., \0 or 0) to the pointer. For example, consider the
following code:
#include <stdio.h>

int *p = NULL;

Here, the pointer variable p is a NULL pointer. This indicates that the pointer
variable p does not point to any part of the memory. The value for NULL is defined
in the header file "stdio.h". Instead of using NULL we can also use '\0' or O. The
programmer can access the data using the pointer variable p if and only it does not
contain NULL. The error condition can be checked using the following statement:

if (p = = NULL)
printf("p does not point to any memory]n");
else {
printf("Access the value of p\n");

Note: A pointer variable must be initialized. If it is too early to initialize a pointer


variable, then it is better to initialize all pointer variables to NULL in the beginning of
the code.This avoids unintentional use of an un-initialized pointer variable.

Example 2.3.4.1: Consider the following statements:

int *x;
int y;

x = y; /* Error */

Note: The value of data variable can not be assigned to a pointer variable. So, th
statementx = y; results in an error. The correct statement isx = &y.
Q Systematic Approach to Data Structures using C 2.13

2.3.5 Accessing variables through pointers


, .

Once a pointer variable is initialized with address of a variable, the question is "How
to access the value of a variable using pointer?" The value of a variable can be
accessed using pointer variable using unary operator * (called asterisk). This operator
is called indirection operator or dereferencing operator. For example, consider the
following program segment:

int x = 100, y;
int *p;

p=&x; 1* Address of x is stored in pointer variable p *1


y= *p; 1* Since p has the address of x, the value of data
1* variable x i.e, 100 is copied into y *1

Note: By specifying *p, the value of the variable whose address is stored in p can be
accessed. Here, p should be a pointer variable.

Example 2.3.5.1: The data can be accessed usmg pointers after declaration and
initialization.

Step1 : Declaration consider the following declaration:


Variables
Address

int *p; 1p 5000


t I

I Garbage val ue
I
int *q; q 5002 I
Garbage value
I
I
int *r; r 5004 I Garbage value
I

int x = 10; x 5006 ~O

Afterdeclaration, the pointer variables p, q and r does not contain valid addresses and
hence are called dangling pointers. The variable x is initialized to 10 as shown in
figure above. Once declaration is over, the next step is to initialize the pointer
variables.
2.14 Q Pointers

Step 2: Initialization Consider the following statements:

Variables

1 Adress
I

p=&x; p 5000 I
I
I
q=&x; q 5002 I
I

r=&x; r 5004 I

x 5006
I

~O
+- U
After executing these statements, the pointer variables p, q and r contains the address
of integer variable x and logical representation is shown in the figure above.

Step 3: Accessing the item 10: The item 10 can be accessed using the variables, p, q,
r and x as shown below: -

'Using p:
I
printf("&p =%u, p = %u, *p = %d\n",&p, p, *p); I /* Output */
&p = 5000, P = 5006, *p = 10
I
Using q:
I
printf("&q =%u, q = %u, *q = %d\n",&q, q, *q); I /* Output */
I &q = 5002, q = 5006, *q = 10
Using r: I
Printf("&r =%u " r = %u *r = %d\n" ,&r " r "r);,
I /* Output */
I &r = 5004, r = 5006, *r = 10

Note: Even though the variables p, q and r have different addresses, they contain
address of x only. So, different pointer variables (p, q and r in this example) may
contain address of one variable (x in this example). So, the value of x can be accessed
and changed using the variables p, q, rand x. In general) there can be multiple
pointers to a variable. .
Q 'Systematic Approach to Data Structures using C 2.15

Example 2.3.5.2: Program to add two numbers using pointers

PROGRAM TRACING
1. #include <stdio.h>
2.
3. void rnainf) Execution starts from main
sum
4.{
5.
6
int a ~ 10, b = 20, sum;
IT]
7. int *pa, *pb;
8.
9. pa = &a;
10. pb = &b;
II.
12. sum = *pa + *pb; sum = 10 + 20 =30 -.J

13.
14. Output
15. printf("Sum = %d\n", sum); Sum = 30
16. }

Explanation: Observe the following points

• In line 5 the variables a and b are initialized to 10 and 20 respectively.


• In line 7, the variables pa and pb are declared as pointer variables which are used
to store address of integer variables.

• In line 9, pa holds the address of a


• in line 10, pb holds the address of b.
• In line 12, the values of a and b are accessed using pa and pb with the help of *
operator indirectly. So, * is called indirection operator.
• In line 15 the sum of two numbers is displayed.
2.16 Q Pointers

Example 2.3.5.3: Program to read two numbers and then add two numbers using
pointers·

PROGRAM TRACING

1. #include <stdio.h>
2.
3. void mairu) Execution starts from main
4.{
5. int a, b.rsum;
6
7. int *pa, *pb;
8.
9. pa= &a; pb
10. pb = &b;
II. Input
12. scanf("%d %d",&a, &b); 10 20
13. a = 10 b = 20
14. sum = *pa + *pb; sum = 10 + 20 =30 -----~
15. Output
16. printf("Sum = %d\n", sunr); Sum = 30
17.}

Explanation After executing statement 12, the values 10 and 20 which are read from
the keyboard are copied into memory locations identified by. a and b. Then those
values are accessed using pointer variables pa and pb, added and result is stored in the
variable sum.

Note: In the statement in line 12 i.e.,


scanf("%d %d", &a, &b);
we are using &a and &b. In line 9 and 10, &a and &b are already copied into pointer
variables pa and pb. So, in place of &a and &b, we can use the pointer variables pa
and pb as shown below:
scanf("%d %d", pa, pb); 1* Since pa contains &a, pb contains &b *1

Note: there is no need of writing &pa and &pb, since pa and pb already contains the
addresses.
Q Systematic Approach to Data Structures using C 2.17
>

Example 2.3.5.4: What is the output of the following program?


PROGRAM TRACING
#include <stdio.h>
\

void main(void)
{
1* Local definitions *1
int a, b, c; aD bD cD
int *p, *q, *r; pD qD rD
1* statements *1
a~ ~ 4 I cD
a = 8, b = 4, P = &b;
pi qD rO
I
:§5
4
q = p, r = &c; a~ ~ ...
I

pi -1' ql
I
I
p = &a, *q = lO;

:ffi ~~ :ffi
*r = *p;

:ffi ~~ :ffi
*r = a + *q + *&c;
a I 8
I bl 10
I cI ,. I
26

pi I
Output
I ·ql I I rI I I
printf("%d %d %d\n",a, b, c); 8 10 26
printf("%d %d %d", *p, *q, *r); 8 10 26
}
.
2.18 ~ Pointers

Example 2.3.5.5: Consider the following program segment:


int x;
int *p;

x= *p; /* Error: since pointer variable p is not initialized */


*p =x; /* Error: since pointer variable p is not initialized */

Note: The pointer variable should be used only after initializing with address of a
data variable.

2.4 Pointers and functions


In this section, let us see "How pointers can be passed as arguments to the functions?"
and we shall see the advantage of using pointers while writing functions. Consider the
following program: .

#include <stdio.h>
int sum(int a, int b); 1* prototype declaration *1
r ~oi~mainO ----------1
I {~ .I
I intm,n,c; I .I~--(-. -.--) --. -1
I I int sum int x, int y I
I printf("Enter m and n"); I :{ int z; I
I scanf("%d %d",&m, &n); I I I
I c = sum(m, n"
I I z =x + y; I
I .........:..' I I I
I = %d", c); I 1 I
r- - - J
printf("Sum return z;

L~ -1 Calling function . I~ -I Called function I-I


Execution always starts from the function maim), After reading the values for the
variables m and n, the function sumi) is called. Here, the function maim) calls the
function sumf) and so mainO function is called calling function and the function
sumt) is called "called function ".
Q Systematic Approach to Data Structures using C 2.19

Working of the function: The activities during execution are shown below:
• Execution starts from the function main/)
• Te values for data variables m and n are read from the keyboard
• The function sunu) is called
• The function sumO receives two values using the variables m and n are copied
into x andy
• The function computes the sum of x and y
• The result is returned to calling function maim)
• The function mairu) prints the result.

Now, let us see "What are the different ways of passing parameters to the functions?"
There are two ways of passing parameters to the function:

~ Pass by value (also called call by value)

L Pass by reference (also called call by reference)

2.4.1 Pass by value (Call by value)


Now, let us see "What is pass by value?" and "Explain with example"

Definition: When a function is called we may send values of some variables to the
calling function. These variables are called actual parameters. In the called function,
variables should be declared with the same type as the actual parameters. These
variables are called formal parameters. The values of actual parameters are copied
into formal parameters. If the values of the formal parameters changes in the
function, the values of the actual parameters are not changed. This way of passing
parameters is called pass by value or call by value. -
To explain the concept of pass by value, let us type the following program
shown in example 2.4.1.1 and observe the output.

Working After executing the program observe the following points:


• The values of actual parameters a and b are copied into formal parameters m
andn.
• In the function exchanget), the values of m and n are exchanged.
• But, the values of actual parameters a and b have not been exchanged.

Note: This technique where in actual parameters have not been changed even though
the formal parameters have been changed is called pass by value. .
2.20 Q Pointers

Example 2.4.1.1: Program to show the concept of pass by value


I
#include <stdio.h> TRACING
I
void exchangel(int m, int n) ~ Formal parameters m D
{ I '-r-~
int temp; I /
m = 20, n = 10 \
temp=m; I / (Exchanged) \
m=n; I / \
n = temp; 1/ \
}
: \\ Note: Dotted lines indicate values I
void maint) are copied I
{ \ . I
int a, b; \ I
\ No exchange I
a = 10, b === 20;

exchange (a, b)j ~ Actual parameters ~ a


I -------
printf("a = %d and b = %d\n", a, b); I Output
} 1 I a = 10 and b = 20

Remember: In pass by value (call by value) any change done on formal parameters
will not have any affect on actual parameters.

2.4.2 Pass by reference (Call by reference) - Pointer as formal parameter

Now, let us see "What is pass by reference?" and "Explain with example"
Definition: When a function is called we may send addresses of some variables to the
calling function. The variables that are used when a function is called are actual
parameters. In the called function, the corresponding variables should be declared as
pointers with the same type as the actual parameters. These variables are called
formal parameters. The addresses of actual parameters are copied into formal
parameters. Using these addresses, if the values of the formal parameters changes in
the function, the values of the actual parameters are also changed. This way of
passing parameters is called pass by reference or call by reference.
To explain the concept oipass by reference, let us type the program 2.4.2.1
and observe the output.
~ Systematic Approach to Data Structures using C 2.21

Example 2.4.2.1: Program to show the concept of pass by reference

PROGRAM TRACING

#include <stdio.h>
I
void exchange (int *m, int *n); I
void exchangekint *rn, in! *nll : m IL-..+-....I
{ ~ Formal parameters I,/"
int temp;
temp = *m;
I
*m= *n; I
*n = temp; I
} I
void maint)
I
{ I
int a, b; I
a = 10, b = 20; :
exchangeIC&a, &b)~ Actual parametere+-j-s- a G b I 20 I
printf("a = %d and b = %d\n", a, b); II Output (After exchange)
} a=20 b=10
I '
Working Observe the following points when the program is executed:
• The addresses of actual parameters a and b are copied into formal parameters m
andn.
• So, in the function header of exchanger), the variables m and n are declared as
pointer variables.
• Since, they contain addresses, they can access values of a and b using indirection
operator *.
• Thus, the values of a and b can be changed using pointer variables m and n.

Note: This process of passing parameters so that the values of actual parameters are
changed using formal parameters is called pass by reference.
2.22 Q Pointers

- Remember: In pass by reference (call by reference), the values of the actual


parameters can be changed using formal parameters. This is because; the formal
parameters contain addresses of actual parameters.

Now, let us see "What are the differences between pass by value and pass by
reference?" The various differences between pass by value and pass by technique are
shown below:

Pass by value Pass by reference


l. When a function is called the values l. When a function IS called the
of variables are passed. addresses of variables are passed

2. The type of formal parameters should 2. The type of formal parameters should
be same as type of actual parameters be same as type of actual parameters,
,
but they have to. be declared as
pointers
:

3. Formal parameters contains the values 3. Formal parameters contains the


of actual parameters addresses of actual parameters

4. Change of formal parameters m the 4. The actual parameters are changed


function will not affect the actual since the formal parameters indirectly
~ parameters in the calling function manipulate the actual parameters

5. Execution IS slower smce all the 5. Execution IS faster since only


values have to be copied into formal addresses are copied
parameters

6. Information transfer through 6. Information transfer through


parameters is not possible parameters is possible. That is more
than one value can be transferred
through the parameters.
Note: Only one value can be sent using
-
return statement.

2.4.3 Functions returning pointers


A function can return a single value using return statement or multiple values using
pointers in parameters. The C program with a function returning a single value is
shown in example 2.4.3.1.
Q Systematic Approach to Data Structures using C 2.23

Example 2.4.3.1: Program to return the larger of two numbers

PROGRAM TRACING
#include <stdio.h> values of x and yare copied
~ -

int largest(int a, in t b) a = 20, b = 10


{
if (a> b) Is 20 > 10
return a; Yes: return 20
else
return b;
}
Execution starts
void maint)
{
int x, y, big; 1
Input
printf("Enter the values ofx and y\n"); Enter x and y
scanf("%d %d",&x, &y); x = 20 y= 10

big = largest(x, y); big = 20

printf("Maximum (%d, %d) = %d\n",x, y, big);


}

Working The sequence of operations that are carried during the execution of the
program are shown below:
• Execution starts from function maim).
• Accepts the values for x and y
• Control is transferred to the function largesn).
• The values of actual parameters x and yare copied to formal parameters a and
b.
• Larger of these two numbers is returned to the function maint) and is copied
into variable big.
• The function maint) displays the result

Note: In the above program, the function returns an integer value to the calling
function mainf).
2.24 .Q, Pointers

Since pointer is also a data type in C, we can return a pointer from a function. The
program to find the larger of two numbers and returning pointer to larger number is
shown below:

Example 2.4.3.2: Program to return pointer to larger of two numbers


PROGRAM TRACING
#include <stdio.h>

int *largest(int *a, int *b) a


{
if (*a > *b)
return a;
else
return b;
}

void mairu)
{ x
int x, y, *big; "'"'-.....-...•

printf("Enter the values ofx and y\n");


scanf("%d %d",&x, &y); whichever
••••• ...•is larger
big = largest(&x, &y);
printf("Maximum (%d, %d) = %d\n",x, y, *big);

Working The sequence of operations that are carried out during the execution of the
program are shown below:
~ Execution starts from function mairu) ..
• Accepts the values for x and y
• Control is transferred to the function largestt).
• The addresses of x and yare copied to formal parameters a 'and b respectively.
• Using pointer variables a and b with the help of indirection operator *, we
compute the larger of x and y and return the address oflarger number.
• Once control is returned to the function maim), the pointer variable big holds
the address of larger of x and y and .the result is displayed using indirection
operator *.
Q Systematic Approach to Data Structures using C 2.25

Example 2.4.3.3: What is the output ofthe following program?

#include <stdio.h>

int *someO
{
int *p, x = 10; /* Local variables */
p=&x;
return p;
}

void mainr)
{
int *p;

p = sorne/);

printf("Result = %d\n", *p);


}

Analysis: We may be thinking that our answer is "Result = 10". After executing the
program we may get "Result = 10". Even then, our program is 100% wrong because
of the following reasons.
• Note that in the function somet), the variables p and x are local variables.
• As control enters into the function, memory is allocated for these variables and
once control goes out of the function, memory for these variables is de-
allocated.
• So, we are returning address of a memory location which is de-allocated.
• This de-allocated memory may be used by other parts of the program.
Although, you get an answer for this simple program, but definitely for larger
program we get wrong answer.

Note: So, returning a pointer to a local variable is a serious logical error. But, not
syntax error.

2.4.4 Pointers to Pointers

We have used pointers which directly points to data. In this section, let us see "What
is pointer to a pointer?"
2.26 J;l, Pointers

Deflnition: It is possible to make a pointer to point to another pointer variable. A


variable which contains address 'of a pointer variable is called pointer to a pointer.
For example, consider the following declarations:
int a;
int *p1;
int **p2;

• The first declaration instructs the compiler to allocate the memory for the variable
a in which integer data can be stored.
• The second declaration tells the compiler to allocate a memory for the variable pi
in which address of an integer variable can be stored.
•. The third declaration tells the compiler to allocate a memory for the variable p2 in
which address of a pointer variable which points to an integer can be stored. The
memory organization for the above three declarations is shown below:
p2
r Garbage
value
pI
r--=:J __....
~value
Garbage
a

Example 2.4.4.1: Memory organization after executing following assignment


statements;
a = 10;
l 'p l = &a;
p2 = &pl;
The memory organization after executing the statement a = 10 is shown below:

r
p2
Garbage
value
pI
~Garbage
~value
a

The memory organization after executing the statement p.l = &a is shown below:

r
p2
Garbage
value I
pI

j-----+) 1 10
a

The memory organization after executing the statement p2 = &pI is shown below:
p2 pI a

I 1-------+1)1 j-~)I 10 I,
~ Systematic Approach to Data Structures using C 2.27

The data item 10 can be accessed using three variables a, pI and p2 are shown below:

a refers to the data item 10.


*pI Also refers to the data item 10. Here, using pI and only one
indirection operator, the data item 10 can be accessed.
**p2 Also refers to the data item 10. Here, using p2 and two indirection
operators the data item 10 can be accessed (i.e., *p2 refers to pl and
**p2 refers to a)

The following program illustrates the way the data item 10 can be accessed using the
variable a, using a pointer variable p l and pointer to a pointer variable p2.

Example 2.4.4.2: Program to access 10, using a variable, pointer variable and pointer
to a pointer variable
#include <stdio.h> TRACING
void maim)
{
int
int
int
a',
*pl;
**p2; I
p2
r Garbage
value
pI
~Garbage
value
CJ
a

a = 10;
I
p2
r Garbage
value
pI
~Garbage
value
~
a

,.
pl = &a;

I
r
. p2
Garbage
value
I =j
pI

~I I
a
10

p~ pl a

p2 = &pl; I j ~I=j ~I I 10

Output
printf("a = %d\n",a); a = 10
printf("*pl = %d\n", *pl); *pl = 10
printf("**p2 = %d\n", **p2); **p2 = 10
}
2.28 Q, Pointers

Example 2.4.4.3: If x is declared as integer, which of the following statements is


true and which is false?
a. The expression * &x and x are the same.
b. The expression *&x and &*x are the same.

Ans: a) The expression *&x and x are the same. This statement IS true for the
following reasons:
• &x represent the address of the variable x.

• The expression * &x


represents the value stored in the memory location whose
address is given by &x.

Note: The indirection operator denoted by * and address operator denoted by & are
the inverse of each other and cancel each other. So, the expression *&x can be can
also be represented by x.

Ans: b) The expression * &x and & *x are the same. This statement is false for the
following reason:
• The expression *&x and the expression x are the same. But, the expression &*x is
illegal. This is because, the operators & and * are unary operators and are right
associative. So, *x is evaluated first. But, *x can be used only if the variable x
.1
contains address. But, it is given that x is declared as an integer variable not as a
pointer variable. So, &*x is illegal.

Example 2.4.4.4: Given the following declarations:


int a = 5;
int b=7;
int *p = &a;
int *q = &b;

What is the value of each of the following expressions?


a. ++a;
b. ++(*p);
c. - - (*q);
d. --b;

Solution: The tracing of the above program segment is shown below:


Q Systematic Approach to Data Structures using C 2.29

1* Memory representation for the declarations *1


int a = 5; a
int b=7;
int *p = &a;
int *q = &b; p

1* Increment a *1 a
++a;

1* Access a using pointer variable p *1 a


++(*p);

1* Access b using pointer variable q*1 a


--(*q);
p

1* Decrement b *1 a
--b;

Output a=7 b=5


*p = 7 *q = 5

Example 2.4.4.5: What is the error (if any) in each of the following expressions?
a. int x = 5;

b. int *x = 5;
C. int a·,
int *x = &a;
d. int a·,
int **p = &a;
2.30 Q Pointers

Solution: The valid and invalid statements along with reasons for invalidity are
shown below:

a. int x= 5; 1* valid *1

b. int *x = 5; 1* Invalid because of following reason *1

Reason for invalid: Since the variable x is declared as a pointer variable, it


should contain only the address of an integer variable. Here, instead of storing the
address of a variable, a constant digit 5 is stored in variable x which is illegal.

c. int a', 1* Valid *1


int *x = &a; 1* Valid statement *1

d. int a', 1* Valid *1


int up = &a; 1* Invalid because of following reason *1

Reason for invalid: In the first statement, the variable a is declared as an integer
variable. This is valid declaration. In the second statement, address of variable a
is stored in the variable p. In such case, p should be declared as pointer to integer
as shown below:
int *p = &a.
But, the variablep is declared as pointer to pointer variable which is an error.

Example 2.4.4.6: Which of the following program segments IS valid? Give the
reasons for invalidity:
a. int *x;
scanf("%d", &x);
b. int *x;
scanf("%d", &*x);
c. int *x;
scanf("%d", *x);
d. int a;
int *x = &a;
scanf("%d", x);
Q Systematic Approach to, Data Structures using C 2.31

Solution: The valid and invalid statements along with reasons for invalidity are
shown below:
a. int *x;
scanf("%d", &x); 1* Invalid *1

Reason: The function scanft) requires address of data variable as an argument. Here,
x is declared as a pointer variable and it has not been initialized. So, the program
segment can be modified as shown below:
int a; 1* Declare data variable *1
int *x; 1* Declare pointer variable *1

x = &a; 1* Assign address of data variable to pointer variable *1


scanf("%d", x);
or
If it is given that &x has to be the argument for the function scanfi), then
The program segment can also be modified as
shown below:
int x;
scanf("%d", &x);

b. int *x;
scanf("%d", &*x); 1* Invalid *1

Reason: The variable x is declared as a pointer variable and it has not been initialized.
So, the program segment can be modified as shown below:
. int a; /* Declare a data variable *1
int *x; 1* Declare a pointer variable *1

x=&a; 1* Initialize a pointer variable *1

scanf("%d", &*x);'

Note: &a, x and &*x are all one and the same. So, instead of using &*x, we can also
usex or&a as an argument.

c. int *x;
scanf("%d", *x); 1* Invalid : Explanation is same as the above *1

..
2.32 .Q Pointers

d. int a·,
int *x = &a; 1* x is a pointer variable and it has been initialized *1

scanf("%d", x); 1* Valid *1

Example 2.4.4.7: Write a program to read the data to an integer variable a using the
variables p, q and r given the following declarations:
int a;
int *p;
int **q;
int ***r;

Solution: The program to read a value into variable a using the variables a, p, q, r is
shown below:

#include <stdio.h>

void mainr) Memory organization during execution


{
1* Local variables *1
int
int
int
a;
*p;
**q;
rQ qQ pQ a[2J
Garbage value Garbage value Garbage value
int ***r;
r q
1* After initialize p *1
p=&a; CjJetJ
Garbage value Garbage value

r q p a
1* After initialize q *1
q=&p;
Q I 3--1 =j \ )[ij
Garbage value I a
1* After initializing r *1
r=&q;
l
Q Systematic Approach to Data Structures using C 2.33

/* Read the value for variable a using variable a */


r q p a
printf("Enter the number: ");
scanf("%d", &a);
printf("a = %d\n", a);
I 3-1 3---i erG
I
/* Read the value for variable a using variable p */

printf("Enter the number: ");


scanf("%d", p);
printf("a = %d\n", a);

/* Read the value for variable a using variable q */

r q p a
printf("Enter the number: ");
scanf("%d", *q);
printf("a = %d\n",a);
13-1 3-1 =tG
/* Read the value for variable a using variable r */

}
printf("Enter the number:");
scanf("%d", **r);
printf("a = %d\n", a);
r

I 3-1.3---i
q

--r~
p a

Output
Enter the number: 10
a = 10
Enter the number: 20
a=20
Enter the number: 30
a = 30
Enter the number: 40
a =40

Note: While reading a value into a variable a, it is required to send the address as an
argument to the function scanfi) as shown below:
scanf("%d",&a);

Instead of &a in the scanfl) statement, we can also use p or *q or **r.


2.34 Q Pointers

Example 2.4.4.8: In the following program segments identify the logical error if any?
a. int **x;
int *y;
y=&x;
b. int **x;
int *y;
x=&y;
c. int **x;
int **y;
x=&y;
d. char c='A';
char **x;
char *y;
y=&c;
printf("%c", *x);

Solution: The logical errors identified for each of the program segment are shown
below:
a. int **x; /* Valid */
int *y; /* Valid */

y=&x; /* Invalid: Logical error */


Reason: Since x is a pointer to a pointer, it can contain address of a pointer
variable y. But, the reverse is not true. So, y = &x has logical error. At the same
time, there is no proper initialization of pointer variables. The correct statements
can be written as shown' below:
int **x;
int *y;
int a;

y=&a;
x=&y;

b. int **x; /* Valid */


int *y; /* Valid */
x=&y; /* Valid */
Q Systematic Approach to Data Structures using C 2.35

Reason: Logical error exists still in above program segment, since the variable y
has not been initialized. The correct code can be written as shown below:
int **x;
int *y;
, int a;
x=&y;
y=&a;
Note: All the pointer variables should be initialized. Otherwise, it results m
logical error.

c. int **x;
int **y;
x = &y; 1* Invalid: Logical error exists *1
Reason: Since x is a pointer to a pointer variable, it should contain address of a
pointer variable. But, y is declared as pointer to a pointer variable which is an
error. So, the correct declaration is shown below:
int **x;
int *y;
int a;
y=&a;
x=&y;

d. char c = 'A';
char **x;
char *y;
y=&c;
printf("%c", *x); 1* Invalid: It is a logical error *1
Note: The pointer to a pointer variable x is used in printfi). But, the variable x has not
been initialized. So, it is a logical error. The cor:rect code can be written as shown
below:
char c = 'A';
char **x;
char *y;
y=&c;
x=&y;
printf("%c", *x);
2.36 Q Pointers

2.4.5 Compatibility and void pointer

In this section, let us see "What is compatibility with respect to data variable and
pointer variable?"

Definition: We should not store the address of a data variable of one type into a
pointer variable of another type. During assigning we should see that the type of data
variable and type of the pointer variable should be same or compatible. Otherwise, it
results in compile error also called syntax error. Consider the following examples:

Example 2.4.5.1: The following program segment is correct:


int a;
int *x;

x=&a;
Note: The type of pointer variable x and type of data variable a are same. Hence, we
say that type of both variables are compatible.

Example 2.4.5.2: The following program segment is wrong:


int a;
float *x;

x = &a; 1* Invalid: data variable is integer and pointer variable


is float *1
Note: The type of pointer variable x is float and type of data variable a is into Since
their types are different, we say that types of both variables are incompatible.

Example 2.4.5.3: The following program segment is wrong:


char a;
float *x;

x=&a; 1* Invalid: data variable is character and pointer variable


is of type float *1

Note: The type of pointer variable x isfloat and type of data variable a is char. Since
their types are different, we say that types of both variables are incompatible.
Q Systematic Approach to Data Structures using C 2.37

Now, the question is "Is it possible to use incompatible pointer types while
assigning?" The answer is yes. This is achieved with type casting a pointer. Now, let
us see "What is type casting a pointer?"

Definition: As we convert the type of one data variable into type of another data
variable using type casting, we can make an assignment between incompatible pointer
types using explicit type casting. This process of converting the type of a pointer
forcibly to another type is called type casting a pointer. For example,

Incompatible pointer assignment Valid pointer assignment


int a', int a',
float *x; float * x;

x=&a; 1* Error *1 1* type casting a pointer *1


x=(~*)&a; 1* valid *1
type casting
Note: Type of pointer variable x and I ,
type of data variable are different i.e.,
they are not compatible. Note: The type of data variable on
R.H.S IS converted into type of
pointer variable on L.H.S

Note: But, we should be very careful when the type of pointer is converted into
another type. It is extremely dangerous and must be used very carefully. Otherwise, it
results in runtime error which is very difficult to debug and trace.

Note: Now, let us recall what we have studied:


• A pointer variable of type integer should contain address of integer
variable
• A pointer variable of type character should contain address of character
variable.
• A' pointer variable of type float should contain address of floating point
variable and so on.

Now the question is "Is there a way of defining a pointer variable to point to any data
type?" Yes, the answer is void pointer. Now, let us see "What is a void pointer?"

Definition: A void pointer is a special type of pointer. It can point to any data type.
Also, any pointer can be assigned to a void pointer. Hence, void pointer is also called
2.38 Q Pointers

- universal pointer or generic pointer. For example, a void pointer can be created as
shown below:

void *p;

Now, the pointer variable p can contain address of data variable of any type such as
int, float, char, double etc. The only limitation is that the pointed data can not be
referenced directly using indirection operator. This is because, its length is always
undetermined. So, Note: type casting must be used explicitly to convert the void
pointer to a pointer of specific data type.

Example 2.4.5.4: What is the output of the following program


,.
1. #include <stdio.h>
2. ,,
3.void mairu)
4.{ , x
·5. int x= 10; p y
6.
7.
double
void
y=3.14156;
*p; lG
, ~
I 3.141561
8. garbage value
9. I
10.
J.
'x p
y
II.
12.
13.
p=&x; :I 10 I+----IE E I
I 3.141561

14. ,'Output
15.
16.
printf("x = %d\n", *((int *)p));
, x = 10

17. , x p y
18. p=&y;
19.
20.
~G ( -, _ >( 3.141561

2l. 'Output
22. pr!n!f("y = %f\n", *((doub-le *)p))~ y = 3.14156
23.}

Note: Using void pointer (generic pointer) p, we can print integer value.Iline f~) by
typecasting to int*. The double value is printed (line 22) by typecasting to double"
Q Systematic Approach to Data Structures using C 2.39

Working The working of the program is explained below:


• The execution of the program starts from function maint)
• Memory is allocated for the variables x, y and p where x is initialized to 10, Y
is initialized to 3.14256 and p with garbage value.
• After executing p = &x in line 12, the void pointer p points to x
• Using p and type casting, integer value of x is displayed.
• After executing p = &y in line 18, the void pointer p points to y.
• Using p and type casting, double value ofy is displayed (line 22).

Note: The void pointer can point to any type of data. It can point to integer, character
etc. But, accessing using void pointer requires explicit type casting as shown in line
15 and line 22.

2.4.6 L-value and R-value


In this section, let us see "What is L-value and R-value?"

Definition: An object that that occurs on the left hand side of assignment operator is
called lvalue. In other words, lvalue (pronounced as L value) is defined as an
expression or a storage location to which a value can be assigned.
For example, variables or an array element such as a[O], a[i], a[i][j] can appear
on LHS of '=' sign and their values can be changed. So, they are called lvalues.

Note: lvalues can be loaded (or modified). Since they appear on LHS of assignment
operator, they are called lvalues.

Definition: Rvalue refers to the expression on right hand side of the assignment
statement. In other words anything that occur on the right hand side of assignment
statement is called rvalue, The R in Rvalue indicates read the value of the expression
or read the value of the variable.
For example: 5, a+2, a[2]+4, a++, --y etc., are rvalues since they can occur on
right hand side of the production.

Note: rvalues can only be read and can not be modified. They appear on RHS of
assignment operator.

Note: In short, anything that we can place on the left hand side of the assignment
statement is an lvalue and anything that we can place on the right hand side of the
assignment or whose value can only be read is an rvalue.
2.40 Q Pointers

Example 2.4.6.1: Identifying lvalue and rvalue in the statement sum = a + b;


Solution: sum = a + b:
Y '--y--J'
LHS RHS
lvalue rvalue
Can be loaded/modified Read only and can not be modified

Example 2.4.6.2: Identify the lvaues and rvalues in the following statements
a. sum = 10;
b. x =b + 2;
c. a[i] = 100 + a[i];
d. *p = 50;
Solution: The lvalues and rvalues for each of the above statements is shown below:
Statements lvalues rvalues

sum = 10; sum 10


x = b + 2; x b+2
a[i] = 100 + a[i]; a[i] 100+a[i]

*p = 50; *p 50

lvalues can be modified and hence normally they occur on LHS of assignment
operator. So, in the above statements sum, x, a[i} and *p are lvalues since they occur
on left hand side of '=' operator.

rvalues can not be modified and they can be only be read and normally they occur on
RHS of assignement operator. So, in the given statements 10, b+2, 100+a[i} and 50
are rvalues since they occur on the right hand side of '='·operator.

Example 2.4.6.3: Consider the following initialization


canst int x = 10; 1* x is a non-modifiable lvalue *1
x = 5; 1* x can not be modified since it is non-modifiable lvalue *1

Note: A variable can either be lvalue or rvalue depending on whether it is towards left
of assignment or to the right of assignment. For example,
a =b;
Q Systematic Approach to Data Structures using C 2.41

Here, the variable a is an lvalue and the variable b is an rvalue. In the following
statement:
b = a;

the variable b is an lvalue and variable a is an rvalue

Note: Even if an expression is lvalue, if it is part of the larger expression from which
rvalue is obtained, then the whole expression is an rvalue. For example,
• a[2] is an lvalue but, a[2]+4 is an rvlaue
• b is an lvalue but, the expression b++ is an rvalue

Now, the question is "Is a function can be made an lvalue?" The I answer is yes. It is
possible to make an assignment to a function call also i.e., a function call can appear
on the left hand side of assignment operator ('='). But, this is possible only if the
function returns an address. For example, consider the following program:

Example 2.4.6.4: Program showing function name as an lvalue


PROGRAM TRACING
1. #include <stdio.h>
2.
a b
3. /* Function returns the address of largest item */
4. int* max(int *a, int *b)
5.{
6. return (*a > *b)? a : b;
7.}
8.
n
9.void main/) ~E----Execution starts from here m
10.{
1l.
12.
int m =44, n = 22; 0
13. /* Obtain address of larger number and print */ Output
14. printf("Max(%d, %d) = %d\n",m, n, *max(&m,&n)); 44
15.
16.
17.
18.
/* largest number is changed 55 */
*max(&m,&n) = 55; G m n

19. /* Obtain address oflarger number and print */ Output


20. printf("Max(%d, %d) = %d\n",m, n, *max(&m,&n)); 55
2l.}
I I
2.42 Q Pointers

Working The way the above program is executed is shown below:


• Execution starts from the function main
• Memory is allocated for variables m and n with values 44 and 22
• In line 14, the function maxO is called with &m and &n. Instead of returning
largest number, the function maxf) returns address of largest number i.e., &m
(because m is larger) and its contents are printed. So, the output will be 44.
• In line 17, the address of largest number (i.e., &m) is returned and its value is
changed to 55 using the name of the function on LHS.
• After executing line 17, the value of m will be 55.
• Again in line 20, the function maxt) is called with &m and &n. Again, the address
of largest number is returned and its contents are printed which is 55.

Note: The maxt) function returns address of a larger of the two variables passed to it.
Since the return value is an address, *max(&m, &n) acts as a pointer to location m.
So, assigning 55 to the expression *max(&m, &n) is equivalent to assigning it to m
itself. '

Note: If the value returned by function is an address of a variable (should not be local
to the function), then it clearly indicates that the returned value is actually an address
whose value can be modified. Hence, a function if it returns an address its value can
be changed and hence it is an lvalue.

1 2.4.7. Answers to selected ptoblems

Example 2.4.7.1: Declare and define the following:


a. A pointer variable pi pointing to an integer
b. A pointer variable ppi pointing to a pointer to an integer
c. A pointer variable pf pointing to a float
d. A pointer variable ppc pointing to a pointer to a char

Solution:
a. A pointer variable pi pointing to an integer along with its definition IS
shown below:
int i:, 1* i is an integer variable *1
int *pi 1* pi is a pointer variable *1

pi = &i; 1* pi contains an address of integer variable *1


,Q Systematic Approach to Data Structures using C 2.43

b. A pointer variable ppi pointing to a pointer to an integer


Ans: int 1; /* i is an integer variable */

int *pi; /* pi is a pointer variable. */

int **ppi; /* ppi is a pointer to a pointer variable.


It should contain address of
a pointer variable */

pi = &i; /* contains address of integer variable */


ppi = &pi; /* contains address of a pointer variable of type
integer */

c. A pointer variable pf pointing to a float


Ans: float f; /* f is a floating point variable */ .
float *pf; /* pf is a pointer variable pointing to float */

pf= &f; /*.contains address of a floating point pointer


variable */
d. A pointer variable ppc pointing to a pointer to a char
Ans: char c; /* c is a character variable */
char *pc; /* pc is a pointer variable. */
char **ppc; /* ppc is a pointer to a pointer variable.
It should contain address of a pointer
variable */
pc = &c; /* contains address of a character variable */
ppc = &pc; /* contains address of an character pointer
variable */

Example 2.4.7.2: Given the following declarations:


int x;
double d;
int *p;
_ double *q;
Which of the following expressions are not allowed?
2.44 ~ Pointers
- a. p = &x;
b. p=&d;
c. q = &x;
d. q = &d;
e. p = x;
Solution:
a. p=&x; /* valid */
The variable p is a pointer to an integer variable and hence it
should contain address of integer variable
b. p=&d; /* Invalid */
Since p is a pointer to integer, it should contain address of
integer variable. But, it contains address of a variable of type
double. So, it is invalid.

c. q=&x; /* Invalid */
The variable q should contain address of a variable of type
double. But, it contains address of integer variable. So, it is
invalid.

d. q = &d; /* Valid */
l
The variable q is pointer to a double. So, it should contain
address of double variable.
e. p=x; /* invalid */
-
Since p is a pointer to integer, it should contain address of
integer variable. Instead of storing the address, we are storing
the value of x. So, it is invalid.

Example 2.4.7.3: Given the following declaration:


int ***p;

What is the type of each of the following expressions?


a.p
b. *p
c. **p
d. ***p

Solution: The type of each of the following expression is shown below:


~ Systematic Approach to Data Structures using C 2.45

a. p - refers to pointer to a pointer to a pointer to integer


b. *p - refers to pointer to a pointer to an integer
c. **p - refers to a pointer to an integer
d. ***p - refers to an integer

Example 2.4.7.4: If x is a variable, identify the lvalues and rvalues In the


following expressions. Explain.
a. x
b. *x
c. &x
d. *x + 2 """)

Solution:
a. x /* lvalue and rvalue. */
Since x a variable, its value can be read and modified. So, when x value
is read, it is rvalue and when x value is being modified it is lvalue.
b. *x /* Ivalue and rvalue .:*/
The expression *x can be used if x is a pointer variable. The expression
*x means the value pointed to by x. The value pointed to by x can be
read as well as modified. So, when the value is being modified it is
lvalue and when the value is being read it is rvalue.
c. &x /* rvalue. *1
Since &x represent address of x and this value can not be modified. So,
it is rvalue.
d. *x + 2/* rvalue. */
Here, *x+2 is an expression. An expression can not be modified and
hence it is rvalue. -

Example 2.4.7.5: What are the operators that require an lvalue as an operand.
Solution: The operators that require an lvalue as an operand are shown below:

----+ Address operator Ex:&a


----+ Postfix operator Ex: x++, a--
--+ .Prefix operator E-x: ++x, --a
----+ Assignment operator
(left operand) Ex: a= 1, sum+=4
2.46 ~ Pointers

-Example 2.4.7.6: The following are invalid rvalue expressions? Give reasons.
a. a + 2 = 6
b. &(a + 2)
c. &4
d. (a+2)++;
e. ++(a+2);

Solution:
a. a + 2 = 6. /* Invalid rvalue */
An expression is always rvalue. Its value can be read but can not
be modified. So, it is invalid.

b. &(a + 2); /* Invalid rvalue */


Here a + 2 is an expression and hence it represent an rvalue. The
&'operator should have lvalue as the operand. So, it is invalid.

c. &4; /* Invalid rvale */


In this expression, 4 is an rvalue. The & operator should have
lvalue as the operand. So, it is invalid.

d. (a+2)++ . . /* Invalid rvalue */


In this expression, a + 2 is an rvalue. The increment/decrement
l
operator should have lvalue as the operand. So, it is invalid.

e. ++(a+2). /* Invalid rvalue */


In this expression, a + 2 is an rvale. The increment/decrement
operator should have lvalue as the operand. So, it is invalid.

Example 2.4.7.7: If x and yare variable names and a is an array, identify the syntax
errors in the following statements with respect to lvalues and rvalues.
a. *x = *x + 2;
b. &x = &a[O];
c. y = &(x + 2);
d. a[5] = 5;

Solution:
a. *x = *x + 2; /* Valid */
,!;1,Systematic Approach to Data Structures using C 2.47

b. &x = &a[O]; /* Syntax error */


Left hand side of assignment statement must be lvalue
i.e., its value should be modified. But, we can not modify
address of a variable because &x is rvalue. So, it is
invlaid.

c. y = 8?(x + 2); /* Syntax error */


x+2 is an rvalue. The & operator requires lvalue as the
operand.

d. a[5] = 5; /* Valid */

Example 2.4.7.8: Write a function prototype statement with function name calc that
returns void and contains a reference parameter to an integer p and a reference
parameter to a long double q.

Solution: The following facts are given:


function name => calc
return_type => void
formal parameters:
p is a reference parameter to an integer => int *p
q is a reference parameter to long double => long double *q

The syntax of function prototype is shown below:


return_type function name (formal parameters);

~ ~ ~
void calc int *p, long double *q

So, the function prototype is shown below:

void calc (int *p, long double *q);

Example 2.4.7.9: Write a function prototype statement with function name spin
that returns a pointer to an integer and contains a reference parameter to an intger
p and a pointer parameter to the address of a long double q.
2.48 Q Pointers

Solution: The fo.llowing facts are given:


function_name => spin
return_type => int * (pointer to an integer)
formal parameters:
p is a reference parameter to an integer => int *p
q is a reference parameter to long double => long double *q

The syntax of function prototype is shown below:


return_type function name (formal parameters);

~ ~ ~
int * spin int *p, long double *q
So, the function prototype is shown below:
int * spin (int *p, long double *q);

Example 2.4.7.10: In the following program, show the configuration of all the
variables and the output
#include <stdio.h>
void main(void)
{
.). /* Local definitions */
int a',
int *x;
int **y;
/*Statements */
a = 100;
x=&a;
y=&x;
printf("%d\n", a);
printf("%d\n", *x);
printf("%d\n", **y);
printf("%p", x);
printf("%p", y);
}

Solution: The configuration of all variables along with output is shown below:
Q Systematic Approach to Data Structures using C 2.49
#include <stdio.h>

int maint) Memory organization during execution


{
1* Local variables *1
int
int
int
a·,
*x;
**y;
{;J xQ aD
Garbage value Garbage value
y x a
1* statements *1
a = 100;
Q Q 8
Garbage value Garbage value

x=&a; -,
y X a
4J I =j )1 100
I
Garbage val ue

y X a
y=&x;
< r
1
1
.1
'I
1
1 :: 100 I
]002 1004 ]006
Output
printf("%d\n", a); 100
printf(" %d\n", *x); 100
printf'%d\n", **y); 100
printf(" %p\n", x); 1006
printf'%p\n",y); 1004
return 0;
}

Example 2.4.7.11: Write a program that creates the structure shown in following
figure and then reads an integer into variable a and prints it using each pointer in
turn i.e., the program must read an integer into variable a and print it using t, u, v,
w, x, y and z.
2.50 ~ Pointers

Solution: The complete program to read the value for a and print it using all
pointer variables. The complete program is shown below:
#include <stdio.h>
void maint)
{
int a·, /* An integer variable */
int *t; /* pointer to integer */
int **u, **v; /* Pointer to pointers */
int ***w, ***x, ***y, ***z; /* Pointer to pointer to pointers */
t=&a;
u= v= &t;
w = x = &l+;
y= z= &v;
,
printf("Enter the value for a\n");
scanf("%d" ,&a);
printf("*t = %d\n", *t);
printf("**u = %d\n", **u);
printf("**v = %d\n", **v);
printf("***w = %d\n", ***w);
printf("***x = %d\n", ***x);
printf("***y = %d\n", ***y);
printf("***z = %d\n", ***z);
}
Q Systematic Approach to Data Structures using C 2.51

2.5 Pointer applications


There are too many uses of pointers, But, the basic uses of pointers are shown
below:
Basic uses of pointers

L With arrays
~ in dynamic memory

There is one to one correspondence between arrays and pointers. So, there exists a
close relationship between arrays and pointers. Now, let us see the relationship
between arrays and pointers.

2.5.1 Arrays and pointers


Consider the following declaration:
int a[ 5] = {10, 20, 30, 40, 50};
r:
This declaration informs the compiler to allocate five memory locations and
initialize all memory locations with initial values as shown below:

a = 0100
Note: Assuming size of integer
&a[O] -+ O~ ie
I a[O] is 2 bytes, two bytes are reserved
&a[l] ~ 0102 (
W a[l] . for each memory location
I

&a[2] ~ 0104 3iO a[2]


I Note: The starting address of the
&a[3] ~ 0106 4b a[3] first byte of the array is called
I

&a[4] ~ 0108 s:o


I
a[4]
base address

Once the memory is allocated, the variable a contains 0100 which is the starting
address of the Oth item. This is called base address. But, the value 0100 stored in a
can not be changed. So, even though a contains an address, since its value can not
be changed, we call a as pointer constant.
Note: The array a is pointer constant only to the first element and not for the
whole array.

Note: &a[O] and a have the same pointer value 0100 and hence they are same.

a <E(~---+) &a[O] <E(~---+). (a + 9)


same same
2.52 Q Pointers

To justify above points, now let us see "What is the output of the following
program?"
PROGRAM TRACING
I a = 0100
#inc1ude <stdio.h> I
I &a[O] -+ O~ ~O
I
void maint)
l&a[l] ~ 0102 jo
{ I

int a[5] = {10, 20, 30, 40, 50}; I &a[2] ~ 0104 30


I I

40
&a[3] ~ 0106 I

I &a[4] ~ 0108 SO
I

I Output
printf("%p %p\n", &a[O], a, a+O); I 0100 0100 0100
} I
Note: We may get different answer in our computer. But, whatever it is, observe that
the value of &a[O] or a or a+O are same.

Now, let us, see "How to access the address of each element?" The address of each
item can be accessed using two different ways:
..~

address operator base address


with index with index

&a[O] i.e, 1000 (a+O) i.e., 0100


&a[l] i.e., 1002 (a+l) i.e., 0102
&a[2] i.e., 1004 (a+2) i.e., 0104
&a[3] i.e., 1006 (a+3) i.e., 0106
&a[4] i.e., 1008 (a+4) i.e., 0108

In general~ ~
&a[i] ( ) (a+i) wherei=Oto4
is same as o to 5-1
o to n - 1 (in general)
~ Systematic Approach to Data Structures using C 2.53

Note: The various ways of accessing the address of ith item in an array a is shown
below:
Normally used

&i[a] is same as i + a

So, &ali] or a+i or i+a or &i[a] are one and the same.

Once we know the address, we can obtain the data stored in that address using the
indirection operator The indirection operator * and & are inverse of each other and
hence they cancel each other. Fore example,
*(&a[O])' is same as a[O]
*(&a[4]) is same as a[4] and so on.
In general, t~a[i]) is same as a[i]
cancel each other to get a[i]
Note: The various ways of accessing the data of ithitem in an array a is shown below:

*&a[i] or a[i] is same as *(a + i) Normally used


!same same
*&i[a] or i[a] is same as *(i + a)

So, *(a+i) or *(i+a) or a[i] or i[a] are one and the same.

To justify this answer, consider the following program:

#include <stdio.h> a = 0100


I &a[O] ~ 0 100"'::tl io a[O]
void maint) I I

jo
&a[l] ~ 0 102 a[l]
{ I I

int a[5] = {10, 20, 30, 40, 50}; I &a[2] ~ 0 104 30 a[2]
int i = 3; I &a[3] ~ 0 106
I

40 a[3]
I
I &a(4) ~ 0 108 So a[4)
I
r
printfC"%d %d %d %d %d %d \n", *(&a[i)), a[iJ, *(a+i), *(i+a), i[a], *&i[a]);
}
Output
+
40
+
40
+
40
+ 40+
40
+
40
2.54 g Pointers

2.5.2 Pointer arithmetic and arrays


Pointer concept can be used in arrays for the following purposes:
• To access an item in l-dirnensional array
• Pointer arithmetic
• To access an item in 2-dimensional array

2.5.2.1 Pointers and 1-dimesional arrays


ow, to understand the relationship between I-dimensional array and a pointer, let
us see "How to compute the address of each element in an array?" Let us take
various cases based on the data type: '

Example 2.5.2.1.1: Consider an array of characters with fo llowing statement:


char a[5] = {'A' , 'B' , 'C' ,'D' ,'E'}' ,

Assuming base address of a = 0100, the memory map along with calculation of
address of a[i] is shown below:
a~ 0100
-
a+O or&a[O] ~ A 0100=0100+0=0100+0*1
-
a + 1 or &a[1.] ~ B 0101 = 0100 + 1 = 0100 + 1*1
-
a+2 or&a[2] ~ C 0102=0100+2=OJOO+2*1
-
a + 3 or &a[3] ~ D 0103 = 0100 + 3 = 0100 + 3*1
-
a+4or&ar41~ E 0104 = 0100 + 4 = 0100 + 4*1
-

,Index
Base address<
ofitem~
~I II
! SiZeOf(!ar)

I In general, address of (a[iD = Base address + Index of item * sizeof (char) I

Example 2.5.2.1.2: Consider an array of integers with following stat ment:


int a[5] = {I 0,20, 30, 40, 50};

Assuming base address of a = 0100, the memory map along with calculation of
address of a[i] is shownbelow:
Q Systematic Approach to Data Structures using C 2.55
a = 0100
~
a + 0 or &a[O] ~ 0100 = 0100 + 0 = 0100 + 0*2
a + 1 or &a[l] ~ 0102 = 0100 + 2 = 0100 + 1*2
a + 2 or &a[2] ~ 0104 = 0100 + 4 = 0100 + 2*2
a + 3 or &a[3] ~ 0106 = 0100 + 6 = 0100 + 3*2
a+4 or&ar41 ~ 0108 = 0100 + 8 = 0100 + 4*2

r----
Base addres: ~
Index of item ~
J II
sizeof (int)
!
I In general, &a[i] = Base address + Index of item >;< sizeof (int) I
Example 2.5.2.1.3: Consider an array of floating point numbers with following
statement:
float a[S] = {lO.S, 20.S, 30.S, 40.S, SO.S};

Assuming base address of a = 0100, the memory map along with calculation 0
address of a[i] is shown below:
a = 0100
~
a + 0 or &a[O] ~ ;10.51 0100 = 0100 + 0 = 0100 + 0*4
I I I

a + 1 or&a[l] ~ ;20.51 0104=0100+4 =0100+1*4


I I I

a + 2 or &a[2J ~ 1 30.5: 0108 = 0100 + 8 = 0100 + 2*4


I I

a + 3 or &a[3] ~ ;40.5: 0112 = 0100 + 12 = 0100 + 3*4

r
I I

a + 4 or &ar41 ~ ,SQ. 5; 0116 = 0100 + 16 = 0100 + 4*4


, •

....---
Base address
Index of item~
II
sizeof (float)
!
I In general, &a[i] = Base address + Index of item * sizeof (float) -1

Note: In general, &a[iJ = Base address + Index of item * size of (data type)
2.56 Q Pointers

Example 2.5.2.1.4: Consider the following declaration:


int a[5] = {10, 20, 30,40, 50};
int *p;

p = &a[O]; 1* Same asp = a *1

Assuming base address of a = 0200, the memory map along with calculation 0
address of a[i] is shown below:
p = a = 0200

P + 0 or &p[O]~. O~ To a[O]
f---:t-::-
p + 1 or &p[l]~ 0202 ~O a[l]
p + 2 or &p[2]~ 0204 r--ro- a[2]
p + 3 or &p[3]~ 0206 no
~
I

a[3]
p + 4 or &p[4]~ 0208 ~O a[4]

Using pointer variable p each item in the array can be accessed as shown below:
• Othitem can be accessed using *(p+O) or p[O] or O[p]
• l" item can be accessed using *(p+1) or p[l] or l[p]
• 2nd item can be accessed using *(p+2) or p[2] or 2[p]
• 3rd item can be accessed using *(P+3) or p[3] or 3[p]
• 4thitem can be accessed using *(P+4) or p[4] or 4[p]

Note: With respect to above memory configuration, let p = &a[2] (which is same as
p = a + 2) This indicates that pointer variable p points to a[2]. When a pointer is not
pointing to the Othitem in an array, the index can be negative.
For example, p[-2] or p[-I] etc., are valid.

2.5.2.2 Largest of N numbers

Consider 5 elements 10, 20, 50, 2,5 and 15. It is required to find the largest of these 5
numbers. Now, let us see "How to write the program to find largest ofN numbers?"

Design: Assume the variable big contains 10 which is the Othelement of the array and
°
pos is which is the position of that element. The equivalent code can be written as:

°
big = a[O]; 1* Assume first item is big *1
pos = 0; . 1* Store as the position of Oth item *1
}....
Inltlalizatlon
Q Systematic Approach to Data Structures using C 2.57

Since Othitem 10 is in big, the rest of the items such as a[l}, a[2], a[3] and a[4}
should be compared with big as shown in figure:

J J J ~
I
if ( a[i] > big)
a[O] a[l] a[2] a[3] a[4]
_20--LOD--:-50~ 25
I:.....~~I;,;..:.:..' I 15
{
big
pos
=
= t;
a[i]; a~ ~l~
}
big = 10

If the above condition is true, then a[i] is larger and it is stored in big along with its
position i. It is clear from the above figure that i varies from 1 to 4 which can be
written as shown below:
i = 1 to 4.

t same
i = 1 to 5-1 where 5 indicates the number of elements
~
In general, i = 1 to n-I where n = 5 indicates the number of elements. So, the code can
be written as shown below:

for (i = 1; i <= n-l ; i++)


{
if ( a[i] > big)
{
big = a[i]; Main logic
pos = 1;
}
}

Note: When we know the program using arrays, we can easily write the program
using pointers. \Ve have seen that a[i} is same,as *(a+i) or *(i+a) or i[a]. So replace
a[i] by *(a+i) to get the program using pointers.

Now, the complete program to find the largest of N elements using an array and
using pointer with indexing is shown below: _ -
2.58 Q Pointers

Example 2.5.2.2.1: Program to compute largest and its position

Usinz Arrays Usina Pointer with indexinz


#includc <stdio.h> #include <stdio.h>

void mainf) void maini)


{ {
int a[10], n, i, big, pos; int a[10], n, i, big, pas;

printf("Enter number of elements\n"); printf("Enter number of elernentsin'');


scanf("%d" ,&n); scanf("%d" ,&n);

printf("Enter the elements\n"); printf("Enter the elements\n");


for (i = 0; i <= 11-1;i++) for (i = 0; i <= n-L; i++)
scanf("%d" ,&a[i]); scanf("%d",a+i); 1* (a+i) = &a[i) */
big = a[O); big = :i«a+O);
pos = 0; pos = 0;

for (i = 1; i <= n-l ; i++) for ( i = 1; i <= n-l ; i++)


{ {
if ( a[i) > big) if ( *(a+i) > big)
{ {
big = a[i]; big = *(a+i);
pas = 1; pas = 1;
} }
} }

printf("Largest = %d\n" ,big); printf("Largest = %d\n",big);


printf("Position = %d\n", pos+ 1); printf("Position = %d\n", pos+l);
} }

2.5.2.3 Pointers and other operators


Like normal variables in an expression, pointer variables in expressions can also be
used. If p l and p2 are pointer variables that are declared and initialized properly, *pl
and *p2 represent the values to be manipulated. So, operations such as relational,
arithmetic, logical etc., can be performed on 'kpl and *p2.
9 Systematic Approach to Data Structures using C 2.59

Example 2.5.2.3.1: Valid statements with operations such as multiplication and


addition
• x = *pl * *p2; II The values pointed by p l and p2 are multiplied

• sum = sum + *pl; II The value pointed to by p l is added to sum

• *p I = *p 1 + 1; II value pointed to by p l is incremented by 1

Example 2.5.2.3.2: Suppose, we want to divide the value pointed by p l by the value
pointed to by p2, then we may write the following statement:
x = *pl l*p2; II Error: This expression is wrong because 1* before p2
I; is treated as beginning of the comment in C

The error in the above statement can be eliminated by re-writing the statement as
shown below:
x = *pl I *p2 II Correct: Since there exists space between I and *, it is
II treated as division operation not as beginning of the
II comment

Note: Even though various operations can be performed on *pl and *p2 (since they
represent the values to be manipulated), the operations are restricted on p l and p2
since they contain only the addresses. The various operations that can be performed
on pointer variables are shown below:
Adding an integer to a pointer
Operations Subtracting an integer from pointer
performed
on pointers Subtracting two pointers
Comparing two pointers
2.5.2.4 Adding an integer to a pointer

Note: Addition can be performed when one operand is a pointer and other operand
is an integer.

Example 2.5.2.4.1: Consider the following declaration:


int a[5] = {10, 20, 30, 40, 50};
int *p 1, *p2;
p l = a;
2.60 ~ Pointers

p2 = a;
The various valid and invalid statements are shown, below:
• p l = p l + 1; 1* Valid *1
• p l = pl + 3; 1* Valid *1

• p l + p2; 1* Invalid: Two pointers can not be added *1

• pl++; 1* Valid: Same as pI = pI + I *1

Example 2.5.2.4.2: Pointer arithmetic using increment operator

int a[5]={IO, 20, 30, 40, 50}; float a[5]={10, 20, 30, 40, 50};
int *p; float *p;

p = a; 1* p points to a *1 p=a; 1* ppointstoa */

Assuming base address of a is Assuming base address of a is


0100, the variable p points to 0100, the variable p points to
first item as shown below: first item as shown below:

a~ a~
p~ 0100 1--------;-~_0_____1 p~ 0100 iO$55
1
20
0102 1---+-----1 0104 20 :
~O
0104 1----;-,:-----1 0108 : ~O: I

40
0106 1----+---1 0112 : 40 :
0108 '---_5_0----' 0116 Li 50 i~
After executing the statement:
After executing the statement:
p++;
p++;
the pointer variable p will not
the pointer variable p will not
contain 0101. Instead, it contains
contain 0101. Instead, it contains
0104 because, if p is incremented
0102 because, if p is incremented
it will point to the next floating
it will point to the next integer.
point number.
Note: Each time p++ is executed, Note: Each time p++ is executed,
its value will be incremented by 2 its value will be incremented by 4
because size of integer is 2 bytes. because size of floating point
In other words, p points to the number is 4 bytes. In other words,
next item. p points to the next item.
Q Systematic Approach to Data Structures using C 2.61

Note: In general, if p is a pointer variable pointing to an array, after executing the


statement:
p++;

the pointer variable is incremented by:


• 1 for character array
• 2 for integer array
• 4 for floating point array and 8 for double and so on. In other words, the
pointer points to the next item of an array.

2.5.2.5 Display array elements using pointers

Now, let us see "How to write a program to display array elements using pointer?"

Design: 'Consider the following array and assume p points to the beginning of the
array. To start with p points to 0100 and *p refers to 10. Let us observe the outputs in
various iterations shown below:

.. 0100 0102 0104 0106 0108 0110


b egmnmg I io
of array t I i{)

tp
I 30
tp
up 50
tp
I
t
p p P
Iterations: i = 0 1 2 4
print 10 and increment p using ~(__ ...JI
printf("%d\n", *p); II 10
p++; II 0102
print 20 and increment p using +- --J

printf("%d\n", *p); II 20
p++; II 0104
print 30 and increment p using +------------'
printf("%d\n", *p); II 30
p++; II 0106
print 40 and increment p using+--------------I
printf("%d\n", *p); II 40
p++; II 01Q8
print 50 and increment p using~(---------------'
printf("%d\n", *p); q II 50
p++; II 0110
2.62 ~ Pointers

In general, if statements:

r-::tf("%dln'
U~; " *p);

°
are repeatedly executed for i = to 4, we get the output 10, 20, 30, 40 and 50. The
C equivalent statement using for loop is shown below:

for (i = 0; i <= 4; i++) /* i <= 4 is same as i < 5 */


{
printf("%d\n", *p);
p++;
}

The complete program is shown below:

Example 2.5.2.5.1: Pprogram to display array elements using pointer

#include <stdio.h>

void maint)
{
int a[] = {l0, 20, 30, 40, 50 };
int *p;
int 1;

p = a; /* same as p = &a[O] */

for (i = 0; i <= 4;'i++)


{
printf("%d ",*p);
p++;
}
printf("\n");
}
Q Systematic Approach to Data Structures using C 2.63

2.5.2.6 Sum of N numbers using pointers

In the previous example, instead of printfi) within the for loop, if we use the
statement
sum = sum + *p;

then we add all the elements of the array. The complete program to add n elements is
shown below:

Example 2.5.2.6.1: Program to compute sum of elements of array

#include <stdio.h>

void maim)
{
int a[] = {10, 20, 30, 40,50 };
int *p;
int 1, sum;

p = a; /* point p to the first element */


sum = 0; °
/* Initialize sum is */

for ( i = 0; i <= 4; i++)


{
sum = sum + *p; /* Same as */
p++; } sum = sum + *p++; or sum = sum + *(P++);
}

printf("Sum of all the numbers = %d\n",sum);


}

Note: Observe that by executing p++, we can point p to the next element. On similar
lines by executing p--, we can point p to the previous element in an array.

2.5.2.7 Subtracting an integer from' a pointer

Note: Subtraction can be performed when first operand is a pointer and the second
operand is an integer.
2.64 Q Pointers

.
Example 2.5.2.7.1: Consider the following declaration and initialization:
int a[5] = {l0, 20, 30, 40, 50};
int *pI;

p l = &a[4];

The various valid and invalid statements are shown below:


• pI =pI-I; /*Valid */

• pI = p l - 3; /*Valid */
• pI--; /*Valid:: Same as pI = p l - ~ */
• --pI; /*Valid:: Same as p I = p l - I */
• pl = I - pl; /*Invalid:: Illegal pointer subtraction
Note: The first operand should be a pointer where as
second operand should be integer. */

Example 2.5.2.7.2: Write a program to display array elements using pointer fro
last element to first element.

Note: ~s we execute p++, pointer variable p points to next element, if we execute p--
pointer variable p points to the previous element.

Design: To get the array elements in reverse order, point the variable p to point to th
end of the array and replace p++ by p- - in the previous program. The complet
program is shown below:

#include <stdio.h>

void mainf)
{
int a[] = {10, 20, 30, 40,50 };
int *p;
int 1;

p = &a[4]; /* point p to the last element*/


~ Systematic Approach to Data Structures using C 2.65

for ( i = 0; i <= 4; i++) a~ Output


{ ••.;y 0100 ~O
P ~ ~:. ~ 0102 I--~~-O-t----l
printf("%d ", *p);
p--; ":~
'..1
0104 ~o
0106 1---~4-0t----i
}
printf("\n"); 0108 L--_S_0-l-'
}
P points to previous element after executing p--
and items are accessed from bottom to top.

2.5.2.8 Subtracting two pointers


If two pointers are associated with the same array, then subtraction of two pointers is
allowed. But, if the two pointers are associated with different arrays, even though
subtraction of two pointers is allowed, the result is meaningless.

Example 2.5.2.8.1: Consider the following declaration and initialization:


int a[5] = {l0, 20, 30,40, 50};
int *p1;
int *p2;
float *f;

p l = a; 1* same as p l = &a[O] *1
p2 = &a[4];

The various valid and invalid statements are shown below:


• p2 - p l ; 1* Valid *1
• p1-p2; I*Valid *1
• f - pl ; 1* Invalid: Since type of both operands is not same *1

The memory map for the above declaration is shown below:


pl 4 elements away p2
~ ) ~
0100 0102 0104 0106 0108
I to I 2-0 I 3.0 40 I 50

Note: Observe following facts from above figure: _


• p2 has a pointer value 0108 and p l has a pointer value 0100.
2.66 .!!!l Pointers

• But, p2 - p l is not 0108-0100. Actually, it is (0108-0100)/sizeof(int) i.e.,


(0108-0100)/2 = 4
• So, p2 - p l gives us 4 which indicates that p2 is at a distance of 4 elements
away from p 1.
• So, p2 - p l +1 gives the number of elements in the array

2.5.2.9 Comparing two pointers

If two pointers are associated with the same array, then comparison of two pointers is
allowed using relational operators. But, if the two pointers are associated with
different arrays, even though comparisons of two pointers is allowed, the result is
meaningless.

Example 2.5.2.9.1: Consider the following declaration and initialization:


int a[5] = {10, 20, 30, 40, 50};
int *pl;
int *p2;
float *f;
pl = a; /* or p l = &a[O] */
p2 = &a[4];
The various valid and invalid statements are shown below:
l • p2!= pl ; /* Valid */;
• p l = p2; /* Valid */;
• p l <= p2; /* Valid */;
• p l >= p2; /* Valid */
• f != p l ; /* Invalid: Since type of both operands is not same */
Note: Multiplying and dividing a pointer variable with any other variable or integer is
not allowed.

Example 2.5.2.9.2: Consider the following declaration and initialization:


int a[5] = {10, 20, 30, 40, 50};
int ,*pl;
int *p2;
int b;

p l = a;
p2 = a;
~ Systematic Approach to Data Structures using C 2.67

The following are valid and invalid statements:


p2 = p l / p2; /* Invalid: Division of two pointers not allowed */
p2 = p l /2; /*Invalid: Dividing a pointer is not allowed */
p l = p l * p2; /* Invalid: Multiplication of pointer is not allowed*/
p l = p l * 2; /* Invalid: Multiplying of a pointer is not allowed */

b = *pI * 2; /* Valid: Multiplication of dereference value allowed */


b = *p2 / 2; /* Valid: Division of a dereference value is allowed */

Now, let us see "How to write a program to display array elements by comparing
of two pointers?"
Design: Let us use two pointers p and q where p points to the first element of array a
and q points to the last element of array a as shown below:
p q
~ ~
0100 0102 0104 0106 0108
a I to I i-o 01 3.0 40 I 50

Observe from the above figure that as long as p <= q, value pointed to by p can be
printed and updated using the following statements:

while (p <= q)
{ I Output
printf("%d ", *p); I 10 20 30 40 50
p++; I
} I
So, the complete program is shown below:

Example 2.5.2.9.3: Program to display array elements by comparing pointers

#include <stdio.h>

void maim)
{
int a[] = {10, 20, 30, 40, 50 };
int *p;
int *q;
2.68 Q Pointers

p = &a[O]; 1* point p to the first element *1


q = &a[4]; 1* point q to the last element*1

while (p <= q) 1* Comparing two pointer values *1


{ •
printf("%d ", *p);
p++;
}
printf("\n");
}

Note: Two pointer subtractions and two pointer comparisons are generally performed
ifboth the pointers point to the same array.

2.6 Passing an array to a function

As we pass various parameters to functions, we can also pass name of an array as a


parameter. Note: Name of an array is a pointer to the first element. So, when we pass
an array to a function we should not use the address operator. The syntax of a
function call is:
function_name (a); 1* Here a should have been declared as array */

The two ways of declaring and using the array in the called function are:
• using pointer declaration ---------}
• using array declaration

!
void function _name(int a[]} void function_name(int *a)
{ {
/* ith item can be accessed /* ith item can be accessed
using a[i] using *(a+i)
*/ */
} }

Note: Easier way of writing a program using pointers


• write a program using arrays i.e., may be using a[i] or a[j] etc.
• Then replacing a[i] by *(a+i) and a[j] by *(a+j) we get the program using
pointers.
Q Systematic Approach to Data Structures using C 2.69 .

Now, let us discuss the method of searching an element in an array of n elements


using binary search. First, let us see "What is binary search? What is the concept used
in binary search?"

Definition: A binary search is a simple searching technique which can be applied if


the items to be compared are either in ascending order or descending order.
The general idea used in binary search is similar to the way we search for the
telephone number of a person in the telephone directory. Obviously, we do not use
linear search. Instead, we open the book from the middle and the name is compared
with the element at the middle of the book. If the name is found, the corresponding
. telephone number is retrieved and the searching has to be stopped. Otherwise, we
search either the left part of the book or right part of the book. If the name to be
searched is less than the middle element, search towards left otherwise, search
towards right. The procedure is repeated till key item is found or the key item is not
fuund. -
Once we know the concept of binary search, the next question is "How to
, search for key in a list of elements?" Now, let us see how to search for an item. The
procedure is shown below:

Procedure: The program can be designed as follows. If low is considered as the


position of the first element and high as the position of the last element, the position
of the middle element can be obtained using the statement

mid =( low + high) /2;

The key to be searched is compared with middle element. This can be done using the
statement
if (key = a[mid] )
{
*position = mid; /* Obtain position of item in the array*/
return;
}

After executing the statement, if they are equal, the position of item in the array is
returned. If this condition. is false, key may be in the left part of the array or in the
right part of the array. If key is less than the middle element, the table in the left part
has to be compared from low to mid-I. Otherwise, the right part of the array has to be
compared from mid + 1 to high. This can be achieved by using the following
statement.
2.70 ,!;l Pointers

if ( key < a[mid] )


high = mid -1;
else
low = mid + 1;
Note that, as all the above statements are executed repeatedly, the gap between low
and high will be reduced. Finally, when low exceed high, it indicates that item not
found. Now, the complete C function is shown in following example.

Example 2.6.1: C function to search for ~mitem using binary search

Using arrays Using pointers

void search(int item, int a[], int n, int *pos) void search(int item, int *a int n, int *pos
{ {
int low, high; int low, high;

1* Initialization *1 1* Initialization *1
low = 0; low = 0;
high = n-l ; high = n-I;

while ( low <= high) while ( low <= high)


{ {
1* Find the mid point */ 1* Find the mid point+/
mid = ( low + high) I 2; mid = ( low + high) I 2;

1* If item found, return position *1 1* If item found, return position *1


if (item = a[mid] ) if ( item == *(a+mid))
{ {
*pos = mid; *pos = mid;
return; return;
} }

if ( item < a[mid] ) if ( item < *(a+mid) )


I*search left side *1 I*search left *1
high = mid - 1; high = mid - 1;
else else
I*search right side *1 I*search right side *1
low = mid + 1; low = mid + 1;
} }

*pos = -1; 1* Item not found *1 *pos = -1; 1* Item not found */
} }
Q Systematic Approach to Data Structures using C 2.71

The complete C program to search for an item using binary search is shown in
example:

Example 2.6.2: C program to search for any item in array using binary search

#incIude <stdio.h>
#incIude <process.h>

/* Include function binary search: Example: 2.7.1 */

1* Function main starts */


void maim)
{
int i,n,item,a[20], position;

printf("Enter the value of ntn");


scanf(If%dlf,&n);

printff'Enter n valuesvn");
for ( i = 0; i < n; i++) scimf("%d",&a[i]);

printf("Enter the item to search\n");


scanf("%d" ,&item);
search(item, a, n, &position);

if (position = -1)
printf("Item not found\n");
else
printf("Item found at %d position\n", position);
}

2.7 Pointers and two dimensional arrays/ Pointer to I-dimensional arrays

A 2-dimensional array can be considered as a collection of l-dimensional arrays. So,


we can have a single pointer which can point to these contiguous l-dimensional
arrays. The syntax to define a 2-dimensional array is shown below:
datatype array_name[expl] [exp2]; /* Ex: int a[2][3] */

where
2.72 Q Pointers

• data_type refers to the data type of the elements stored in array


• arrayname is the name of the array
• exp 1represent the maximum number of elements in that row
• exp2 represent the maximum number of elements in that column.

Using pointers it can be declared as shown below:


data_type (*ptr) [exp2]; /* Ex: int (*a)[3] */

where
• data_type refers to the data type of the array
• ptr is the name of the pointer variable which replaces [exp 1] in the earlier
notation
• exp2 represent the maximum number of elements in that column.

For example, consider the declaration with a 2-dimensional array initialized with 3
rows and 4 columns along with a pointer variable p as shown below:

int a[3][ 4] = {
{10, 20, 30, 40},
{50, 60, 70, 80},
{25, 35, 45, 55}
};

int (*p)[ 4]; /* p is a pointer to an array consisting of 4 elements */

p = &a[O][O]; /* p points to first row of the given matrix */

Here, p is defined as a pointer to a group of I-dimensional arrays, each having 4


elements in an array. The memory organization for the above program segment is
shown below:

Row 2

rr
&a[O][O]
lOOO 1033

r
p p+2 P +3

r
Q Systematic Approach to Data Structures using C 2.73

Note: Observe the following points


• p which is same as (p + 0) points to row-O
• (p+ 1) points to row-I
• (p+2) points to row-2 and so on.
In general, observe the following points: .
• p or p+O points to row-O '
• p+i points to row-i
• *(p + i) points to Othitem in ith row
• *(p + i) + j points to jth item in ith row
• *(*(p+i) +j) value stored in ith row and ith column
Note: In general, by using &p[i][j] or *(p+i) +j, we can obtain the address of ith row
and r column and by using p[i][j] or *(*(p+i) +j), we can obtain the item in ithrow
and J" column.
Disadvantage It is better to use the conventional method to access the elements of a
multi-dimensional array rather than using the pointers because of the following
reasons:
• For 2-dimensional onwards, the pointer notation is more complicated and
hence there is no advantage.
• In fact, the readability decreases and hence difficult to read and understand.
So, for multi-dimensional arrays, most programmers use indexing rather than
pointer notation.
Now, let us see "How to read and write a matrix?" Any item can be accessed by
specifying the row index and column index. Normally, we access the items row by
row as shown below:

I t t t + (Columns)
A nm o 1 2 3 n=4
o a[O][O] a[O][I] a[O][2] a[O][3]

1 a[I][O] a[l][l] a[1][2] a[1][3]

2 a[2][O] a[2][1] a[2][2] a[2][3]


(rows) m =3
Note that any element can be accessed by specifying a[i][j]

index variable i = 0, 1,2


index variablej = 0,1,2,3
i.e., 0 to m-I
i.e., 0 to n-I
:
_
1 I
,
2.74 Q Pointers

Note: To access each item row wise in 2-dimensional array, the row index i should be
in the outer loop and column indexj should be in the inner loop. So, the C statements
to access any element a[i][j] can be written as:
for (i = 0; i <= m-l; i++) for (i = 0; i < m; i++) /*m -Rows */
{ {
for U = 0; j <= n-l; j++) for U = 0; j < n; j++) /*n-Columns*/
{ ~ {
a[i][j]; a[i][j]; /*access */
} }
} }

To read 2-dimensional array of size m x n: In the above program segment, to read


the elements of matrix a, include scanfO just before a[i][j]. The complete function to
read a matrix is shown below:

Example 2.7.1: C function to read a matrix

Using arrays I U sing pointer to


I 1-dimensional array
I
void read_matrix(int m, int n, int a[][10]~void read_matrix (int m, int n, int (*a)[lO]
{ {
inti,j; inti,j;

/* To access m - rows */ /* To access m - rows */


for (i = 0; i < m; i++) for (i = 0; i < m; i++)
{ {
/* To-access n - columns */ /* To access n - columns */
for U = 0; j < n; j++) for (j = 0; j < n; j++)
{ {
/* read the item */ /* read the item */
scanf("%d",&a[i][j]); scanf("%d", *(a+i) + j );
} }
} }
} }
Q Systematic Approach to Data Structures using C 2.75

To print a 2-dimensional array of size m x n: Similarly, the C function to display a


2-dimensional matrix is shown below:

Example 2.7.2: C function to display a matrix


I

Using arrays I Using pointer to


I 1-dimensional array •
I
void write_mtrix(int m, int n, int a[][lO]) void write_mtrix (int m, int n, int (*a)[lO] )
{ {
int i, j; int i, j;

1* To access m - rows *1 1* To access m - rows *1


for (i = 0; i < m; i++) for (i = 0; i < m; i++)
{ {
1* To access n - columns *1 1* To access n - columns *7
for (j = 0; j < n; j++) for (j = 0; j < n; j++)
{ {
1* read the item *1 1* read the item *1
printf("%d" ,a[i] [j]); printf("%d", *(*(a+i) + j) ); .
} }
printf ("\n"); printf ("\n");
} }
} }

Procedure: Let a and b are two matrices of size m x n. We know that each item of a
can be accessed using the following code:
for (i = 0, i < m; i++) 1* m - rows *1
{
for (j = 0; j < n; j++) 1* n - columns *1
{
a[i][j]; 1* Access each item of a *1
}
}
2.76 Q Pointers
-
Instead of accessing only the elements of matrix a, we access the corresponding
elements of b, perform the addition and store it in the matrix c. This is achieved by
replacing a[i][j] in the above program segment inside the for loop by the statement:
c[i][j] = a[i][j] + b[i][j];
So, the complete C function to add two matrices a and b of size m x n is shown
below:

Example .7.3: C function to add two matrices a and b.

Using arrays I Using pointer to


I 1-dimensional array
void add_matrix(int m, int n, int a[][10],1void add_matrix(int m, int n, int (*a)[10],
int b[][10], int c[][10J) I int (*b)[10], int (*c)[10])
{ H
int i,j; int i,j;
I
for (i = 0; i < m; i++) : . for (i = 0; i < m; i++)
{ I {
for U = 0; j < n; j++) for U = 0; j < n; j++)
{ I {
c[i][j] = a[i][j] + b[i][j]; I *(*( c+i)+j) = *(*( a+i)+j) + *(*(b+i)+j)
}
} I
} I} } I
} I

The various operations that can be performed to add two matrices are shown below:

Various operations to be·performed C code / reference to C code


Step 1: Input the size of matrices (say m x n) scanf("%d %d",&m, &n);
Step 2: Input matrix a Refer example 2.7.1
Step 3: Input matrix b Refer example 2.7.1
Step 4: Matrix c = Matrix a + Matrix b Refer example 2.7.3
Step 5: Output matrix c Refer example 2.7.2
Step 6: Finished

The complete program to add two matrices along with various inputs and outputs is
shown below:
Q Systematic Approach to Data Structures using C 2.77

Example 2.7.4: C Program to add two matrices using conventional method and using
pointer to I-dimensional array

#include <stdio.h>

1* Include: Example 2.7.1: To read a matrix *1


1* Include: Example 2.7.2: To display a matrix *1
1* Include: Example 2.7.3: To add two matrices *1
void maini)
{
int a[IO][lO]; 1* Holds the elements of matrix a *1
int b[IO][IO]; 1* Holds the elements of matrix b *1
int c[IO][IO]; 1* Holds sum of matrices a and b*1
int m:, 1* Rows of input and resultant matrix *1
int n', 1* Columns of input and resultant matrix *1
printf("Enter the size of matrix\n");
scanf("%d %d",&m, &n);

printf("Enter the elements of matrix a\n");


read_matrix(m, n, a);

printf("Enter the elements of matrix b\n");


read_matrix(m, n, b);

add_matrix(m, n, a, b, c);

printf("The sum of two matrices\n");


write _matrix(m, n, c);
}

2.8 Understanding complex declarations


Note that it is very difficult to interpret and understand the declarations especially
related to pointers. To read and understand the complicated declarations, we can
follow the right-left rule. Now, let us see"What is right-left rule?" .
2.78 Q Pointers

Definition: The right-left rule can be stated as follows:


• Start with the identifier in the center of declaration
• Read the declarations in a spiral manner once going right and then left, again
right and left and so on till all entities are read i.e, right-left reading of each
symbol is done alternatively. This concept can be represented pictorially as
shown below:

end

start

Example 2.8.1: Interpret the declaration: int x. The declaration can be pictoriall
represented as shwon below:

Note: Read and interpret the entity in each box


in the direction of the arrow mark along with
labels.

start i.e., x is an int. In other words, x is an integer

Example 2.8.2: Interpret the declaration: .int *p. The declaration can be pictoriall
represented as shwon below:
to
Reading in the direction of
arrow along with the labels we
have:
p is a * to int
i.e., p is a pointer to an integer
start [By reading * as pointer, int as
integer]
Q Systematic Approach to Data Structures using C 2.79

Example 2.8.3: Interpret the declaration: int a[10]. The declaration can be pictorially
represented as shwon below:

is an array of
Reading in the direction of arrow
along with the labels we have:

a is an array of 10 int
i.e., a is an array of 10 integer
start
[By reading int as integer]

Example 2.8.4: Interpret the declaration: int *p[5]. The declaration can be
pictorially represented as shwon below:
to
Reading in the direction of
arrow along with the labels we
have:
p is an array of 5 * to int
i.e., p is an array of 5 pointers
start to integers where * is pointer,
int is integer

Example 2.8.5: Interpret the declaration: int (*p) [5]. The declaration can be
pictorially represented as shwon below:

Note: Preference is given for the


expression wi thing parantheses.
Reading in the direction of arrow
along with the labels we have:
'p is a * to an array of [5] int i.e.,
start p is a pointer to an array of 5
integers where * is pointer, int is
integer
2.80 Q Pointers

Example 2.8.6: Interpret the declaration int a (int b). The declaration can be
pictorially represented as shwon below:

is a function
end I ~
I int a I I (int b) I
II I...---r---i with b as integer parameter

i
start
returning
Note: If an identifier is followed by ( .... ), it indicates a function call or function
declaration. So, reading in the direction of arrow along with the labels we have:
a is a function with (int b) and returning int
i.e., a is a function which accepts b an integer as a parameter and returning an integer

2.9 Memory allocation functions

Memory can be reserved for the variables either during compilation or during
execution time (run time). This gives rise to various memory allocation techniques.
Now, let us see "What are the various memory allocation techniques?" Memory can
be allocated for variables using two different techniques:

Memory ~llocation--c Static allocation (User declarations and defmitions)


techniques Dynamic allocation (Using predefined functions)

Now, let us see "What is static memory allocation?"

Definition: If the memory is allocated (i.e., reserved) for various variables during
compilation time itself, the allocated memory space can not be expanded to
accommodate more data or can not be reduced to accommodate less data. In this
technique, once the size of the memory allocated is fixed, it can not be altered even
during execution time. This method of allocating the memory during compilation time
is called "static memory allocation". For example, consider the following declaration:

int a[lO];
Q Systematic Approach to Data Structures using C 2.81

During compilation, the compiler will allocate 10 memory locations (each location
consisting of 2 bytes say) for the variable a. In the worst case, 10 elements can be
inserted. Less than 10 elements lead to under utilization of allocated space and more
than 10 elements can not be inserted.

Disadvantages
• The memory is allocated during compilation time. Hence, the memory allocated is
fixed and can not be altered during execution time
• Leads to under utilization if more memory is allocated
• Leads to overflow if less memory is allocated
• The static nature imposes certain limitations and can find their applications only
when the data is fixed and known before processing.

Note: If there is an unpredictable storage requirement, then static allocation technique


is not at all used. This is the point where the concept of dynamic allocation comes
into picture. Now, the question is "What is dynamic memory allocation?"

Definition: Dynamic memory allocation is the process of allocating memory during


execution time (i.e., run time). This is a pretty unique feature of C when compared
with other high level languages. This allocation technique uses predefined functions
to allocate and release memory for data during execution time. So, if there is an
unpredictable storage requirement, then the dynamic allocation technique is used.
Dynamic allocation will be used commonly in the following data structures:
• dynamic arrays (discussed at the end of section 2.9.2.1)
• linked lists, trees (discussed in chapter 9 and 10)

The linked lists and trees are inherently dynamic in nature, growing and shrinking as
needed. So, to implement these data structures, the program should be able to allocate
and free memory as and when required.

Now, let us see "What are the differences between static memory allocation and
dynamic memory allocation?" The various differences between static allocation and
dynamic allocation technique are shown below:

Static allocation technique Dynamic allocation technique

1. Memory is allocated during 1. Memory is allocated during-


compilation time execution time
2.82 Q Pointers

-2. The SIze of the memory to be 2. As and when memory is required,


allocated IS fixed during memory can be allocated. If not
compilation time and can not be required, memory can be de-
altered during execution time allocated. The size of the memory
required may vary duririg execution
time.
3. Used only when the data size is 3. Used only for unpredictable
fixed and known in advance before memory requirement.
processmg

4. Execution is faster, since memory is 4. Execution is slower since memory


already allocated and data has to be allocated during run time.
manipulation IS done on these Data manipulation IS done only
allocated memory locations after allocating the memory.
\

5. Memory is allocated either in stack 5. Memory is allocated only in heap


area (for local variables) or data area
area (for global and static
variables).
6. Ex: arrays 6. Ex: Dynamic arrays, linked lists,
trees
.l

2.9.1 Memory map of C program

Before we discuss various memory allocation functions and the concept of dynamitic
memory allocation, let us see "What is the memory allocation process associated with
C program?" or "What is the memory map of C program?" A compiled C program
creates and uses the following logical distinct regions of memory:

Program memory
global/static
Memory
heap
stack

Let us assume the size of the memory is 1MB = 1024 x 1024 bytes = 1048576 bytes
of memory. All these locations are numbered sequentially from 0 to 1048575
(memory organization in C) is shown below:
Q Systematic Approach to Data Structures using C 2,83

Addresses
00000
Program Code 00001

Various functions of C Reserved for the program


(User defined functions)
(Standard functions)

Reserved for global and static


Global and static variables } variables defined in program

Heap memory } Reserved for dynamic allocation

+ ~
Heap area grows downwards

Stack area grows upwards


t t
Reserved for local variables
Stack i'04'SS'74} defined in program
(local variables) 1048575
CONCEPTUAL USE OF MEMORY

Note: Addresses are in ascending order from 0 to 1048575. The addresses for
program, data, global and static variables along with memory reserved for dynamic
allocation will be in increasing order. But, the addresses of the local variables will be
in decreasing order.

• Program memory This is the first region in the memory which is reserved for
various functions such as maim), user defined functions and standard functions.
Before execution all the necessary functions are loaded into this part of the
memory (Note: Loading is the process of copying machine code of the program
to be executed from the secondary devices into main memory).

• Global/static memory The second region is the memory where global variables
and static variables are stored. Since the lifespan of these variables is till the end
of the program, this part of the memory is reserved for these variables till the end
of the program. Note: For the detailed example, see the section 1.15.1, page 1.70.
2.84 Q Pointers

• Heap The third region is the large free memory available to the program only
during execution. This free memory available between stack area and global data
area is called heap. If memory is allocated from this area, size of heap decreases
and when memory is de-allocated the size of heap increases. In other words,
during execution size of heap changes. So, if we keep allocating the memory and
never de-allocate, there i~ possibility of "overflow" during dynamic allocation
process. In such situations, the memory allocation functions returns NULL
pointer.

• Stack This is the last area in the memory. This part of the memory holds local
variables, return address of the function calls along with arguments to functions if
any. The stack memory, heap and global memory together is called data memory:

i.e., Data memory = stack memory + heap + global/static memory


Note: In the stack area higher memory blocks are allocated for the variables defined
earlier and lower memory blocks are allocated for the variables defined later. So, all
the variables defined will have higher address values and variables defined later will
have' lower address values. For the detailed example, see the section 1.15.2, page
1.72.

2.9.2 Memory management functions


Now, let us see "What are the various memory management functions in C?" The
.1 various predefined memory management functions that are used to allocate or de-
allocate memory are shown below:
malloc 0.

Memory calloc
management
functions realloc
free

Using the functions malloct), calloct) and realloc/) additional memory space can be
allocated whereas using the function freet) unwanted space can be deleted there by
optimizing the use of storage space.

Note: If there is no space in the heap region, memory can not be allocated and this.
situation is called "Overflow of memory". In such situations, the functions malloct),
calloct) and realloct) returns NULL. It is the responsibility of the programmer to
check for overflow of memory ..
Q Systematic Approach to Data Structures using C 2.85
2.9.2.1 malloc(size)

Now, let us see "What is the purpose of using malloc?" This function allows the
program to allocate memory explicitly as and when required and the exact amount
needed during execution. This function allocates a block of memory. The size of the
. block is the number of bytes specified in the parameter. The syntax is shown below:
#include <stdlib.h> 1* Prototype definition of malloct) is available *1

ptr = (data_type *) malloc(size);

where
• ptr is a pointer variable of type data_type
• data_type can be any of the basic data type or user defined data type
• size is the number of bytes required
• On successful allocation, the function returns the address of first byte of allocated
memory. Since address is returned, the return type is a void pointer. By type
casting appropriately we can use it to store integer, float etc.
• If specified size of memory is not available, the condition is called "overflow of
memory". In such case, the function returns NULL.

Note: It is the responsibility of the programmer to check whether the sufficient


memory is allocated or not as shown below:
void function_nameO
{

ptr = (data_type *) malloc(size);


if (ptr = NULL)
{
printf("Insufficient memory\n");
exit(O);
}

Note: Many data structures, such as linked lists, trees etc., uses this function to
allocate the memory from heap area.
2.86 Q Pointers

Example 2.9.2.1.1: Now, let us see "What will happen if the following program
segment is executed?
int *ptr;
ptr = (int .*) malloc (10);

The compiler reserves the space for the variable ptr in the memory. No initialization
is done if ptr is a local variable (It is initialized to NULL if it is global variable).
Now, using the function malloct) we can request a block of memory to be reserved. A
block of memory may be allocated or may not be allocated. Now, let us discuss both
the situations.
Case 1: Un successful allocation of memory: Consider the following memory
status:
0098 0100 0102 0104 0106 0108 0110 9999

~p~~r~1 J1'ree: f
~ -7 ~(---- Used by other programs )
memory

Now, let us execute the statement:

ptr = (int *) malloc (10);


.1
Since 10 bytes of free memory space is not available, the function malloci), can not
allocate memory and hence the function returns NULL and is copied into ptr. The
memory status after execution of above statement is shown below:
0098 0100 0102 0104 0106 0108 0110 9999

Since ptr contains NULL, it indicates that memory has not been allocated and the
user should not use ptr to store some data. Instead, if ptr is NULL appropriate
message has to be displayed using the following statement:

if (ptr = NULL) )
{
printf("Insufficient memory\n"); .
return;
}
Q Systematic Approach to Data Structures using C 2.87

If ptr is not NULL, it indicates that memory has been allocated successfully and
allocated memory can be used to store the data. This situation is discussed below:

Case 2: Successful allocation of memory: Consider the following memory status:


0098 0100 0102 0104 0106 0108 0110 9999

I ?
p;r I-~(=~~~---,-_
I
Free memory ---------7)
~ I

Now, let us execute the statement:

ptr = (int *) malloc (10);

Since 10 bytes of free memory space is available, the function malloct), allocates a
block of 10 bytes of memory and returns address of the first byte. This returned
address is stored in pointer variable ptr as shown below:

0098 0100 0102 0104 0106 0108 0110 9999


I 01 00 J_~.....;.;.---t.,_...a----&.....o.,....;_r I I I
ptr }'Jk 10 bytes are reserved ) rE= .Free memory ~ r

Note: ptr points only to the first byte of memory block of 10 bytes reserved using
malloct)'
. function. Butthe allocated ·memory is not
. . .
ihi·tialized.

Now, let tis' see "How to r~ad the data into allocated memory?" Because of type cast
(int *), every two bytes are used to store an integer. So, totally 5 integers can be read
and stored in the allocated memory of 10 bytes using the following statement:

for (i = 0; i < 5; i++)


scanf("%d", ptr+i); 1* Input: 10 30 20 60 50 *1
. If we input 10, 30, 20, 60 and 50 after executing the above statement, these numbers
are stored in memory as shown below:

0102 0104 0106 0108 0110 9999


2.88 Q Pointers

Note: The expression ptr + i can be written using array notation as &p[i] or &i[p].

Now, let us see "How to access the data from allocated memory?" The contents of
the above memory locations can be accessed using *(ptr+i) with the help of de-
reference operator or using p[i] or i[p] using array notation. The equivalent
statements are: .".

for(i = 0; i < 5; i++) ~


printf("%d ", *(ptr+i) ~;

Example 2.9.2.1.2: Program showing the usage of malloct) function

#include <stdio.h> TRACING


#include <stdlib.h>
void maint) Execution starts from here
{
int" i.n;
int *ptr;
Inputs
printf("Enter the number of elements\n"); Enter the number of elements
scanf("%d",&n); 5
.1
ptr = (int *) malloc (sizeof(int)* n);

/* If sufficient memory is not allocated *,


if (ptr = NULL)
{
printf("Insuffient memory\n");
return;
}
/* Read N elements */
printf("Enter N elements\n"); Enter N elements
for (i = 0; i <n; i++)
scan f("%d ,ptr+i);
II 1020304050
printf("The given elements are\n");
for (i = 0; i < n; i++) The given elements are
printf("%d ", *(ptr+i)); 10 20 30 40 50
}
Q Systematic Approach to Data Structures using C 2.89

ow, let us see "What is dynamic array?"

Definition: A dynamic array allows us to keep the number of elements of the array
unspecified at the time of declaration. The number of elements that it can hold can be
specified during execution time. Using malloct), required number of bytes can be
allocated and operate on that memory as if it were an array using indexing. Thus, we
can have -a dynamically allocated array Later, required data can be stored in these
locations during execution time. The allocated memory can also be de-allocated if not
used.

Note: Example 2.9.2.1.2 (see previous page) shows how memory can be dynamically
allocated for an array of n elements and shows how data can be written into these
memory locations and how the data can be read from these memory locations.

2.9.2.2 calloc{n, size)

Now, let us see "What is the purpose of using calloc?" This function is used to
allocate multiple blocks of memory. Here, calloc - stands for contiguous allocation of
multiple blocks and is mainly used to allocate memory for arrays. The number of
blocks is determined by the first parameter n. The size of each block is equal to the
number of bytes specified in the parameter i.e., size. Thus, total number of bytes
allocated is n*size and all bytes will be initialized to O. The syntax is shown below:

#include <stdlib.h> /* Prototype definition of calloct) is available */

ptr = (data_type *) calloc{n, size);

where
• ptr is a pointer variable of type data_type
• data_type can be any of the basic data type or user defined data type
• n is the number of blocks to be allocated
• size is the number of bytes in each block

Now, let us see "What does this function return?" The function returns the following
values:
• On successful allocation, the function returns the address of first byte of allocated
memory. Since address is returned, the return type is a void pointer. By type
casting appropriately we can use it to store integer, float etc.
2.90 Q Pointers .

• "If specified size of memory is not available, the condition is called "overflow of
memory". In such case, the function returns NULL.

ote: It is the responsibility of the programmer to check whether the sufficient


memory is allocated or not as shown below:

void function_nameO
{

ptr = (data_type *) calloc(size);


if (ptr = NULL)
{
printf("Insufficient memory\n");
exit(O);
}

Example 2.9.2.2.1: What will happen if the following program segment' is executed?
int *ptr; . ,
ptr= (int *) calloc (5, sizeoflintj);

'Sol~iioQ: Th~.:compiler. rese~v'~s th~ space for'the variable. ptr 'In thernemory. No
initializationis done it ptr is alocal 'variable (It is initialized to NULL, if it is' global
variable) .. 'Now~ using the function calloct) we can request specified number of
blocks of memory to be reserved. The specified blocks of memory may be allocated
or may not be allocated. Now, let us discuss both the situations.

Case 1: Un successful allocation of memory: Consider the following memory


status:
0098 0100 0102 0104 0106 0108 0110 9999
? J
-p-tr--r~ F'r~e ,'~
' I' ,
:~(
__ ~_
[J=l ~ ~,
Used by other programs )
.mernory ,

Now, Let us execute the statement:


ptr = (int *) calloc (5, sizeoftintj);
~ Systematic Approach to Data Structures using C 2.91

Since5*2 = 10 bytes of free memory space is not available, the function calloct), can
notallocate memory and hence the function returns NULL and is copied into ptr. The
memorystatus after execution of above statement is shown below:
0098

ptr ,~ ~I(
0100

Free
I
memory
0102 0104

~---
0106 0108 0110

Used by other programs


9999

Since ptr contains NULL, it indicates that memory has not been allocated and the
user should not use ptr to store some data. Instead, if ptr is NULL appropriate
messagehas to be displayed using the following statement:

if (ptr = NULL)
{
printf("Insufficient memory\n");
return;
}

If ptr is not NULL, it indicates that memory has been allocated successfully and
allocatedmemory can be used to store the data. This situation is discussed below:

Case 2: Successful allocation of memory: Consider the following memory status:


0098 0100 0102 0104 0106 0108 0110 9999
I I
?
p~r r:(~:_-_- _ Free memory ----------7)
! r

ow, let us execute the statement:


ptr = (int *) calloc (5, sizeofiintj);

Since 5*2 = 10 bytes of free memory space is available, the function calloct),
allocates 5 blocks of 2 bytes each, initializes each byte to 0 and returns the address of
the first byte. This returned address is stored in pointer variable ptr as shown below:

0100 0102 0104 0106 0108 0110 9999


2.92 Q Pointers

Note: ptr points only to the first byte and the allocated memory is initialized to O's.

Now, let us see "How to read the data into allocated memory?" Because of type cast
(int *), every two bytes are used to store an integer. So, totally 5 integers can be read
and stored in the allocated memory of 10 bytes using the following statement:

for (i = 0; i < 5; i++)


scanf("%d", ptr+i); 1* Input: 10 30 20 60 50 *1

If we input 10, 30, 20, 60 and 50 after executing the above statement, these numbers
are stored in memory as shown below:
0100 0102 0104 0106 0108 0110 9999
'-------=:l~~~~~~~~ I I J
=>fE= Free memory ~ I
i ote: The expression ptr + i can be written using array notation as &p[i) or &i[p).

Now, let us see "How to access the data from allocated memory?" The contents of
the above memory locations can be accessed using *(ptr+i) with the help of de-
reference operator or using p[i) or i[p) using array notation. The equivalent
statements are: .~..

for(i=0;i<5;i++) ~
~'~~.:2~l~.~
1l~~~~~~~;,:,';'~
-.~
~o
printf("%d ", *(ptr+i) ); '''~f1;''..> " ••

The program below shows how to find maximum of n numbers which uses the
concept of dynamic arrays using calloct) function. This program prints the largest of n
elements along with its position. Note that the value of n is supplied only during
execution time. This is straightforward program and it is self-explanatory.

Example 2.9.2.2: Program to find maximum of n numbers using dynamic arrays

#include <stdio.h>
#include <stdlib.h>

void mairu)
{
int *a, i, j, n;
Q Systematic Approach to Data Structures using C 2.93

printf("Enter the no. of elements\n");


scanf("%d",&n); .

/* Allocate the required number of memory locations dynamically */


a = (int *) calloc( n, sizeof(int) );

if(a = NULL) /* If required amount of memory */


{ /* is not allocated */
printf("Insufficient memory\n");
return;
}

printf("Enter %d elements\n", n); /* Read all elements */


for ( i = 0; i < n; i++)
{
scanf("%d",&a[i]);

j = 0; /* Initial position of the largest number */

for (i = 1; i < n; i++)


{

if ( a[i] > a[j] ) j = i; /* obtain position of the largest element*/


}

printf("The biggest = %d is found in pos = %d\n",a[j], j+ 1);

/* free the memory allocated to n numbers */


free(a);

Note: In the above program &a[i] or &aU] can be replaced by a + i OF a + j. At the


same time a[i] and ajj] can be replaced by *(a + i) and *(a . j) respectively.

ow, let us see "What is the difference between malloct) and callocf)?' Even though
malloct) and callocr) are used to allocate memory, there is significant difference
between these two techniques. The difference between these two lies in the way the
memory is allocated' and initialized along with the number of parameters passed to
them.
2.94 Q Pointers

rnalloc '{',...
. --
calloc
1. The syntax of mallocr) is: 1. The syntax of calloc is:
ptr = (data_type*) malloc(size); ptr = (data_type *) calloc(n, size);

The required number of bytes to Takes two arguments: n number of


be allocated IS specifies as blocks to be allocated size IS
argument i.e., size in bytes number of bytes to be allocated for
each block.
2. Allocates a block Of memory of 2. Allocates multiple blocks of
size bytes memory, each block with the same
size
3. Allocated space will not be 3. Each byte of allocated space IS
initialized initialized to zero
4. Since no initialization takes place, 4. calloci) IS slightly more
time efficiency IS higher than computationally expensive because

- calloci).

5. This function can allocate the


of zero filling but, occasionally,
more convenient than malloct)
5. This function can allocate the
required size of memory even if required number of blocks
the memory IS not available contiguously. If required memory
contiguously but available at can not be allocated contiguously, it
returns NULL.
different locations.

6. Allocation and initialization of 6. Allocation and initialization of


allocated memory with G's can be allocated memory with O's can be
done using the following done usmg the following
statements: statements:

p = rnalloc(sizeof(int) * n); i
p = calloc(sizeof(int) * n);
memset(p, 0, sizeof(int) * n)

2.9.2.3 realloc(ptr, size)

Now, let us see"What is the purpose of using realloc?"

Before using this function, the memory should have been allocated using malloct) or
calloct). Sometimes, the allocated memory may not be sufficient and we may require
~ Systematic Approach to Data Structures using C 2.95

additional memory space. Sometimes, the allocated memory may be much larger and
we want to reduce the size of allocated memory. In both situations, the size of
allocated memory can be changed using realloci) and the process is called
reallocation of memory. The reallocation is done as shown below:
• realloct) changes the size of the block by extending or deleting the memory at
the end of the block.
• If the existing memory can be extended, ptr value will not be changed
• If the memory can not be extended, this function allocates a completely new
block and copies the contents of existing memory block into new memory
block and then deletes the old memory block. The syntax is shown below:

#include <stdlib.h> /* Prototype definition of realloc( is available */

ptr = {data_type *)realloc(ptr, size);

where
• ptr is a pointer to a block of previously allocated memory either using
malloct) or calloct).
• size is new size of the block

if (ptr == NULL)
{ /* Memory is not allocated */
printft'Tnsufficient memory\n");
return;
}

Now, let us see "What does this function return?"This function returns the following
values:

• On successful allocation, the function returns the address of first byte of allocated
memory.
• If specified size of memory can not be allocated, the condition is called "overflow
of memory". In such case, the function returns NULL.

Now, let us discuss each of the above case one by one.


2.96 ~ Pointers

Case 1: Reducing the size of the allocated memory. Consider the following
memory status
0098 0100 0102 0104 0106 0108 0110 9999

allocated by
malloct) or calloct) programs
Assume, ptr points to the address of the first byte of memory block. After executing
the statement:
ptr = (int *) realloc(ptr, 3*sizeof(int) )

only 3*2 = 6 bytes are re-allocated starting from 0100 and last block of memory
starting from 0106 is de-allocated and the resulting memory status is shown below:

0098 0100 0102 0104 0106 0108 0110 9999

l'
ptr ~re-allocated---7~ Free -7 ~ Used by other -7
by realloc memory programs
Observe from the above memory status that memory is deleted from the end of block
t ere by free memory space is increased.

Case 2: Extend the allocated memory without changing the starting address.
Consider the following memory status

0098 0100 0102 0104 0106 0108 0110 9999


0100
ptr l' ~ allocated by -7 ~ Free -7 ~ Used by other -7
malloct) or calloct) memory programs

Assume, ptr points to the address of the first byte of memory block. After executing
the statement:
ptr = (int *) realloc(ptr, 4*sizeof(int) )

only 4*2 = 8 bytes are re-allocated starting from 0100 and the resulting memory
status is shown below: .
Q Systematic Approach to Data Structures using C 2.97

0098 0100 0102 0104 0106 0108 0110 9999

Used by other -7
programs

Observe from the above memory status that free memory space is reduced by re-
allocating the extra memory.

Case 3: Extend the allocated memory by changing the starting address. Consider
the following memory status.

0098 0100 0102 0104 0106 0108 0110 9999

Used bY-7 +-<--


Free memory
other
programs
Assume, ptr points to the address of the first byte of memory block and integers 10
and 20 are stored in that memory block. After executing the statement:
ptr = (int *) realloc(ptr, 4*sizeof(int) )

4*2 = 8 bytes should be re-allocated. But, the existing memory block can not be
extended because there is no free space at the end of the current block. So, realloc
allocates a completely new block, copies the existing memory contents to the new
block and deletes the old allocation as shown below:

0098 0100 0102 0104 0106 0108 0110 9999


0100
l' Used bY-7 ~(--
ptr +- Free -7
'- memory / other
v programs
de-allocated
by realloc

After copying the data from old block to new block, the remaining locations of new
block are not initialized and hence are represented using ?? Thus, the function
realloct) guarantees that re-allocating the memory will not. destroy the original
contents of memory.
2.98 Q Pointers

Example: 2.9.2.3.1: C program showing the usage of realloct) function.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void maint)
{
char *str;
/* allocate memory for the string */
str = (char *) malloc(lO);
strcpy(str, "Computer");
str = (char *) realloc(str, 40);
strcpy(str, "Computer Science and Engineering");
}

2.9.2.4 free(ptr)

Now, let us see "What is the purpose of using freer)?':

This function is used to de-allocate (or free) the allocated block of memory which is
allocated by using the functions callocr), malloct) or realloct). It is the responsibility
.lof a programmer to de-allocate memory whenever it is not required by the program
and initialize ptr to NULL. The syntax is shown below:

#include <stdlib.h> /* Prototype definition of freer) is available */

free(ptr);
ptr = NULL;

Here, ptr is a pointer to a memory block. Now, let us see how this function works. For
example, consider the following memory configuration where ptr points to a memory
block containing 200 integers ranging from 01 to 0200.

11
ptr
Q Systematic Approach to Data Structures using C 2.99

After executing the statement:

free(ptr);

the following memory configuration is obtained.

i...--....-.il-( ---L...........--L--...;...F-L..--.-.J.-----L..----'-------i, ~
l' ree memory 7"

ptr
This shows the memory allocated for 200 integers is de-allocated and is available as
part of the free memory (heap area).Observe from the above figure that even after
freeing the memory, the pointer value stored in ptr is not changed. It still contains the
address of the first byte of the memory block allocated earlier. Using the pointer ptr
even after the memory has been released is a logical error. Note: These logical errors
are very difficult to debug and correct. So, immediately after freeing the memory, it is
better to initialize to NOLL as shown below:

/* allocate the memory */

/* de-allocate the memory */


free (ptr);
ptr=NULL;

Example: 2.9.2.4.1: Sample program to shown the problems that occur when freet) is
not used.

1. #iocIude <stdlib.h>
2.
3. void maim)
4. {
5. int *a;
6.
7. a = (int *) malloc(sizeof(iot)); a
8. *a = 100; ".
9. ......•.. ;l.

10: a = (int *) malloc(sizeof(iot));


11. *a = 200;
illQJ
12. }
2.100 ,!;l Pointers

Now, let us see "What will happen if the above program is executed?" The various
activities done during execution are shown below:
• When control enters into the function main, memory for the variable a will be
allocated and will not be initialized.
• When memory is allocated successfully by malloc (line 7), the address of the
first byte is stored in the pointer a and integer 100 is stored in the allocated
memory (line 8).
• But, when the memory is allocated successfully by using the function malloe
in line 10, address of the first byte of new memory block is copied into a
(shown using dotted lines.)

Observe that the pointer a points to the most recently allocated memory, thereby
making the earlier allocated memory inaccessible. So, memory location where the
value 100 is stored is inaccessible to any of the program and is not possible to free so
that it can be reused. This problem where in memory is reserved dynamically but no~
accessible to any of the program is called memory leakage. So, care should be taken
while allocating and de-allocating the memory. It is the responsibility of the
programmer to allocate the memory and de-allocate the memory when no longer
required.

Note: Observe the following points:


• It is an error to free memory with a NULL pointer
.l • It is an error to free a memory pointing to other than the first element of an
allocated block
• It is an error to refer to memory after it has been de-allocated

Note: Be careful, if we dynamically allocate memory in a function. We know that


local variables vanish when the function is terminated. If ptr is a pointer variable
used in a function, then the memory allocated for ptr is de-allocated automatically.
But, the space allocated dynamically using malloc, calloc or realloc will not be de-
allocated automatically when the control comes out of the function. But, the allocated
memory can not be accessed and hence can not be used. This unused un-accessible
memory results in memory leakage.

2.10 Array of pointers

In the section 2.7, we have seen how a 2-dimensional array can be represented using
pointer to an array. But, a 2-dimensional array can be expressed in-terms of array of
pointers also. The conventional array definition is

data_type array_name[expl][exp2];
~ Systematic Approach to Data Structures using C 2.101

Using array of pointers, a 2-dimensional array can be defined as

data_type *array_name[expl];

where
• data_type refers to the data type of the array
• array_name is the name of the array
• expl is the maximum number of elements in the row.

Note that exp2 is not used while defining array of pointers. Consider a 2-dimensional
vector initialized with 3 rows and 4 columns as shown below:

int p[3][4] = {
{10, 20, 30, 40},
{50, 60, 70, 80},
{25, 35, 45, 55}
};
The elements of matrix p are stored in memory row-wise (can be stored column wise
also) as shown below:

1033

prO] p[l)
i
p[3]

Using array of pointers we can declare p as

int *p[3];
Here, p is an array of pointers. p[O] gives the address of the first row, p[l] gives the
address of the second row and p[2] gives the address of the third row. Now, p[O]+O
gives the address of the element in Othrow and Othcolumn, p[O]+ 1 gives the address of
the element in Othrow and 1stcolumn and so on. In general,
• address of ithrow is given by a[i]
• address of an item in ithrow and fh column is given by
p[i] + j
• the element in i" row and r
column can be accessed using the indirection
operator * a by specifying
*(p[i] + j)
2.102 Q Pointers

ote: Even though standard array indexing notation is easier to understand, pointer
arithmetic is faster and more efficient. Since efficiency is most important in most of
the applications, CIC++ programmers commonly use pointers to access array
elements.

Example 2.10.1: C function to read a matrix using array of pointers

1* Function to read the elements of a matrix *1


void read_matrix(int m, int n, int *a[10])
{
int i, j;

for (i = 0; i < m; i++)


{
for U = 0; j < n; j++)
{
scanf("%d", a[i]+j);
}
}
}

~xample 2.10.2: C function to display a matrix using array of pointers

1* Function to display the elements of a matrix *1


void write_matrix(int m, int n, int *a[10])
{
int i, j;

for (i = 0; i < m; i++)


{
for U = 0; j < n; j++)
{
printf("%d ",*(a[i]+j»;
}
printf("\n") ;
}
}
Q Systematic Approach to Data Structures using C 2.103

Example 2.10.3: C function to display a matrix using array of pointers


void add_matrix(int m, int n, int *a[10], int *b[lO], int *c[10])
{
int i,j;

for (i = 0; i < m; i++)


for (j = 0; j < n; j++)
*(c[i]+j) = *(a[i]+j) + *(b[i]+j);
}

The main program which calls all above functions and to find sum of two matrices is
shown below:

Example 2.10.4: C function to display a matrix using array of pointers

#include <stdio.h>

1* Include: Example 2.10.1: Function to read a matrix *1

1* Include: Example 2.10.2: Function to display a matrix *1

I*Include: Example 2.10.3: Function to add two matrices *1

void maint)
{
int i, m, n, a[10][20], b[10][20], c[1O][20], *p[10], *q[10], *r[10];

for (i=O; i<10; i++)


{
p[i] = &a[i][O];
q[i] = &b[i][O];
r[i] = &c[i][O];
}

printf("Enter the size of matrix i.e., rnxn\n");


scanf("%d %d",&m, &n);

printf("Enter the matrix a\n");


read_matrix(m, n, p);
2.104 &;l Pointers

printf("Enter the matrix b\n");


read_matrix(m, n, q);

add_matrix(m, n, p, q, r);

printf("The resultant matrix is\n");


write_matrix(m, n, r);

Now, let us see "What is the advantage of array of pointers?" The advantage can be
explained by considering the following example:

Example 2.10.5: Give the memory representation for the following initialization
statement:
char a[5] [11] = {
"DHARMARA YA",
"BHIMA",
"ARJUNA" ,
"NAKULA",
"SAHADEV A"
};
Solution: From the declaration, it is clear that a is a 2-dimensional array with 5 rows
and 15 columns. These five memory locations are initialized with values terminated
by \0 as shown below:
o 2 3 4 5 6 7 8 9 10
D H A R M A R A Y A \0
B H I M A \0
A R J U N A \0
a~~
N A K U L A \0
4 S A H A D E V A \0
t
Iri general, using a[i] for i ~ 0 to 4, we can access each name.

Note: The array a is 2-dimensional vector of 5xll size thus requiring 55 memory
locations. The size of each row is fixed. If the string size is less than the given size, it
results in ragged array as shown in above figure
Q Systematic Approach to Data Structures using C 2.105

ow, let us see "What is ragged array? What is the disadvantage of ragged array?"
Observe from previous example that totally 5 x 11 = 55 memory locations are
reserved so that each name can have at most 11 characters including the \0 character.
Here, 11 memory locations are fixed for each string. So, even if the string is small, 11
memory locations are fixed for that small string. The remaining locations on the right
of the string may be empty giving rise to uneven (ragged) right border. For ragged
right border see the memory representation shown in example 2.10.5. This type of
array is called ragged array.

This is a disadvantage, as most of the memory is wasted if strings are small.


This disadvantage can be overcome using array of pointers. Now, we will see "How
to declare array of pointers using which we can store strings?" The declaration is
shown below:

Example 2.10.6: Give the memory representation for the following initialization
statement:
char *a[5] = {
"DHARMARA YA",
"BHlMA",
"ARJlJNA",
"NAKULA",
"SAHADEV A"
};

Solution: From the declaration, it is clear that a is an array with 5 rows. These five
memory locations are initialized with values terminated by \0. Observe that an array a
has 5 memory locations each of which points to a name. The memory representation
is shown below:

r--
o 1 2 3 4 5 6 7 8 9 10
a[O] r--
D H A R M A R A IY IA I \0 I
a[l] f-- B H I M A \0
a[2] r-- A R J U N A \0
a[3] N A K U L A \0
r--
a[4] ~ S A H A D E V A I \0 I
Observe from this memory representation that there is no wastage of memory.
2.106 Q Pointers

2.11 Pointers to functions

Pointer to a function (also called function pointer) is a very powerful and confusing
feature of C/C++. Function pointers provide some extremely interesting, efficient and
elegant programming techniques. Unfortunately, probably due to their complicated
syntax, step motherly treatment is given in most of the books and addressed quite
briefly and superficially. Actually, function pointers are less error.prone than normal
pointers since we will never allocate or de-allocate memory for the functions. All we
have to do is to understand what they are and learn their syntax.
A function, like a variable, has a physical location in the memory. Like
assigning address of a variable to pointer, it is possible to assign address of a function
to a pointer. This address is the entry point of a function and this is the address used
when the function is invoked.
Once a pointer points to a function, the function can be invoked using this
pointer. Using function pointer, it is possible to pass functions as parameters (similar
to the way the variables are passed as parameters). The address of a function can be
obtained by specifying the name of the function without any parentheses or arguments.
This is similar to the wayan array's address is obtained with only the array name,
without using indices. The syntax to declare a pointer to a function is shown below:

type (*fp) ( );

were
• type is the type of value returned from the function
• fp is pointer to a function

Note: The parentheses around *fp is mandatory. In case parentheses around *fp are
missing, then the meaning changes (It means fp is a function which returns a pointer
to the specified type).

Note: Now, we should be in a position to distinguish between

type *fp( );
and
type (*fp) ();

Now, let us write various functions to evaluate arithmetic functions and see how these
functions can be called normally and using function pointers.
Q Systematic Approach to Data Structures using C 2.107

Example 2.11.1: C functions to add, subtract, multiply and divide

/* Function to add two numbers */


float Plus (float a, float b)
{
return a + b;
}

/* Function to subtract b from a */


float Minus (float a, float b)
{
return a-b;
}

/* Function to multiply two numbers */


float Multiply (float a, float b)
{
return a*b;
}

/* Function divide a by b */
float Divide (float a, float b)
{
return aIb;
}

The function which can call all the above functions can be written as shown below:

Example 2.11.2: C functions to perform add, subtract, multiply and divide using
switch

/* Function to perform a+b, a-b, a*b and alb */


void Operation(float a, char op_code, float b)
{
float result;
2.108 .Q Pointers

1* Perform the operation specified in op_code *1


switch( op_code)
{
case '+' :
result = Plus (a, b);
break;
case '-' :
result = Minus(a, b);
break;
case '*' :
result = Multiply (a, b);
break;
case 'I' :
result = Divide (a, b);
break;

1* Display the result *1


printf("The result using switch statement = %f\n", result);
}

The complete program to add, multiply, divide and subtract two numbers is shown
below:

Example 2.11.3: C program to perform various arithmetic operations

#include <stdio.h>

1* Include: Example 2.11.1 and 2.11.2 *1

void maint)
{
Operation(10, '+', 20); 1* Perform 10 + 20 *1

Operation(10, '-',20); 1* Perform 10 - 20 *1

Operation(10, '*', 20); 1* Perform 10* 20 *1

Operation(lO, 'I', 20); 1* Perform 10 I 20 *1


}
.!;l Systematic Approach to Data Structures using C 2.109

Using function pointer, the above program can be written as shown in example 2.11.4.
Even though this is a simple example, the usage of function pointer is very clear from
this example.

Example 2.11.4: C Program to add, subtract, multiply and divide two numbers using
function pointer

#include <stdio.h>

1* Include: Example 2.11.1: Functions to perform various arithmetic operations *1

1* Invokes functions Plus/Minus/Multiply/Divide based on which is called *1


void Operation(float a, float (*pt2_f)(float, float), float b)
{
1* Invoke function Plus/Minus/Multiply/Divide *1
float result = (*pt2 _ f) (a, b);

.
1* Display the result *1
printf("The result using function pointer = %f\n", result);

void maint)
{
1* Function Plus is invoked to get 10 + 20 *1
Operation( 10, Plus, 20);

1* Function Minus is invoked to get 10-20 *1


Operation(lO, Minus, 20);

1* Function Multiply is invoked to get 10*20 *1


Operation( 10, Multiply, 20);

1* Function Divide is invoked to get 20/10 *1


Operation(20, Divide, 10);
}

Note: Observe how simple it is to write a program using function pointer.


2.110 Q Pointers

2.12 Advantages and disadvantages of pointers

By this time, we should have understood the full concepts of C pointers and given
any problem we should be in a position to solve. After understanding the full
concepts of pointers, we should be in a position to answer the question "What are
the adv antages and disadvantages of pointers?"

Ad" antages
• More than one value can be returned using pointer concept (pass by reference).
• Very compact code can be written using pointers.
• Data accessing is much faster when compared to arrays.
• Using pointers, we can access byte or word locations and the CPU registers
directly. The pointers in C are mainly useful in processing of non-primitive
data structures such as arrays, linked lists etc.

Disadvantages
• Un-initialized pointers or pointers containing invalid addresses can cause
system crash.
• It is very easy to use pointers incorrectly, causing bugs that are very difficult to
identify and correct.
• They are confusing and difficult to understand in the beginning and if they are
misused the result is not predictable.

Exercises

1. What is a pointer variable? What are the advantages and disadvantages of


pointers?
2. How a pointer variable can be declared and initialized? Explain with example
3. What are pointers? Why they are required? (JuI/Aug 2003)
4. What is a pointer? Explain how to declare a variable as a pointer.
(Jan/Feb 2003)
5. What is pointer to an array? Explain with example
6. Distinguish between call by value and call by reference (Jan/Feb 2004)
7. Write a C program to demonstrate the use of pointers (JuIlAug 2004)
8. Write a function using pointers to determine the length of the string
(Jan/Feb 2004)
9. What are the arithmetic operations that can be performed on pointers and what
arithmetic operations are not possible?
Q Systematic Approach to Data Structures using C 2.111

10. What are the similarities and differences between pointer to an int and pointer
to a float? . (Feb/Mar 2005)
11. What is the difference between *a[10], (*)[10], (*a)O?
12. Give the memory map for the following declarations assuming variables as
a. Global variables
b. Local variables
int *pi; 1* Pointer to an integer *1
float *pf; 1* Pointer to a float number *1
char *pc; 1* Pointer to a character *1
13. Find the final values stored in the variables x, y and z at the end of the
program:
void mainO
{
int x, y, z, *p, *q;
x = 10;
y = 15;
z= 20;
p=&x;
q=&z;
*q = *p + y - 3;
y = y- (*p);
*p = *q-z;
}

14. What do you mean by dynamic memory allocation? Explain the different
functions used for this. (VTU) July/Aug 2004
15. What is a pointer? Explain the conceptof pointer
16. What are pointer constants?
17. What is a pointer variable? How to initialize a pointer variable? How to
access the value of a variable using pointer?
18. Defme the following: pointer, pointer value, pointer constant, pointer variable
19. What are the steps to be followed while using pointers?
20. How to declare pointer variables?
21. What is a dangling pointer?
22. What is a NULL pointer? What is its use?
23. How pointers can be passed as arguments to the functions?
24. What are the different ways of passing parameters to the functions?
25. What is pass by value? Explain with example
26. What is pass by reference? Explain with example.
27. What are the differences between pass by value and pass by reference?
2.112 Q Pointers

28. What is pointer to a pointer? Explain with example.


29. What is a void pointer? Explain with example.
30. What is L-value and R-value? Explain with example.
31. Is it possible to use a function as lvalue. Explain with example.
32. Write a program to add n numbers using pointers
33. Write a program to display array elements by comparing pointers.
34. Write a binary search program using pointers
35. What is pointer to an array? Explain with example
36. What is array of pointers? Explain with example
37. What is static memory allocation? Explain with example
38. What is dynamic memory allocation? Explain with example
39. Explain the purpose of mallocr) with an example.
40. Explain the purpose of calloct) with an example.
41. Explain the purpose of realloct) with an example.
42. Explain the purpose of freet) with an example.
43. What is the difference between mallocr) and calloct)?
44. What is the need for allocating the memory dynamically?
45. Explain the memory map of a C program
46. What is a dangling pointer? Explain with an example
47. What is memory leak? Explain with an example
48. Explain dynamic memory allocation with an example
49. What are various memory management functions? Explain.
50. What is dynamic array? Explain with example.
51. What is the advantage of array of pointers? How to declare array of pointers
using which we can store strings?
52. What is ragged array? What is the disadvantage of ragged array? How this
disadvantage can be overcome?
53. Explain pointer to a function with example
54. What are the advantages and disadvantages of pointers?
55. What will happen if the foUowing program segment is executed?
int *ptr;
ptr = (int *) maUoc (10);

Chapter 3: Strings
-----,
I What are we studying in this chapter? I
• String Concepts
• C strings
• String I/O functions
• Array of strings
• String manipulation functions
• Memory formatting
• Programming examples. -1 hours

3.1 String concepts

No software exists without the manipulation of strings. In all our previous


programs, we have already used strings without our knowledge. For example, we
have used the statement:

printf (" Enter the value for n " );

Here, the sequence of characters enclosed within a pair of double quotes (shown in
red color) is a string. Strings are generally used to store and manipulate data in text
form like words or sentences. Before proceeding further, let us see "What is a
string? How strings are represented?"

Definition: An array (sequence) of characters is called e string, A string is most


conveniently represented using a sequence of storage locations in memory. The
storage representations of strings are classified as shown below:

Storage
represe~tation of
-C Fi~ed length string

stnngs variLn~e::::ntrollea string

~ Delimited string
3.2 .I;l Strings

3.1.1 Fixed length format

Now, let us see "What is fixed length string?"

Definition: A fixed length string is a string whose storage requirement is known


when the string is created. In this string, irrespective of number of characters the
string has, the length of the string is always fixed. Once the string is defined, the
length of a string cannot be changed. It is "fixed" for the duration of program
execution. In this format, the non data characters such as spaces are added at the end
of the data.
For example, the strings "RAMA"and "KRISHNA" are stored in fixed format
whose size is fixed for 10 bytes is shown below:
6 blank characters
r ./-.--------""" Note: The string "RAMA"
is a 10 byte string ending
with 6 blank characters

Note: The string "KRISHNA"


3 blank is a 10 byte string ending
characters with 3 blank characters
Note: The blank character.
can not be used as data since
~ 10 bytes it acts as end of the string.

Now, let us see "What are the disadvantages of fixed length strings?" The various
drawbacks of this format are shown below:
• If the length reserved for string is too small, it is not possible to store the larger
data.
• If the length reserved for string is too large, too much memory is wasted (see
the above figures).
• Once the string is defined, the length of a string cannot be changed. It is
"fixed" for the duration of program execution.
• The problem of distinguishing data from nondata. Normally, nondata
characters such as spaces are added at the end of the data
The above disadvantages can be overcome using variable length format.

3.1.2 Variable length format

Now, let us see "What is variable length format?"


Q Systematic Approach to Data Structures using C 3.3

Definition: As the name implies, variable-length strings don't have a pre-defined


length. In this string, neither the precise length nor maximum length is known at
creation time. The storage structure for a string can expand or shrink to accommodate
any size of data. But, there should be a mechanism to indicate the end of the data. The
two common techniques to implement variable length strings are:
• length controlled string
• delimited string

3.1.2.1 Length controlled string

Now, let us see "What is length controlled string?"

Definition: A length controlled string is a string whose length is stored as part of the
string itself. This technique uses a count that specifies string length. The count is
normally stored as the first byte followed by the' string. This count is used by the
string manipulation functions to determine the actual length of the data.
For example, the strings "RAMA"and "KRISHNA" are stored using length-
controlled format as shown below:

string
___
----A'----....,
4 A

5 bytes

string
string
length ~
r--"--o. r ------- .

Note: The first byte contains string length. Since its length is 1 byte (8 bits) we can
have a string length whose range is from 0 to 255. So, the string length should not
exceed 255 characters. This disadvantage can be overcome using delimited string.
As we use various delimiters such as semicolon, colon, comma, dot/period (denoted
by.), in a sentence in English, the string also can have delimiters.
3.4 Q Strings

3.1.2.2 Delimited string

Now, let us see "What is delimited string?"

Definition: In a variable-length string, the string ends with a delimiter NULL( denoted
by \0) character. This string which ends with a delimiter denoting the end of the string
is called a delimited string.
For example, the strings "RAMA"and "KRISHNA" are stored using a
delimiters as shown below:
string
r__
------A ---

5 bytes

. string delimiter
r------~ ------""~
~

3.2 C Strings
l
Now, let us see "What is a string in C language?"

Definition: There is no separate data type for string in C language. In C language, a


string is an array of characters and terminated by NULL character which is denoted
by the escape sequence '\0'. A null-terminated string is the only type of string
defined by C.

Now, let us see, "How the strings are stored in memory?" A string is stored as a
sequence of characters in an array terminated by \0. For example, consider the string:
"VIVEKANANDA"

This string is stored in the form of an array as shown below:


Q Systematic Approach to Data Structures using C 3.5
--------------------~------~
Note that the characters are stored from location zero. Each location holds one
character starting from 0 to 10. The string always ends with NULL character denoted
by '\0'. Here, the string "VIVEKANANDA" is called a string literal.

3.2.1 String literal

Now, let us see "What is a string literal?"

Definition: A string literal is a sequence of characters enclosed within two double


quotes. A string literal is also called string constant.For example,
"Rama"
"You see C is actually sea"
are all string literals. Now, let us see "What will happen when a string literal is
defined?" When a string literal is defined, the C compiler does the following
activities:
• The compiler creates an array of characters
• Initialize each location of array with the characters specified within double
quotes in sequence
• Null-terminate the string i.e., append \0 at the end of the string. This is done by
the compiler automatically.
• Store the starting address of the string constant that can be used later.
~
For example, the literals "RAMA" and "SEETA" can be stored in the memory as
shown below:

l;~l_t---~----t
~------~~~--~
__
'~SE~L~]Ql
_~~~?TA"[l]
"SEETA"[2]
E
E
S

"RAMA"[3] A "SEETA"[3] T
"RAMA"[ 4] \0 "SEET A"[ 4] A
L---------_.
"SEET A" [5] \0
3.2.2 Referencing string literal
Now, let us see "How to reference string literals?" As array of integers are stored in
contiguous memory locations, it is clear from the above figures that a string literal is
also stored in memory contiguously one after the other. So, each character of the
literal can be accessed using indexing (array or pointer concept can be used). For
example, consider the following program:
3.6 Q Strings

Example 3.2.1: Accessing individual characters of the string using index


#include <stdio.h>
void maint)
{
printf("%c ","RAMA"[O]); ~ _~~~~IQl_+-_-i---,:~m
printf("%c ","RAMA"[l]); ~ _:'R~~J1L_
printf("%c ","RAMA"[2]); ~ t----i

printf("%c ","RAMA"[3]); ~ "RAMA" 3


}

The entire string can be referenced and printed as shown below:

Example 3.2.2: Accessing the string without using index

#include <stdio.h>

Note: Since a string is an array of characters, a string can be accessed one character at
a time using the index as shown in example 3.2.1. or the entire string can be treated as
one unit and can be printed as shown in example 3.2.2.

3.2.3 Character vs string containing single character


Even though a string is an array of characters, there is significance difference between
a string and an array of characters. Now, let us see "What is the difference between a
character and string containing a single character?" The various differences are shown
below:
A character A string containing a single character
1. A character is enclosed within 1. A string containing a single character
two single quotes. For example, is enclosed within two double quotes.
'0' represent a character 0 For example, "0" represent a string. 0
(zero) (zero)
Q Systematic Approach to Data Structures using C 3.7

2. A character occupies one byte 2. A string containing single character


in memory occupies two bytes in memory: One
byte for the character and another byte
for the \0 which acts as delimiter.
3. There is no empty character as 3. An empty string is denoted by"". An
such in set of characters. empty string has only one character \0
which acts as delimiter
4. A character can be moved from 4. A string always requires string
one location to another location function strcpy to move from one
with the help of an assignment location to another location.
operator
5. A character can be compared 5. A string can be compared with other
with another character usmg string containing zero or more
any of the relational operators characters usmg string function
such as >, >=, <, <=, =, l= strcmp

Now, we should be in a position to answer the question "What is the difference


between 0, '0', "0" and '\0' and "\O"? Let us see what each means and how many
bytes are required:

0 It is an integer zero. It occupies two bytes of memory. A value of 0 is stored


mmemory.
'0' It is a character. It occupies only byte. ASCII value of 0 is stored in
memory.
"0" It is a string containing a single character. It occupies two bytes. The first
byte contains ASCII value of 0 and second byte contains \0 and acts as
delimiter .
'\0' It is NULL character and occupies 1 byte of memory. So, sizeof '\0' is 1
byte. It is not empty character. There is no empty character as such.
"\0" It is a string containing a null-character. So, the null-character ends with \0.
Together, the string "\0" occupies two bytes. So, size of "\0" is 2 bytes.

3.3 String variable

Now we move on to the next question "What is a string variable?"

Definition: There is no separate data type for strings in C. They are treated as arrays
of type char. So, a variable which is used to store an array of characters i.s called a
3.8 Q Strings

string variable. As the numbers can be stored and manipulated using variables, the
strings can also be declared, initialized and manipulated using arrays. Consider the
following example:

char a[80];

Here, the string variable a can hold maximum of 80 characters including NULL (\0)
character.

3.3.1 String as variable

Now, let us see "How to declare a string variable?"

As a variable has to be declared before it is used, a string variable also has to be


declared before it is used in any of the functions. Consider the following declaration:

char a[80];

Using this declaration the compiler allocates 80 memory locations for the variable a
ranging from 0 to 79 as shown below:

a
78 79
Since the size of a character is 1 byte, each character in the array occupies I byte.
The array thus declared can hold maximum of 80 characters including NULL
character.

Note:During declaration, we must provide enough storage for the data and the
delimiter. The storage space must be 1 byte larger than the maximum data size so
as to accommodate \0 at the end of the string.

For example, consider the following statement:

char a[lO];

U sing the above declaration, 10 bytes are allocated. If we use the statement:

strcpy( a, "HELLO");
Q Systematic Approach to Data Structures using C 3.9
the string "HELLO" is copied into the variable a as shown below:

part of the array but


not part of the string
.--- __ .A.__ ---...

,,6 8 9,/
y

junk characters

Observe the following points:


• 10 memory locations are reserved for the variable a ranging from 0 to 9
• The string "HELLO" is copied into these memory locations one by one from
left to right. Each character of the string occupies 1 byte.
• The compiler has terminated the string with NULL character '\0'.

3.3.2 Initializing strings

Now, let us see "What is initialization? What are the various ways of initializing
strings?" Initialization is the process of assigning values to a variable before doing
manipulation. The initialization can be done in various ways.
• Initializing locations character by character
• Partial array initialization
• Initialization without specifying the size
• Array initialization with a string
• Using character pointer

3.3.2.1 Initializing locations character by character

Consider the following declaration with initialization:

char b[9] = {'C', '0' , 'M' , 'P', 'U' , 'T', 'E', 'R'}·,

The compiler allocates 9 memory locations ranging from 0 to 9 and these locations
are initialized with the characters in the order specified. The remaining locations
are automatically initialized to null-characters as shown below:
3.10 ~ Strings

Note: It is the responsibility of the programmer to allocate sufficient memory so as


accommodate NULL character at the end. Note that ASCII values of C, 0, M, P,
U, T, E, R are stored in memory.

3.3.2.2 Partial array initialization


If the number of characters to be initialized is less than the size of the array, then
the characters are stored sequentially from left to right. The remaining locations
will be initialized to NULL characters automatically. For example, consider the
partial initialization shown below:

char a[lO] = { 'R', 'A', 'M', 'A'};


The above statement allocates 10 bytes for the variable a ranging from 0 to 9 and
initializes first four locations with the ASCII characters of'R', 'A', 'M', 'A'. The
remaining locations are automatically filled with NULL characters (i.e., '\0') as
shown below:
a-+

.1 3.3.2.3 Initialization without size

Consider the declaration along with initialization shown below:

char b[] = {'C', '0' , 'M', 'P', 'U', 'T', 'E', 'R'}',
For this declaration, the compiler will set the array size to the total number
of initial values i.e., 8. The characters will be stored in these memory locations in
the order specified as shown below:

Note: sizeof(b) will be 8. Note that \0 is not included at the end of the string.

3.3.2.4 Array initialization with a string


Consider the following declaration with string initialization:
.
Q Systematic Approach to Data Structures using C 3.11

char b[] = "COMPUTER";

Here, the string length is 8 bytes. But, string size is 9 bytes. So, the compiler
reserves 8+ 1 memory locations and 'these locations are initialized with the
characters in the order specified. The string is terminated by \0 by the compiler.
The array b is initialized as shown below. .

7
~
Even though the string "COMPUTER" contains 8 characters, because it is a string,
it always ends with null character. So, the array size is 9 bytes (i.e., string length +
1 byte for null character).

3.3.2.5 Using character pointer

Consider the following declaration with string initialization:


char *p = "COMPUTER";
Here, the string length is 8 bytes. So, the compiler allocates 9 memory locations
(one more than the string length) initialize all these locations with the characters in
the order specified and ends with \0 character. Finally, the address of the literal is
copied into the pointer variable p as shown below:

Now, let us look at the various ways of initialization and generally made mistakes
during initialization:
I
char b[9] = "COMPUTER"; Correct
char b[8] = "COMPUTER"; Wrong. This is because, string length is 8. So,
array size should be 8+1 which is 9. But, 8 has
been specified as the size of the array.
char b[8] = 'computer'; Wrong. The string should be enclosed between
two double quotes
char b[lO]= {'R',A','M','A'}; Correct. This is partial initialization
char b[8] = COMPUTER; Wrong. String should be enclosed within two
double quotes
-,....

3.12 ~ Strings

3.3.3 Strings and the assignment operator

Since, string is an array of characters, the name of the string is a pointer constant. The
constants can not be used on the left hand side of assignment operator. For example,

"Krishna" = "Rama"; /* Invalid: The string "Krishna" is a pointer


constant. So, it should not occur on
LHS of assignment operator */
char str1[10] = "Rama"; /* Valid */ .

Example 3.3.3.1: Copy a string from one memory location to other memory location

char strl [10] = "Rama"


char str2[10];

str2 = str1; /* Compiler error: Because str2 is a pointer constaiand is an


rvalue. So, it can not be changed */

Note: If we want string str1 to copy into str2 then it can be done using two different
ways (discussed in section 3.6.2)
~ • Using string function strcpy(str2, str1) as shown in example 3.6.2.1
• By copying the individual items of str1 to str2 as shown in example 3.6.2.2

3.4 String input/output functions

The strings can be read from the keyboard and can be displayed onto the monitor
using various functions. "What are various I/O functions used in case of strings?"
The various input and output functions that are associated with strings can be
classified as shown below:

Formatted Input function Ex: scanfl)

Formatted Output function Ex: printfO


110
Functions Un-formatted Input functions Ex: getst), fgetst)

Un-formatted Output functions Ex: putst), fputst)


Q Systematic Approach to Data Structures using C 3.13

3.4.1 Formatted input function - scanf()

Earlier we have used scanf() to read integer, floating point numbers etc. Now, let
us see "How a string can be read using scanfi)?" The string can be read using the
following conversion codes:

Conversion codes
of strings
-C String conversion code %s

The Edit set conversion code (% [... ])

3.4.1.1 String conversion code %s

Now, let us see "What is the role of string conversion code %s while reading the
strings?" The %s conversion code does the following things in sequence:
• If white spaces are present before the string, then they are removed from
the input stream (Note: A white space can be blank char cter, new line
character \n, tab \t etc.)
• All nonwhite space characters are copied into the array till it finds another
white space. Then the copied string is terminated by '\0'. But, the white
space and characters following are left in the input stream.

Example 3.4.1.1.1: What string is available in variable sl if the following statements


are executed?

char sl[15];
scanf("%s", sl); 1* Note: We should not use & operator while reading
string. Specifying &s 1 is an error *1

if the input through the keyboard is:


@@@@@@RAMA0KRISHNA.J

Note: In the above input:


• 0 is blank character
• .J is the Enter character which indicates end of input

Solution: The sequence of operations that are carried out when above string is read
using %s conversion code are shown below:
3.14 Q Strings

c--
&
&
& D is a blank character and represent white space. All white space
>- characters are ignored and will not be copied into variable sl.
~ D
D
~
"\
R These characters and are copied into variable one after and string sl
A can be represented as shown below:
~
f----

A
IR f A I M I A I \0 I? I? I? I? I? I? I? I? I? I.? I
D .~ iD is converted into \0 and stored in sl
K
R
I
S } These characters remain in the input stream and will not be copied into
H sl
N
A
.J .I

Input stream

Nete: Observe that after copying "RAMA", all. other subsequent characters are still
in the input stream. All these characters from the input stream can be removed using
the function fflush(stdin). The complete program segment is shown below: .
char sl[15];
scan f("%s", s 1); 1* Read non white space characters *1
fflush(stdin); 1* Remove the remaining characters from
the input stream *1
Example 3.4.2.1.1: What strings are available in variables sl and s2 if the following
statements are executed?
char sl[15];
char s2[1 0];
scanf("%s", s 1);
scanf("%s",s2);
if the input through the keyboard is:
@@8@@@RAMADKRISHNA.J
Q Systematic Approach to Data Structures using C 3.15

Solution: The sequence of operations that are carried out when above string is read
are shown below:

\} is a blank character and represent white space. All white space


characters are ignored and will not be copied into variable s1.

R }r-T__hTes_e~Ch~a_r_a~ct_e_rs~ar_e-r-co_p_iTe_d_i~nt~o
can be represented as shown below: __va~r_ia_b~1_~_s_1r-0_n_eT"""a_ft~er~a_nd~s_tr
.

M: s1

K
R
I
S s2
H
N
A
.J

Output: s1 = "RAMA" and s2 = "KRISHNA"

Example 3.4.3.1.1: What will happen if the following program is executed?

void maim)
{
char sl [15];
char s2[15];

scanf("%4s", sl);
scanf("%s", s2);

printf("%s\n",sl );
printf("%s\n",s2);
}
3.16 Q Strings

Solution:
Step 1:
Let us see "What is the significance of %4s in scanf("%4s", sl)?" Here, the
field width specification %4s is used to protect the user entering too much data
for the first string sl. The scan! reads 4 characters from the keyboard and
insert \0 at the end. Now, if the user accidentally enters more than 4 characters,
the extra characters are ignored by this statement but, will be left in the input
stream. For example,

Input
RAM~SHNAPARAMAHAMSA

In the above input "RAMA" is copied into sl and "KRISHNA


PARAMAHAMSA" is still in the input stream. So, sl = "RAMA"

The utput obtained after executing each statement is shown below:

PROGRAM TRACING

void rnaint)
{
char sl[5];
char s2[15];
Input
scanf("%4s", s 1); RAMAKRISHNA PARAMAHAMSA
sl = "RAMA"
scanf("%s", s2); s2 = "KRISHNA"
Output
printf("%s\n",sl ); RAMA
printf("%s\n",s2); KRISHNA
}
~ Systematic Approach to Data Structures using C 3.,17
Suppose, we want only first name in s1 and we do not want the remaining characters
of first string to be copied into string s2. In such case, it is required to remove the
extra characters entered for s1 from the input stream. This can be achieved using the
following code:

PROGRAM TRACI G
#include <stdio.h>

void maim)
{
char sl[5];
char s2[15];

1* Accept 4 characters *1 \
scanf("%4s", sl); Input
RAMAKRISHNA PARAMAHAMSA
s1 = "RAMA"
1* Remove rest of s 1
characters from input *1
fflush(stdin); KRISHNA PARAMAHAMSA
is removed from the input stream

1* Read second string into s2 *1


scanf("%s", s2); VIVEKANANDA
s2 = "VIVEKANANDA"
Output
printf("sl = %s\n", s1); RAMA
printf("s2 = %s\n", s2); VIVEKANANDA
}

Step 1: scanf("%4s", s1): The first four characters namely "RAMA" ending with \0 is
copied into s1. So, s1 = "RAMA"

Step 2: fflush(stdin) removes all characters following "RAMA" i.e., the string
"KRISHNA PARAMAHAMSA" is removed from the input stream

Step 3: scanf("%s",s2): The string VIVEKANANDA is copied into s2.


So, s2 = "VIVEKANANDA"
3.18 Q Strings

ow, the question is "What is the disadvantage of scanf("%s", str)?" If the variable
str is declared as array of characters, a string without white spaces should be entered
i.e., it is not possible to store a string having white spaces such as \t and blank
characters. For example,
If the input entered through keyboard is "RAMA KRISHNA
PARAMAHAMSA" then only "RAMA" is stored in str. The remaining characters
are left unused in the input stream. If we want the entire string to be stored in str, it is
not possible using %s. This disadvantage we can over come using C format
specification known as edit set conversion code %[ .... J discussed in next section.

3.4.1.1 Edit set conversion code (%[ ... ])

Advantage Using edit set conversion code, it is possible to enter a line of text with
white spaces such as blank space, \t etc. For example, the text:
"Hello! How you feel about the book?"
can be read into a variable.

Now, let us see "What is the syntax of edit set conversion code?" The syntax is shown
below:
scanf( % [ J, str)
~
edit characters
where
edit characters represent the valid characters that are allowed in the string
and should be enclosed within' [' and ']'

ow, let us see "How edit set conversion code helps in reading the string?" The string
is read as shown below:
• Each character read by scanf is compared with edit characters.
• If the 'character read is in edit character set, it is copied into string str.
• The above procedure is repeated as long as the character read is In edit
character set.
• If the character read does not match with edit character set, the reading process
is stopped.
• The characters following the no matched character remain in the input stream.

Note: If the first character read is not in edit characters, the scanf is terminated and a
\0 is copied into str indicating it is a null string.
~ Systematic Approach to Data Structures using C 3.19

Note: The reading process can also be stopped with the following terminating
conditions:
• If end-of- file is detected the reading stops.
• If the field-width is specified and maximum number of characters have been
read, then also reading stops.

Now, the question is "How to read all the characters except \n using scanfi)?" This
can be done by including all the characters within square brackets as shown below:

scanf("%[ abcdefghijklrnnopqrstuvwxyz 123456789;", str]

or

scanf("%["'\n)", str); 1* read all characters except \n *1

Observe that it is difficult to include all characters except \n using the first scanf
Instead, it is easier to follow the second syntax including an invalid character
preceded by caret (").

Example 3.4.4: What will happen if the following statement is executed?


. scanf("%81 ["'\n]", str);

Solution: The scanf reads all the characters until the user types enter key (which
represent \n character). Once the user types enter key, all the characters typed except
\n are stored in str. The field width 81 is used to read and store first 81 characters.
The rest of the characters are not stored in str but are left in input stream. To delete
all these extra characters from the input stream, we use rtlush(stdin).

3.4.2 Formatted output function - printf()

, Now, let us see "What are the various options that can be used with printfl" The
various options associated with printf are shown below:

Various options
used in printf
-E Filed width specification
Precision specifier
Left justification
3.4.2.1 Field with specification

The syntax to use field width specification in printf statement is shown below:
%ws
3.20 ,!;1,Strings

where
• w is the field with specified (number of columns used for printing string)
• s indicates that the string is being printed.

Tote: If the string to be printed is larger than the field width w, the entire string will
be printed.

ote: If the string to be printed is smaller than the field width w, then appropriate
number of blank spaces are padded at the beginning of the string so as to ensure that
field width w is reached.

Example 3A.2.1.1: What will happen if the following program is executed?


#include <stdio.h>

void maini)
{
char s[] = "RAMANANDA";

printf("%4s\n", s);
printf("% 15s\n" ,s);
}
Solution: The tracing of each statement along with output is shown below:
.l

PROGRAM TRACING-

#include <stdio.h>

void maint)
{
char s[] = "RAMANANDA";
Output
printf("%4s\n", s); RAM A NAN 0 A
Note: Since the string is larger than the field
width 4, entire string is printed

15 columns are reserved


---------------~---------------
printf("I% 15sl\n" ,s);
} ----- .....
v.-----
6 spaces are added in the beginning
~ Systematic Approach to Data Structures using C 3.21

3.4.2.2 Precision specifier

The syntax to use precision specifier in printf statement is shown below:


%w.ns
where
• w is the field with specified (number of columns used for printing string)
• n indicates that first n characters have to be displayed. This gives precision.

Example 3.4.2.2.1: What will happen if the following program is executed?


#include <stdio.h>

void mainO
{
char str[] = "RAMANANDA";

printf("%O.2s\n", str);
printf("%9.4s\n",str);
printf("%9.3s\n", str);
printf("%3.5s\n",str);
}

Solutions The tracing of each statement along with output is shown below:

PROGRAM TRACING

#include <stdio.h>

void mainO
{
char str[] = "RAMANANDA";

printf("%O.2s\n", str);

printf("%9.4s\n",str);

printf("%9 .3s\n" ,str);

printf("%3.5sn\",str);
3.22 ~ Strings

Note: Observe the following points:


• The string is printed right justification by default.
• If w > n, w columns are used to print first n characters. Ex: 2nd and 3rd printf
statements
• If w < n, minimum w columns are used to print first n characters. Ex: 1st and
4thprintf statements

3.4.2.3 Left justification

The syntax "to use field width specification in printf statement is shown below:
%-w.ns
where
• - just before w indicates that string is printed using left justification.
• w is the field with specified (number of columns used for printing string)
• s indicates that the string is being printed.

Example 3.4.2.3.1: What will happen if the following program is executed?


#include <stdio.h>

void maint)
{
char str[] = "RAMANANDA";

printf("%O.2s\n", str);
printf("%9.4s\n" ,str);
printf("%9.3s\n", str);
printf("%3.Ss\n",str);
}

Solution: The output remains same as the previous problem except that the string is
printed in left justified manner as shown below:

#include <stdio.h>

void maint)
{
char s[] = "RAMANANDA";
,
Q Systematic Approach to Data Structures usi

printf("%-0.2s\n", s); I IKlEJ


I
printf("%-9.4s\n",s); I
I
printf("%-9 .3s\n" ,s);
I
printf("%-3 .5s\n" ,s); I
} I

3.4.3 Un-formatted input functions - getst), fgetst)


C provides another alternative and easy approach to read a string of charac
getst) function. Now, let us see "What is the syntax? How does the func
work?'; The syntax is shown below:
gets(str);
where str is a array of characters.
Working: The function accepts string from the keyboard. The string en
include the white spaces. The input will terminate only after pressing <E
Once the <Enter Key> is pressed, a null character (\0) is attached at the '
string as shown below:

<Enter key> null (


t str
:_---:;H=E.;;;::L;;;;:L;..;:o:;...;\~n--+1
gets(str) --~) [}[]]II]1
Memory CO)
keyboard

Note: The newline(\n) character in the input indicates end of string. But, it j
by null(\O) character in the memory by the function getst).

3.4.3 Un-formatted output functions - putst), fputst)


Now, let us see "What is the syntax and How does the function putsi) w
syntax is shown below:
puts(str);
where str is an array of characters.

Working: This function displays a string of characters including the wh


All the characters will be displayed till the null char.acter(\O) is encoi
newline character \n is appended to the output.
3.24 .Q. Strings

Example 3.4.3.1: Program to convert all lower case letters to upper case letters.
PROGRAM TRACING
#include <stdio.h>
#include <ctype.h>
void maint)
{
char text[80];
int 1;
Input
printf("Enter the text\n"); Enter the text
gets(text); Hello How are you
/* convert the text into upper case */
for ( i = 0; text[i] l= '\0'; i++)
{
1
converted to uppercase

text [i] = toupper (text[i]); HELLO HOW ARE YOU


}
Output
puts(text); HELLO HOW ARE YOU
}

Note· Each character in the array text is accessed, converted into upper case using the
built in function touppert). Since, its prototype declaration is available in a header
file "ctype.h", this header file is included.

3.5 Arrays of strings


As we can have array of integers and array of floating point numbers, we can also
have array of strings. ow, let us see "How to declare an array of strings?" To create
an array of strings, we should use two-dimensional array as shown below:
char a[row] [col];
I 1_» Maximum length of each string
~ Number of strings
'-------+ Name of the array
Suppose, it is required to store the names of 5 students. In such case, we can have the
following declaration:
char a[5][20];
Q Systematic Approach to Data Structures using C 3.25

From the above declaration it is observed that:


• 5 in the declaration indicate that at most 5 student names can be stored
• 20 indicate that each name can have at most 20 characters.

Example 3.5.1: Give the memory representation for the following initialization
statement:
char a[5] [11] = {
"DHARMARA YA",
"BHIMA",
"ARJUNA",
"NAKULA",
"SAHADEV A"
};

Solution: From the declaration, it is clear that a is a 2-dimensional array with 5 rows
and 15 columns. These five memory locations are initialized with values terminated
by \0 as shown below:
o 1 2 3 4 5 6 7 8 9 10
D H. A R M A R A Y A \0
B H I M A \0
A R J U N A \0
a~~ N A K U L A \0
4 S A H A D E V A \0
t
In general, using a[i] for i = 0 to 4, we can access each name.

Note: It is clear from the above figure that each name can be accessed using array a
along with index values 0, 1, 2, 3 and 4. Thus using a[O], a[l], a[2], a[3] and a[4] we
can access all the names. The array elements can be printed as shown below:

for (i = 0; i <= 4; i++)


{
printf("%s\n", a[i]);
}
The programming statement to read 5 names can be written as shown below:
for (i = 0; i <= 4; i++)
{ Note.using scanf("%s\n", a[i]); is
scanf("%s", a[i]); the normal error committed by us.
} Remove \n after %s
3.26 .Q Strings
ow, let us see "What is ragged array? What is the disadvantage of ragged array?"
Observe from the above declaration that totally 5 x 11 = 55 memory locations are
reserved so that each name can have at most 11 characters including the \0 character.
Here, 11 memory locations are fixed for each string. So, even if the string is small, 11
memory locations are fixed for that small string. The remaining locations on the right
of the string may be empty giving rise to uneven (ragged) right border. For ragged
right border see the memory representation shown in example 3.5.1. This type of
array is called ragged array.
This is a disadvantage, as most of the memory is wasted if strings are small.
This disadvantage can be overcome using array of pointers. Now, we will see "How
to declare array of pointers using which we can store strings?" The declaration is
shown below:
char *a[5] = {
"DHARMARA YA",
"BHlMA",
"ARJUNA",
"NAKULA",
"SAHADEV A"
};

Observe that an array a has 5 memory locations each of which points to a name. The
memory representation is shown below:
1

o 2 3 4 5 6 7 8 9 10
a[O]
- D H A R M A R A IY IA I \0 I
a[l]
- B H I M A \0
a[2]
- A R J U N A \0
a[3]
- - N A K U L A \0
a[4]
- - S A H A D E V A I \0 I
-
Observe from this memory representation that there is no wastage of memory.
3.6 String" handling functions
Now, let us see "What is the need for string handling functions" String is not a
standard type, but it can be treated as a derived data type. So, we can not manipulate
the strings directly using C operators. For this reason, C provides a rich set of string
handling functions similar to mathematical functions such as sqrtt), powt), sinet) etc.
Now, let us see "What are string handling functions in C?" The vanous string
handling functions that are supported in C language are shown below:
Q Systematic Approach to Data Structures using C 3.27

String functions Description of each function


strlen(str) Returns length of the string str
strlen( str) Returns length of the string str
strcpy( str 1, str2) Copies the string str2 to string str1
strncpy( str 1,str2,n) Copies at most n characters of string str2 to string str1
strcat( strl ,str2) Append string str2 to string str 1
strncat(strl,str2,n) Append first n characters of string str2 to string str 1
strcmp(strl,str2) Compare two strings str1 and str2
strstr( str 1,str2) Finds the first occurrence of string str2 in string str 1
strset( str l,c) Sets all occurrence in strl to the character identified by c.
strchr( str,c) Scans the string str for the first occurrence of character c.
strrchr(str,c) Find the last occurrence of the character c in string str.
strlwr( str) Converts the string str to lowercase.
strupr( str) Converts the string str to uppercase
strrev( str) Reverses the string str.

Note:All these functions can be accessed by including the header file string.h in the
beginning of the program. Before using these functions, the programmer should
ensure that the string is terminated by null character '\0'. Otherwise, the result will be
unpredictable and we get wrong results. The descriptions of some of these functions
are provided in the next section.

3.6.1 strlen{str) - String Length


First, let us see "What is the prototype of the function strlen?"The prototype of strlen
defined in header file "string.h" is shown below:

int strlen (char *str);

Let us see "What is the role of the function strlen( str)?" This function returns the
length of the string str i.e., It counts all the characters up to '\0' but, except '\0'. So,
an empty string has length zero. The program to show its usage is shown below:
3.28 Q Strings

Example 3.6.1.1: Program to show the usage of strlent)


PROGRAM TRACING
#include <stdio.h>
#include <string.h>
void maim)
{
char str[] = "RAMA"; str=
o 1 2 3 4
printf("Length = %d\n", strlen(str)); . Length = 4
}

Now, let us see "How to implement strlent) function?" Consider the string "SSVVIT"
str

To start with, the index variable i is zero. Now, keep incrementing the index variable i
as long as str[i] is not equal to '\0' using the statement:
i = 0;
while (str[i] != '\0')
i++;
Once control comes out the loop, the index variable i gives the length of the string.
The complete C function is shown 15elow:

Example 3.6.1.2: Function returning the string length

Using arrays I Using pointers


int my_ strlen( char str[]) lint my_stden(char *str) lint my_strlen(char *str)
{ I{ I{
int i = 0; lint i = 0; I char *ptr = str;

1* compute th e Iengt h *1 II 1* compute length *1 II while (*ptr++)


wh.ile (str[i] != '\0') I while (*(str +i) )
++ i++; I
1 ; I I return ptr-str;
return i; I return i; I}
} I} I
~ Systematic Approach to Data Structures using C 3.29

The complete program which reads the string and compute the length using user-
defined function is shown below:

Example 3.6.1.3: Program using the user-defined function my strleru)

#include <stdio.h>

/* Include: Example 3.6.1.2: tocompute the length */

PROGRAM TRACING

void maint) I
{ I
char str[20];
int 1;
I
I Input
printf("Enter the string\n"); I Enter the string
gets(str); I Rama
i= my_strlen(str) ;
I i= 4
I
I Output
printf("Length = %d\n", i); I Length = 4
I
}

3.6.2 strcpy(dest, src) - string fOgy

First, let us see "What is the prototype of the function strcpy?" The prototype of
strcpy defined in header file "string.h" is shown below:

char *strcpy (char *dest, char *src);

Now, we shall see "What is the role of the function strcpy?" The function strpcy
copies the contents of source string src to destination string dest including '\0'. So,
the size of destination string dest should be greater or equal to the size of source
string src. After copying, the original contents of destination. string dest are lost. The
program to show its usage is shown below:
3.30 Q Strings

Example 3.6.2.1: Program to show the usage of strcpyt)


PROGRAM TRACING
,
#include <stdio.h>
#include <string.h> ,
I
void main(void)
{ 'stc~
char src[] = "RAMA"; I 0 1 2 3 4
char dest[ 6]; I ~ ~ ~ ~ ~
dest I ~ I A I M I A I \0 I I
strcpy( dest, src); 1 2 3 4 5
"I Output
printf("Destination string %s", dest); I Destination string = RAMA
}
=
,
Now, let us see "How to implement strcpyt) function?"

Design: Copy each character of source string src to destination string dest as long as
chara ter is not '\0'. This is pictorially represented as shown below:
dest ~ src
SIT ~ I
o dest[O] = src[O]
1 dest[l] = src[l]
2 dest[2] = src[2]
3 dest[3] = src[3]
4 dest[4] = src[4]
5 dest[5] = src[5]
6 t t
In general, dest[i] = src[i]
where initial value of i = 0

Observe from above figure that as long as src[i] != '\0' it is required to copy src[i] to
dest[i] and increment i after copying each character. The partial code can be written
as shown below:
~ Systematic Approach to Data Structures using C 3.31

1* Copy as long as \0 is not encountered *1


i = 0;
while (src[i] != '\0')
{
dest[i] = src[i];
i++;
}

Note: It is the responsibility of the programmer to attach null character '\0' at the end
of the string. The equivalent code for this is shown below:

1* Terminate the string with null character *1


dest[i] = '\0';

So, the final function to copy the contents of source string src to destination string
dest using arrays as well as using pointers is shown below:

Example 3.6.2.2: Function to copy string src to string dest using 3 m~thods.

Using arrays Using Pointers

void my_strcpy(char dest[], char srcj'[) II void


{ my_strcpy(char *dest, ~har *src)

{ int i = 0; I 1* .s,9pythe string *1


while ( *src != '\0')
I
*dest++ = *src++;
1* Copy the string *1 I
while (src[i] != '\0') I 1* attach null character at end *1
{ *dest = '\0';
dest[i] = src[i];
i++; b
} I Note: Following is most efficient one
I. void my_strcpy(char *dest, char *src)
1* Attach null character at the end *A {
dest[i] = '\0'; I. while (*dest++ = *src++)
}
I , .
}

Note: Observe the null statement ";" in the third version of my_strcpy. It does nothing.
The condition in the while loop i.e., *dest++ = *src++ is repeatedly executed and
each character of the source is copied into destination including \0. Once \0 is reached,
the condition fails and control comes out of the loop.
3.32 Q Strings

The complete program which uses the user defined function is shown below:

Example 3.6.2.3: Program using the user-defined function mystrcpyt)


#include <stdio.h>
/* Include Example 3.6.2.2 to compute the length */
void maint) I TRACING
{ I
char src[20];
I
char dest[20];
I Input
printf("Enter the string\n"); I Enter the string
gets(src); I RAMA
I
my_ strcpy( dest, src); I dest = "RAMA"
I Output
printf("Dest string = %s\n", dest); I Dest string = RAMA
}

Now, let us take some examples and see how strcpy works.

E~mple 3.6.2.4: Consider the following program segment.

char s 1[] = "RAMA";


char s2[] = "BHlMA";
char s3 [] = "KRISHNA;

strcpy(sl, s3);

"What is the output after executing the statement strcpy()?"

Solution: The memory representation for the strings s1, s2 and s3 before executing
strcpyi) is shown below:

,;:::,--K~~~~y-~::=~==~=~=--:7
s1 s2 s3
ow, let us execute the statement:
strcpy(sl, s3);
Q Systematic Approach to Data Structures using C 3.33

After executing, the memory organization for the strings sl, s2 and s3 is shown
below:
Copy from s3 to sl

r 'r------ ------
~K~~ __ ~~~~~~
sl s2 s3

Observe that the string s2 has the value "NA" and original contents of s2 are
destroyed after strcpyt).

Note: For correct operation of strcpyt), the destination .string sl should be greater
than or equal to source string s3. But, this is not so in this example. The size of sl is
too small to hold the string of s3. Here, the contents of s3 including \0 is accessed and
will be copied into string sl. Since there is no space is sl to hold the data, the
remaining data of s3 is copied to string s2 also. This destroys the contents of string s2.

3.6.3 strncpy( dest, src,n) - string number f.oQY

First, let us see "What is the prototype of the function strncpy'l" The prototype of
strncpy defined in header file "string.h" is shown below:

char *strncpy (char *dest, char *src, int n);

where
• dest is the destination string
• src is the source string
• n is the number of bytes to be copied into destination string
Let us see "How does the function stmcpy work?" The basic functionality of this
function is to copy n characters from source string to the destination string. Based on
the value of n, the copying activity is performed as shown below:
• If source string is less than n, the entire string is copied from source to
destination and then null characters are placed in the destination string until n
characters have been copied.
• If the source string src is longer than n characters, copying stops after n
characters have been copied. Then, the destination string will not have a
delimiter \0 and hence it will be invalid string.
3.34 Q Strings

Example 3.6.3.1: Show the memory representation before and after executing
strncpy in the following program segment:
char sl[10];
char s2[8] = "RAMA";
strncpy(sl, s2, sizeof(sl));

Solution: The memory representation for the variables sl and s2 before executing
strncpy is shown below:

After strncpy(sl, s2, 10);

Example 3.6.3.2: Show the memory representation before and after executing
strncpy in the following program segment:
char sl[5] = "RAMA";
~ char s2[5] = "VEER"
char s3[1 0] = "BHISHMA";

strncpy(sl, s3, 5);

Solution: The memory representation for the variables sl, s2 and s3 before executing
strncpy is shown below:

r.---- sl,A•..••
-- •..••.
"
s2
r~---A---..." s3
~_--------"--------_"'
8 9
After strncpy(sl, s3, 5);
~ Systematic Approach to Data Structures using C 3.35

Note that sl is invalid string since it has no delimiter \0. If we print sl, s2 and s3 the
following output is obtained: .
s 1 = BHISHVEER (Invalid string s 1: It is not ending with \0)
s2 = VEER .
s3 =BHISHMA
Note: Care should be taken so that the string sl (destination string) is sufficiently
larger.

3.6.4 strcat(sl, s2) - string concatenate

First, let us see "What is the prototype of the function strcat? and how does it work?"
The prototype of strcat defined in header file "string.h" is shown below:

char *strcat (char *s 1, char *s2);


where
• sl is the first string
• s2 is the second string
Working: The function copies all the characters of string s2 to the end of string s1.
The delimiter of string sl is replaced by the first character of s2. Only condition is
that the size of sl should be sufficiently long enough to store a string whose length is
s1 + s2. For example, the memory representation for the variables sl and s2 before
executing strcat is shown below:

789 5 6 7

After strcat(sl, s2);

Note: Length of resultant string = length of string sl + length of string s2 and the
copied string in the destination string is shown in boldface

Now, let us see "How to implement strcau) function?" Let us design our own
function strcat and call this function as my_strcat.

Design: This is very simple and straightforward approach. Given two strings sl and
s2 perform the following activities:
3.36 .Q Strings

• Obtain the position of the null character of strl as shown below:


Using arrays Using pointers
1* obtain position of null character of strl *1 while (*strl)
for ( i = 0; strl [i] != '\0'; i++) str1++;

• Copy the second string to the end of the first string

1* Copy second string to destination string *1 while (*str2)


for (j = 0; str2[j] != '\0'; j++) {
str1[i+j] = str2[j]; *str1 ++ = *str2++;
}
• Attach null character at the end using the statements:
str1 [i+j] = '\0' *strl = '\0';

So, the complete C function to implement my_strcat is shown in example 3.6.4.1.

Example 3.6.4.1: C function to implement my_strcat using arrays and pointers


Using arrays Using pointers
void my_ strcat( char str 1[J, char str2 []) void my strcat(char *str1, char *str2)
{ {
. 1* obtain position of\O of strl *1 1* obtain position of\O of strl */
for (i = 0; strl[i] != '\0'; i++) while (*str1).
str1++;

1* Copy str2 to end of str1 *1 1* Copy str2 to end of strl *1


for ( j = 0; str2[j] != '\0'; j++) while (*str2)
str1[i+j] = str2[j]; *str1 ++ = *str2++;

1* Attach \0 to the end of strl *1 1* Attach \0 to the end of str1 *1


str1 [i+j] = '\0'; *str1 = '\0';
} }

Note: The strcat using pointers can be written more efficiently and in very compact
manner as shown below: -,
~ Systematic Approach to Data Structures using C 3.37

void my_strcat(char *strl, char *str2)


{
while (*strl)
str 1++;

while (*strl ++ = *str2++)

"The complete program which uses the my_strcat is shown in example 3.6.4.2.

Example 3.6.4.2: C function to implement my_strcat using arrays and pointers

#include <stdio.h>

/* Include example 3.6.4.1: Function to implement my_strcat */

void maint) TRACING


{
char sl[15] = "RAMA"; sl = "RAMA"
char s2[] = "KRISHNA"; s2 = "KRISHNA"

my_strcat(sl,s2); After concatenation


Output
printf("Concatenated string = %s\n",s 1); Concatenated string =
} RAMAKRISHNA

3.6.5 strncat(sl, s2,n) - string-number concatenate

First, let us see "What is the prototype of the function strncat? and how does it
work?" The prototype of strncat defmed in header file "string.h" is shown below:

char *stmcat (char *sl, char *s2, int n);


where
• sl is the first string
• s2 is the second string
• n is the number of characters of string s2 to be concatenated.
3.38 Q Strings

Working: If the length of string s2 is less than n, the function copies all characters of
string s2 to the end of string sl. The delimiter of string sl is replaced by the first
character of s2. The working is exactly same as strcat shown in previous section. But,
if the length of string s2 is grater than n:then first n characters of string s2 are copied
to the end of sl attaching \0 at the end. For example, the memory representation for
the variables sl and s2 before executing strncat is shown below:

After strncat(sl, s2,4);

3.6.6 strcmp(sl, s2) - string £ompare

First, let us see "What is the prototype of the function strcmp? and how does it
work?" The prototype of strcmp defined in header file "string.h" is shown below:

int strcmp (char *sl, char *s2);


where
• ~ sl is the first string
• s2 is the second string

Working: This function is used to compare two strings. The comparison starts with
first character of each string. The comparison continues till the corresponding
characters differ or until the end of the character is reached. The following values are
returned after comparison:
• If the two strings are equal, the function returns 0
• If sl is greater than s2, a positive value is returned
• If sl is less than s2, the function returns a negative value.

Now, let us see "How to implement strcmp without using built in function?"

Design: Given the two strings sl and s2, the comparison starts with first character of
each string and continues as long as they are equal. During this process, both the
pointers sl and s2 are incremented to point to the next character and if end of the
character is encountered, with respect to sl, control comes out of the loop. The
equivalent statement for this can be written as shown below:
Q Systematic Approach to Data Structures using C 3.39

while (*sl = *s2)


{
if (*sl = '\0') break; /* Go out ofloop, with null character of sl */

s 1++, s2++; /* Point to next character of each string */


}

The control comes out of the loop if corresponding two characters differ or null
character \0 is encountered. Since the characters are represented by numerical values
(ASCII), let us take the difference of corresponding characters which results in zero,
positive or negative numbers using the follo:ving statement:

return *sl - *s2;

The complete function is shown in example 3.6.6.1.

Example 3.6.6.1: C function to implement my_strcmp

int my_ stcmp( char *s 1, char *s2)


{
while (*sl = *s2) /* Compare as long as the characters are equal */
{
if(*sl = '\0') break; /* Go out ofloop, with null character ofs1 */

s 1++, s2++; /* Point to next character of each string */


}

return *sl - *s2; /* Difference of two characters */


}

The above function returns one of the following values:


• zero ifs1 = s2
• positive if sl > s2
• negative if sl < s2

Now, "How to use the above value in the calling function?" The function my_strcat
should be called as shown below:
3.40 Q Strings

The complete program showing the usage of user defined function my_strcmp is
shown below:

Example 3.6.6.2: C program showing the usage of my_strcmp


#include <stdio.h>
1* Include: example 3.6.6.1: Function my_strcmp *1
void maint)
{
char sl[] = "RAMA";
char s2[] = "KRISHNA";
int difference;

difference = my_strcmp(sl, s2);

if (difference = 0)
printf("String sl = string s2\n");
else if (difference >0)
printf("String sl > string s2\n");
else
printf("String sl < string s2\n");
}

Example 3.6.6.3: Let sl = "RAMA" and s2 = "RAMA". What is the output of


strcmp(sl, s2)?

Solution: The two strings sl and s2 are compared as shown below:

s1 R =~ R s2
sl A =~ A s2
sl M =~ M s2
sl A =~ A s2

r sl \0 =~ \0

Comparison stops at this point since *sl = \0


s2

Note: By executing sl ++ and s2++ we can access subsequent characters and compare
the two strings. But, once \0 is encountered in sl, control comes out of the loop.
*sl - *s2 = \0 - \0 = 0 and hence two strings are equal.
Q Systematic Approach to Data Structures using C 3.41

Example 3.6.6.4: Let s1 = "RAM" and s2 = "RAMA". What is the output of


strcmpts), s2)?

Solution: The two strings s1 and s2 are compared as shown below:

I---
s1;t=~R
s1 A =~ A s2 s2
>-=-=-
s1 M =~ M s2

r s1 \0 f.~X
~
s2

stops at this point since \0 is not equal to A

Note: By executing sl++ and s2++ we can access subsequent characters and compare
the two strings. Control comes out of the loop since '\0' is not equal to 'A'. So,

*sl - *s2 = 0 - 65 = - 65 COis ASCII value 0[\0,65 is ASCII value of 'A'

Since, the result is negative, string s1 < string s2

Example 3.6.6.5: What would be printed from the following program block?
char sl [5] ::;:"xyzt";
char *s2 = "xyAt";
int dif;
dif= strcmp (sl, s2);
p rintfC"%d\n" ,dif);
Solution: The two strings s1and s2 are compared as shown below:

=~ x s2
=~ s2
f.~

r
A s2
t
\0

Note: Comparison stops at this point since 'z' is not equal to 'A' and control comes
out of the loop. So, diff'= *sl - *s2
='z'-'A'
= 122 - 65 = 57
Output: 57 which is positive and indicates s1 is greater than s2.
3.42 ~ Strings

3.6.7 strncmp(sl, s2, n) - string number Qompare

First, let us see "What is the prototype of the function strncmp'l and how does it
work?" The prototype of strncmp defined in header file "string.h" is shown below:

int strncmp (char *s1, char *s2, int n);

where
• sl is the first string
• s2 is the second string
• n is the number of characters to be compared

Working: This function is used to compare first n number of characters in two


strings. The comparison starts with first character of each string. The comparison
continues till the corresponding characters differ or until the end of the character is
reached or specified number of characters have been tested. The following values are·
returned after comparison:
• If the two strings are equal, the function returns 0
• If sl is greater than s2, a positive value is returned
• If sl is less than s2, the function returns a negative value.

The following table shows the results for strncmp(sl, s2, n) with different values of
sl, s2 and n.

Stringl String2 n Return value Output


BHIMAl23 BHIMAl23 8 0 Stringl = String2
BHIMA123 BHlMA456 5 0 Stringl = String2
BHIMAl23 BHlMA456 6 negative Stringl < String2
BHIMAl23 BHIMA 5 0 Stringl = String2
BHlMAl23 BHIMA 6 positive String 1 > String2
BHIMA BHIMAA 6 negative . Stringl <String2
BHIMA ARTUNA o or-1 0 Stringl = String2

3.6.8 strchr(sl, ch) - string containing character

First, let us see "What is the prototype of the function strchr? and how does it work?"
The prototype of stchr defined in header file "string.h" is shown below:

char *strchr (char *s, char ch);


Q Systematic Approach to Data Structures using C 3.43

where
• s is the first stririg
• ch is character to be searched for

Working: This function searches for the first occurrence from the beginning of the
string and following values are returns:
• On success, a pointer to the character is returned.
• On failure, NULL is returned

Example 3.6.8.1: Let s = "MONALIKA". What is the output obtained after executing
each of the statements one after the other?
p = strchr(s, 'A');
q = strchr(s, '\0');
r = strchr(s+5, 'A');

Solution: The memory representation and the pointer p after executing the statement:

p = strchr(s, 'A');

p
Note: Here, 'A' is the character to be searched and p points to the first occurrence of
'A'. Also, P - s = 3 gives the position of character 'A' in the string "MONALIKA"

The memory representation and the pointer q after executing the statement:

q = strchr(s, '\0');

Note: Here, '\0' is the character to be searched and q points to the first occurrence of
'\0'. Also, q - s = 9 gives the position of character '\0' in the string "MONALIKA"
3.44 Q Strings

The memory representation and the pointer r after executing the statement:

r = strchr(s+5, 'A');

Note: Here, 'A' is the character to be searched from s+5 onwards and r points to the
first occurrence of 'A' from s+5. Also r-s = 7 gives the position of character 'A' in
the string.

3.6.9 strrchr(sl, ch) - string rear character


First, let us see "What is the prototype of the function strrchr'l and how does it
work?" The prototype of strrchr defined in header file "string.h" is shown below:

char *strrchr (char *s, char ch);


where
• s is the first string
• ch is character to be searched for
.lWorking: This function searches for the first occurrence from the end of the string
and following values are returned:
• On success, a pointer to the character is returned.
• On failure, NULL is returned

Example 3.6.9.1: Let s = "MONALIKA". What is the output obtained after executing
each of the statements one after the other?
p = strrchr(s, 'A');

Solution: The memory representation and the pointer p after executing the statement'
p = strrchr(s, 'A');

p
~ Systematic Approach to Data Structures using C 3.45

ote: Here, 'A' is the character to be searched and p points to the first occurrence of
'A' in the string "MONALIKA" from the end, Also, p - s = 7 gives the position of
character 'A' in the string "MONALIKA"

Example 3.6.9.2: What would be printed from the following program block?
char s 1[50] = "xyzt";
char *s2 = "uabefgnpanm";
char *s3;
char *s4;
char *s5;
char *s6;
s3 = sl;
s4 = s2;
strcat (s1, s2);
s5 = strchr(sl, 'y');
s6 = strrchr(s2, On');
printf("%s\n", s3);
printf("%s\n", s4);
printf("%s\n", s5);
printf("%s\n", s6);

Solution: The memory representation for the various variables when the program is
being executed is shown below:
sl
char sl[50] = xyzt"; s3[IJ ~
char *s2 = uabefgnpanm"; sS[IJ
char *s3'
char *s4~ s4 [IJ
char *s5; s6 [IJ
char *s6;

1* After executing *1 s3
s3 = sl;
s4 = s2; ss[IJ
s4

s6 [IJ

-,
3.46 Q Strings

/*After executing */
strcat (sl, s2); s3

/* After executing */
s5 = strehr'(s l , 'y');
s6 = strrchr(s2, On');

s3

s5
s2
S4G-+~

s6 [:J
Output
printf("%s\n", s3); xyztuabefgnpanrn
printf("%s\n", s4); uabefgnpanrn
printf("%s\n", s5); yztuabefgnpanrn
printf("%s\n", s6); nrn

3.6.10 strstr(s1, s2) - string in string


First, let us see "What is the prototype of the function strstr? and how does it work?"
The prototype of strstr defined in header file "string.h" is shown below:

char *strstr (char *str, char *sub_str);


where
• str is the string
• sub_str is sub string be searched in str
Working: This function is called string in string (strstr). This function searches the
substring in string for the first occurrence from the beginning. The following values
are returned:
• On success, a pointer to the character is returned.
• On failure, NULL is returned
Q Systematic Approach to Data Structures using C 3.47

Example 3.6.10.1: Let s = "MONALIKA", What is the output obtained after


executing the following statement?
p = strstrr(s, "ALlKA");

Solution: The memory representation and the pointer p after executing the statement:
p = strrchr(s, 'ALlKA');

o 1 2 345 6. 7 8
slMlolNIAILIIIKIAlwl
i
p
Note: Here, p-s = 3 gives the position of the substring "ALIKA" in the string
"MONALIKA"

Example 3.6.10.2: What would be printed from the following program block?
char sl[50] = "uabefgnpanm";
char *s2 = "ab";
char *s3 = "pan";
char *s4 = "bef';
char *s5 = "panam"
char *s6;
char *s7;
char *s8;
char *s9'
, ,

s6 = strstr(sl, s2);
s7 = strstr(sl, s3);
s8 = strstr(sl, s4);
s9 = strstr(sl, s5); .

printf("%s\n", s6);
printf("%s\n", s7);
printf("%s\n", s8);
printf("%s\n", s9);
3.48 Q Strings

Solution: The memory representation for the various variables when the program i
being executed is shown below:

char s1[50] = "uabefgnpanm"; u a b e


char *s2 = "ab" 0 L[ilillQ].::.....J.~..L..:.......L....:.-J.-=--...l..£!......l....~....L.....l.---L..--'_....l....-
, s2 r:::L..-- a b \0
char *s3 = "pan"; L-J . ,..
char *s4 = "bef'; s3~~
char *s5 = "panam" s4~~
char r:::L..--~
char
**s6°
7'
s ;
s5L-J ,..~
char *s8°, s6m
char *s9; s7m
s8m
s9m

s6 = strstr(sl, s2); 1* returns pointer to ab in the string s1 *1


s1

s6

s7 = strstr(sl, s3);

s7 s3~~

s8 = strstr(sl, s4); 1* Returns pointer to bef in the string sl *1


s1

s8 s4~~
s9 = strstr(sl, s5);

s9B-+INULL I ~~
s5
ote: Since string panam is not present in string sl, the function returns NULL
Q Systematic Approach to Data Structures using C 3.49

Output
printf("%s\n", 86); abefgnpanrn
printf("%s\n", s7); panrn
printf("%s\n", s8); befgnpanrn
printf("%s\n", s9); (null)

3.6.11 strspn(sl, s2) - s!I"ingman


First, let us see "What is theprototype of the function strspn? and how does it work?"
The prototype of strspn defined in header file "string.h" is shown below:

int strspn (char *s 1, char *s2);

where sl and s2 are two strings.


Working: This function keeps comparing each character of string sl in order from
left to right with contents of string s2. As long as the corresponding character of sl is
available in s2, the search continues with next character. The search stops when a
character in sl does not match with any of the characters in s2 ..The function returns
the following values:
• returns number of characters in sl that have so far successfully matched with
one of the characters of s2.
• return 0 - if no characters in sl match with any of the characters of s2.

Example 3.6.11.1: Let strl = "BHISHMACHARI" and str2 = "IHSBM" What is the
output if the following statement is executed:

Ie? = strspn (str1, str2);

Solution: The memory representation for these two strings is shown below:

strl str2
o 1 2 3 4 5 6 7 8 9 10 11 12 o 1 2 3 4 5
IBIHIIISIHIMIAlclHIAIRlllwl ~
y

These characters are


available in str2.
'A' is the first character in strl which is not available
in str2. The number of characters that have been
scanned so far = 6. So, the function returns 6.
3.50 Q Strings

3.6.12 strcspn(sl, s2) - string number §Qan

First, let us see "What is the prototype of the function strcspn'l and how does it
work?" The prototype of strcspn defined in header file "string.h" is shown below:

int strcspn (char *s1, char *s2);

where sl and s2 are two strings.

Working: This is complement of strspn. This function keeps comparing each


character of string sl in order from left to right with contents of string s2. As long as
the corresponding character of sl is not available in s2, the search continues with next
character. The search stops when a character in sl match with any of the characters in
s2. The function returns the following values:
• returns number of characters in sl that have not been matched with one of the
characters of s2.
• return length of the string - if no characters in sl match with any of the
characters of s2.

Example 3.6.12.1: Let str1 = "BHISHMACHARl" and str2 = "VASUDEV". What


is the output if the following statement is executed:

len = strcspn (str1, str2);

Solution: The memory representation for these two strings is shown below:

These characters are


not available in str2.
'S' is the first character in str1 which is available in str2.
The number of characters that have been scanned so far
is equal to 3. So, the function returns 3.
Q Systematic Approach to Data Structures using C 3.51

Example 3.6.12.2: Let str1 = "BHISHMACHARI" and str2 = "GOD". What is the
output if the following statement is executed:
len = strcspn (str l, str2);
Solution: The memory representation for these two strings is shown below:

strl str2
o 1 2 3 4 5 6 7·8 9 10 1112 o 1 2 3
~

These characters are


not available in str2.
Since no character in str1 is available in str2, the number
of characters that have been scanned so far is equal to
length of sl = 12. So, the function returns 12.

Example 3.6.12.3: What would be printed from the following program block?
char *sl = "abefgnpanm";
char *s2 = "ab";
char *s3 = "pan";
char *s4 = "bef';
char *s5 = "panarn";
int dl;
int d2;
int d3;
int d4;
dl = strspn(sl, s2);
d2 = strspn(sl, s3);
d3 = strcspn (sl, s4);
d4 = strcspn (sl, s5);
printf("%d %d %d %d\n", dl, d2, d3, d4);

Solution: The memory representation for the various variables when the program is
being executed is shown below:

char *s 1 = "abefgnpanm"; sl~ a b e f


char *s2 = "ab"; s2~[illISQ]
3.52 Q Strings

*s3 = "pan";
char
char *s4 = "bef';
s3G---+~
char *s5 = "panam"; s4G---+~
int dl; s5G---+~
int d2;
int d3;
int d4; s2
Available in s2
G---+~
r-"-..
dl = strspn(sl, s2);

d1 = 2 because, 'e' is the l"


character not available in s2
s3
d2 = strspn(sl, s3);
Available in s2 G---+[ilili]JQ]
s1G---+ a b e f m \0
o 1 2 3 9 10
~
d2 = 1 because, 'b' is the 1st
character not available in s3
s4
Not available in s2 G---+C8illJ::sQJ
d3 = strcspn (s1, s4);
1
~
d3 = 1 because, 'b' is the 1st
character available in s4
s5
G+~
d4 = strcspn (sl , s5);
s1G---+ a b e f \0
o 1 2 3 10
~
d4 = 0 because, 'a' is the 1st
character availa.ble in s5
printf ("%d %d %d %d\n", dl, d2, d3, d4); /* Output: 2, 1, 1, 0 */
~ Systematic Approach to Data Structures using C 3.53

3.6.13 strpbrk(sl, s2) - similar to string span

First, let us see "What is the prototype of the function strpbrk? and how does it
work?" The prototype of strpbrk defined in header file "string.h" is shown below:

char *strpbrk (char *sl, char *s2);

where s1 and s2 are two strings.

Working: This is exactly similar to strcspn. This function keeps comparing each
character of string s1 in order from left to right with contents of string s2. As long as
the corresponding character of s1 is not available in s2, the search continues with next
character. The search stops when a character in s1 match with any of the characters in
s2. The function returns the following values:
• returns pointer to the first matched character
• return NULL - if no characters in s1 match with any of the characters of s2.

Example 3.6.13.1: Let str1 = "BHISHMACHARI" and str2 = "VASUDEV". What


is the output if the following statement is executed?

p = strpbrk (str1, str2);

Solution: The memory representation for these two strings is shown below:

These characters are


not available in str2.
p points to'S'. Because'S' is the first character in str1
which is available in str2.
So, printf("%s",p) results in the output "SHMACHARI"

3.7 Memory formatting


Using scant we -know how to read integers, floating point numbers, strings etc that
are entered from the keyboard. Now, let us see "What are memory formatting
functions in C?"...The two memory formatting functions in Care shown below:
3.54 ~ Strings

Memory formattmg
functions in C
.-c sscanf
sprintf

Now, let us discuss each of these functions in detail.

3.7.1 sscanf (.§.tring scan format)

Let us see "What is the need for the function sscanfl" We know that we can read
integers, floating point numbers and strings from the keyboard. Instead of reading
these data from the keyboard, we can also read from a string stored in memory. For
this purpose, we use sscanf
Before studying various details, let us see "What is the prototype of the
function sscanf and how does it work?" The prototype of sscanf defined in header
file "string.h" is shown below:
convert into copy
appropriate converted
input type data
~r A ,~

int sscanf( char *str, "format string" , variables);


where
• str is the string. This contains the data to be scanned. The string might have
been read from a file or using gets function.
• format string consists of control string that is used in scanf For example, %d,
%f, %s etc.
• variables It is a list of variables into which the formatted data obtained will be
copied

Working: The function is same as the scanf function except that data is read from
memory instead of from the keyboard. The fiiiiction sscanf accepts the input from the
string in memory and based on the format string, the input data is converted into
appropriate data type and will be copied into respective variables as shown below:

sscanf
string
Ex: str = "Krishna 900 98.99"
n n n n/ name = Krishna
variables ~ total_marks = 900
average = 98:99
Q Systematic Approach to Data Structures using C 3.55

For example, consider the following program segment:


char str[] = "KRISHNA 99 98.99";
char name[ 10];
int total_marks;
float average;
sscanf(str, "%s %d %f', name, &total_marks, &average);
Let us see how the above program segment is executed:
• The first parameter string str="KRISHNA 99 98.99"
• The data in str="KRISHNA 99 98.99" is converted to string, integer and
float value using format string %s %d and %f
• The converted data is copied into· variables name, totaCmarks and average
respectively.

The program that displays the name, total_marks and average value obtained from
the string str is shown below: .

Example 3.7.1.1: Program showing the usage of sscanf.


#include <stdio.h>
void maim)
{
char str[] = "KRISHNA 99 98.99"; str = "KRISHNA 99 98.99"
char name[lO];
int total_marks;
float average;

sscanf (str,
"%s %d %f', Convert the string based on
name, &total_marks, &average format specifiers and copy
); into variables.
name = "KRISHNA"
total marks = 90
average = 98.99 -
Output
printf ("Name = %s\n",name); Name = "KRISHNA"
printf("Total marks = %d\n", total_marks); Total marks = 90
printf("Average = %f\n", average); Average = 98.99
3.56 Q Strings

Note: Except the first parameter, the rest of the syntax is same as the syntax used to
read a string, an integer and a float value from the keyboard. With the presence of the
first parameter str, the data is read from str instead of from the keyboard.

3.7.2 sprinf (string print format)

Let us see "What is the need for the function sprintfl" We know that we can display
integers, floating point numbers and strings on the display unit. Instead of displaying
on the display unit, we can also write the same data into a string in the memory. For
this purpose, we use sprintf.
Before studying various details, let us see "What is the prototype of the
function sprintf and how does it work?" The prototype of sprintf defined in header
file "string.h" is shown below:
convert from
appropriate
output typeto string input
,.---A--,. r A , ,--A----..
int sprintf(char *str, "format string", variables);
where
• variables It is a list of variables from which the data is read from the function
sprintf.
• format string consists of control string that is used in printf. For example,
.1 %d, %f, %s etc.
• str is the destination string. The various types of data are converted into string
format and stored in str. The string may be written into a file or can be printed
on the screen using puts function.

'Working: The function is same as the printffunction except that data is written into a
string instead on the display unit. The function sprintf accepts various data types from
the list of variables, and based on the format string, the data is converted into string
and will be stored in str as shown below:

sprintf

string
Ex: str = "Krishna 900 98.99"
nnnn name = Krishna
variables ~ total_marks ~ 900
average = 98.99
~ Systematic Approach to Data Structures using C 3.57

For example, consider the following program segment:

char str[30];
char name[lO] = "KRISHNA";
int total_marks = 900;
float average = 98.99;

sprintf(str, "%s %d %f', name, total_marks, average);

Let us see how the above program segment is executed:


• The third parameter is the list of variables which has the data. For example,
name = "KRISHNA", total_marks = 900, average = 98.99.
• This data which is in the form of string, integer and float value is converted
into string format using format string.
• The converted string is copied into string str.

The program that displays the name, total_marks and average value represented in
the form of string str is shown below:

Example 3.7.2.1: Program showing the usage of sprintf

#include <stdio.h>

void maint) TRACING


{
char str[30];
char name[lO] = "KRISHNA"; name = "KRISHNA"
int total_marks = 900; total marks = 90
float average = 98.99; average = 98.99

sprintf(str, "%s %d %f',


name, total_marks, average);
str = KRISHNA 90 98.99

Output
printf ("string = %s\n", str); string = KRISHNA 90 98.99
}
3.58 ~ Strings

3.8 Programming examples


Let us take some programmmg examples and see how to implement vanous
functions.

3.8.1.strrev(str) - string reverse

First, let us see "What is the prototype of the function strrev? and how does it work?"
The prototype of strrev defined in header file "string.h" is shown below:

char *strrev (char *str);

where str is the string to be reversed. This function reverses all characters in the
string str except the terminating null character '\0'. The function returns pointer tothe
reversed string. For example, consider the following program

#include <stdio.h> I TRACING


#include <string.h> I
I
void maint)
{
I
char str[] = "INDIA"; I str = "INDIA"
I
strrev( str); I str = "AID NI"
I Output
printf("String = %s\n", str); I AIDNI
}

3.8.2 Check for palindrome

Before writing the program, let us see "What is a palindrome?"

Definition: A palindrome is a string which happens to be the same if we read from


left to right and right to left. For example, the strings "LIRIL", "RADAR",
"MADAM", "MALAYALAM" etc. are strings of palindromes.

Now, let us see "How to write a C function to check whether the string is a
palindrome or not?"
\

Design: Let us write a function is~ali which returns 1 if the string is palindrome or
zero if not a palindrome. If the given string and reversed string is same let us return1
Q Systematic Approach to Data Structures using C 3.59
indicating the string is a palindrome. Otherwise, we return 0 indicating the given
string is not a palindrome. So, first let us see "How to reverse the string?" Consider
the following string strl.

Now, access each item of strl from left to right and store in str2 from right to left as
shown below:

str2[4] = strl[O] str2[.4-0] = strl[O]


str2[3] = strl[l] str2[4-1] = strl[l]
str2[2] = strl [2] which can be written as str2[ 4-2] = str 1[2]
str2[1] = strl[3] str2[4-3] = strl[3]
str2[0] = strl[4] str2[4-4] = strl[4]

In general, str2[4 - i] = strl[i]


str2[5-1-i] = strl[i]
str2[n-l-i] = strl [i] i = 0 to 4

where n is the string length of given string. Thus, in general the string can be reversed .
using the following code:

1* Compute the length of the string *1


n = strlen(strl);

1* Reverse the given string *1


for (i = 0; i < n; i++)
{
str2[n-l-i] = strl[i];
}

Once the string is reversed, if strl is same as str2, the string is a palindrome.
Otherwise, the string is not a palindrome. Now, let us compare each character of strl
with each character of str2. During comparing if corresponding characters do not
match the string is not a palindrome. So, the function should return O. The complete
function is shown below:
· 3.60 Q Strings

Example 3.8.2.1: Function to check whether the string is a palindrome or not


int is~ali (char strl [])
{
int 1, n;
char str2[15];

n = strlen(str1);
for(i == 0; i < n; i++) 1* Reverse the given string *1
str2[n-l-i] = strl[i];
1* Compare the given string and reversed string */
for (i = 0; i < n; i++)
if (str1 [i] != str2[i]) /* If there is a mismatch */
return 0; /* String is not palindrome */
return 1; /* String is a palindrome */
}

The complete program is shown below:

Example 3.8.2.2: Program to check whether the string is a palindrome or not


#include <stdio.h>
#include <string.h>
/* Include: Example 3.8.2.1: Function to check for palindrome */
void maint)
{
int flag;
char str[30];
printf("Enter the string\n");
scanf("%s",str);
flag = ispalitstr);
:if (flag = 0)
printf("The string is not a palindrome \n");
else.
prlntf(t'The string is a palindrome\n");
}
.Q Systematic Approach to Data Structures using C 3.61

3.8.3 Count vowels and consonants

Let us write a program to read a sentence and count the number. of vowels and
consonants. The solution to this problem is simple. Examine each character read,
check whether the character is an alphabet. If so, convert to lowercase and check
whether the character belongs to anyone of 'a', 'e', 'i', '0', 'u'. If so, increment
vowel_count else increment con_count. The corresponding C program is shown
below:

Example 3.8.3.1: Program to count vowels and consonants in a string

#include <stdio.h>
#include <ctype.h>
#include <string.h>

void maint) TRACING


{
char str[40], ch;
int i, vowel_count, con_count;
Input
printf("Enter the sentence"); Enter the sentence
gets(str); ARJUNA BHIMA
vowel_count = con_count = 0;
for (i = 0; i < strlen(str); i++)
{
if (isalpha(str[i]))
{ J •

ch = tolower(str[i]);
if (ch = 'a'[lch = 'e'llch = 'i'[lch = 'o'llch = 'u')
vowel_ count++; vowel count = 5
else ,/

con_ count++; con count = 6 .U

}
}
Output
printf("No. of vowels = %d\n",vowel_count); No. of vowels = 5
printf("No. of consonants = %d\n" ,con_count); No. of consnants = 6
}
3.62 Q Strings

3.8.4 String sorting

Let us write a program to read the names and sort them using bubble sort. The
function to sort the names using bubble sort is shown below:

Example 3.8.4.1: Function to sort names using bubble sort

void sort_names(char a[10][30], int n)


{ ~
int i,j;
char temp[30];

for (j=l ; j < n; j++)


{ ,
for (i = 0; i < n-j; i++)
{
if ( strcmp (a[i], a[i+ 1] ) > 0 )
{
strcpy (temp, a[i]);
strcpy (a[i],a[i+1]);
strcpy (a[i+l], temp);
}
}
}
}

The complete program to sort the names using the above function is shown below:

Example 3.8.4.2: Program to sort names using bubble sort

#include <stdio.h>
#include <string.h>

/* Include: Example 3.8.4.2: Function to sort the names */

void mairu)
{
char a[ 10] [30];
int 1, n;
Q Systematic Approach to Data Structures using C 3.63

printf("Enter the total number of names \nil);


scanf("%d" ,&n);

printf("Enter the names\n");


for (i = 0; i < n; i++)
scanf(" %s",a[i]);

sort_names(a, n);

printf("Sorted Names\n");
for (i =' 0; i < n; i++)
printf("%s\n" ,a[i]);
}

3.8.5 Upper case to lowercase and vice-versa

Let us write a program to read a sentence and replace the lowercase letters by
uppercase and vice versa. The solution to this problem is simple. Examine each
character read, check whether the character is uppercase letter. If so, convert it into
lower case else convert into to uppercase. The complete C program is shown in
below:

Example 3.8.5.1: Program to convert lower to upper and upper to lower case letters

#include <stdio.h>
#include <ctype.h>
#include <string.h>

void maim)
{
char str[30], dest[30];
int i;

printf("Enter the sentence");


gets(str);

strcpy(dest,str); /* Obtain a copy of the sentence */


3.64 ~ Strings

for (i = 0; i < strien( dest); i++)


{
if (dest[i] >= 'A' && dest[i] <= 'Z')
dest[i] = toiower(dest[i]); r:

else
dest[i] = toupper(dest[i]);
}

printf("The input sentence is\n");


puts(str);

printf("The case converted sentence is\n");


puts(dest);
}
~ Systematic Approach to Data Structures using C 3.65

Exercises

1. What is a string? How strings are represented?


2. What is fixed length string? What are the disadvantages of fixed length strings?
3. What is variable length format? What is length controlled string? What is
delimited string?
4. What is a string in C language? How the strings are stored in memory?
5. What is a string literal? What will happen when a string literal is defined? How to
reference string literals?
6. What is the difference between a character and string containing a single
character?
7. What is the difference between 0, '0', "0" and '\0' and "\O?
8. What is a string variable? How to declare a string variable?
9. What is initialization? What are the various ways of initializing strings?
1O. What are various I/O functions used in case of strings?
11. How a string can be read using scanfi)? What is the role of string conversion code
%s while reading the strings?
12. What is the significance of%4s in scanf("%4s", s1)?
13. How to read all the characters except \n using scanf()?
14. What is the disadvantage of scanf("%s", str)?
15. What is the syntax of edit set conversion code? How edit set conversion code
helps in reading the string?
16. What are the various options that can be used withprintf?
17. How does the function getsr) and putstjwork? What is the syntax?
18. How to declare an array of strings?
19. What is ragged array? What is the disadvantage of ragged array?
20. How to declare array of pointers using which we can store strings?
21. What is the need for string handling functions? What are string handling functions
in C?
22. What are memory formatting functions in C?
23. What is the need for the function sscanfand sprint}? What is the prototype of the
function sscanf and sprintf and how does they work?
24. Write a program to check whether the given string is palindrome or not?
(JuUAug 2003)
25. Explain any five string handling functions in C with appropriate examples:
(JuUAug 2003)
26. Write a program to count the number of digits, number of alphabets, number of
white spaces and other characters in a sentence
3.66" ,!;j, Strings

27. How strings are processed in C? How are they declared and initialized? Explain
with example. (Jul/Aug 2004)

28. Explain the following string handling functions with examples


• strcpy • strchr
• strncpy • strrchr
• strlen (J1!UAug 2003) • strstr
• strcat (JuUAug 2003) • strspn
• stmcat • strcspn
• strcmp • strbrk,
• stmcmp • strtok

29. Write a program to convert all alphabets into upper case in a sentence
30. Write a program to count the number of vowels and consonants in a sentence.
31. Write a program to arrange names in ascending order.
32. Write a C function to count the number of vowels and consonants in a string
33. Write a C function to convert lower case to upper case and vice-versa
Chapter 4: Derived Types-enumerated,
Structure and union
I What are we studying in this chapter? I
• The type definition
• Enumerated types
• Structure
• Accessing structures
• Complex structures
• Array of structures
• Structures and functions
• Unions
• Bit-fields - 5 hours

4.1 Introduction

In this chapter let us discuss about the need for the various derived types such as
enumerated, structures andunions. First we shall see"What is a derived data type?"

Definition: The various primitive data types that are available in C language are int,
float, char, double and void. Using these primitive data types, we can derive some
other data types. Such data types that are derived from the basic data types are called
deriveddata types. The various derived data types are shown below:

Arrays

Pointers
Derived
data Enumerated
types
Structure

Union

Arrays and pointers have already been discussed in earlier chapters. The derived data
types are normally derived from basic data types.
4.2 ~ Derived types - enumerated, Structure and Union

4.2 The type definition

Now, let us see "What is type definition?" or "What are user-defined data types?"
Definition: The typedefis a keyword that allows the programmer to create a new data
type name for an existing data type. So, the purpose of typdef is to redefine the name
of an existing variable type. The general syntax of the typedef is shown below:

keyword.J
Any existing C
r
typedef ~ata ytyPJt.new_name 1, new _name2,. :;'..


New names for the existing data type
data type

Note that using typedef, we are not creating new data types. Instead, we are creating
only new name for the existing data type. These new data type names are called user-
defined data types. For example, consider the following type definition:

typedef int MARKS, ID_NUMBER;

In the above example, MARKS and ID_NUMBER are the new data type names given
to the data type int and are called user-defined data types. Now, let us see "How to
deelare the variables using user-defined data types?"

Example 4.2.1: Suppose, we want to store marks scored in various subjects in


variables subl, sub2, sub3 and the identification numbers in the variables sl , s2 and
s3. These variables can be declared as shown below:
int sub 1, sub2, sub3;
int sl, s2, s3;

Using the user-defined data types, the variables can be declared as shown below:
typedef int MARKS, ID_NUMBER;
MARKS sub1, subj2, subj3;
.ID_NUMBER sl, s2, s3;

Note: Normally, the user defined data types will be in uppercase. This alerts the
programmer that there is something unusual about the type:

Note: The various advantages of typedef are shown below:


Q Systematic Approach to Data Structures using C - 4.3

Providesa meaningful way of declaring the variables [Example 4.2.1]


• Increasesthe readability of the program .{Example 4.2.1] .:
• A complex and lengthy declaration can be reduced to short and meaningful
declaration[look at section 4.4.2.3, page 4.13]
• Helpsus to understand the source code and also save time and energy spent in
understandingthe program.

4.3 Enumerated data types

First we shall see "What is the need for enumeration data types?" We know that
wordsspeak more than numbers (as pictures speak more than words). For example,
wemayuse integers 1, 2, 3, 12 to represent months for easy programming. It is
morereadable and understandable if we replace these numbers by some meaningful
anddescriptive names such as Jan, Feb, Mar, ..... Dec. This concept of replacing
integers by some meaningful and descriptive names gives rise to new data type called
enumerated data type. Now, let us see "What is enumerated data type? What is the
vntax of enumerated data type?"

Definition:An enumerated data type is a user defined data type which can take the
integervalues from a list. These integer values are replaced by meaningful and
descriptivenames so as to enhance the readability of the program. These descriptive
namesare called enumerators or enumerator constants. The syntax is shown below:

keyword +- enum tag_name

/{
enumerators
curly braces
"<, }; Note:
constants
Enumerators are· integer
but represented using
meaningful and descriptive names.

where
• enum is the keyword in C language
• enum tag_name together represent the user defined data type
• memberl, member2, are integer constants but represented using
descriptive names. These are called enumerator constants or enumerators. The
list of these enumerators is called enumerator list.
4.4 Q Derived es - enumerated, Structure and Union

Note: The members inside the braces are not variables; instead they are intege
constants but represented using descriptive names. Here, the compiler automaticallj
°
assigns integer value to member l. The subsequent members have the values 1,2, :
and so on.

Once we know how to define enumerated data type, the next question is "How tc
declare the variables?" The syntax of declaring the variables are shown below:

enum tag_name variables;

where
• enum ta~name is the user defined data type
• variables are list of identifiers separated by commas and terminated by
semicolon.

Example 4.3.1: Give the enumerated definition for the months of the year and declare
two variables ml and m2 using the enumerated data type.

Solution: The enumerated defmition for the months of the year along with the
declaration is shown below:

enum months
{
jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec
};

enum months mI, m2;

Instead of writing the definition and declaration in two separate lines, we could have
written as shown below:
enum months
{
jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec
} mI, m2;

Note: In the above declaration, enum months is the data type. The compiler assigns
the values 0, 1, 2, 3 11 to the names j an, feb, mar, dee.
-

l;!. Systematic Approach to Data Structures using C - 4.5

Example 4.3.2: Give the enumerated definition for the days of the week and declare
two variables dl and d2 using the enumerated data type.

Solution: The enumerated definition for the days of the week along with the
declaration is shown below:

enum days {sun, mon, tue, wed, thu, fri, sat};

enum days d1, d2;

Instead of writing the definition and declaration in two separate lines, we could have
written as shown below:
enum days
{
sun, mon, tue, wed, thu, fri, sat
} dl, d2;

Note:In the above declaration, enum days is the data type and the variables dl and
d2 are the variables of type enum days. The compiler assigns the values 0, 1,2, ... 6 to
thenames sun, mon, tue, ..... sat.
It is also possible to explicitly assign any value to enumerator. In such case, the
successive unassigned enumerators will take values one greater than the value of the
previous enumerator.

Example 4.3.3: Assigning a values to the enumerators

Consider the following enumerated declaration:

enum days {sun = 4, mon, tue, wed, thu=O, fri, sat} d1, d2;
Observethat the first enumerator sun = 4. So, for the subsequent enumerators the
compiler assigns the values 5, 6, 7 as shown below:

sun = 4, mon = 5, tue = 6, wed = 7;

But, observe that the enumerator, thu is initialized to 0. So, the subsequent
enumerators will have the values 1, 2,,3 and so on. So, the final enumerators along
withtheir values are shown below:
sun = 4, mon = 5, tue = 6, wed = 7, thu = 0, fri = 1, sat = 2

Any manipulation done on integer variables can also be done on the variables dl and
d2. It is also possible to associate typdef with enumerated data type as shown below:
4.6 ~ Derived types - enumerated, Structure and Union

Example 4.3.4: Declare the variables dl and d2 using typedef for enumerated data
type by considering the example 4.3.2

Solution: The variables dl and d2 can be declared as shown below:


enum days {sun = 4, mon, tue, wed, thu=O, fri, sat};
enum days dl, d2;

Using typedefwe can declare the variables dl and d2 as shown below:'

typedef enum {sun = 4, mon, tue, wed, thu = 0, fri, sat } DAYS;
DAYS dl, d2;

Note: Using typedef we can write more readable code. In this example, we can say
the variables dl and d2 are of type DAYS.

4.4 Why Structures? '

We know that an array is a collection of similar data items such as integer, float, char
etc. If more number of data items of same data type are grouped, we normally use
arrays. For example, the marks of 5 students can be stored using array as shown
below:
marks[5] = {80, 90, 45, 99, 100};
he ordinary variables and arrays can handle variety of situations. But, in real world,
we often deal with entities that are collection of dissimilar data types. For example,
suppose we want to have the information related to a student. We may be interested
Ill:

• name of the student (string type)


• roll number (int type)
• average marks (float type)

Note that the above information is a collection of various items of dissimilar data
types. So, arrays can not be used (because, array is a collection of similar data types).
This is where the structures are used.

4.4.1 Structure and its definition

Now, ~e shall see "What is a structure? What is the syntax of a structure?"

Definition: A structure is defined as a collection of logically related variables under a


single name. All these variables may contain data items of similar or dissimilar data
Q Systematic Approach to Data Structures using C - 4.7

types.Usingthese variables each item of a structure can be selected. Each variable in


thestructurerepresents an item and is called member or field of the structure. Each
field hasa type.
The general format or syntax of a structure is shown below:

struct tag_name
/{ type 1 memberl;
type2 member2;
curly braces

~}; Note: semicolon is must at the end of structure definition.

where
• struct is the keyword which tells the compiler that a structure is being defined.
• memberl, member2,..... are called members of the structure. They are also
called fields of the structure.
• The members are declared within curly braces. The members can be any of the
data types such as int, char, float etc.
• There should be semicolon at the end of closing brace

Example 4.4.1.1: Structure definition for storing student information.

Assumethe student information consists of the following:


• Name of the student Name is made up of sequence of characters. Ex: "RAMA"
• Roll number:It is of type integer. Ex: 99
• Average marks.It is of type floating point value Ex: 98.56

Since the above information is related to student and all the above information is
logically related to a student, we can use the structure. The structure definition to hold
the information of student is shown below: (

struct student

./{ char name[IO];


curly braces int roll_number;
float average_marks;
~};
4.8 Q Derived types - enumerated, Structure and Union

In the.above example, observe the following points.


• struct is the keyword
• student is called the name of the structure. The name of the structure is also called
structure tag.
• name, roll_number and average_marks are called fields of the structure. They
are also called members of structures and are associated with data types char, int
and float.

The structure definition does not reserve any space in memory for the members. So, it
is called a structure template and memory will not be allocated for the template. This
is pictorially represented as shown below:

name array of 10 characters


I 10 bytes

roll number integer I 2 bytes

average_marks float
I 4 bytes

Note: The various items in a structure can be same or different data types. But, all the
items should be logically related. Do not combine un-related data. For example, for
the ab ve structure definition, let us have a field zebra. The field zebra is in no way
related to student information and hence has to be avoided.

4.4.2 Structure declaration

Once we know how to define the structure, the next question is "How to declare a
structure?" As variables are defined before they are used in the function, the
structures are also should be defined and declared before they are used. A structure
can be declared using three different ways as shown below:

t
Tagged structures
Structure variables
Typedefmedstructures
4.4.2.1 Tagged Structure

Now, let us see "What is a tagged structure? Explain with example"


,!;l Systematic Approach to Data Structures using C - 4.9

Definition: The structure definition associated with structure name is called tagged
structure.The syntax of tagged structure definition is shown below:

struct tag_name

/{ type! memberl;
type2 member2;
curly braces

where
~ };Not~;::~~coi~~;smust
• struct is the keyword which tells the compiler that a structure is being defined.
• tag_name is the name of the structure
• member l , member2, 00 are called members of the structure. They are also
•••

called fields of the structure. The members are declared within curly braces.
The members can be any of the data types such as int, char, float etc. In
general, they are represented as type l , type2,oo...typen.
• The closing brace must end with semicolon.

Example 4.4.2.1.1: Structure definition using tagged structure.


Suppose we want represent the information related to a student with following fields:
• name of the student (string type)
• roll number (int type)
• average marks (float type)
The tagged structure definition is shown below:
struct student
{ /

char name[lO];
Structure definition using
int roll_number;
tagged structure
float average_marks;
};

Note the following points with respect to above structure definition:


• struct is the keyword which has to be written as it is.
• student is an identifier representing the structure name. It is also called tag
name.
• name, roll_number and average_marks are members of a structure and are not
variables. So, they themselves do not occupy any memory.
4.10 Q Derived types - enumerated, Structure and Union

Once we know how to define a structure , next we should know "How to declare the
variables using tagged structure?" The declaration of a structure variable has four
parts:
• keyword struct
• followed by tag name (also called structure name)
• followed by list of variables separated by commas
• followed by terminating semicolon

Example 4.4.2.1.2: Structure declaration using tagged structure.

derived data type


~

keyword
tag name
.J
E
T T'-»
struct student cse, ise ;
Terminated by semicolon
Structure variables

The various parts of above declaration are:


• struct is the keyword
• student is the name of the structure. It is also called tagname.
• struct student together represent the data type. Since it is derived from basic data
tppes, it is called derived data type.
• cse and ise are variables of type struct student. Now, the memory is allocated for
the variables cse and ise.

The complete structure definition along with structure declaration is shown below:

1* Structure definition *1
struct student
{
char name[lO];
int roll_number;
float average_marks;
}; 1* No memory is allocated for structure *1

1* Structure declaration *1 .
struct student cse, ise; 1* Memory is allocated for the variables */
Q Systematic Approach to Data Structures using C - 4.11

'ote:Memory is not reserved for the structure definition since no variables are
associatedwith the structure definition. But, once the structure definition is associated
with variables such as cse and ise, the compiler allocates memory for the structure
variables.
The number of bytes allocated for the variable cse is shown below:
• 10 bytes are allocated for the field name. }
• 2 bytes for the field roll_number. 10 + 2 + 4 = 16 bytes
• 4 bytes for the field average_marks.

~ote:The total size of the memory allocated is the sum of sizes of individual
members.So, totally 16 bytes are reserved for the variable cse and another 16 bytes
arereserved for the variable ise.

4.4.2.2 Structure variables

Letus see "How to define the structure along with structure variables?" The syntax of
structure definition and declaration is shown below:

struct

typel member l ;
type2 member2;
curly braces

~ } v l, v~,:.:.:.:.~vn; :~~;~: semicolon is ~ust at the end of variables


~
structure variables

• struct is the keyword which tells the.compiler that a structure is being defined .
.• memberl, member2, ..... are called members of the structure. They are also
called fields of the structure.
• The members are declared within curly braces. The members can be any of the
data types such as int, char, float etc.
• v l, v2, ..... vn are structure variables that follow curly brace. Each variable
should be separated by a comma and the last variable must be followed by
semicolon.

Note: The tag name is missingin this method of defining and declaring the structure
variables.
4.12 Q Derived types - enumerated, Structure and Union

Example 4.4.2.2.1: Structure declaration and definition using structure variables.

Suppose we want to represent the information related to a student with following


fields:
• name of the student (string type)
• roll number (int type)
• average marks (float type)

The structure definition associated with structure variables is shown below:


struct
{
char name[10J;
Structure definition using
int roll_number;
structure variables
float average_marks;
} cse, ise;

Note the following points:


• name, roll_number and average_marks are members of a structure and are
not variables. So, they themselves do not occupy any memory.
• But, once the structure definition is associated with variables such as cse and
ise the compiler allocates memory for the structure variables.
~
The number of bytes allocated for the variable cse is shown below:
• 10 bytes are allocated for the field name. }
• 2 bytes for the field roll_number. 10 + 2 + 4 = 16 bytes
• 4 bytes for the field average_marks.

Note: The size of the memory allocated is the sum of size of individual members. So,
totally 16 bytes are reserved for the variable cse and another 16 bytes are reserved for
the variable ise.

Note: This structure definition and declaration is normally not used because of the
following reasons:
• Without a tag, it is not possible to declare variables in later stages especially in the
functions.
• Normally structure definitions are placed at the beginning of the program file,
before the functions. In such case, the variables associated with this structure will
Q Systematic Approach to Data Structures using C - 4.13

be treated as global variables. In the structured programming it is better to avoid


the usage of global variables.

4.4.2.3 Type-Defined Structure

Now, let us see "What is a type-defined structure? Explain with example"

Definition: The structure definition associated with keyword typedef is called type-
defined structure. This is the most powerful way of defining the structure. The syntax
of type-defined structure is shown below:

typedef struct
/{ type! member l ;
type2 . member2;
curly braces

~ } TYP~~~; Note: semicolon is must after TYPE_ID

where
• typedef is the keyword added to the beginning of the definition
• struct is the keyword which tells the compiler that a structure is being defmed.
• member l , member2,..... are called members of the structure. They are also
called fields of the structure. The members are declared within curly braces.
• The closing brace must end with type definition name (TYPE_ID in the syntax
shown) which in turn ends with semicolon.

Note: Using typedef it is not possible to declare a variable. But, we can have user-
defined data types. Here, TYPE _ID can be treated as the new data type.

Note: Normally all typedef statements are defined at the beginning of the file
immediately after #includes and #define statements in a file.

Example 4.4.2.3.1: Structure definition and declaration using type-defined structure.

Suppose we want to represent the information related to a student using following


fields:
• name of the student (string type)
• roll number (int type)
• average marks (float type)
4.14 Q Derived types - enuinerated, Structure and Union

The type-defined structure definition is shown below:

typedef struct
{
char name[ 10];
int [011_ number;
float average_marks;
} STUDENT;

Note the following points:


• The keyword typedef should be followed by the another keyword struct
• name, roll_number and average_marks are members of a structure and are
not variables. So, they themselves do not occupy any memory.
• The closing brace ends with type definition name STUDENT which in turn
ends with semicolon.

Note: In the above definition, STUDENT is the user-defined data type.

Now, let us see "How to declare the variables using type-defined structure?" The
declaration of a structure variable has three parts:
• First part contains the user-defined data type
• followed by list of variables separated by commas
• followed by terminating semicolon

Example 4.4.2.3.2: Structure declaration using type-defined structure.

Consider the following declaration:

user-defined data type ~ - T


STUDENT cse, ise ;

I :. 'Terminated by semicolon
Structure variables

In the above declaration, STUDENT is the user-defined data type. This statement
declares that the variables cse and ise are variables of type STUDENT. The complete
structure definition along with typedef definition and declaration is shown below:
Q Systematic Approach to Data Structures using C - 4.15

1* Structure definition *1
typedef struct
{
char name] l 0]; Structure definition
int ro11_number; using typedef
float average_marks;
} STUDENT; 1* No memory is allocated for structure *1
1* Structure declaration *1
STUDENT cse, ise; 1* Memory is allocated for the variables *1

The above structure definition and declaration can also be written as shown below:

Example 4.4.2.3.3: Structure declaration 'using tagged structure and type-defined


structure.

1* Structure definition *1
struct student
{
char name[lO];
int roll_number;
float average_marks;
}; 1* No memory is allocated for structure *1
typedef struct student STUDENT;;I* STUDENT is user-defined data type *1

1* Structure declaration *1
STUDENT cse, ise; 1* Memory is allocated for the variables *1

Note: The word student which is written using fully lowercase letters is the tag name
of the structure whereas, STUDENT which is written using fully capital letters is the
user-defined data type.

4.4.3 Structure initialization

Now, let us see "How are structures initialized?" The syntax of initializing structure
variables is similar to that of arrays i.e., all the elements will be enclosed within curly
braces i.e., '{' and '}' and are separated by commas. The syntax is shown below:

struct tag_namevariable = {vl , v2, ... vn};


4.16 Q Derived types - enumerated, Structure and Union

where
• "struct tag_name" is derived data type.
• vl , v2, vn are all the initial values. These values are called
initializers; they should be separated by commas and should be
enclosed between '{' and '}'

Example 4.4.3.1: Initialization along with structure definition.

Solution: Consider the structure definition for an employee with three fields name,
salary and id as shown below:

struct employee
{
char name[20];
int salary;
int id;
, };

The above structure can be initialized as showri below:

struct employee /* Define employee structure */


{ /* Various members are */
char name[20]; /* member name */
int salary; /* member salary */
int id; /* member employee id */
} a = {"Shivashankar", 10950, 2001}; /* Variable a has values */
/* name = "Shivashankar" */
/* salary = 10950 */
/* id = 2001 */

Note: The various members of the structure have the following initial values:
• The first member name has the value "Shivashankar"
• The second member salary has the value 10950
• The last member in the structure id has the value 2001.

Example 4.4.3.2: Initialization during structure declaration.

Solution: Consider the structure defmition for an employee with three fields name,
salary and id as shown below:
Q Systematic Approach to Data Structures using C - 4.17

struct employee .
{
char name[20];
int salary;
int id;
};

struct employee a = {"Shivashankar", 10950, 200!};

Note: The various members of the structure have the following initial values:
• The first member name has the value "Shivashankar"
• The second member salary has the value 10950
• The last member in the structure id has the value 2001.

Example 4.4.3.3:' Initialization during structure declaration with more than one
variable
Solution: Consider the following initialization:

structemployee
{
char name[20];
int salary;
int id;
} a, b = {"Shivashankar", 10950, 200!};

Note: The various members of the structure have the following initial values for the
variable b:
• The first member name has the value "Shivashankar"
• The second member salary has the value 10950
• The last member in the structure id has the value 2001.

Note: Only the variable b is initialized and the variable a is not initialized. Now,
"How to initialize the variable a as well as b?" To get the answer, look at the
following example.

Example 4.4.3.4: Initialization. during structure declaration with more than one
variable

The initialization of both the variables a and b can be achieved as shown below:
4.18 Q Derived types - enumerated, Structure and Union

/* Structure definition and Initialization */


struct employee
{
char name[20];
int salary;
int id;
}
a = {"Rama", 20000, lOOO},b = {"Shivashankar", 10950, 2001};

Initializing both variables a and b can also be 'done as shown below:

struct employee
{
char name[20];
int salary;
int id;
};

struct employee a = {"Rama", 20000, 1000};


struct employee b = {"Shivashankar", 10950, 2001};
I

Note: Structures with automatic storage class (i.e., structures that are local variables)
can also be initialized .
.1

Now, let us see some important points to remember when we initialize the structures.
• The members of the structure can not be initialized in the structure definition. For
example,
struct employee
{
char nanie[20] = "Shivashankar";
int salary = 20000;
int id = 25;
};

is invalid.

• The initial values are assigned to members of the structure on one-to-one basis
i.c . the ilucs are assigned to various members in the order specified from the
fir t J1lCl1l ~ . For example, the following statement:
.Q Systematic Approach to Data Structures using C - 4.19

struct employee a = {"Shivashallkar", 10950, 2001};

is valid. Here, the string "Shivashankar" will be assigned to the first member,
10950 is assigned to the second member and 2001 will be assigned to the third
member.

• During partial initialization (i.e., if there are fewer initial values i.e., few
initializers, than the members of a structure), the values are assigned to members
in the order specified and the remaining members are initialized with default
values. If the remaining members are of type integer or float, they are initialized
with the default value zero and if the remaining members are of type string or
character, they are initialized with default value of '\0'. For example, in the
initialization statement

struct employee a = {"Shivashankar"};

observe that the string "Shivashankar" will be assigned to structure member


name. The other members of the structure namely salary and id are initialized to
zero by default.

• During initialization, the number of initializers (i.e., the values to be initialized to


members of a structure), should not exceed the number of members. It leads to
syntax error. For example, for the following statement

struct employee a = {"Rama", 10950, 2001,.10.2};

the compiler issues a syntax error saying "too many initializers".

• During initialization, there is no way to initialize members in the middle of a


structure without initializing the previous members. For example,

struct employee a = {I 0950, 2001 };

is invalid, even though it is syntactically correct. Because, without initializing the


first member namely name, we are trying to initialize last two members. In this
case, the number 10950 will be copied .into name field, the number 2001 will be
copied into salary field and the result is unpredictable:
4.20 Q Derived types - enumerated, Structure and Union

4.5 Accessing structures

We know that variables can be accessed and manipulated using expressions and
operators. On similar lines, the ~tructure members can be accessed and manipulated.
Before manipulating let us see "How structure members are accessed?" The members
of a structure are separate entities and so should be processed individually. A member
of a structure can be accessed by specifying the variable name followed by a period
(also called dot) which in turn is followed by the member name using the syntax
shown below: .

variable. member

For example, consider the structure definition and initialization shown below:

struct employee
{
char name[lO];
float salary;
int id;
};

struct employee a = {"RAMA", 10950.0, 2001};

The memory representation for the above structure is shown below:

The various members can be accessed using the variable a as shown below:
• By specifying a.name we can access the string "RAMA".
• By specifying a.salary we can access the value 10950.000060
• By specifying a.id we can access the value of 2001

Now, the question is "How to display the various members of a structure?" The
various members of a structure can be accessed and printed as shown below:
Q Systematic Approach to Data Structures using C - 4.21

Programming statements : Output


printf("%s\n", a.name); : Shivashankar
printf("%d\n", a.salary); I 10950.000000
printf("%d\n", a.id); I 2001
I

Once we know how to display the members of a structure, let us see "How to read the
values for various members of a structure?" We know that format specifications such
as %s %d %f are used to read a string, an integer and a float. The same format
specifications can be used to read the members of a structure. For example, we can
read the name of an employee, the salary and id as shown below:

gets (a.name); 1* or scanf("%[I\\n]); *1


scanf ("%f', &a.salary);
scanf ("%d", &a.id);

Now, let us see "How to write a program to simulate the multiplication of two
fractions?" Before writing the program, let us give the design procedure by taking
example:

Design: Consider two fractions 2/8 and 3/7. These two numbers can be multiplied and
as shown below:

~*~=~
8 7 56

Since there are no fractional data types in C language, this can be simulated using
structures. A fraction number can be defined as a structure with two members namely
numerator and denominator as shown below:

typedef struct
{
int numerator;
int denominator;
} FRACTION;

Let a and b are two given fractions and c is the resultant fraction. The resultant
fraction c can be computed as shown below:
c.nurnerator = a.numerator * b.numerator
c.denominator = a.denominator '" b.denominator
4.22 Q Derived types - enumerated, Structure and Union

Now, the complete program is shown below:

Example 4.5.1: Program to simulate the multiplication of two fractions

#include <stdio.h>

typedef struct
{ .

int numerator;
int denominator;
} FRACTION;

void maint)
{
I
FRACTION a, b, c; I TRACING
I Input
printf("Enter fraction! in the form x/y: "); I Enter fraction 1: 3/8
scanf("%d/%d" ,&a.numerator, &a.denominator); I
printf("Enter the fraction2 in the form x/y: "); I Enter fraction2: 4/7
scanf("%d/%d" ,&b.numerator, &b.denominator); I
I
c.numerator = a.numerator * b.numerator; , I
c.denominator = a.denominator*b.denominator; I Output
.1 3/8 * 4/7 = 12/56
printf("%d/%d * %d/%d = %d/%d\n",a.numerator, a.denominator,
b.numerator, b.denominator,
c.numerator.c.denorninator);
}

4.5.1 sizeof a structure (Concept of Slack Bytes)


Now, let us see "What is the size of the structure?"

Definition: The size of a structure is defined as the sum of sizes of each member of
the structure. For example, consider the structure declaration shown below:

struct student

char name[10]; /* Assume size of char is 1 byte */


int .roll number; /* Assume size ofint is4 bytes */
double average_marks; /* Assume size of double is8 bytes */ .
} a;
Q Systematic Approach to Data Structures using C - 4.23

The size of each member of the structure is shown below:

a.name array of 10 characters 10 bytes

a.roll number integer 4 bytes

a.average_marks double 8 bytes

So, total size of the structure = 22 bytes

If 2000 is the starting address of the variable a, then the starting address of each
member depends on sum of sizes of previous members' and the complete memory
'map is, shown below:
i
,,
2000
, ,
2002 .
I

2004
,,
I
a.name (10 bytes)
,
+ 10 2006 I
I

I
2008 I

+4L
I
2010 I

,, >- a.roll_number (4 bytes)


2012
I
2014 I

2016 ,
I

>- a.average_marks (8 bytes)


2018 ,
I

- ,,
2020 •. , .
"'~--""'y""'----~
2 bytes
Fig. 4.5.1 Memory map for members of a structure

Note: The address of a member = address of its immediate previous member +


the size of its immediate previous member
4.24 ,!;!, Derived types - enumerated, Structure and Union

Address of member name = 2000


Address of member roll number = 2000 + 10 = 2010
Address of member average_marks = 2010 + 4 = 2014

. Note: The address of each member is greater than the address of its previous member
and hence, address of each member is different.

Some times, the size of the structure will not be equal to-sum of sizes of the individual
members. This is because of slack bytes. Now, let us see "yv'hat are slack bytes?"

Definition: In some computers, the memory for the members of a structure is


allocated in sequence based purely on the size of individual members. In some
computers, the memory for the members of a structure is allocated at certain
boundaries called "word boundaries". In such case, extra bytes are padded at the end
of each member whose size is less than the largest data type so that the address of
each member starts at the word boundary. These extra bytes that are inserted to
maintain the boundary requirements are called slack bytes. These extra bytes do not
contain any valid information and are useless and waste the memory.
For example, if char, int, float and double are the data types of members of a
structure, then a member whose type is double occupy more -memory. Assuming
sizeof double is 8 bytes, then the address of each member is multiple of 8. Consider
the structure declaration shown below:

struct student
{
char namej l O]; 1* Assume size of char is 1 byte *1
int roll_number; 1* Assume size of int is 4 bytes *1
double average_marks; 1* Assume size of double is 8 bytes *1
}a ;
The size of each member of the structure is shown below:

a.name array of 10 characters 10 bytes


1
a.roll number integer 4 bytes
1
a.average _marks double -I 8 bytes

Sum of sizes of individual structure members 22 bytes


Q Systematic Approach to Data Structures using C - 4.25

Let us see "What is the size of structure if slack bytes are introduced?" If 2000 is the
starting address of the variable a, then the starting address of each member depends
on sum of sizes of previous members along with the word boundary and the complete
memory map is shown below:

Divisible by 8 ---+ 2000


2002
2004' a.name (10 bytes)
2006
2008
2010
2012 6 slack bytes
2014
Divisible by 8 ---+ 2016
a.roll_number (4 bytes)
2018
2020
4 slack bytes
2022
Divisible by 8 ---+ 2024
2026
a.average_marks (8 bytes)
2028
2030

2 bytes
Fig. 4.5.2 Memory map showing slack bytes

Note: The size of the structure is 32 bytes which is greater than the sum of sizes of
each member. So, when slack bytes are used, the size of a structure is greater than or
equal to the sizes of its individual members,

Note: Data can be accessed much faster way if present in word boundaries. So, even
though slack bytes do not contain valid information, they are useful so that data is
available always in word boundaries and can be accessed very fast.
4.26 Q Derived types - enumerated, Structure and Union

Nete: In the structure definition, double is the largest data type with size 8 bytes. So,
the starting address of each member should be divisible by 8.
Note: The starting address of each member is divisible by 8. But, we can access only
the specified number of bytes of a member. The extra bytes that are not used are slack
bytes. The shaded region represents the slack bytes.

4.5.2 Structure operations

The various operations can be performed on structures and structure members. Any
operation that can be performed on ordinary variables can also be performed on
structure members. But, some operations 'Cannot be performed on structure variables.
The following sections deals with operations that are carried on structure and
structure members \
4.5.2.1 Copying of structure variables
Copying of two structure variables is achieved using assignment operator. But, one
structure variable can be assigned to another structure variable of the same type.

Example: 4.5.2.1.1: Usage of assignment operators using structure variables.

Consider the structure definition and declaration statements shown below:

struct struct
.1
{ {
char name[lO]; char name[lO];
int salary; int salary;
int id; int id;
} a, b; } c, d;
Note: Observe that even though the members of both structures are same in number
and type, both are considered to be of different structures.
So, the statements
a =b; c = d;
and
b==a: . d=c:
are valid. But, the following statements
a=c; c = a;
b=d; and d=b;
are invalid.
Q Systematic Approach to Data Structures using C - 4.27

4.5.2.2 Comparison of two structure variables or members

In the previous section, we have seen that copying of two structure variables of same
type is allowed. But, we should remember that comparing of two structure variables
of same type or dissimilar type is not allowed.

For example, the following operations are invalid, even though a and b are of the
same type.
a=b;. 1* Invalid: Comparison is not allowed between structure variables *1
a !=b; 1* Invalid: Comparison is not allowed between structure variables *1

However, the members of two structure variables of same type can be compared using
relational operators. For example, if a and b are two structures, then the following
relational operations are valid:

Operation Meaning
a.member l = b.member2 Compare member! of a with member2 of
b and return true if they are same, false
otherwise .
a.member I != b.member2 Return true if the member! of a and
member2 of b are not same and false
otherwise.
, .
Note: The arithmetic, relational, logical and other various operations can be
performed on individual members of structures but not on structure variables. But, if
we want to compare we can do so by comparing the individual members of a structure.

4.5.2.3 Arithmetic operations on structures

The members of a structure are similar to anyother variables and so any operation
that can be performed on a variable, the same operation can be performed on structure
members also. So, members of a structure can be manipulated by using expressions
and operators.
For example, ++a.salary is equivalent to ++(a.salary) and &a.salary is
equivalent to &(a.salary). The expression &a denotes the starting address of the
structure variable. Some of the expressions involving the variable a and its members
are shown below:
4.28 Q Derived types - enumerated, Structure and Union

- f

Expression Meaning
++a.salary Increment the salary before accessing its value.

a.salary++ Increment the salary after accessing its value


&a.salary Access the address of a.salary
&a Access the beginning address of the structure

4.5.2.4 Difference between structures and arrays


/

Now, let us see "What are the differences between arrays and structures?" Both arrays
and structures are derived data types. The various differences between the two are:
Arrays Structures

• An array IS a collection of
related data elements of the
• Structure IS a collection of
variables of similar or dissimilar
same type. In other words, array data type. In other words,
is used to represent homogenous structures are used to represent
data # the heterogeneous data.
• An array items can be accessed
by using its subscript or using
• Structure items can be accessed
using ''." (read as dot operator) or
de-referencing/indirection (*) "->" (called selection operator in
operator for pointers case of pointers)
-
4.5.3 Pointer to Structures

We know that a pointer is a variable which contains address of another variable. On


similar lines we can have pointer to structures. Now, let us see "What is pointer to a
structure?"

Definition: A variable which contains address of a structure variable is called pointer


to a structure. For example, consider the following declaration:

typedef struct
{
char name[lO];
int ro 11_number;
float average_marks;
} STUDENT;
Q Systematic Approach to Data Structures using C - 4.29

void mairu)
{
STUDENT a;
STUDENT *p;

p=&a;

Here, p is a pointer to a structure. Using this pointer, various members of the structure
can be accessed using two methods:

t Using de-referencing operator * and dot (.) operator

Using selection operator (-»

4.5.3.1 Using de-referencing operator * and dot (.) operator

If p is pointer to a structure, then the structure itself can be accessed using indirection
operator as shown below:

*p 1* Refers to the whole structure *1

Once the structure is accessed, each member of the structure can be accessed using
dot operator as shown below:
(*p).name 1* Access the name *1
(*p).roll_number 1* Access roll number *1
(*p ).average _marks 1* Access average marks *1

Note: The parentheses in all the three expressions are necessary. We should not omit
the parentheses. For example,
*p.name 1* Invalid way of accessing the member >1:1
*p.roll_ number 1* Invalid way of accessing the member *1
*p.average _marks 1* Invalid way of accessing the member *1

4.5.3.2 Using selection operator

If P is pointer to a structure, then the members of the structure can also be accessed
using selection operator denoted by -> (which is formed by the minus sign and
4.30 Q Derived types - enumerated, Structure and Union

greater- than symbol). Using this operator, various members of the structure can be
accessed as shown below:
p->name 1* Access the name *1
p->roll_ number 1* Access roll number *1
p->average_marks 1* Access average marks *1

Note: This method is preferred over the previous method. So,


(*p ).name can be written as p->name
(*p).roll_number can be written as p->roll_number
(*p ).average _ marks can be written as p->average _marks

4.5.3.3 Simulation of digital clock

Now, let us see how to design and write the program to simulate the digital clock.

Design: A structure with three members representing seconds, minutes and hours is
shown below:
typedef struct
{
int see; 1* Represent seconds *1
int mm; 1* Represent minutes *1
int hrs; 1* Represent hours *1
} CLOCK;

where CLOCK is considered as user-defined data type. If the variable c can be


declared as shown below:

CLOCKc;

The following condition and codes help us to simulate the digital clock:

• If value of seconds reaches 60, then we reset the seconds value to 0 and increment
minutes. The code for this case can be written as shown below:

if (c->sec = 60)
{
c->sec = 0;
c->min++;
}
,!;l Systematic Approach to Data Structures using C - 4.31

+ When minutes is being incremented, if value of minutes reaches 60, then we reset
the minutes value to 0 and increment hours. The code for this case can be written
as shown below:

if (c->min = 60)
{
c->min = 0;
c->hrs++;
}

+ When hours is being incremented, if the value reaches to 24, it is reset to O. The
code for this case can be written as shown below:

if (c->hrs = 24)
{
c->hrs = 0;
}

So, the complete C program is shown below:

Example 4.5.3.1: Program to simulate the digital clock

#include <stdio.h>

/* Structure definition for the clock */


typedef struct
{
int hrs;
int mm;
int see;
} CLOCK;

/* Function to increment the time by one second */


void increment(CLOCK *clock)
{
clock ->sec++;

if (clock->sec = 60)
{
clock->sec = 0;
clock ->t:nin++;
4.32 ~ Derived types - enumerated, Structure and Union

if (clock->min = 60)
{
clock->min = 0;
clock ->hrs++;

if (clock->hrs = 24) clock->hrs = 0;


}
}
}

/* Function to show the time */


void show(CLOCK *clock)
{
printf("%2d:%2d:%2d\n", clock->hrs, clock->min, clock->sec);
}

void maim)
{
CLOCK clock = {II, 59, 57}; /* Initialize time to 11:58:57 */

int 1, 0

1 for (i = 0; i <= 10; i++)


{
increment( &clock);
show( &clock);
}
}

4.6 Complex structures

Using structures we can deal with various complex problems. The complex structures
include the following:
• Nested structures
• Structures containing arrays
• Structures containing pointers
• Arrays of structures
Let us discuss each of these one by one
Q Systematic Approach to Data Structures using C - 4.33

4.6.1 Nested structures


Let us see "What is a nested structure?" A structure which includes another structure
is called nested structure i.e., a structure can be used as a member of another structure.

Example 4.6.1.1: Structure definition using nested structures


Consider the student information such as name, university seat number and marks of
three subjects. The marks of three subjects can be defined in the structure as shown
below:
r+ struct subject
{
int marksl; 1* Marks in subject 1 *1
int marks2; 1* Marks in subject 2 *1
int marks3; 1* Marks in subject 3 *1
};
I
Now, the complete student information consisting of name, university seat number
and the marks of three subjects can be represented using a structure as shown
below:
typdef struct
{
char name[lO]; 1* Name of the stude t *1
int USN; 1* University serial n mber *1
:struct subjectlmarks; 1* Marks of three subiects *1
} STUDENT; 1* STUDENT is the user defined data type *1

Note that the above structure consists of a member identified by marks whose type is
struct subject (shown using arrow mark). So, this is nested structure. Consider the
following declaration:
STUDENTs; 1* Variable s is of type STUDENT *1
Using the variable s, we can access the various fields using dot operator as shown
below:
s.name ~* Access name of the student *1
s.USN 1* Access USN of a student *1
s.marks.marks 1 1* Marks of subjectl *1
s.marks.marksz 1* Marks of subject 2*1
s.marks.marks3 I~ Marks of subject 3 *1
4.34 Q Derived types - enumerated, Structure and Union

Note: To access marksl using the variable s we have to use the dot operator twice
i.e., s.marks.marksl I

The program to arrange the student details in alphabetical order is shown below:

Example 4.6.1.2: Program to arrange student's information in ascending order using


nested structures.
#include <stdio.h>
#include <string.h>
void mainf)
{
. struct subject
{
int marksl; /* Marks of subject 1 */
int marks2; /* Marks of subject 2 *!
int marks3; /* Marks of subject 3 */
};

typdef struct
{
char name[lO]; /* Name of the student */
int USN; /* University serial number */
struct subject marks; /* Marks of 3 subjects */
} STUDENT;
STUDENT temp, a[9];
int i, j, n;
printf("Enter the number of students\n");
scanf("%d", &n);
printf("Enter the student details\n");
for (i = 0; i < n; i++)
{
printf("Details of%d student\n",i+l);
printf("Name = "); scanf(" %[I\\n]", a[i].name);
printf("USN = "); scanf("%d", &a[i].USN);
printf("Marksl = "); scanf("%d", &a[i].marks.marksl);
printf("Marks2 = "); scanf("%d", &a[i].marks.marks2);
printf("Marks3 = "); scanf("%d", &a[i].marks.marks3);
}
~ Systematic Approach to Data Structures using C - 4.35

for (j = 1; j < n; j++)


{
for ( i = 0; i < n-j; i++)
{
if (strcmp(a[i].name, a[i+l].name) > 0)
{
temp = a[i];
a[i]=a[i+l];
a[i+l] = temp;
}
}
}

printfr'The sorted recordxn'');


for ( i = 0; i < n; i++)
{
printf(tt%s %d %d %d %d\ntt,a[i].name,a[i].USN,a[i].marks.marksl,
a[i] .marks.marks2, a[i].marks.marks3);
}
}

4.6.2 Structures containing arrays

Now, the question is "Is- it possible to use arrays within structures?' The answer is yes.
Arrays can be used within structure as members. A single or multi-dimensional array
of int, float, char and double can be used within the structures.

Example 4.6.2.1: Structure definition which contains array as a member

Consider the student information consisting of name, USN and marks of 3 subjects.
The structure definition is shown below:

typedef struct
{
char name [10]; /* Name of the student */
int USN; /* University serial number */
int marks[3] 1* Marks of 3 subj ects* ~
} STUDENT;
4.36 Q Derived types - enumerated, Structure and Union

Note: Here, STUDENT is user-defined data type. Observe that the member marks is
an array of integers. This array is used to store the marks of three subjects. The
member name is also an array. But, it is array of characters.
Consider the following declaration:
STUDENTs;
Using the variable s, we can access the various fields using dot operator as shown
below:
s.name 1* Access name of the student *1
s.USN 1* Access USN f a student *1
s.marks[O] 1* Marks of subjectl *1
s.marks[l] 1* Marks of subject 2*/
s.marks[2] /* Marks of subject 3 *1

Let us write a program to arrange the student information as we did in previous


example. But, the marks of three subjects are represented using an array. The
complete program is shown below: .

Example 4.6.2.2: Program to demonstrate arrays within structures

#include <stdio.h>
#include <string.h>

void maint)
{
struct student
{
char name[lO]; 1* Name of the student *1
int USN; 1* University serial number *1
int marks[3]; 1* To hold marks of 3 subjects *1
};

int n; 1* Number of students *1


intj; 1* The pass required while sorting *1
int i; 1* Used to access the student record *1

struct student temp; 1* Temporary record used for s rting *1


struct student a[ 10]; 1* Holds the details of 10 students *1
Q Systematic Approach to Data Structures using C - 4.37

printf("Enter the number of students\n");


scanf("%d", &n);

printf("Enter the details of %d students\n" ,n);


for (i = 0; i < n; i++)
{
printf("Details of%d student\n",i+l);
printf("Name = "); scanf(" %[A\n]", a[i].name);
printf("USN = "); scanf("%d", &a[i].USN);
printf("Marks1 = "); scanf("%d", &a[i].marks[O]);
printf("Marks2 = "); scanf("%d", &a[i].marks[l]);
printf("Marks3 = "); scanf("%d", &a[i].marks[2]);
}

1* Sort the student record based on name *1


for (j = 1; j < n; j++)
{
for (i='O; i < n-j; i++)
{
if (strcmp(a[i].name, a[i+ l].name) > 0)
{
temp = a[i];
a[i] = a[i+l];
a[i+1] = temp;
}
}
}
printf("The sorted record\n");
for ( i = 0; i < n; i++)
{
printf("%s %d %d %d %d\n",a[i].name,a[i].USN,a[i].marks[O],
a[i].marks[l], a[i].marks[2]);
}

Note: Compare example 4.6.12 and 4.6.2.2. Observe that the logic of both programs
remain same. The difference is in the structure definition and the method of accessing
the marks of 3 subj ects while reading and printing. Rest of the program remains same.
4.38 Q Derived types - enumerated, Structure and Union

4."0.3 Structures containing pointers

We have seen that members of a structure can be arrays, ints, floats etc. Now, the
question is's It possible to use pointers \\ ithin structures?" Yes, a pointer can also be
used as a member of the structure. In fact, pointers are common when we use
structures.

Example 4.6.3.1: Structure containing pointers as members


For example, the following structure definition defines a new data type called DATE:

typedef struct
{
int day;
int month;
int year;
} DATE;

In the above type definition, day is represented as integer. Suppose, we have the
following declarations in our program:

char mon[] = "Monday";


char tue[] = "Tuesday";
cfiar . wed[] = "Wednesday";
char thu[] = "Thursday";
char fri[] = "Friday";
char sat[] = "Saturday";
char sun[] = "Sunday";

ote that the days are represented as strings. If it is required to store the days as
strings, then the earlier type definition and declaration with respect to DATE can be
written as shown below:

typdef struct
{
char *day;
int month;
int year;
} DATE;
,/

DATEd;
Q Systematic Approach to Data-Structures using C - 4.39

Suppose we want to store the date as "Thursday 11 1965". This can be done using the
following statements:

d.day = "Thursday"; 1* Note: pointer to a string is copied instead of string *


d.month = 11;
d.year = 1965;

4.7 Array of structures


As we have an array of integers, we can have an array of structures also. For example,
suppose we want to store the information of 10 students consisting of name, marks
and year of passing. The structure definition can be written as shown below:

1* Definition of employee structure *1


typedef struct
{
char name[20];
int marks;
int year;
} STUDENT;

To store the information of more number of students, we can have the following
declaration:
STUDENT a[10];

Notel a is an array consisting of 10 memory locations. Each location is of type


STUDENT and hence the information of 10 students can be stored.

Now, the next question is "How to access the elements of array and information
related to a particular student?" Since a is an array, each student information can be
accessed by specifying the index along with member name. The information of ith
student can be accessed by specifying:
a[i].name 1* Access the name ofith student *1
a[i].marks 1* Access the marks of ith student *1
a[i].year 1* Access the year *1

Now, let us see "How to arrange the student information in alphabetical order?" using
insertion sort.
4.40 Q Derived types - enumerated, Structure and Union

lote: The program along with design has already been discussed using arrays in
section 1.12, page 1.50. Here, it is being written using structures and pointers.

Example 4.7.1: To sort n student details in alphabetical order

#include <stdio.h>
#include <string.h>

typedef struct
{
char name[20];
int marks;
int year;
} STUDENT;

void insertion_sort(int n, STUDENT am


{
STUDENT *first, *last, *i, *j;
STUDENT item;

/* Sort the elements using insertion sort */


first = &a[O];
last = &a[n-1];

for (i = first + 1; i <= last; i++)


{
item = *i;
j=i-1;

while (strcmp(item.name,(*j).name) < 0 &&j >= first)


{
*U + 1) = *j;
j=j-l;
}

*U + 1) = item;
}
}
Q Systematic Approach to Data Structures using C - 4.41

void mairu)
{
int n,l;
STUDENT a[lO];

printf("Enter the number of students\n");


scanfC'%d",&n);

1* Read n elements *1
printf("Enter n students details\n");
for (i = 0; i < n; i++)
{
scanf("%s %d %d", a[i].name, &a[i].marks, &a[i].year);
}

insertion_sort(n, a);

1* Display the sorted elements *1


printf("The sorted student records are\n");
for (i = 0; i < n; i++)
{
printf("%s %d %d\n", a[i].name, a[i].marks, a[i].year);
}
}

Input Output
Enter the number of students The sorted student records are
5 Aruna 700 1065
Enter n students details Mona 999 1999
Mona 999 1999 Nirmala 800 1972
Suguna 800 1970 Padma 850 1965
Nirmala 800 1972 Suguna 800 1970
Aruna 700 1065
Padma 850 1965

4.8 Structures and functions


We should note that structures are more useful if we are able to pass. them to functions
and return them. Now, let us see "What are the various methods of passing structures
to functions?"The structures or structure members can be passed to the functions in
various ways as shown below:
4.42 ~ Derived types - enumerated, Structure and Union

Various ways of passing


structures to functions -f By passing individual members of structure

By passing the whole structure

By passing structures through pointers


_
-; ,.

Now, let us discuss each of these in detail.

4.8.1 Sending individual members

A function can be called by passing the members of a structure as actual parameters.


For example, the program to simulate the multiplication of two fractions shown in
example 4.5.1, section 4.5 can be written using a function as shown below:

Example 4.8.1.1: Program to simulate the multiplication of two fractions by passing


individual members to the function

#include <stdio.h>

typed f struct
{
int numerator;
int denominator;
} FRACTION;

lnt multiply(int x, int y)


{
return x * y;
}

void maint)
{
FRACTION a, b, c;
priotf("Enter fraction! in the form xly: ");
scaof("%d/%d",&a.numerator, &a.denominator);

priotf("Enter the fraction2 in the form xly: ");


scaof("%d/%d" ,&b.numerator, &b.denominator);
Q Systematic Approach to Data Structures using C - 4.43

c.numerator = multiply (a.numerator, b.numerator);


c.denominator = multiply (a.denominator,b.denominator);

printf("%dI%d * %dI%d = %dI%d\n",a.numerator, a.denominator,


b.numerator, b.denominator,
c.numerator,c.denominator);
}

Disadvantage Observe that the function multiply 0 is called by passing individual


members of a structure. Passing the individual members to a function is more tedious
as the number of structure members increases. This method is inefficient when the
structure size is too large. This disadvantage we can over come by passing the whole
structure as shown in subsequent sections.

4.8.2 Sendingthe whole structure

Now, the question is "Is there any better way of writing the above program?" Yes,
there is. The better way is to represent the fractional number using structure as shown
below:
typedef struct
{
int numerator;
int denominator;
}FRACTION;
Note: Here, FRACTION is the user-defined data type
Then, use three variables x, y and z of type FRACTION .. Pass two variables x and y
as parameters to the function. The function can multiply the given two fractions
storing the result as shown below:
• Multiply the numerators and store the result as numerator
i.e., z.numerator = x.numerator * y.numerator;

• Multiply denominators and store the result as denominator


i.e., z.denominator = x.numerator * y.numerator;

The complete program is shown below:


4.44 Q Derived types - enumerated, Structure and Union

Example 4.8.2: Program to simulate the multiplication of two fractions

#include <stdio.h>

typedef struct
{
int numerator;
int denominator;
} FRACTION;

int multiply(FRACTION x, FRACTION y)


{
FRACTION z;

z.numerator = x.numerator * y.numerator;


z.denominator = x.numerator * y.numerator;

return z;
}

void mainf)
{
~ FRACTION a, b, c;

printf("Enter fractionl in the form x/y: ");


scanf(l%dI%d" ,&a.numerator, &a.denominator);

printf("Enter the fraction2 in the form x/y: ");


scanf(l%dI%d",&b.numerator, &b.denominator);

c = multiply (a, b); I


printf("%dI%d * %dI%d = %dI%d\n",a.numerator, a.denominator,
b.numerator, b.denominator,
c.numerator,c.denominator);
}

Note: The above program is most efficient way to multiply two fractions when
compared with program given in 4.8.1.1.
,!;lSystematic Approach to Data Structures using C - 4.45

4.8.3 Passing structures through pointers

Instead of passing structures as parameters, we can also pass address of structures as


parameters. In such case, the formal parameters should be declared as pointers. The
program for multiplication of two fractions shown in previous section can be written
exclusively by passing the addresses with three functions:
• read _ fractioru) - is used to read a fraction from the keyboard
• print_ fractioru) - is used to the print the result on the screen
• mul_ fractioru) - is used to multiply two fractions

Example 4.8.3.1: Function to read a fraction

void read _fraction(FRACTION *x)


{
printf("Enter fraction in the form x/y: ");
scanf("%d1%d" ,&x ->numerator, &x->denominator);
}

Note: &x->numerator can be written as as &(*x).numerator. ~


Similarly, &x->denominator can be written as &(*x).denominator.
Example 4.8.3.2: Function to multiply two fractions x and y
void mul_ freaction(FRACTION *x, FRACTION *y, FRACTION *z)
{
z->numerator = x->numerator * y->numerator;
z-c-denominator = x->denominator * y->denominator;
}

Example 4.8.3.3: Function to print the product of two fractions •

void print_fraction(FRACTION *x, FRACTION *y, FRACTION *z)


{
printf("%d1%d * %d1%d = %d1%d\n",x->numerator, x->denominator,
y->numerator, y->denominator,
z->numerator, z->denominator);

The complete program to multiply two fractions is shown in example 4.8.3.4.


Example 4.8.3.4: Program to· simulate the multiplication of two fractions using
pointers to structures
4.46 Q Derived types - enumerated, Structure and Union

#include <stdio.h>

typedef struct
{
int numerator;
int denominator;
} FRACTION;

1* Include: Example 4.8.3.1: Function to read a fraction =r


1* Include: Example 4.8.3.2: Function to multiply two fractions x and y *1
1* Include: Example 4.8.3.3: Function to print the product of two fractions *1

void maint)
{
FRACTION a, b, c;

printf("Enter the first fraction :");


read _fraction( &a);

printf("Enter the second fraction :");


read _fraction( &b);

mul_fraction (&a, &b, &c);

print_fraction(&a, &b, &c);


}

4.8.4 Uses of structures



Now, we can summarize the use of structures as shown below:
+ Structures are used to represent more complex data structures
+ Related data items of dissimilar data types can be logically grouped under a
common name and all the items can be accessed using a common name.
+ Can be used to pass arguments so as to minimize the number of function
arguments.
+ When more than one data has to be returned from the function, then structures
can be used.
+ Extensively used in applications involving database management
+ . To make the program more readable.
~ Systematic Approach to Data Structures using C - 4.47

4.9 Operation on complex numbers

Now, the question is "Is it possible to perform various operations on complex


numbers using C?" The answer is no. This is because the various data types in C
language are int, float, char and double. There is no special data type to represent or
manipulate complex numbers in C. Then, "How to represent complex numbers in C?"
This is where structures come to help. Using structure we can represent and store
complex numbers. Using structures, let us try to frame our own data type called
COMPLEX which has two parts real part and imaginary part. and then perform
various operations on these complex numbers. Thus a complex number can be
represented using a structure as shown below:

typedef struct
{
float r; 1* real part *1
float i; 1* imaginary part *1
} COMPLEX;

Note: Here, COMPLEX is the new data type which is derived from structure. Since
we have framed this data type, COMPLEX is called user-defined data type.

Now, to store two complex numbers we need to use two variables. This can be done
as shown below:
COMPLEX a, b; '1* a and b represent 2 complex variables *1

4.9.1 Addition of two complex numbers

.
Now, let us see "How to add two complex numbers?" Given two complex numbers
( x + yi ) and ( a + bi), in mathematics addition can be performed as shown below:
.
x + Y1
+ a + bi
(x + a ) + (y + b)i

Implementation in C: Observe that real part of result = Real part of 151 number +
Real part of 2nd number and Imaginary part of result = Imaginary part of 151 number +
Imaginary part of 2nd number. So, if a and b are two complex numbers with r as the
real part and i as imaginary parts respectively, then the resulting complex number c
which is sum of a and b is given by

c.r = a.r + b.r;


c.i = a.i + b.i;
4.48 Q Derived types - enumerated, Structure and Union

TIYefunction to add two complex numbers a and b is shown below:

Example 4.9.1.1:C function to add two complex numbers


COMPLEX add(COMPLEX a, COMPLEX b)
{
COMPLEXc;
c.r = a.r + b.r;
c.i = a.i + b.i;

return c;
}

4.9.2 Subtract one complex number from other


Now, let us see "How to subtract one complex number from the other?"Given two
complex numbers (x + yi ) and ( a + bi), we can subtract (a + bi) from (x + yi) as
shown below:
x + yi
- (a + bi)-
(x - a) + (y- b)i

Implemen tation in C: Observe that real' part of result = Real part of 1sr number-
Real part of 2nd number and Imaginary part of result = Imaginary part of 1sr number-
Imaginary part of 2nd number. So, if a and b are two complex numbers, then the
resulting complex number c is given by

.c.r = a.r - b.r;


c.i = a.i - b.i;

The function to add two complex numbers a and b is shown below:

Example 4.9.2.1: C function to subtract one complex number from the other
COMPLEX subtract(COMPLEX a, COMPLEX b)
{
COMPLEXc;
c.r = a.r - b.r;·
c.i = a.i - b.i;

return c;
}
Q Systematic Approach to Data Structures using C - 4.49

4.9.3 Multiplying two complex numbers


Now, let us see "How to multiply two complex numbers?" Given two complex
numbers (x + yi ) and ( a + bi), multiplication can be performed as shown below:

(x + yi) (a + bi) = (xa + xbi + yai + ybi")


= (xa - yb) + (xb + ya)i

Implementation in C: Observe that real part is obtained by multiplying real parts of


two complex numbers and subtracting the product of two imaginary parts. So, if a and
b are two complex numbers, then the real part of complex number c is given by

c.r = a.r*b.r - a.i*b.i

Imaginary part is obtained by multiplying real part of 1st number with imaginary part
of 2nd number and adding to the product of imaginary part of 1sl number with real part
of 2nd number i.e.,

c.i = a.r*b.i + a.i*b.r

The function to multiply two complex numbers a and b is shown below:

Example 4.9.3.1: C function to multiply two complex numbers


COMPLEX multiply (COMPLEX a, COMPLEX b)
{
COMPLEXc;

c.r = a.r*b.r - a.i*b.i;


c.i = a.r*b.i + a.i*b.r;

return c;
}

4.9.4 Dividing a complex number by the other


Now, let us see "How to divide a complex number by other complex number?" Given
two complex numbers (x + yi) and (a + bi), let us divide (x + yi) by (a + bi). This can
be done mathematically as shown below:
4.5Q Q Derived types - enumerated, Structure and Union

(x + yi) (x + yi)(a - bi) xa - xbi + yai - ybi2 (xa + yb) (ya - xb)i
= +
(a + bi) (a + bi)(a - bi)

So, the real part is obtained by adding the product of two real parts with the product
of two imaginary parts and dividing the result by a2 + b2 which is sum of squares of
reat part and imaginary part of the dividend. If a and b are two complex numbers,
then the real part of c (which is the result) is given by

c.r = (a.r*b.r + a.i*b.i ) / (b.r*b.r + b.i*b.i);

The imaginary part of the result is obtained by multiplying the imaginaty part of 1st
number with real part of 2nd number and then subtract the product of real part of 1st
ttutnber and imaginary part of 2nd number. Finally, the whole result should be divided
by a2 + b2. If a and b are two complex numbers, then the imaginary part of c(which is
~t result) is given by
I

c.i =( a.i=b.r - a.r*b.i ) / (b.r*b.r + b.i*b.i);

•Thus, the function to divide a by b and storing the result in c is shown below:

Example 4.9.4.1: C function to divide a by b


COMPLEX divide (COMPLl:X a, COMPLEX b)
~.{
COMPLEXc;

c.r = (a.r*b.r + a.i*b.i) / (b.r*b.r + b.i*b.i);


c.i = ( a.i*b.r - a.r*b.i ) / (b.r*b.r + b.i*b.i);

return c;
I }

4.9.5 Reading a complex number

f
The function to tead a complex number is shown below:
••
~ Systematic Approach to Data Structures using C - 4.51

Example 4.9.5.1: C function to read a complex number

/* function to read a complex number */


COMPLEX read_complexO
{
COMPLEX x;
float a;

printf("RPart = ");' scanf("%f',&a);


x.r= a;

printf("IPart = "); scanf("%f',&a);


X.I = a;

return x; /* Complex number */

Note: The function read_complexO reads a complex number and the function
write_complexO is used to display a complex number. These two functions are self-
explanatory and left as an exercise to the reader to understand the logic.

4.9.6 Writing a complex number


The function to display a complex number is shown below:

Example 4.9.6.1: C function to display a complex number

/* function to display a complex number */


void write_complex(COMPLEX a)
{
if (a.i >=0)
printf("%5.2f + %5.2fi\n",a.r, a.i); /* To print +ve imaginary part */
else
printf("%5.2f %5.2f i \n",a.r, a,i); /* To print -ve imaginary part */
}

The complete program to add, subtract, multiply and divide two complex numbers is
shown below:
4.52 Q Derived types enumerated, Structure and Union
Example 4.9.7.1: C program to perform arithmetic operations on complex numbers

#include <stdio.h>
/* Structure definition of a complex number */
typedef struct
{
float r; /* real part */
float i: /* imagi nary part */
} MP~.-
/* Irrcf ucio: xnrnpfe 4.9.1.1: C function to add two complex numbers */
/* Include: Example 4.9.2.1: function to subtract a complex number from the other */
/* Include: Example 4.9.3.1: C function to multiply two complex numbers *
/* Include: Example 4.9.4.1: C function to divide a by b *1
/* Include: Example 4.9.5.1: C function to read a complex number */
/* Include: Example 4.9.6.1: C function to display a complex number *1
void maint)
{
COMPLEX a; /* First complex number *1
cOMPLEXb; 1* Second complex number *1
cOMPLEXc; 1* Resultant complex number */
IInput
printf("Enter first complex number\n"); I Enter first complex number
a = read complext); Rpart = 4
I Ipart = 2
printf("Enter second complex number\n");1 Enter the second complex no.
b = read_complexO; I Rpart = 2
I Ipart = 2
printf("First complex number = ");. I First number = 4.00 + 2.00i
write_complex(a);
I
printf("Second complex number = "); I Second number = 2.00 + 2.00i
write _complex(b);
I
c = add(a,b); I
printf("Sum of complex numbers = "); I Sum = 6.00 + 4.00i
write _complex( c); I
c = subtract(a 'b)' J
printf("Diffc Ten e = ''); I Difference = 2.00 + O.OOi
write_complex(c); I
Q Systematic Approach to Data Structures using C - 4.53

c = multiply(a,b);
I
printf("Product of complex numbers = "); : Product = 4.00 + 12.00i
write _complex( c);
I
c = divide(a,b);
printf("Division of complex numbers = "); : Divsn result = 1.50 + -0.50i
write _ complex( c);
I

4.10 Union and its definition

In this section, we shall see another concept called union which is derived from
structures. Let us see "What is a union?"

Definition: A union is a derived data type like structure. So, union can also be treated
as a collection of variables under a single name. All these variables may contain data
items of similar or dissimilar data types. Each variable in the union is called a
member or a field.
Now let us see "How union is declared and used in C?" The syntax,
declaration and use of union is similar to the structures but its functionality is totally
different. Thus, the general format (syntax) of a union definition is shown below:

union tag_name
{
type 1 member 1;
type2 member2;

}; Note: semicolon is must

Observe the following points while defining a union.

• union is the keyword which tells the compiler that a union is being defined.
• member1, member2, ..... are called members of the union. They are also called
fields of the union.
• The members are declared within curly braces. The members can be any of the
data types such as int, char, float etc.
• There should be semicolon at the end of closing brace
4.54 Q Derived types - enumerated, Structure and Union
F or the pointer
arrow/selection op
Example 4.10.1: Consider the following definition and declaration:
pointer variable x,
typedef union x->i
{ x->c
int 1; union definition x-><
double .d:'
char c', Let us consider SI
Note: For the union definition memory is not allocated
} ITEM; union.

ITEM x; } union declaration Example 4.10.3:


Note: For the union declaration memory is allocated
#include <stdio.h
Note that ITEM is the derived data type and the variable x is of type ITEM. The
void maint)
definition of a union does not allocate memory since the definition is not associated
{
with any variable. But, in the declaration, the definition is associated with a variable
typedefu
x. So, the memory is allocated for the variable x.
{
int
ch
Example 4.10.2: Another way of declaring the same variable x is shown below: fill
} STUDE
union item
{ STUDEl'I
int 1; Note: Since the variable x is associated with the
double d; definition, the memory is allocated. x.marks:
char c; printf("~
} x;
x.grade =
printf("(
Now, let us see "How to reference or access members of the union?" To access the
members of union, the same syntax used to access various members of a structure can x.perce
be used. For example, by using the dot operator ('. '), we can access various members printf(".
of the union as shown below:
}
x.i
x.d Observe the fo
x.c ~ After execi
value 100
The variable x is associated with union can also be declared as a pointer as shown garbage val
below:
union item *x;
Q Systematic Approach to Data Structures using C - 4.55

For the pointer variables, the indirection operator * and dot operator or
arrow/selectionoperator -> can be used to access the members. For example, using
pointervariable x, the members can be accessed as shown below:

x->i or (*x).i
x->d or (*x).d
x->c or (*x).c

not allocated Let us consider some examples to understand the difference between structure and
uruon.

; allocated

ITEM. The
I Example4.10.3: Program to access various members of a union

#include<stdio.h>

t associated voidmaint)
h a variable {
typedef union
{
int marks;
elow: char grade;
float percentage;
} STUDENT;

with the STUDENT x;


: Output
x.marks = 100;
printf("Marks: %d\n",x.marks); I
x.grade = 'A';
access the printf("Grade : %c\n",x.grade);
ucture can
; members

Observe the following points during execution of the above program:


~ After executing the statement x.marks = 100, the member marks will hold the
as shown value 100 whereas other members such as grade and percentage contains
garbage value and should not be accessed.
4.56 Q Derived types - enumerated, Structure and Union·

•.. After executing the statement x.grade = 'A', the member grade will hold the
value 'A' whereas other members marks and percentage contains garbage value Example 4.1
and should not be accessed following stn
• After executing the statement x.percentage = 99.5, the member percentage will
hold the value 99.5 whereas other members marks and grade contains garbage typed
value and should not be accessed. {

ote: It is observed from the above output that only one member of union can hold a
value at a time. It is not possible to access all the members simultaneously. So, the
variable of type STUDENT can be treated as integer variable or char variable or float } DA'
variable. Now, consider the same program with structure
DAT)
Example 4.10.4: Program to access various members of a structure
Solution: Th
#include <stdio.h> member ofth
bytes. In this
void maint) are allocated
{ members nan
typedef struct
{
int marks;
char grade;
float percentage;
1
} STUDENT;

STUDENTx~

x.marks = 100;
x.grade = 'A';
x.percentage = 99.5; I Output The memory
I
printf("Grade : %c\n",x.grade); arks: 100
printf("Marks: %d\n",x.marks); rade: A
1000
printf'('Percentage: %f\n", x.percentage); JL-----+: ercentage: 99.5
} I
I ~

Fig
Note: It is observed from the above output that the all the members of a structure can
hold individual values at a time. It is possible to access all the members of a structure
simultaneously.
~ Systematic Approach to Data Structures using C - 4.57

rade will hold the


tainsgarbage value Example 4.10.5: Now, let us see "What IS the memory representation for the
following structure and union?"
er percentage will
e contains garbage typedef union typedef struct
{ {
char c·, char c·,
of union can hold a int ,
1· int 1",

ltaneously.So, the float f, float f,


ar variable or float } DATA; } DATA;

DATA x; DATA x;

Solution: The memory allocated by the compiler is large enough to hold the largest
member of the union. Suppose, int occupy 2 bytes, char occupy 1 byte, float occupy 4
bytes. In this example, the member d occupies more memory (4 bytes) and so 4 bytes
are allocated for the variable x. But, this allocated memory is shared by all the
members namely i, d and c as shown below:

1000 1001 1002 1003


~ I
+-c---1
i

e f ,

Fig. 4.10.a sharing of memory by union members

The memory representation for the structure with same fields is shown below:

1000

~c~r------T_
1001

i-.I. 1002 1003

;]----.o.-J
1004

--,+---I
1005 1006 1007

Fig. 4.10.b Unique ~emory locations for members of structure


of a structure can
bersof a structure
.•
4.58 Q Detived types - enumerated, Structure and Union

Now, let us see "What are the differences between a structure and union?" consider
the following examples:
Definition: The
Structure Union normally is usee
1. The keyword struct is used to define a 1. The keyword union is used to define together using a
structure a union. the various bits c
or union. So, bit
2. When a variable is associated with a 2. When a variable is associated with a allows the user t(
structure, the compiler allocates the umon, the compiler allocates the
memory for each member. The sizeof memory by considering the size of the
Bit-fields can pn
structure is greater than or equal to largest member. So, size of union is
tighter packing
the sum of sizes of its members. The equal to the size of largest member
reasons:
smaller members may end with (Fig. 4.1 O.a)
• Data can
unused slack bytes (see section 4.5.1,
• Some de
figure 4.5.2)
within a'
3. Each member within a structure IS 3. Memory allocated IS shared by reset me
assigned unique storage area individual members of union prograrm
(Fig. 4.1 O.b) (Fig. 4.1 O.a) I • Certaine
• Even th:
4. The address of each member will be 4. The address IS same for all the using bit
in ascending order This indicates that members of a union. This indicates and undt
memory for each member will start at that every member begins at offset
different offset values (Fig 4.1 O.b) values (Fig. 4.1 O.a) Now, let us see
1

5. Altering the value of a member will 5. Altering the value of any of the part of the struc
not affect other members of the member will alter other member
s
structure: See example 4.10.4 values. See example 4.10.3

6. Individual members can be accessed 6. Only one member can be accessed at


at a time. See example 4.10.4 a time. See example 4.10.3

7. Several members of a structure can be 7. Only the first member of a union can
initialized at once be initialized

where
4.11 Bit-field • data_~
• Identif
We can access and manipulate individual bits using bit-wise operators in C language.
• biUen
Another alternative method of accessing bits is using bit-fields. Now, let us see "What
is a bit-field?" Note:The col
d union?" consider ~ Systematic Approach to Data Structures using C - 4.59

Definition: The bit-field is a special feature available in C language which is


n
normally is used to manipulate the bits. A group of several bits can be packed
is used to define together using a structure. Since bit-fields are defined within a structure or union,
the various bits can be accessed in a way we access individual members of a structure
associated with a or union. So, bit-field is defined as a special type of structure or union element that
iler allocates the allows the user to access individual bits. ~
ringthe size of the
, size of union is Bit-fields can provide greater control over the structure's storage allocation and allow
largestmember tighter packing of information in memory. Bit-fields are useful for the following
reasons:
• Data can be densely packed using bit-fields.
• Some devices will transmit encoded status information in one or more bits
within a byte. Using the bitwise operators onecan see the flags that are set or
is shared by reset and based on this information necessary action may be taken by the
of union programmer.
• Certain encrypted routines some times access the bits within a byte
ame for all the • Even though bit manipulations can be performed using bitwise operators,
n. This indicates using bit-fields the programs will be more structured and we can easily read
and understand.
begins at offset

Now, let us see "What is the syntax of bit-field?" The bit-field can be defined" as a
of any of the part of the structure in the following manner.
r other member
4.10.3 struct tag
{
an be accessed at data_type identified :bit_Iength;
4.10.3 data_type identifier2: bit_length;

er of a union can
data_type identifier3:bit_Iength;
};
where
• data_type if of type int or unsigned int
• identifierl, identifier2 etc., are the names of the bit-fields
orsin C language.
• bit_length is the number of bits used for the identifiers
, letus see "What
Note:The colon (':') is in between the identifiers and bit_lengths
4.60 Q Derived types - enumerated, Structure and Union

If int occupies 2 by!


Example 4.11.1: Structure containing bit-fields with declaration total memory requii
Suppose we want
Consider the following definition and declaration consisting of various bit-fields: memory. This can hi

1* No memory is allocated for defining bit-fields *1 Field


typede struct
Name
{
Sex
char name[30];
unsigned sex : 1;
Age
unsigned age : 5;
Rollne
unsigned rollno : 7;,
Brancl
unsigned branch: 2;
} STUDE T;

STUDENT a[IOO]; 1* Memory is allocated for the variable a */


So, in total 30 byn
As in case of structures, just by defining bit-fields, memory will not be allocated. But,
information can be 1
if the defmition is associated with a variable as shown in the declaration, memory will
bytes for 100 studen1
be allocated.
compressing the in:
combined into a sing
part of the structure i:
Let us see, "When to use bit-fields?" by considering examples. Suppose, we want to
store the information of n students such as name, sex, age, roll_number and branch.
typdef struet
Suppose there are four branches "Computer Science", "Information Science",
{
"Electrical Science" and "Electronics and Communication". The name of the student
char
and branch are array of characters and so, we reserve 30 bytes to store the name and
unsign
30 bytes to store the branch. The declaration using structure can be
unsign
unsign
typedef struct
unsign
{ } STUDE T;
char name[30]; 1* Name of the student *1
char sex; 1* Sex of the student *1
STUDENTa[
int age; 1* Age of the student *1
int rollno; 1* Roll number of the student */
Note: The bit-fields
char branch[30]; 1* Branch of the student *1
structure or union.
} STUDENT;
Consider the progran
STUDENT a[1 00]; 1* Capacity to store info of 100 students */
message.
4.60 Q Derived types - enumerated, Structure and Union
, .
If int occupies 2
Example 4.11.1: Structure containing bit-fields with declaration total memory n
Suppose we w
Consider the following definition and declaration consisting of various. bit-fields: memory. This c

1* No memory is allocated for defining bit-fields *1 F


typede struct 1-
{ S
char name[30];
unsigned sex : 1; j
unsigned age : 5; f
unsigned rollno : 7;, I
unsigned branch: 2;
} STUDE T;

STUDENT a[100]; 1* Memory is allocated for the variable a */


So, in total 3
As in case of structures, just by defining bit-fields, memory will not be allocated. But, information ca
if the definition is associated with a variable as shown in the declaration, memory will bytes for 100 ~
be allocated. compressing 1
combined into
part of the stru
Let us see, "When to use bit-fields?" by considering examples. Suppose, we want to
store the information ofn students such as name, sex, age, roll_number and branch. typdef
Suppose there are four branches "Computer Science", "Information Science", {
"Electrical Science" and "Electronics and Communication". The name of the student
and branch are array of characters and so, we reserve 30 bytes to store the name and
30 bytes to store the branch. The declaration using structure can be

typedef struct
{ } STU
char name[30]; 1* Name of the student *1
char sex; 1* Sex of the student *1 STUD
int age; 1* Age of the student */
int rollno; 1* Roll number of the student *1 ote: The b
char branch[30]; /* Branch of the student *1 structure or u
} STUDENT;
Consider the
STUDENT a[100]; 1* Capacity to store info of 100 students */ message.
Q Systematic Approach to Data Structures using C - 4.61

Ifint occupies 2 bytes and a character 1 byte, the size of the structure is 65 bytes. So,
totalmemory required, to store the information of 100 students will be 6500 bytes.
Suppose we want to compress the information to occupy minimum amount of
memory.This can be done as follows:

Field Length Contents


Name 30 bytes Name of the student
Sex 1 bit 0- Female
1 - Male
Age 5 bits Age of the student
Rollno 8 bits Roll no of the student
Branch 2 bits 00 - Computer Science
01 - Information Science
10 - Electrical Science
11 - Electronics and Communication

So, in total 30 bytes for the name and 16 bits i.e., 2 bytes for the rest of the
information can be used. In this technique, we use 32 bytes per student and 3200
bytes for 100 students. Thus, we can reduce the usage of the memory significantly by
compressing the information. The fields sex, age, rollno and branch can be
combined into a single integer value called bit-field. The bit-field can be declared as a
part of the structure in the following manner.

typdef struct
{
char name[30]
unsigned sex : 1;
unsigned age : 5;
unsigned rollno : 7;
unsigned branch: 2;
} STUDENT;

STUDENT a[100];

Note: The bit-fields can be accessed III the same way we access members of a
structure or union.

Consider the program to enter the values for bit-fields and display the appropriate
message.
Q Systematic Approach to Data Structures using C - 4.61

Ifint occupies 2 bytes and a character 1 byte, the size of the structure is 65 bytes. So,
totalmemory required, to store the information of 100 students will be 6500 bytes.
uppose we want to compress the information to occupy minimum amount of
memory.This can be done as follows:

Field Length Contents


Name 30 bytes Name of the student
Sex 1 bit 0- Female
1 - Male
Age 5 bits Age of the student
Rollno 8 bits Roll no of the student
Branch 2 bits 00 - Computer Science
01 - Information Science
10 - Electrical Science
11 - Electronics and Communication

So, in total 30 bytes for the name and 16 bits i.e., 2 bytes for the rest of the
information can be used. In this technique, we use 32 bytes per student and 3200
bytesfor 100 students. Thus, we can reduce the usage of the memory significantly by
compressing the information. The fields sex, age, rollno and branch can be
combined into a single integer value called bit-field. The bit-field can be declared as a
part of the structure in the following manner.

typdef struct
{
char name[30]
unsigned sex : 1;
unsigned age : 5;
unsigned rollno : 7;
unsigned branch: 2;
} STUDENT;

STUDENT a[100];

ote: The bit-fields can be accessed In the same way we access members of a
structure or union.

Consider the program to enter the values for bit-fields and display the appropriate
message.
4.62 ~ Derived types - enumerated, Structure and Union

Example 4.11.2: Program to show the usage of bit-fields and its use
#include <stdio.h>
/* Structure definition to represent student information */
typdef struct
{
char name[30];
unsigned sex :1;
unsigned age :5;
unsigned rollno :8;
unsigned branch :2;
} STUDENT;
void maint)
{
STUDENT a[lO];
int i, n, sex, rollno, branch, a ge;
printf("Enter the no: of students\n");
scanf("%d" ,&n);
for (i = 0; i < n; i++)
{
printf("Enter the information of student = %d\n" ,i+ 1);
printf("Name : "); /

scanf(" %s",a[i].name);
printf("Sex : ");
scanf("%d",&sex);
printf("Age : ");
scanf("%d" ,&age);
printf("Roll no : ");
scanf("%d",&rollno );
printf("Branch : ");
scan f("%d ",&branch);
a[i].sex = sex;
a[i].age = age;
a[i].rollno = rollno;
a[i].branch = branch;
}
~ Systematic Approach to Data Structures using C - 4.63

printf(" Name Sex Age Rollno Branch\n");

for (i = 0; i < n; i++)


{
printf("%20s ",a[i].name);

switch(a[i].sex)
{
case 0:
printf(" Female");
break;
case 1:
printf(" Male ");
break;
}

printf("%4d %5d" ,a[i].age,a[i).rollno);

switch(a[i].branch)
{
case 0:
printf(" Computer Science\n");
break;
case 1:
printf(" Information Sciencein");
break;
case 2:
printf(" Electrical Science\n");
break;
default:
I

printf(" Electronics and Communication\n");


break;
}
}
}

ow, let us see "What are the various restrictions imposed while using bit-fields?"
The various restrictions in using the bit-fields are shown below:
4.64 Q Derived types - enumerated, Structure and Union

• Address of a bit-field can not be accessed.


• Pointers cannot be used to access bit fields.
• Bit-fields can not be declared as static.
• No field can be longer than 32 bits (1 long word).
• It is not possible to declare arrays of bit fields.
• The ampersand operator (&) cannot be applied to fields, so there cannot be
pointers to bit fields. Hence, we can not use scanf to read values into bit-
fields.

Exercises:

1. What is a structure? Explain with syntax and an example.


2. What is the difference between a structure and an array?
3. How a structure can be initialized? Explain with an example
4. How the members of a structure can be accessed? Explain when'.' is used and
when' ->' or * operators are used to access the fields within the structure?
5. What is a structure? How does a structure differ from an array? How are structure
members assigned values and are accessed? Explain.
6. Explain array of structures with example
7. What are nested structures? Explain with an example
8. Is it possible to have structures within structures? Explain with an example
9. Is it possible to return the value of a structure using return statement? If the values
of two or more structures is needed in the calling function, what to do? Explain
with an example.
10. Write a C program to add, subtract, multiply and divide two complex numbers.
Each function should return a complex number after performing the respective
operations. r
11. What is a union? How is it different from structure? With a suitable example show
how union is declared and used in C.
12. What is the difference between structure and union?
13. Write a C program to arrange the student record based on increasing order ofro11
numbers, increasing order of marks, increasing order of their age. Assume the
student record contains the following fields': name, age, branch, marks, roll
number and address.
~GE OF €'
Q'v\, ,...- 1'G>:
••.•••...•••
(j rr """",
~«'
~/' ~~i /
!:Y (\.,:~ \.O~··-z.
~(
r (~o.
\.0.··· . )
....) ~
~I
p..cc. »> "?' ~
Chapter ~: Binary Files ~\. C&\\. I
'-
~O'·'··· /'"
r-------------------------------------.~~~ .J Cl~
I What are we studying in this chapter? '~~ e;;;: __
~
-"-! ~/

• Classification of Files
• Using Binary Files
• Standard Library functions for files - 2 hours

S.1 'Files and Classification of files

We know that the function scanf() is used to enter the data from the keyboard and
printl'() is used to display the result on the video display unit. This works fine when
the input data is very small. But, as the volume of input data increases, in most of the
applications. we find it necessary to store the data permanently on the disk and read
from it for the following reasons:
• It is very di Ificult to input large volume of data through terminals
• It is time consuming to enter large volume of data using keyboard.
• When we are entering the data through the keyboard, if the program is
-terminatcd for any of the reason or computer is turned off, the entire input data
is lost.

To overcome all these problems, the concept of storing the data in disks was
introduced. Here, the data can be stored on the disks; the data can be accessed as and
when required and any number of times without destroying the data. The data is
stored in the form of a file. Now, let us see "What is a file? How the data is stored in a
file?"

Definition: A file is defined as a collection of related data stored in auxiliary devices


such as disks, CDs etc. The data is recorded on the auxiliary devices using Os and 1s
(called bits). The auxiliary devices will not assign any relationship between the
various bits. The pictorial representation of data on auxiliary storage device is shown
below:

01 00 oon 1 01 00 001 0 0100 0011 0000 1101 0011 0001 0000 110 I f
'if

EOI'
Note: EOF stands for End Of f.ile
S.! tl inary files

Once we know the definition of file, let us see "What are the various types of files?"
When the data stored in auxiliary device is read by the program, the data (stored in
terms of as and Is) can be interpreted as either a text file or a binary file. Thus, there
are two types of files as shown below: EOF

Data on an auxiliary device i


01000001 0100 0010 0100 0011 0000] 101 0011 0001 0000 1101 6

'---------------------------~--------------------------~
File
~TextFile
4 Binary File
Thus, it is very clear that even though the data is stored in terms of as and 1s on a
disk, wc can interpret them either as text file or binary file.

5.1.1 Text file


Now, let us see "What is a text file?"

Definition: A text file is the one where data is stored as a stream of characters that
can b processed sequentially. In the text format, data are organized into lines
terminated by newline character. The text files are in human readable form and they
can be created and read using any text editor. Since text files process only characters,
they can read or write only one character at a time. A newline may be "converted to
carriage return and line feed character. Note: newline character = carriage return +
linefeed
Because of these translations, the number of characters written/read may not
be the same as the number of characters written/read on the external device.
Therefore, there may not be a one-to-one relationship between the characters
written/read into the file and those stored on the external devices.
For example, the data 2345 requires 4 bytes with each character occupying
exactly one byte. A text file can not contain integers, floating-point numbers etc. To
store the data such as integers, floating point numbers etc., they must be converted to
their character-equivalent formats, For example, the data 2345 in text file is stored as
sequence of4 characters '2', '3', '4' and '5'. The following figure shows
• How 6 characters are entered from the keyboard
• How the 6 characters entered from keyboard are stored in file
t How the 6 characters stored in a file are displayed on the monitor/printer
41(A) 42(B) 43(C) OD(.J) 31(l) OD(.J) EOF
~~~~~~
010000010100001001000011 0000 1101 0011 0001 00001101 [:.,

ABC.J ABC Hardcopy


1...1 1

Note: In the above figure, the symbol.J represent the return key and its ASCIl
character is osoo (13 in decimal). The ASCII values of A, B, Care Ox41 (65
decimal),Ox42 (66 in decimal), Ox43 (67 in decimal) respectively. The ASCII values
of 1,2,3 etc. are Ox31 (48 in decima\) ,Ox32(49 in decima\) and so on. The symbol 6.
represents end of file.

5.1.2 Binary file

Now, let us see "What is a binary file?"

Definition: A binary file is the one where data is stored on the disk in the same way
as it is represented in the computer memory. The binary files are not in human
readable form and they can be created and read only by specific programs written for
them. The binary data stored in the file can not be read using any of the text editors.
For example, the data 2345 takes 2 bytes of memory and is stored as Ox0929
i.e., Ox09 is stored as one byte and Ox029 is stored as other byte. The number of
characters written/read is same as the number of characters written/read on the
external device. Therefore, there is one-to-one relationship between the characters
written/read into the file and those stored on the external devices.

Now the question is "What is the difference between a text file and a binary file?"
TIle differences between these two types of files are shown below:

Text file Binary file

1. Human readable format 1. Not in human readable format


5.4 Q Binary files

2. Data is stored as lines of characters 2. Data is stored on the disk in the same
with each line terminated by \n which way as it IS represented III the
may be translated into carriage return computer memory
-I- line feed

3. Translation of newline character to 3. No translation of any type


carriage return + line feed

4. Data can be read using any of the text 4. Data can be read only by specific
editor programs written for them

5. The number of characters written/read 5. The number of characters written/read


may not be the same as the number of is same as the number of characters
characters written/read on the external written/read on the external device
device . ch as disk such as disk

6. There may not be a one-to-one 6. There IS one-to-one relationship


relationship between the characters between the characters written/read
written/read into the file and those into the file and those stored on the
stored on the external devices. external devices.
7. The data 2345 requires 4 bytes with 7. The data 2345 requires 2 bytes and
each character requiring one byte. So, stored as Ox0929.The data 2345 is
it is stored as Ox32, Ox33, Ox34, Ox35 stored as Ox09 and Ox29 thus
(ASCII values) thus requiring 4 bytes requiring 4 bytes.

5.2 Using Binary files

Normally the binary files are associated with structures as shown in figure below:

File

~II,----
structures
Q Systematic Approach to Data Structures using C 5.5

Each rectangle in the figure represents a structure. At the end of a file there is a file
marker (6) which denotes end of file (EOF) marker. The four steps that are used
during the manipulation of binary files are shown below:

Declare a file pointer variable

Open a file
Steps in using
the files Read the data from the file or write the data into file

Close the file

5.2.1 Declare a file pointer variable

We know that all the variables are declared before they are used. Likewise, a file
pointer variable also should be declared. Now, let us see "How to declare a file
pointer variable?" A file pointer variable fp should be declared as a pointer to a
structure of type FILE as shown below:

#include <stdio.h>

FILE *fp; /* Here, fp is a pointer to a structure FILE */

void maint)
{
/* File operations */
}

Note that rILE is the derived data type which is defined already in header file stdio.h.
as a structure. The structure details are hidden from the programmer and this structure
is used to store information about a file.

Note: The file pointer fp can be used either as a local or global variable. In the above
syntax, the file pointer fp is used as a global variable. The file pointer fp can be used
to open a file, update a file and to close a file in sequence.

Analogy: The information of all the students in a college is maintained by the college
office. The information of a particular student such as name, address, branch and
semester details along with CET ranking, percentage of marks in PUC etc. is stored in
a file. If we want to read, write or update the student details we have to open a file,
5.6 Q, Binary files

update a file and finally close it. The same sequence of operations can be carried out
with respect to files in C also. Here too, before updating a file, it has to be opened and
after updating the file, it has to be closed.

Note: The first operation to be done before updating the file is opening a file. The last
operation to be done after updating is closing the file. .

5.2.2 States and modes of a file


Before opening a file, let us see "What are the various modes in which a file can be
opened/created successfully?" The various modes in which a file can be
opened/created successfully along with meanings are shown below:
Mode Meaning
r open a text file for reading

w create a text file for writing

a Append to a text file


Text file
r+ open a text file for read/write

w+ '.create a text file for read/write

a+ append or create text file for


J.
read/write
Modes
of a file
rb open a binary file [or reading

wb create a binary file for writing

ab append to an existing binary file


Binary file
r+b Open a binary file for read/write

w+b Create a binary file for read/write

a+b Append or create a binary file for


read/write

Note: It is clear from the above figure that the file can be either in read or write state.
If the file can not be opened successfully or can not be created then it is an error and
the file state will be error state. This results in three possible file states as shown
below: .
Q Systematic Approach to Data Structures using C 5.7

File states --E .


read state
write state
elTor state

Now, let us discuss each of the modes in detail:

r (read mode) This mode is used for opening an existing file to perform read
operation. The various features of this mode are shown below:
• Used only for the text file
• If the file does not exist, an error is returned IEOF
• The contents of the file are not lost 1..-----------, '+'
• The file pointer points to the beginning File contents 16
~----------~
I
File position after opening

w (write mode) This mode is used to create a file. The various features of this mode
are shown below: .
• Used only for the text file
• If the file does not exist, a file is created. .
• If the file already exists, the original contents of the file are lost
• The file pointer points to the beginning EOF

Pile position after opening

a (append mode) This mode is used to insert the data at the end of the existing file.
The various features of this mode are shown below:
• Used only for the text file
• If the file does not exist, a file is created
• If the file already exists, the file point er pomts to teen
h d I EOF
'
,
• The new data' is inserted at the end 'V

• Existing data can not be modified I File contents ~


~

File position after opening


5.8 g Binary files

Note: lfwe have + as the suffix for the above modes, then in all the above three cases
the file is opened for read/write operation with the same features as specified earlier.
For example, r+ (read/write), w+Iread/write), a+(read/write at the end)

rb (read mode) This mode is used for opening an existing file to perform read
operation. The various features of this mode are shown below:
+ Used only for the binary file
+ If the file does not exist, an error is returned IEep
+ The contents of the file are not lost r----------------, ~
File contents 6
• The file pointer points to the beginning T---------------~1

File position after opening


wb (write mode) This mode is used to create a file. The various features of this mode
are shown below:
+ Used only for the binary tile
+ If the file does not exist, a tile is created.
+ If the file already exists, the original contents of the file are lost
• The file pointer points to the beginning EOF

File position after opening


ab (append mode) This mode is used to insert the data at the end of the existing file.
The various features of this mode are shown below:
+ Used only for the binary tile
+. If the file does not exist, a tile is created
+ If the file already exists, the file pointer points to the end
+ The new data is inserted at the end -
+ Existing data can not be modifiedf-;' 1..,( )F
~
1 File contents 6
,

File position after opening


Note: Having a suffix -\- for the above three modes, then the tile is opened for
read/write operation. The remaining features remain same. The modes rb+, wb+ and
ab+ are same as r+b, w+b and a+b respectively.
~ Systematic Approach to Data Structures using C 5.9

Note: A mode with substring + is called update mode. This is because; the substring
which is part of the mode as explained earlier represent read/write operation.
-I-

5.3 Standard library functions for files

Now, let us see "What are the standard .library functions that are used for binary
files?" The various standard file library functions that we discuss with, respect to
binary files are shown below:
File open and close functions
~-~ Block read and write functions
Categories of
tile functions . ---11---" File positioning functions
- System file operations
•...••
-~ File status functions

Now, let us discuss each of these separately

5.3.1 File open and close functions

Once we know various modes in which a file can be opened or created, let us see
"How to open a file?" The file should be opened before reading a file or before
writing into a file. The syntax to open a file for either read/write operation is shown
below: .
#include <stdio.h>
FILE *fp;

fp = fopen(char *filename, char *mode)

where
• fp is a file pointer of type FILE
• filename holds the name of the file to be opened. The filename should be a
valid identifier.
• mode details are provided in section 5.2.2. This informs the library function
about the purpose of opening a file.

Return valuesThe function may return the following:


• File pointer of type FILE if successful
• NULL if unsuccessful
5.10 Q Binary files

If the file pointer fp is not NULL, the necessary data can be accessed from the
specified file. If a file cannot be opened successfully for some reason, the function
retuins NULL. We can use this NULL character to test whether a file has been
successfully opened or Hot using the statement:

if (fp = NULL)
{
printf("Error in opening the file\n");
exit(O);
}

1* Using fp access file contents *1

Now, let us see "When to close d how to close a file?" When we no longer need a
file, we should close the file. This is the last operation to be performed on a file. A
file can be closed using close function. This ensures that all buffers are flushed and all
the links to the file are broken. Once the file is closed, to access the file, it has to be
re-opened. If a file is closed successfully, 0 is returned otherwise EOF is returned.
The syntax is shown below:

#include <stdio.h>

void maim)
{
FILE *fp;

fp = fopen("t.c", "rb");

if( fclose(fp) = EOF)


{
_printf("Error in closing the file\n");
return;
}

}
~ Systematic Approach to Data Structures using C 5.11

ote: If a program is terminated, all the opened files will be closed automatically.
But, as a programming practice, it is better to close all the opened files once we know
that the file pointers are not required.

5.3.2 Block read and write (Block 1/0) functions


We know that data are stored in the memory in the form ofO's and 1's. When we read
and write the binary files, the data are transferred just as they are found in memory
and hence there are no format conversions. Now, let us see "What are the functions
that are required to transfer the block of data to/from binary files?" The various input
and output functions that transfer block of data are shown below:

Categories of
I/O functions
-C freadr)
fwrite/)
Now, let us discuss each of these one by one.

5.3.2.1 File read - freadf)


Now, let us see "What is the syntax of fread? How does the function work.')" This
function is used to read a block of data from a given file. The prototype of freadi)
which is defined in header file "stdio.h" is shown below:

int fread (void *ptr, int size, int n, FILE *fp);

Before executing the function, we have to pass the following parameters:


• fp is a file pointer of an opened file from where the data has to be read from.
• ptr: The data read from the file should be stored in memory. For this purpose,
it is required to allocate the sufficient memory and address of the first byte is
stored in ptr. We say that ptr now points to buffer.
• n is the number of items to be read from the file.
• size is the length of each item in bytes.

Working: When the freadt) function is executed, the function reads n number of
items, each of length size bytes (n * size bytes) from the file associated with fp. The
data read from the file is copied into the memory location pointed to by ptr.

Returns
• Number of items successfully read
• If no items have been read or when error has occurred or end-of-file IS
encountered, the function returns 0 (zero).
5.12 Q Binary files

Note: Since this function will not return EOF, we have to check for possible error
using feof'() or ferrort) functions.

Example 5.3.2.1.1: Read a floating point value from the file and store it in variable f.
fread( &f, sizeof(float), 1, fp);

Example 5.3.2.1.2: C function to read 5 integers from the file and store it in array a.

#include <stdio.h>

void main/)
{
inta[lO];

fread(&a, sizeof(int), 5, fp);

The pictorial representation after executing freadt) is shown below:

fp - before fread fp - after fread EOF

............
rTfl6
III:: . [JJJJ'
[JJJJ III :' [JJJJ<:'
! II WJJ
4*5 = 20 bytes

::
! II :'[[0'I!; I DID'
[[[J III:: <

[JJJJ
< • <

a[l] a[2] a[3] a[4] a[5]

fread(&a, sizeof(int), 5, fp);

Note: 20 bytes (5 integers) are read from the file from the file pointer fp to the buffer
area identified by a. Here, location a is the place where the data read from the file is
stored. So, a is called buffer area. ote the position of file pointer fp before and after
fread operation.
Q Systematic Approach to Data Structures using C 5.13

ow, let us write a program to read n integers from the binary me. Assume the file
"test.dat" contains the integers stored in binary form,

Example 5.3.2.1.3: Program to read a file of integers from the file "test.dat"

#include<stdio.h>

void maint) I TRACING


{ I
FILE *fp; I
I
int a[10],n,i; I
char file_ name[20]; I
I
I
Input
priotf("Enter the file name\n"); I Enter the file name
scaof("%s" ,file_name); I test.dat
I

printf("Enter the number of integers\n"); Enter number of integers .


scanf("%d",&n); 3

if ((fp = fopenffile jiame.t'rb'') = NULL) fp


.L test.dat
{
printf("Error
return;
in opening the file\n"); ~ 10 20 30 40 50 60 I
}
-1 ,1/ ,1,.,1/
Iread] a, sizeof(int), n, fp); I
I
10 20 30 (After fread)
I a[O] ar 11 <1r2]
I
fp
I
I .L test.dat
I
I r 10 20 30 40 50 601
I

for (i = 0; i < n; i++)


{
printf("%d\n",a[i]); Output
102030
5.14 Q Binary files

.
Note: The sequence of operations carried out during the execution of above program
are:
• The file "test.dat" is opened and fp points to the first byte of opened file as shown
in figure.
• Since n = 3, three numbers are read from the file
• The three integers are copied into a[O], a[l] and a[2] respectively.
• After reading the file pointer fp points to 40 as shown in figure.
• Three items 10, 20 and 30 are displayed on the screen.

Now, let us see "How to read the data from a file into a structure?" For this to happen,
let us consider the following structure defmition:

Example 5.3.2.1.4: Read the information of a structure from the file using freadt).

typdef struct
{ Pictorial representation of structure
char name[25];
int marks1;
int marks2;
int marks3; marks3
} STUDENT; ~--+ marks2
'----- .• marks 1
STUDENT a, b[10];

Note: The structure has four fields. The memory is allocated for the structur
variables a and b. The pictorial representation of the memory allocated for variable a
and file contents before freadt) is executed is shown below:

a I__IJJI]]] buffer
Q Systematic Approach to Data Structures using C 5.15

~ow,let us see what will happen if the following statement is executed.

fread(a, sizeof(STUDENT), 1, fp);

The function reads a single structure from the file and store it in the variable a. The
pictorialrepresentation of the file pointer and variable a after fread operation is
shown below:

File contents fp EOF


~

I -, I II I I-, OTIIIJ .........


\ lIIillI" ~
.. l. ~
. ~

"'- Copied into ~

a/ OTIIIJ buffer

ote:After reading the first structure from the file, the file pointer fp is automatically
lpointsto next structure.

I Example 5.3.2.1.5:
For the structure definition shown in previous example, "What
willhappen when the following statement is executed?"

fread (b, sizeof(b), 10, fp);

Soiution:The function reads 10 structures from the file and store them in the variable
b one after the other starting from b[O], b[l], b[9]. The file pointer fp points to
theeleventh structure in the file.

5.3.2.2 File write - fwriteO

Now, let us see "What is the syntax of fwrite? How does the function workTThis
function is used to write a block of data into a given file. The prototype of fwritet)
whichis defined in header file "stdio.h" is shown below:

int fwrite (void *ptr, int size, int n, FILE *fp);


5.16 Q Binary files

Before executing the function, we have to pass the following parameters:


• fp is a file pointer of an opened file into which the data has to be written.
• ptr: The data to be written into the file should be stored in the memory. The
address of the first byte is stored in ptr. We say that ptr now points to buffer.
• n is the number of items to be written into the file.
• size is the length of each item in bytes.

Working: When fwritef) function is executed, the function reads n number of items,
each of length size bytes (i.e., n*size bytes) from the buffer pointed to by ptr and
writes into the file associated with fp. In other words, the data from the buffer which
is pointed by ptr is written into the file associated with fp.

Returns Number of items successfully written

Note: If number of items written is less than n, then an. error has occurred. It is the
responsibility of the programmer to use this value to check whether the write
operation is successful or not.

Example 5.3.2.2.1: Write a floating point value from variable f into file

fwrite(&f, sizeof(float), 1, fp);

Example 5.3.2.2.2: C function to write 5 integers stored in array a into the file

#include <stdio.h>

void maint)
{
int a[8] = {10, 20, 30, 40, 50, 60, 70, 80};

1* Here, file is opened successfully in write mode *1

fwrite(&a, sizeof(int), 5, fp);


The pictorial representation after executing fwrite 0 is shown below:


Q Systematic Approach to Data Structures using C 5.17

fp - before fwrite fp - after fwrite EOF

·: .. ... .;::..
· .. ..
::

ITIIJ" ITIIJ"
·~ ~;
..
;::

!'...~ ~ ITIIJ"
. ..
.~ ..~~ ......... ···ITIIJ·
::
. ..
tJ.

4*5 = 20 bytes

:· :
III::' ITIIJ'
ITIIJ. III :: ITIIJ'
III :: ITIIJ
, , ,

a[l] a[2] a[3] a[4] a[5]

fwrite( &a, sizeof(int), 5, fp);

Note: 20 bytes (5 integers) are read from the buffer a and are written into the file
associatedwith file pointer fp. Note the position of file pointer fp before and after
executingfwrite function.

Now, let us write a program to write n integers into the binary file. Assume the file is
"test.dat" .

Example 5.3.2.2.3:Program to write n integers into a file "test.dat"

#include<stdio.h>

void maim) TRACING


{
FILE *fp;
int a[6] = {10, 20,30,40,50, 60};
int n, 1;
char file_name[20];
Input
printf("Enter the file name\n"); Enter the file name
scanf("%s" ,file_name); test.dat

printf("Enter the number of integers\n"); Enter number of integers


scanf("%d" ,&n); 3
5.18 Q Binary files

if ((fp = fopen(file_name,"wb")) = NULL) fp

{
printf("Error in creating the file\n"); 6. (EOF)
return;
}

fwrite (a, sizeof(int), n, fp); a[O] a[ I] a[2] a[3] a[4] a[5]


10 20 30 40 50 60

fp test.dat

10 20 30 6. (EOF)

Contents of file after fwrite


}

Note:The sequence of operations carried out during the execution of above program
are:
• The file "test.dat" is opened in write mode and fp points to the beginning of file as
shown in figure. Observe that the file is empty.
• Since n = 3, three numbers are read from the buffer and are written into file
associated with file pointer fp.
• After writing the file pointer fp points to end-of-file
• Three items 10, 20 and 30 are displayed on the screen.

Now, let us see "How to write the data from a structure into a file?" For this to
happen, let us consider the following structure definition:

Example 5.3.2.2.4: Write the information of a structure into the file using fwritet).

typdef struct
{ Pictorial representation of structure
char name[25];
int marks1;
int marks2;
int marks3; marks3
} STUDENT; L-_-+ marks2
L.- + marks 1
STUDENT a, b[lO];
Q Systematic Approach to Data Structures using C 5019

Note: The structure has four fields. The memory is allocated for the structure
variables a and b. Assume the structure a is initialized to appropriate values. The
pictorial representation of the memory allocated for variable a and file contents before
fwriteO is executed is shown below:

fp EOF File contents

~/
8.

a I'--_.....IITIIIIJ buffer

Now, let us see what will happen if the following statement is executed.

fwrite(a, sizeof(STUDENT), 1, fp);

The function writes the values of structure identified by variable a into the file
associated with file pointer fp. The contents of file after executing fwrite is shown
below:

File contents fp EOF


~/
,
I
~
IIIIII
~
Copied into ~
8.

al . ITIIIIJ buffer
structure

Note: After writing the structure into the file, the file pointer points to end-of-file.
5.20 Q Binary files

Example 5.3.2.2.5: For the structure definition shown in previous example, "What
will happen when the following statement is executed?"

fwrite (b, sizeof(b), 10, fp);

Solution: The function reads 10 structures stored in the variable from b[O],
b[1], b[9] and writes into the file associated with file pointer fp. Finally, the file
pointer fp points to end-of-file.

5.3.3 File status functions

Now, let us see "What is the need for file status functions? What are the various
functions that inform the status of the file?" During input/output operations, the
following operations may be performed by the programmer:
• Reading beyond end of file marker
• Opening a file which is not existing
• Input invalid file name
• Attempting to write to a write-protected file etc.,

Such read and write errors results in abnormal behavior of the program and so should
not be ignored. If proper error checking is not provided, there may be premature
termination of the program or we may get incorrect output. For this reason Chas been
provided with various file status functions which can detect such errors. The various
file status functions provided in C language are shown below:

File status
functions ~
r feofi)
ferrort)
clearern)

5.3.3.1 feofO

Now, let us see "Why feoft) is used? How to use the function feofi)?" After opening
the file in read mode, the contents of the file can be read. During, this process we may
encounter end of file. This function is used to detect whether end of file is reached.
The syntax to check whether end of file is reached or not is shown below:
Q Systematic Approach to Data Structures using C 5.21

#inc1ude <stdio.h>

void mainO
{
FILE *fp;

fp = fopen(char *filename, char *mode)

r-~~~----------------l
I if (feof(fp)) Syntax I
I { I
: printf("End of file is reached\n"); I
I ~~~; :
I}
L . _I

where
• fp is a file pointer of type FILE
• filename holds the name of the file to be opened
• mode details are provided in section 5.2.2. This informs the library function
about the purpose of opening a file.

Return values The function accepts file pointer fp as a parameter and following
valuesare returned.
• true if end of file is detected (true - nonzero value)
• false if end of file is not detected. (false - zero value)

5.3.3.2 ferrur()

Now, let us see "Why ferrort) is used? How to use the function ferron)?" A file can
be opened in read or write mode. During reading from a file or writing into a file
following errors may occur:
• Modifying read only file
• Trying to read a file which is opened in write mode and so on.
5.22 Q Binary files

Th~ macro ferron) is used to detect an error that occurred during read or write
operations on a file. The syntax to check whether any error has occurred or not is
shown below:

#include <stdio.h>

void maint)
{
FILE *fp;
int c;

fp = fopen("test", "w");

c = getc(fp);
,----------------------1
I if (ferror(fp)) Syntax I
I { I
: printf("Error in reading the file\n"); :
I return; I
IL } JI

Note: Here, file is opened in write mode and using the function getct), we are trying
to read from a file. This is an error and this error is detected by the macro ferron) and
displays the message "Error in reading the file". The prototype declaration

int ferror(FILE *fp);

is available in the header file "stdio.h"

Return values The function accepts file pointer fp as a parameter and following
values are returned.
• true if an error is detected. (true - nonzero value)
• false if an error is not detected. (false - zero value)
Q Systematic Approach to Data Structures using C 5.23

5.3.3.3 clearerr'()
Now, let us see "What is the significance of the function clearert)?" During reading
and writing of a file an error may occur. Once an error occurs, the subsequent calls to
ferron) returns true until the error status is cleared. So, to clear the error status the
function clearem) is used. The prototype of this function is:

void clearer(FILE *fp);

and is defined in the "stdio.h"

5.3.4 File Positioning Functions


Now, let us see "What is the need for file positioning functions? What are the various
file positioning functions?" The file positioning functions are required in the
following scenarios:
• For accessing the random data from the file
• For changing the state of the file (from read to write or from write to read)

The various file status functions provided in C language are shown below:

File Positioning
functions
-E rewindt)
ftellO
fseekt)

Now, let us discuss each of these one by one.

5.3.4.1 Rewind file - rewindt)

ow, let us see "What is the need for the function rewindt)?" Explain. The function
rewind/) is used to set the file pointer to the beginning of the file. When the data is
written into the file, the file pointer points to the end of file as shown in figure below:
I EOF
'+'
/).
I File contents

" File positio n after writing

For this to happen, it is required that file should have' been opened in write mode.
Now, to process the entire file, we may have to start reading from the beginning of the
5.24 Q Binary files

file. In such situations, we have to close the file and open it in read mode. Instead, we
can use the function rewindt) which will move the file pointer to the beginning of the
file without closing and re-opening the file. After executing the function rewindt), the
file pointer points to the beginning of the file as shown below:
IEOF
Ir----------, '+'
File contents I fj,

File position after rewind

Earlier we wrote the data and now we are reading the data i.e., read and write
operations are being performed on file. So, always the file should be opened in
read/write mode using the mode "r+" or "rb+". The syntax is shown below:

rewind(fp);

whose prototype is defined in header file "stdio.h" as:

void rewind(FILE *fp);

5.3.4.2 current location - ftellO

Now, let us see "What is the need for the function ftellf)?" Explain. The function
ftellt) gives the current position of the file pointer from the beginning of the file. So, it
always gives the number of bytes from the beginning of the file relative to zero. The
syntax is shown below:

ftell(fp)

where fp is the file pointer. The prototype is defined in header file "stdio.h" as

long ftell(FILE *fp);

For example, consider the following figures:


EOF EOF

I ,I fj,

fp fp
Fig. 5.3.4.a Fig. 5.3.4.b
.!;l Systematic Approach to Data Structures using C 5.25

Notethat with respect to figure 5.3.4.a, ftell(fp) returns 0 and with respect to figure
5.3.4.b,the function ftell(fp) returns 3.

5.3.4.3Set position - fseekt)

Now, let us see "What is the need for the function fseekf)?" Explain. The function
fseekt) is used to set the file pointer at the specified position. In general, it is used to
move the file pointer to the desired position within the file. The file pointer can be
movedbackwards or forward any number of bytes. The syntax is shown below:

Syntax

fseek(fp, offset, start-point);

where
• fp is a file pointer.
• offset can take positive, negative or zero value and specifies the number of
bytes to be moved from the location specified by start-point.
• startpoint can take one of the values as shown below:

Constant V' lue Position of the file


SEEK - SET 0 Beginning of file
SEEK - CURRENT 1 Current position
SEEK - END 2 End of file

Note.The above constants and the following prototype

int fseek(FILE *fp, long offset, int start-point);

is defined in header file "stdio.h".

Return vnlucs'The function returns the following values


• value 0 on success
• non-zero value on failure

If offset is positive, the file pointer fp moves forwards. If it is negative, the file
pointer fp moves backwards.
5.26 Q Binary files

Example 5.3.4.3.1: Various methods of moving the file pointer fp within the file

• fseektfp, 0, 0) - file pointer fp moves to the beginning of the file


• fseektfp, 0, 1) - file pointer fp stays in the current position and is rarely used
• fscekifp, 0, 2) - file pointer fp moves to the end of file
• fseek( fp, n, 0) - file pointer fpmoves n bytes from the beginning of the file
• fseek(fp, n, 1) - file pointer fp moves n bytes from the current position of file
pointer
• fseek(fp, -n, 1) - file pointer fp moves n bytes backwards from the current
position of file pointer
• fseekrfp, -n, 2) - file pointer fp moves n bytes backwards from the end of file.

The following program computes the. size of a given file.

Example 5.3 ..4.3.2: C Program to print the size of a given file

#include <stdio.h> TRACING


#in2lude <process.h> I
I When file is opened
long file_size(FILE "fp)
{
I I fp
long length; I I MONALlKAll
I
I'
I

1* Move file pointer to end of the file *1 I file pointer is moved to end
fseektfp, OL, 2);
: I MONALIKAN

I EOF
I fp
1* Obtain the current position of file pointer *1 I
length = ftelltfp); I length = 8
return length; I
I
I
Q Systematic Approach to Data Structures using C 5.27

void main(void)
{
FILE *fp;
char file_name[20];

printf ("Enter the file name\n");


scanf("%s" ,file_name);

fp = fopen(file_name,"r");

if(fp = NULL)
{
printf("Error in opening the file\n");
exit(O);
}

printf("Filesize of%s is %ld bytes\n",file_name, filesizetfpj);

fcIose(fp );

Note: What is the difference between rewind(fp) and fseek(fp,OL,O)? Both the
functionsmoves the file pointer to the beginning of the file. So, Functionality is same,
butsyntax and number of parameters are different.

5.3.5 System File Operations

So far we have seen various file functions that are used to access the contents or the
file. There are some functions that operate on whole files instead of contents. These
functions use operating system calls and are called system file operations. Now, let us
see "What are system file operations?" The various system file operations that .uv
supported are shown below:
remove a file
System. file operations -
f
Now, let us discuss each of these one by one.
rename a file
create a temporary file
5.28 Q Binary files

5.3.5.1 Remove a file - rernovet)

Now, let us see "How to remove or delete a file?" The function removet) is used to
delete or remove a file. The prototype declaration is shown below:

int remove (char *filename);

This declaration is available in the header file "stdio.h". The parameter filename isa
pointer to the name of the file. "What does this function return?"

Return values The function returns the following values


• value 0 on success
• non-zero value on failure .

Example 5.3.5.1.1: Program to delete a file

#include <stdio.h>

void main(void)
{
char file_name[20];
int status;

printf ("Enter the file name\n");


scanf("%s" ,file_name);

status = remove(file_name);

if (status != 0)
{
printf("Error: File can not be deleted\n");
return;
}

printf("The file %s is successfully deleted\n",file_name);


}
Q Systematic Approach to Data Structures using C 5.29

5.3.5.2 Rename a file - renamet)

Now, let us see "How to rename a file?" The function renamet) is used to rename a
file. The prototype declaration is shown below:' ,

int rename (char *old_filename, char *new_filename);

This declaration is available in the header file "stdio.h". After executing the function,
old_filename is renamed as new filename and old file name does not exist "What
does this function return?"

Return values The function returns the following values


• value 0 on success
• non-zero value on failure

Example 5.3.5.2.1: Program to rename a file

#include <stdio.h>

void main(void)
{
char 0Id_file_name[20];
char new file name[20];
int status;

printf ("Enter the old file name\n");


scanf("%s" ,old_file _name);

printf ("Enter the new file name\n");


scanf("%s" ,new_file_name);

if (status != 0)
{
printf("Error: File can not be renamed\n");
return;
}

printf("The file is successfully renamed\n");


}
5.30 Q Binary files

5.3.5.3 Create a temporary file - trnpfilet)

Now, let us see "What is the purpose of using tmpfilet) function?" This function is
used to create a temporary binary file in "wb+" mode. So, the user can read or write
from this temporary file. This file is created temporarily because; it is automatically
deleted when the program is terminated. The prototype declaration is,shown below:

FILE *tmpfileO;

This declaration is defined in the header file "stdio.h "What does this function
return?"

Return values The function returns the following values


• Pointer to a file of type FILE success
• NULL on failure

To create a temporary file, we must define a file pointer and then open it as shown
below:

FILE *fp;

fp = tempfilet);
1

5.4 Using text files

The various file handling functions that are associated with text files are shown
below:

Text file handling


functions
-C Character related functions Ex: getct), putct)
. re Iate d functions
l':.
~ Stnng Ex: f:scannC:() fpri
nntnl':()
Now, let us discuss each of these functions in coming sections.

5.4.1 getct), putct)

Now, let us see "Wllat is the use of getct) and putct) functions? Explain with syntax"
The function getct) is a macro defined in stdio.h that gets one character from the file
pointer specified. The function putcf) is also a macro that outputs a character to a file
stream specified using file pointer. The syntax of getct) and putct) functions are
shown below:
Q Systematic Approach to Data Structures using C 5.31

Syntax Syntax

int getc(FILE *fp); int putc(int ch, FILE *fp);

On success, the function returns the On success, writes the character


characterpointed to by file pointer fp. stored in ch to the stream pointed to
Thefile pointer fp will automatically by the file pointer fp. If there is any
point to next character in the input error or end-of-file is encountered, the
stream.If there is any error or end-of- function returns EOF.
file is encountered, the function
returnsEOF.

Example5.4.1.1:Program to copy one file to other file using getct) and putct)

#include<stdio.h>
#include<process.h>

voidmaim)
I
FILE *fpl; /* Points to the input file */
FILE *fp2; /* Points to the output file */
char file 1[10]; /* Name of the input file */
char file_2[10]; /* Name of the output file */
int ch; /* used to store character read */
printf("Enter the input file\n");
scanf("%s" ,file_1);

1* Open the input file only in read mode */


if ((fpl = fopen(file_l,"r")) = NULL)
{
printf("0pening input file failed\n");
exit(O);

printf("Enter the output file\n");


'scanf("%s" ,file_2);

1* Open the output file only in write mode *1


fp2 = fopen(file_2,"w");
5.32 Q Binary files

if ( fp2 = NULL )
{
printf("Opening outfile failed\n");
exit(O);
}

/* read till end of file is encountered */


while ( (ch = getcrfp l) != EOF)
{

putc( ch, fp2); /* write each character read into ou put file */
}

/* close both input and output files */


fclose(fp 1);
fclose(fp2);
}

Note: The above program is self-explanatory with proper comments and the reader
should type the program, execute and understand how the program works.

~xample 5.4.1.2: C Program to concatenate two input files

#include <stdio.h>
#include <process.h>

void maim)
{
FILE *fp 1; /* Pointer to first input tile */
FILE *fp2' /* Pointer to second il}l2Ut-.tHe---*I
FILE *fp3: I P~UtPutfile */
--------~-
char file 1[20]; /* First input file name */
char file2[20]; i* Second input file name */
char file3[20]; /* Output file name */
char ch; /* Holds the character from both input files */

printf("Enter the first file\n");


<! scanf("%s",filel);
~ Systematic Approach to Data Structures using C 5.33

1* Open the first input file only in read mode *1


if ( (fpl = fopen(filel,"r")) ---: NULL)
{
printf("Error in opening the first file\n");
exit(O);
}

printf("Enter the second file\ll");


scanf("%s" ,file2);
1* Open the second input file only in read mode *1
if «fp2 = fopen(file2,"r")) = NULL)
{
printf("Error in opening the second file\n");
fcloseffp l);
exit(O);
}

printf("Enter the third file\n");


scanf("%s" ,file3);
,
1* Open the output file only in write mode *1
if «fp3 ='fopen(file3,"w")) = NULL)
{
printf("Error in opening the third file\n");
fclose(fpI);
fclose(fp2);
exit(O);
}

1* Input file is copied to output file *1


while ( (ch = getc(fpl)) != EOF) putc(ch,fp3);

1* Input file is appended to output file *1.


while «ch = getc(fp2)) != EOF) putc(ch,fp3);

fclose(fp 1);
fclose(fp2);
fclose(fp3);
5.34 Q Binary files

Example 5.4.1.3: Program for counting the characters, blanks, tabs and lines in file.
#include <stdio.h>
void maim)
{
FILE *fp; 1* Pointer to the input file name *1
char file_name[20]; 1* Input file name *1
char ch; 1* Holds the character read from file *1
int char_count = 0; 1* Holds count of all characters typed *1
int blank count = 0; 1* Holds count of blank characters *1
int tab_count = 0; 1* Holds count of only tabs *1
int line_count = 0; 1* Holds count of lines *1
printf("Enter the file name\n");
scanf("%s" ,file_name);
1* Open file only in read mode *1
if ( (fp = fopentfile jiame,"r") = NULL)
{
printf("Error in opening the file\n");
exit(O);
}
1* read each character till end of file encountered *1
while ( ( ch = getc(fp) ) != EOF)
{
1* Update character count *1
if ( ch = ' , ) blank _count++; 1* Update blank count *1
if ( ch = '\n' ) line_count++; 1* Update line count *1
if ( ch = '\t' ) tab_count++; 1* Update tab count *1
}
fclose(fp);
printf("Number of characters = %d\n", char_count);
printf("Number of tabs = %d\n", tab_count);
printf("Number oflines = %d\n", line_count);
printf("Number of blanks = %d\n", blank_count);
}
Q Systematic Approach to Data Structures using C 5.35
5.4.2 fscanf'(), fprintft)

Now, let us see "What is the use of fscanfi) function? Explain with syntax"

The function of fscanf and scanf are exactly same. But, instead of getting the input
from the keyboard, we get the input from the file specified. Because input is read
from the file, extra parameter file pointer has to be passed as the parameter. Rest of
the functionality of fscanf remains same as scanf. The syntax of fscanfl) is shown
below:
fscanf(fp, "control string", list);
where
• fp is a file pointer
• format string and list have the same meaning as in scanfi) i.e., the variables
specified in the list will take the values from the file specified by fp using the
specifications provided in format string.

Example 5.4.2.1: Explain what will happen if the following statement is executed.

fscanf(fp, "%d %s %f', &id, name, &salary);

Solution: After executing fscanf, the values for the variables id, name and salary are
obtained from the file associated with file pointer fp. This function returns the number
of items that are successfully read from the file.

Now, let us see "What is the use of fprintfi) function? Explain with syntax"

The function of fprintf and printf are exactly same. But, instead of displaying the
resulton the screen, the result is sent to the file. Since file is used, extra parameter file
pointer has to be passed as parameter. Rest of the functionality of fprintf remains
sameas printf. The syntax of fprintfi) is shown below:
fprintf'(fp, "format string", list);

where
• fp is a file pointer associated with a file that has been opened for writing.
• format string and list have the same meaning as in printf() function i.e., the
values of the variables specified in the list will be written into the file associated
with file pointer fp using the specifications provided in format string.
5.36 Q Binary files

Example 5.4.2.2: Explain what will happen if the following statement is executed.

fprintf(fp, "%d %s %f', id, name, salary);

Solution: After executing fprintf, the values of the variables id, name and salary are
'written into the file associated with file pointer fp. This function returns the number
of items that are successfully written into the file.

Example 5.4.2.3: Structure defmition for the following table:

USN Name Marks! Marks2 Marks3


+ve integer 25 characters +ve +ve +ve
integer integer integer

Solution: The above table can be represented using structure definition as shown b
elow:

typedef struct
{
int usn;
char name[20];
int marks l ;
int marks2;
int marks3;
} STUDENT;

Note: In the above definition, STUDENT is the user-defined data type

Example 5.4.2.4: C function to search for key_usn in the table shown in example
5.&2.3.

1* function to search for USN *1


int search_record(int key_usn, FILE *fp)
{
STUDENT st;
Q Systematic Approach to Data Structures using C 5.37

1* While not end of file *1


for (;;)
{
1* Obtain the student details from the file *1
fscanf(fp,"%d %s %d %d %d",
&st.usn, st.name, &st.marks1, &st.marks2, &st.marks3);

if (feof(fp)) break; 1* If end of file quit *1


if (key_usn = st.usn) return 1; 1* search successful *1
}

return 0; 1* Search failed *1


}

Example 5.4.2.5: C function to append the student record at the end of file
for the structure shown in example 5.6.2.3. -

* To append the student record at the end of the file *1


void append Jecord(FILE *fp)
{ .
STUDENT st; 1* Holds the details of a student *1
printf("USN : "); scanf("%d" ,&st.usn);
printf("Name : "); scanf("%s" ,st.name);
printf("Marks 1: "); scanf("%d",&st.marks1 );
printf("Marks 2: "); scanf("%d",&st.marks2);
printf("Marks 3: "); scanf("%d" ,&st.marks3);

1* Write the student details into the file *1


1* Note: Insert \n at the end of each record as a delimiter *1
fprintf(fp,"%d %s %d %d %d\n",
st.usn, st.name, st.marks1, st.marks2, st.marks3);

Example 5.4.2.6: C function to display the contents of the file for the structure shown
in example 5.6.2.3.

void display Jecords(FILE *fp)


{
STUDENT st;
5.38 Q Binary files

printf("USN Name Marks 1 Marks2 Marks3\n");


for (;;)
{
fscanf(fp, "%d %s %d %d %d",
&st.usn, st.name, &st.marks1, &st.tnarks2, &st.marks3);

if (feof(fp)) break;

printf("%-5d %-10s %-5d\t %-5d\t %-5d\n",


st.usn, st.name, st.marks1, st.marks2, st.marks3);
}

Example 5.4.2.7: The complete C ·program to create a sequential file with at least 5
records, each record having the following structure:

USN Name Marks 1 Marks2 Marks3


+ve integer 25 characters +ve +ve +ve
integer integer integer

where USN stands for University Seat Number, Marksl, Marks2 and Marks3 are the
marks scored by a student in subjectl , subject2 and subject3 respectively. Let us write
necessary functions to
• Display all the records in the file
• To search for a specific record based on USN. Display suitable message

#include <stdio.h>
#include <process.h>
#include <string.h>

typedef struct
{
int usn;
char name[20];
int marks1;
int marks2;
int marks3;
} STUDENT;
~ Systematic Approach to Data Structures using C 5.39
1* Include: Example 5.4.2.4: C function to search for the key USN *1

1* Include: Example 5.4.2.5: C function to append the student record *1

1* Include: Example 5.4.2.6: C function to display the student records *1


void maint)
{
STUDENT st; 1* Student details are stored *1
char fname[10]; 1* File name where student info is stored *1
FILE *fp; 1* File pointer to access the contents*1
int key_usn; 1* University seat number *1
int flag; 1* Holds either true or false *1
int choice; 1* Select the various options add,search,display *1
printf("Enter the file name\n");
scanf("%s" ,fname);

for (00)
, "
{
printf(" 1:Insert Record 2:Search record\n");
printf("3:Display record 4:Quit\n");
printf("Enter the choice\n");
scanf("%d" ,&choice);

switch( choice)
{
case 1:
fp = fopen(fname,"a+");

if (fp = NULL)
{
printf("Fopen failed\n");
break;
}

append _record( fp);

fclose(fp);

break;
5.40 Q Binary files

case 2:
fp = fopen(fuame,"r");
if (fp = NULL)
{
printf("File open failed\n");
break;
}

printf("Enter USN:");
scanf("%d" ,&key _usn);

flag = search _record(key _usn,fp);

if (flag = 0)
printf("Unsuccessful search \n ");
else
printf("Successful search\n");

fclose(fp);

break;
case 3:
fp = fopen(fuame,"r");

if (fp = NULL)
{
printf("File opened failed\n");
break;
}

display Jecords(fp);

fclose(fp );
break;

default:
exit(O);
}
}
}
,!;lSystematic Approach to Data Structures using C 5.41
Note: Even though the program is lengthy, the program is straightforwardand easier
to understand. By looking at the comments the reader is required to understand the
logic.

5.5 Command line arguments"


The operating systems such 'as MS-DOS provide a command line interface. Now, we
shall see "What is command line interface?"
Definition: The interface which allows the user to interact with the computer by
providing instructions in the form of typed commands (which are in text form) is
called command line interface. In the command prompt (see the figure below), the
user types the commands. These commands are made up of equal-sized alphanumeric
and other symbols. Keyboard is the input device to enter these commands.
The screen shot of MS-DOS (MicrnSoft Disk Operating System) is shown
below:
• I

monitor
Command prompt

The above function ,COPY accepts the file Tl.C and copies the contents, of Tl.C to
the T2.C. In the command prompt, if the .user types "COpy ,Tl.C T2.C" the main
function of COpy program accepts three parameters namely COPY, Tl.C and T2.C.
These parameters are called command line arguments ..Now, we shall see "What are
command line arguments?"

Definition: As parameters are passed to the functions, on similar lines, parameters


can also be passed to the function main whenever the program is invoked from the
command prompt. The words that are typed at the command prompt are passed to the
function main of the program which is being invoked at the command prompt.. These
arguments that are passed by the operating system to the function main when the
program is invoked are called command line arguments. To access the command line
parameters the function main should have the followi~g format; ';" i«. ;,', ' ! .

void main(int argc, char *argv[])


{
.l

}
5.4~ Q Binary files

where
• argc is an integer value. Here, argc means argument count
• argv is an array of strings. Here, argv means argument vector. Those strings that
are part of the command prompt are copied into argv[O], argv[l] and so on.

Example 5.5.1: Argument vector and argument count with respect to the command:

C:\> COPY Tl.C T2.C

argv[O]~ COPY
argv[l]~ Tl.C
argv[2]~ T2.C

Since there are three strings at the command line prompt, integer variable argc has the
value 3. The value for the variable argc is not explicitly passed as the parameter and
argv[O] will always have the first parameter i.e, program name. In our example,
argv[O] will have the string "COPY".

5.5.1 Display contents of file

Now, let us write a program to display the contents of file. The file if specified in the
command line has to be opened and the contents have to be displayed. If file is not
specified in the command line, the user should be prompted for the file and that file
should be opened and displayed. The complete program is shown below

Example 5.5.1: C Program to accept a file either through command line or as


specified by user during run time and displays the contents

#include <stdio.h>
#include <process.h>
#include <string.h>

void main(int argc, char *argv[])


{
FILE *fp; 1* File pointer used to display a file *1
char fname[lO]; 1* File to be opened and displayed *1
char ch; 1* Holds the character to be displayed *1
Q Systematic Approach to Data Structures using C 5.43

if (argc = 1)
{
printf("Enter the file name:"); /* No command line file name */
scanf("%s" ,fname);
}
else
{
strcpy(fname, argv[l]); /* Command line file exists */
}

fp = fopen(fname, "r"); .

if (fp = NULL)
{
printf("File opening error\n");
exit/O);
}

priotf("The contents of the file are:\n");


prlo. t4"("
I' --------------------------- \n") ,.

/* File opened successfully and display the contents */


while ( (ch = getc(fp)) != EOF)
{
priotf("%c" ,ch);
}

Note: Let us assume, the file name of the above program is "disp.c". Before
executing this program make sure that the file by name "Hello" exists in the current
directory from where we are running the executable file "disp". Also make sure that
some text is stored in the file "Hello". Use any editor, create a file called "Hello" and
enterthe following text:
Hello how are you
This is the first program using command line arguments
Good luck
Have Fun
Finally save the program in the file name "Hello". Now, compile and execute the
program as shown below:
5.44 Q Binary files

Output
..
I
C:\>disp hello
The contents of the file are:

Hello how are you


This is the first program using command line arguments
Good luck
Have Fun

Oufput

C:\>disp
Enter the file name: Hello
The contents of the file are:
Hello how are you
This is the first program using command line arguments
Good luck
Have Fun

Note: In the first output argv[O] corresponds to disp and argv[ 1] corresponds to the
string "Hello". In the second output argv[l] is NULL. In this ,program, in the
beginning of the function main we are checking whether a file has been specified in
the command line. If file is not specified, the value of argc will be 1 and so the user is
prompted to enter the file name during run time. But, if the value of argc is greater
than 1, the control comes to else statement and the file specified in the command line
is copied to fname which will be used for opening. Rest of the statements in the
program are self-explanatory. .

5.5.2 Obtain text and create file (use only command line parameters)

Let lis consider another program which accepts a file name followed by a text only
through command line parameters. The text appearing in the command line should be
stored in a file which is also passed as a command line parameter. The corresponding
C program is shown below:
Q Systematic A roach to Data Structures usin C 5.45

Example 5.5..2: C Program to accept a file name and text through command line
arguments and create a file with the text
#inc1ude<stdio.h>
#inc1ude<process.h>
void main(int argc, char *argv[])
{
FILE *fp; /* File pointer used to display a file */
int 1; /* To access command line parameters */
char sp-[30]; /* Temporary storage */

if (argc = 1)
{
printf("File name missing in the command iine\n");
exit(O);
}
if (argc = 2)
.
{
printf("File name should be followed by some text\n");
exit(O);
}
/*Command line has file name and text */
/* So, create and open the file */
fp = fopen(argv[l], "w");
if (fp = NULL)
{
printf("The file can not be opened for writing\n");
exit(O);
}
/* Write text in command line into file */
for (i = 2; i < argc; i++)
{
fprintf(fp,"%s ",argv[i]); /* Note: A space after %s is required */
}
fclose(fp);
II
5.46 Q Binary files

5.5.3 Copy from one file to other file (Implementing copy command)

Let us write a C program to copy contents of a file to another file accepting the file
names as the command line arguments.

Example 5.5.3: C Program to implement copy command


#inolude <stdio.h>
#include <process.h>
void main(int argc, char *argv[])
{
FILE *fpI; 1* Source file pointer *1
FILE *fp2; 1* Destination file pointer *1
int ch; 1* used to store character read *1
if (argc != 3)
{
printf("Src/dest files missing in the command line\n");
exit(O); .
}
fp l = fopen(argv[l], "r");
if(fpl = NULL)
{
printf("The source file can not be opened for reading\n");
exit(O);
}
fp2 = fopen(argv[2], "w");
if (fp2 = NULL)
{ .
printf("The destination file can not be opened for writing\n");
exit(O);
}
1* read till end of file is encountered *1
while ((ch =getcrfp l) != EOF)
putc(ch, fp2); 1* write each character read into output file *1
fclose(fp I);
fclose(fp2);
}
Chapter 6: Stacks
I What are we studying in this chapter? I
• Definition and examples
• Representing and implementing stacks in C
• Definition, conversion and evaluation of expressions -7 hours

6.1 Introduction
The digital computers are electronic devices that can transmit, store and manipulate
information. Information is obtained from data and it is the result of processing,
manipulatingand organizing the data.The various types of data that are processed by
the computer are numeric or character (address, names etc.,) in nature. In the coming
chapters, we discuss extensively on various types of data structures. First, we shall see
"What is data structure? What are the various types of data structures?"

Definition:A data structureis a method of storing data in a computer so that it can be


usedefficiently. The Data Structures mainly deal with:
•• The study of how the data is organized in the memory
• How efficiently the data can be stored in the memory
• How efficiently the data can be retrieved and manipulated, and
• The possible ways in which different data items are logically related.
Thedata structures can be classified as shown below:
Integer
Floating point
Primitive -~I--~ Character
/'

Double
Pointers
Data Arrays
structures
Stacks
Linear
Queues
Non Linked lists
primitive

Non-linear ---c: Trees


Graphs
6.2 Q Stacks

Now, let us see "What are primitive data structures?"

Definition: The Primitive Data structures are data structures that can be manipulated
directly by machine instructions.
For example, the integers, floating point numbers (real), characters, pointers
etc., are some of the primitive data structures. In C language, the different primitive
data structures are defined using the data types such as int, float, char and double.

Now, let us see "What are non-primitive data structures?"

Definition: The Non-primitive data structures are data structures that cannot be
manipulated directly by machine instructions.
For example, arrays, structures, stacks, queues, linked lists, files etc., are some
of the non- primitive data structures. The non-primitive data structures are classified
into linear data structures and non-linear data structures. The data structures that show
the relationship of logical adjacency between the elements are called linear data
structures. Otherwise, they are called non-linear data structures .

6.2 Stacks

We have seen that, normally all the plates in a hotel/canteen are placed one above the
other. The plates are inserted from the top only. If a plate is required, the top most
plate is selected. This process of inserting the plates at the top and removing the plates
from the top is called stacking of plates. Let us see how stacks are used in the field of
computer science. Before proceeding further, let us see "What is a stack? What are
the various operations that can be performed on stacks?"
!

Definition: A stack is a special type of data structure (an ordered collection of items)
'where elements are inserted from one end and elements are deleted from the same
end. \'fhis position from where elements are inserted and from where elements are
deleted is called top of the stack. losing this approach, the last element inserted is the
first element to be deleted out, and hence, stack is also called Last In First Out
(LIFO) data structure. The various operations that can be performed on stacks are
shown below:

Stack operations -E Push (Inserting an element on the top of stack)


Pop (Deleting an element from the top of stack)
display (Display contents of stack)
~ Systematic Approach to Data Structures using C - 6.3

6.2.1 Push operation

Let us see "What is push operation?"

Definition: Inserting an element into the stack is called Only one item
is inserted at a time and item has to be inserted only from top of the stack.

Example 6.2.1.1: Stack contents after inserting 4 items 30, 20, 25 and 10 one after
the other with a STACK SIZE 4.

STACK SIZE = 4

~3

~El ~El~~~
oEl ~0m3 000
to
~t 2 25
3~
1
o
20
30
2
1
o
top
~ -I S S S s s
Empty stack insert 30 insert 20 insert 25 insert 10

Figure 6.1 Sequence of insertion operations

When items are being inserted, we may get stack overflow. Now, let us see "What is
stack overflow?"

Definition: When elements are being inserted, there is a possibility of stack being
full. Once the stack is full, it is not possible to insert any element. Trying to insert an
element, even when the stack is full results in.overflow of stack.
For example, consider the stack shown in figure 6.1 with STACK_SIZE 4. We
can insert at the most four elements. After inserting 30, 20, 25 and 10 there is no
space to insert any item. Then we say .that stack is full. This condition is called
overflow of stack.

Now, let us see "How to implement push operation using arrays (static allocation
technique)?"

Design: Before inserting any element, we should ask the question "Where and how
the item has to be inserted?" If we know the answer for this question we have the
6.4 Q Stacks

push function ready. So, let us consider the situation where two elements 30 end 20
are already inserted into the stack as shown in figure 6.2.a. with top = 1.

STACK_SIZE = 4 STACK_SIZE = 4 STACK_SIZE =4 STACK_SIZE =4

3 ~3
~2 ~2
t 3~ 25 2
to 2
~ 3~
1 20 1 1 20 1
o 30 0 o 30 0
-1 S -1 S -1 S -1 S

(a) (b) (c) (d)

Fig. 6.2 Showing the design of push operation

\ .
Suppose, we have to insert an element say item. Now, let us ask "Where this item has
to be inserted?" We know that it has to be inserted at top = 2. For this to happen, we
have to increment top.by 1 (Fig. 6.2.b). This is achieved using the statement:

top = top + 1; 1* Increment top by 1 *1

Then we ask "How item has to be inserted at top position?" This is achieved by
copying item to s[top] (Fig 6.2.c) using the following statement:

s[top] = item; 1* Insert into stack *1

But, as we insert an item, we must ask "When we can not insert item into the stack?"
We can not insert any item when top has already reached STACK_SIZE - 1(Fig.
6.2.d) . In such situation, we have to display appropriate message as shown below:

1* Check for overflow of stack *1


if (top = STACK_SIZE -1)·
{
printf("Stack overflow\n");
return;
l }

Here, STACK - SIZE should be #defined . (preprocessor directive) and is called


symbolic constant. If the above condition fails, the item has to be inserted. Now, the
complete C function for this can be written as shown below:
Q Systematic Approach to Data Structures using C - 6.5

Example 6.2.1.2: C function to insert an integer itemIl.Ising global variables)

void puslu)
{
/* Check for overflow of stack */
if (top = STACK_SIZE -1)
{
printf("Stack overflow\n");
return;
}

top = top + 1;
/* Increment top by 1 */ }
I
s[++top] = item;
s[top] = item; /* Insert into stack */

Note: The array s, the variable top and the variable item are global variables and
should be declared before all the functions. As far as possible let us avoid the usage of
global variables in this book.

Let us re-write the above code by passing parameters. It is clear from the above code
that as the item is inserted, the contents of the stack identified by s and the index top
pointing to topmost element are changed and so they should be passed as parameters
(pass by reference) as shown below:

Example 6.2.1.3:, C function to insert an integer item (by passing parameters)


void push(int item, int *top, int sm
{
/* Check for overflow of stack */
if (*top = STACK_SIZE - 1)
{
printf("Stack overflow\n");
return;
}

*top = *top + 1; /* Increment top by 1 */ } s[++(*top)] = item;


s[*top] = item; /* Insert into stack */
6.6 Q Stacks

The following function inserts a character item into the stack.

Example 6.2.1.4: C function to insert a character item (by passing parameters)

void push(char item, int *top, char s[])


{
1* Check for overflow of stack *1
if (*top = STACK_SIZE -1)
{
printf("Stack overflow\n");
return;
}

*top = *top + 1; 1* Increment top by 1 *it


s[*top] = item; 1* Insert into stack *1 f s[++(*top)] = item;
}

Note: By comparing functions shown in 6.2.1.3 and 6.2.1.4 note that body of the
function has not been changed. But, the type of formal parameters changes.

6.2.2 Pop operation


Let us see "What is pop operation?"
Definition: Deleting an element from the stack is called pop operation. Only one item
can be deleted at a time and item has to be deleted only from top of the stack.

Example 6.2.2.1: Performing pop operation when stack already contains 30, 20, 25,
and 10.

to
3 3 3 3
2 2 2
1 ~ ~ 20 1
top 1
o o 30 ~O 30 top 0
1 -I -I -I -+-1
Stack full After After After
deleting 25 deleting 20 deleting 30
(stack empty)
Figure 6.3 Sequence of Deletion operations
Q Systematic Approach to Data Structures using C - 6.7
The items can be deleted one by one as shown in figure 6.3.The contents of stack and
the top which contains the position of topmost elements are also shown. When items
are being deleted, we may get stack underflow. Now, let us see "What is stack
underflow?"

Definition: When elements are being deleted, there is a possibility of stack being
empty. When stack is empty, it is not possible to delete any item. Trying to delete an
element from an empty stack results in stack underflow.
For example, in the figure 6.3, after deleting 10, 25, 20 and 30 there are no
elements in the stack and stack is empty. Deleting an element from the stack results in
stack underflow.

Now, let us see "How to implement pop operation using arrays (static allocation
technique)?"

Design: Let us delete an item from the top of the stack. This can be achieved by
accessing the top element s[top] as shown below:

item_deleted = s[top]; /* A~cess the topmost item */

and then decrementing top by one as shown below:

top = top - 1; /* Update the position of topmost item */

The above two statements can also be written using single statement as shown below:

item = s[top--]; Note: item = s[--top]; is wrong.

Each time, the item is deleted, top is decremented and finally, when the stack is
empty the value of top will be -1 and so, it is not possible to delete any item from the
stack. Hence, the above statement has to be executed only if stack is not empty and
the code to delete an item from stack can be written as shown below:

Example 6.2.2.1: C function to delete an integer item (using global variables)


int popt)
{
int item_deleted;

if (top == -1) return 0; /* Stack underflow? */


6.8 Q Stacks

item_deleted = s[top--]; 1* Access the item and delete *1

return item_deleted; 1* Send the item deleted to the calling function */


}

Now, let us write the above function without using global variables and by passing
appropriate parameters. We know that to access the top item, we need the index top
and the stack s. So, we have to pass top and s as the parameters. As the value of top
changes every time the item is deleted, top can be used as a pointer variable. The
complete C function (by passing parameters) is shown below:

Example 6.2.2.2: C function to delete an integer item (by passing parameters)


int poptint *top, int s[])
{
int item_deleted; 1* To hold the top most item of stack *1
1* Stack underflow? *1
if (*top = -1) return 0;
1* Obtain the top most element and change the position of top item *1
item_deleted = s[(*top )--];
1* Send the item deleted to the calling function */
return item_deleted;
}

The following function shows how to delete a character item from the stack.
! ~.'

Example 6.2.2.3: C function to delete a character item (by passing parameters)


char pop(int *top, char s[])
{
char iternjleleted; 1* Holds the top most item of sack *1
1* Stack underflow? *1
if (*top = -1) return 0;
1* Obtain the top most element and change the position of top item *1
item_deleted = s[(*top)--]; .
1* Send the item deleted to the calling function */
return item_deleted;
}
Q Systematic Approach to Data Structures using C - 6.9

6.2.3 Display stack items

In the display procedure, if the stack already has some items, all those items are
displayed one after the other. If no items are present, the appropriate error message is
displayed. Let us design the display function.

Design: Assume that the stack contains three elements as shown below:

~~
1
o
-1 S
Usually, the contents of the stack are displayed from the bottom to top. So, first item
to be displayed is 30, next item to be displayed is 20 and final item to be displayed is
25. This can be achieved using the following statements:

Design I, Output
printf("%d\n", illlQ[1);); I 30
printf("%d\n", 20
printf("%d\n", 2); I 25

In generai, we can use printf("%d\n",


!
s [i] );
I
I Note: i = 0 to 2 ( i.e., top).

ote: Please note how the value of i change from 0 to top. Now, the code takes the
following form:

for (i = 0; i <= top; i++)


{
printf("%d\n", s[i]);
}

But, the above statement should not be executed when stack is empty i.e., when top
takes the value .,...1. So, the above code can be modified to include this error condition
andcan be written as shown below:
6.10 Q Stacks

Example 6.2.3.1: C function to display the contents of stack (using global variables)
void displayt)
{
int i;
1* If stack is empty *1
if (top = -1)
{
printf("Stack is empty\n");
return;
}
1* Display contents of stack *1
printf("Contents of the stack\n");
for (i = 0; i <= top; i++)
{
printf("%d\n", s[i]);
}
}

By passing parameters, the function above function can be written as shown below:
Example 6.2.3.2: C function to display contents of the stack (by passing parameters)
void display(int top, int sm
{
int i;
1* Is stack empty *1
if(top = -1)
{
prtntf(t'Stack is empty\n");
return;
}
1* Display contents of stack*l·
printf("Contents of the stack\n");
1 for (i = 0; i <= top; i++)
{
printf("%d\n", s[i]);
}
}
~ Systematic Approach to Data Structures using C - 6.11

6.2.4 Stack implementation using arrays (static implementation of stacks)

In the previous sections we have seen how the stacks can be implemented using
global variables and by passing parameters. The complete program to perform
operations such as push, pop and display using global variables is shown below:

Example 6.2.9: C Program to implement stack using arrays (Using global variables)

#include <stdio.h>
#inelude <process.h>

#define STACK SIZE 5

1* Global variables */

int top; /* index to hold the position of the top most item */
int s[10]; /* Holds the stack items */
int item; /* Item to be inserted into the stack */

1* Include function push shown in example 6.2.1.2 */

1* Include function pop shown in example 6.2.2.1 */

1* Include function display shown in example 6.2.3.1 */

void mainO
{
int item; /* Item to be inserted */
int item_deleted; /* Item to be deleted from the stack */
int choice; /* user choice for push, pop and display */

top = -1; /* Indicates stack is empty */

for (;;)
{
prtntf(" 1:Push 2:Pop\nlt);
printf(1t3 :Display 4:Exit\nIt);
printf'(vlinter the choice'n");
scallf(lt%dlt ,&choice);
6.12 Q Stacks

Continued .....

switch( choice)
{
case 1:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
pusht);
break;

case 2:
item __deleted = popt);

if (item_deleted = 0)
printf("Stack is empty\n");
else
printf("ltem deleted = %d\n",item_deleted);

break;

case 3:
displayt);
break;

default:
exit(O);
}
}
}

The program to perform operations such as push, pop and display by passing
parameters is shown below:

Example 6.2.10: C Program to implement stack using arrays (by Passing parameters)
.1

#include <stdio.h>
#include <process.h>

#define STACK SIZE 5


.
Q Systematic Approach to Data Structures using C - 6.13
Continued ....

1* Include function push shown in example 6.2.1.3 */


1* Include function pop shown in example 6.2.2.2 */
1* Include function display shown in example 6.2.3.2 */
void maint)
{
int top; /* Points to top of the stack */
int s[10]; /* Holds the stack items */
int item; /* Item to be inserted or deleted item */
int item_deleted; /* Item to be deleted from the stack */
int choice; /* user choice for push, pop and display */
top = -1; /* Indicates stack is empty to start with */
for (;;)
{
prfntf("! :Push 2:Pop\n");
printf("3 :Display 4:Exit\n");
printf("Enter the choice\n");
scanf("%d" ,&choice);

switch( choice)
{
case 1:
printf("Enter the item to.be inserted\n");
scanf("%d",&item); .
push(item,&top,s );
break;

case 2:
item_deleted = pop(&top,s);

if (itemdeleted = 0)
printf("Stack is empty\n");
else
printf("Item deleted = %d\n",item_deleted);

break;
6.14 Q Stacks

Continued .....

case 3:
display(top,s);
break;
default:
exit(O);
}
}
}

6.3 Applications of stack

Once we define a stack and how stack is implemented in C, let us concentrate on


"What are the applications of stack?" The various applications in which stacks are
used are:
• Conversion of expressions: When we write mathematical expressions in a
program, we use infix expressions. These expressions will be converted into
equivalent machine instructions by the compiler using stacks. Using stacks we can
efficiently convert the expressions from infix to postfix, infix to prefix, postfix to
infix, postfix to prefix, postfix to infix and postfix to prefix.

• Evaluation of expressions: An arithmetic expression represented in the form of


either postfix or prefix can be easily evaluated.

• Recursion: A function which calls itself is called recursive function. Some of the
problems such as tower of Hanoi, problems involving tree manipulations etc., can
be implemented very efficiently using recursion. It is. a very important facility
available in variety of programming languages such as C, c++ etc.,

• Other applications: There are so many other applications where stacks can be
used: For example, to find whether the string is a palindrome, to check whether a
given expression is valid or not and so on.
1
Now, we shall discuss these applications in detail in the subsequent sections.

6.4 Conversion of Expressions

First, let us see "What is an expression? What are the various types of expressions?"
Q Systematic Approach to Data Structures using C - 6.15
Definition: The sequence of operators and operands that reduces to a single value
after evaluation is called an expression. The operands consists of constants and
variables whereas the operators consists of symbols such as +, -, *, / and so on. The
operators indicate the operation to be performed on the operands specified. The
expressions can be represented as shown below:

Re resentation
fe . .
o expressions -E Infix expression
.
Postfix expression
Prefix expression

Now, let us see "What is an infix expression?"

Definition: In an expression, if an operator is in between two operands, the


expression is called an infix expression. The infix expression can be parenthesized or
un-parenthesized. For example,
. a + b is an un-parenthesized infix expression
(a + b) is a parenthesized infix expression

In the expression, a + b
operand l ~ t 4 operand2
operator

Note: Since the operator is in between two operands, it is called infix expression.
Now, let us see "What is postfix expression?"

Definition: In an expression, if an operator follows the two operands (i.e., operator


comes after the two operands), the expression is called postfix expression. No,
parenthesis is allowed in postfix expressions. The postfix expression is always un-
parenthesized. It is also called suffix expression or reverse polish expression. For
example,
ab+

Now, let us see "What is prefix expression?"

Definition: In an expression, if an operator precede the two operands (i.e., operator


comes before the two operands), the expression is called prefix expression. -No,
parenthesis is allowed in prefix expressions. The prefix expression is always un-
parenthesized. It is also called polish expression. For example,
+ab
6.16 Q Stacks

6.4.1 Precedence and associativity of the operators

While evaluating or converting an expression into other forms •.we should know the
precedence of operators and the associativity of operators. So, let us see "What is
precedence of operators?"

First, we shall see "What is precedence of operators?"

Definition: We know that while evaluating the expressions, some expressions are
given precedence over other expression and are evaluated first and some are evaluated
later. These rules that determine the order in which different operators are evaluated
are called precedence rules or precedence of operators.

Example 6.4.1.1: Evaluating an expression based on precedence rules

6*~-5 Brackets have the highest precedence and are evaluate first

~ -5 Multiplication has higher precedence over subtraction


30 - 5 Subtraction has the least precedence.
~
25 Final result

Normally we associate values to determine the order in which the operators have to
evaluate. Highest precedence operators will have the highest value and lowest
precedence operators will have the least value. The table below shows arithmetic
operators along with priority values

Description Operator Priority Associativity

Exponentiation ($) 6 Right to Left


Multiplication (*) 4 Left to Right
rvision (I) 4 . Left to Right
Arithmetic
Operators Mod (%) 4 Left to Right?
I
Addition (+) 2 Left to Right
Subtraction (-) 2 Left to Right
~ Systematic Approach to Data Structures using C - 6.17

ote: The symbol '$' or '1\' is considered as the operator to perform exponentiation
and should be given first precedence since it has higher priority value. The addition or
subtraction is given the least precedence since it has least priority value as shown in
above table.

TOW, "What if different operators have the same precedence?" During evaluation, if
two or more operators have the same precedence, then precedence rules are not
applicable. Instead, we go for associativity of the operators. Now, we shall see "What
is associativity?

Definition: The order in which the operators with same precedence are evaluated in
an expression is called associativity of the operator. In such case, precedence rules are
not considered. .

Example 6.4.1.2: What is the result of8 + 4 + 3? All of us evaluate the expression as
shown below:
8 + 4 + 3
"--y-J [First add 8 and 4 to get 12]
12 + 3
'--y--' [Next add 12 and 3 to get 15]
15
Observation: In the above expression, same operator "+" is used twice and hence
both operators have the same priority and the precedence rules are not applicable.
Then the question is "How to evaluate?" Normally, we do the evaluation as shown
below:
First we compute 8 + 4 to get 12
Next we compute 12 + 3 to get 15 thus moving from Left to Right.

Since evaluation is done from left to right one after the other, we say that the operator
"+" is left-to-right associative (also called left associative).

Now, let us "Define left-to-right associative (left associative)."

Definition: In an expression, if there are two or more operators having the same
priority and are evaluated from left-to-right, then the operators are called left
associative operators (Left to Right associative operators). We normally denote using
L ~ R. The process of evaluating from left to right is called left associativity.
6.18 Q Stacks

Example 6.4.1.3: What is the result of 2$3$2? if '$' represent exponentiation


operator? We can also denote the exponentiation operator using symbol ''''.

Note: In mathematics 2$3$2 can be represented as 23 We know that 23' = 512. It is


2

not 64. So, to get the answer 512, the computer has to evaluate the expression 2$3$2
as shown below:

2$~ First evaluate 3 $ 2 (i.e., 32 = 9)

2$ 9 Then evaluate 2$9 (i.e., 29 = 512)


'-y--'
512

Observation: In the above expression, same operator "$" is used twice and both
operators have the same priority and the precedence rules are not applicable. Then the
question is "How to evaluate?" Normally, we do the evaluation as shown below:
First we compute 3$2 to get 9
Next we compute 2$9 to get 512 thus moving from right to left.

Since evaluation is done from right to left one after the other, we say that.the operator
"S" is right-to-left associative (also called right associative).

Now, let us "Define right-to-left associative (right associative).

Definition: In an expression, if there are two or more operators having the same
priority and if they are evaluated from right-to-left, then the operators are called right
associative operators.
For example, $ (representing exponentiation operator Note: This is not C
language operator) is a right associative operator

Now, we shall see, "How the precedence of operators and associativity of operators
are used to convert the expressions from infix to postfix or from infix to prefix?"

Note: "Why to convert from infix to postfix or infix to prefix?" We normally evaluate
the expressions by considering infix expressions. But, evaluating postfix or prefix
expressions is much easier and efficient. Also, while evaluating postfix or prefix
expressions, we need not worry about the precedence of operators and associativity of
operators where as .while evaluating infix expressions, we should know the
precedence of operators and whether the operators are left associative or right
associative,
Q Systematic Approach to Data Structures using C - 6.19

6.4.2 Conversion from infix to postfix

Example 6.4.2.1: Obtain the postfix expression for « A +(B- C ) * D) 1\ E +F )

Solution: We can convert into postfix expression based on precedence and


associativity as shown below:

«A + ~) *D) 1\ E +F ) (B-C) has highest precedence

Tl T,=BC-

(T 1 * D) has highest precedence

T2 = T} D *

(A + T2) has highest precedence

T3=A T2+

(T 3 1\ E) has highest precedence

T4= T3 E 1\

~ Converting into postfix by repeated substitution

T4F+
T3 E 1\ F+ {Replacing T4 by T3 E 1\)

AT2+EI\F+ (Replacing T3 by A T2 +)
A r, D*+EI\F+ (Replacing T 2 by T 1 D *)
ABC- D*+EI\F+ (Replacing T 1 by B C -)

Hence, equivalent postfix expression is ABC - D *+E 1\ F +

Example 6.4.2.2: Obtain the postfix expression for X 1\ Y 1\ Z- M +N+P IQ

Solution: We can convert into postfix expression based on precedence and


associativity as shown below:
6.20 ~ Stacks

X$~-M+N+P/Q Y $ Z has highest precedence and right associative

TI T\ =Y Z$

x $ T I has highest precedence

T2 = X 'r, $

P / Q has the highest precedence

T3 = P Q /

Note: All have the same precedence and hence associativity


comes into picture. Here, they are left associative
T4=T2 M-

T4 + N is considered because ofleft associative


Ts=T4 N +

Q Converting into postfix by repeated substitution

Ts T3 +
T4 N + P Q / (Replacing 'r, by T4 N + and T3 by P Q /
T2 M - N + P Q / (Replacing T4 by T2 M-)
X TI $ M - N + P Q / (Replacing T2 by X TI $)
XYZ$$M-N + PQ / (Replacing T I by Y Z $)
Hence, equivalent postfix expression is X Y Z $ $ M - N + P Q /

On similar lines, we can convert all infix expressions into their equivalent postfix
expressions. Now, let us discuss "How to write a program to convert a given infix
expression to its equivalent postfix expression?"
1

Design: Let us use two precedence functions F and G. The function F contains the
precedence values of symbols on top of the stack and function G contains the
precedence values of symbols in the input string. The precedence values associated
with these two functions F and G are shown ill following table.
Q Systematic Approach to Data Structures using C - 6.21

Symbols Stack precedence Input precedence Associativity


function F function G
+,- 2 1 Left
*, f 4 3 Left
$ or A 5 6 Ri!!ht
operands 8 7 Left
( 0 9 Left
) - 0 -
# -1 -
Table 6.1 Precedence values of symbols in the stack and input

By looking at above table, we can easily write two functions F and G that return the
precedence based on whether the symbol is on top of the stack or it is an input
symbol as shown below:

Example 6.4.2.3: C function which returns stack and input precedence values
1* Stack precedence function F *f f* Input precedence function G *f
int F(char symbol) int G( char symbol)
{ {
switch(symbol) switch( symbol)
{ {
case '+': case '+':
case '-': return 2; case '-': return 1;

case '*': case '*':


case 'f': return 4; case 'f': return 3;

case 'A': case 'A':


case '$': return 5; case '$': return 6;

case '(': return 0; case '(': return 9;

case '#': return -1; case ')': return 0;

default: return 8; default: return 7;


} }
}
.
Note the difference in values. This is because of right associative
6.22 Q Stacks
Note: Observe the following points from" the above table/function with respect to
precedence:
• The operators '+' and '-' have the same precedence and are least precedence
operators:
• The operators '*' and'/' also have the same precedence and have the precedence
higher than ~+' and '-' .
•. The operator '$' or '''' indicates exponential operator and has a precedence higher
than '*' and '\' but it is right associative operator.

Note: Observe the following points from the above table/function with respect to
associativity.
• If an operator is left associative, stack precedence value is greater than input
precedence value.
• If an operator is right associative, stack precedence value is less than the input
precedence value.

Procedure: General procedure to convert from infix to postfix form is shown below:'
,
• As long as the precedence value of the symbol on top of the stack is greater than
the precedence value of the current input symbol, pop an item from the stack and
place it in the postfix expression. The code for this statement can be of the form:

while (F(s[topD > G(symbol) )


{
,postfix[j++] = s[top--] 1* Pop from stack and place into postfix *1
}
• Once the condition in while-loop is failed, if the precedence of the symbol on top
of the stack is not equal to the precedence value of the current input symbol, push
the current symbol on to the stack. Otherwise, delete an item from the stack but do
not place it in the postfix expression. The code for this statement can be of the
form

if (F(s[top]) != G(symbol) )
s[++top] = symbol; 1* Push symbol on the stack *1
l else
top--; 1* Drop an element from stack *1

Note: These two steps have to be performed for each input symbol in the infix
expression. _
Q Systematic Approach to Data Structures using C - 6.23
;0
Note: Before conversion starts, stack is empty denoted by symbol '#' on the stack and
output is empty. The formal version of the algorithm can be written as:

top = -1; Innu t con filzuration


s[++top] = '#'; 1* stack empty *1 Stack Input Output
j = 0; 1* Output is empty *1 # (A+(B-C)*D) empty
for each SYmbol in infix expression
{
while (F(s[topD > Gfsymbol) )
postfix[j++] = s[top--];

if (F(s[topD != Gtsymbolj )
I Infix to postfix conversion I
sf ++top] = SYmbol;
else
Output configuration
top--;
} . Stack Input Output
# empty ABC-D*+

The complete C function to convert from infix expression to postfix expression is


shown below:

Example 6.4.2.4: C function to convert from infix expression into postfix expression

void infixyostfix( char infix[], char postfixjj)


{
int top; 1* points to top of the stack *1
int J; 1* Index for postfix expression *1
int 1·, 1* Index to access infix expression *1

char s[30]; 1* Acts as storage for stack elements *1


char symbol; 1* Holds scanned char from infix expression *1

top = -1; 1* Stack is empty *1


s[++top] = '#'; 1* Initialize stack to # *1
j =0; 1* Output is empty. So, j = 0 *1
6.24 Q Stacks

fore i = 0; i < strlen(infix); i++)


{
symbol = infix[i]; 1* Scan the next symbol *1

1* if stack precedence greater, remove symbol


from stack and place into postfix I *
while ( F(s[top]) > G(symbol) )
{
postfix[j] = s[top--]; 1* Pop from stack and place *1
j++; 1* into postfix *1
}

if ( F(s[top]) != G(symbol) )
s[ ++top] = symbol; 1* push the input symbol *1
else
top--; 1* discard '(' from stack *1
}

1* Pop remaining symbols and place */


1* them in postfix expression *1
while ( s[top] != '#')
{
postfix [j++] = s[ top-- ];
}

postfix[j] = '\0'; 1* Attach NULL char .at the end to frame a string *1
}

The complete C program to convert a valid infix expression to postfix expression is


shown below:

Example 6.4.2.5: C Program to convert an infix expression to postfix

#inclllde <stdio.h>
#include <string.h>

1* Include: Example 6.4.2.3: Precedence functions F and G *1

1* Include: Example 6.4.2.4: Function to convert from infix to postfix *1


~ Systematic Approach to Data Structures using C - 6.25

void maint)
{
char infix[20];
char postfix[20];
I Input and output
printf("Enter a valid infix expression\n");
I Enter a valid infix expression
scanf("%s" ,infix);
I (a+b)* c-(d-e))" (f+g)
/* Convert infix to postfix expression */ I The postfix expression is
infix yostfix(infix,postfix); I ab+c=de=fg+?

printf("The postfix expression is\n"); I Enter a valid infix expression


printf("%s\n",postfix); I a"b*c-d+e/f/(g+h)
} I The postfix expression is
I I ab c*d-ef/l!h+/+

Let us trace the above program for the given expression: ( A + ( B - C ) *D)
Example 6.4.2.6: The complete trace of the program for the expression:
(A+(B-C)*D)

Stack sltop] Svrnbol F(s[topl) > C(S) mbol) Postfix

# # ( (-1<9)Push(
#( ( A (0 < 7) Push A
# (A A + (8) I ) Pop A A
#( ( (0 < I ) Push +
#(+ + ( ( 2 < 9 ) Push ( A
#(+( ( B ( 0 < 7) Push B A
# (+ (B B (8) I ) Pop B AB
II- (+ ( ( ( 0 < I ) Push -
# (+ ( - C (2 < 7) Push C AB
#(+(-C C ( 8> 0) Pop C ABC
# (+ (- (2) 0) Pop - A BC-
#(+( (0 = 0) Pop (
don't place in postfix. expr.
#(+ + * (2 < 3 ) Push * A B C-
# (+ * * D (4 < 7) Push D
#( + * D D ) (8) 0) Pop D ABC-D
# (+ * >I<
(4) 0) Pop * ABC-D*
#t+ + (2) 0) Pop + ABC-D*+
#( (0 = 0) Pop
(don't place in postfix exp.)
# # ABC-D*+
6.26 Q Stacks

6.4.3 Conversion from infix to prefix

Example 6.4.3.1: Obtain the prefix expression for « A -i- (B:'- C) * D) " E +F )

Solution: We can convert into prefix expression based on precedence and


associativity as shown below:

((A+(B-C)*D)"E+F) (B-C) has higbest precedence


'--y-l

Tl TI=-BC

((A+~)"E+F ) (T I * D) has highest precedence


- T2 Tz = * TI D

(A + T z) has highest precedence


T, = + A T,

(T3 " E) has highest precedence

T4 = "T3 E

~ Converting into postfix by repeated substitution

+T4 F
+ " T3 E F (Replacing T 4 by /\,T 3 E)
+ /\, + A T2 E F (Replacing T3 by + A T2)
+ /\, + A * T, D E F (Replacing T2 by * T, D )
+/\'+A*-BCD EF (Replacing T I by - B C)

Hence, equivalent postfix expression is + " + A * - BCD E F


. ,

Example 6.4.3.2: Obtain the prefix expression for X" Y " Z - M + +P/Q

Solution: We can convert into prefix expression based on precedence and


associativity as shown below:
~ Systematic Approach to Data Structures using C - 6.27

X$~-M+N+P/Q Y $ Z has highest precedence and right associative


Tl Tl = $YZ

X$T1-M+N+P/Q
Ly-J
x $ T 1 has highest precedence

T2 T2 = $ X 'r,
P I Q has the highest precedence

T3 = / P Q

Note: All have the same precedence and hence associativity


comes into picture. Here, they are left associative
T4= -T2 M

T4 + N is considered because ofleft associative

Converting into postfix by repeated substitution


~
+Ts T3
+ + T4 NIP Q (Replacing T, by + T4 Nand T3 by / P Q)
+ + - T2 M N IP Q (Replacing T 4 by - T 2 M)
+ + - $ X T, M NIP Q (Replacing T 2 by $ X T 1 )
++-$X$YZMN /PQ (Replacing T 1 by $ Y Z )
Hence, equivalent postfix expression ++-$X$YZMN /PQ

On similar lines, we can convert all infix expressions into their equivalent prefix
expressions. Now, let us discuss "How to write a program to convert a given infix
expression to its equivalent prefix expression?"

Design: To obtain a prefix expression from infix expression, the procedure that is
followed while converting from infix to postfix expression is used with the following
modifications:
• The precedence functions are different from that of the precedence functions
shown in table 6.1. The precedence functions used to obtain a prefix expression
are shown below: .
6.28 Q Stacks

Symbols Stack precedence Input precedence Associativity


function F function G

+.- 1 2 Left
"*, I 3 4 Left
$ or" 6 5 Ri{!ht
operands 8 7 Left
( - 0 Left
) 0 9 -
# -1 - -
Table 6.2 Precedence values of symbols in the stack and input

• Reverse the infix expression .and follow the same procedure that we have used to
convert from infix to postfix
• The prefix expression is obtained by reversing the result.

Example 6.4.3.3: C function which returns stack and input precedence values
/* Stack precedence function F *1 1* Input precedence function G *1
int F(char symbol) int G(char symbol)
{ {
switch( symbol) switch( symbol)
{ {
case '+': case '+':
case '-': return 1; case '-': return 2;

case '*': case '*':


case 'I': return 3; case 'I': return 4;

case '''': case "":


case '$': return 6; case '$': return 5;

case ')': return 0; case '(': return 0;

case '#': return -1; case ')': return 9;


1
default: return 8; default: return 7;
} }
} }

Note the difference In values. ThIS ISbecause of nght associative


Q Systematic Approach to Data Structures using C - 6.29
1·ott': Observe the following points from the above table/function with respect to
precedence: ,
• The operators '+' and '-' have the same precedence and are least precedence
operators.
• The operators '*' and '/' also have the same precedence and have the precedence
higher than '+' and' -'. .
• The operator '$' or '1\' indicates exponential operator and has a precedence higher
than '*' and '\' but it is right associative operator.

Note. Observe the following points from the above table/function with respect to
associativity.
• If an operator is left associative, stack precedence value is less than input
precedence value.
• If an operator is right associative, stack precedence value is greater than the input
precedence value.

Procedure: General procedure to convert from infix. to prefix form is shown below:
• As long as the precedence value of the symbol on top of the stack is greater than
the precedence value of the current input symbol, pop an item from the stack and
place it in the prefix expression. The code for this statement can be of the form:

while (F(s[top]) > G(symbol))


{
prefixjj++] = s[top--] /* Pop from stack and place into prefix */
}

• Once the condition in while-loop is failed, if the precedence of the symbol on top
of the stack is not equal to the precedence value of the current input symbol, push
the current symbol on to the stack. Otherwise, delete an item from the stack but do
not place it in the prefix expression. The code for this statement can be of the form

if (F(s[top]) != G(symbol) )
s[++top] = symbol; /* Push symbol on the stack */
else
top--; /* Drop an element from stack */

Not: These two steps have to be performed for each input symbol in the infix
expression,
6.30 Q Stacks

The complete C function to convert from infix expression to postfix expression is


shown below:

Example 6.4.3.4: C function to convert from infix expression into prefix expression
void infix-'prefix( char infix]'], char prefix[])
{ .
int top; 1* Points to top of the stack *1
char s[30]; 1* Acts as storage for stack elements *1
int J; ;* Index for prefix expression *1
int 1- , 1* Index to access infix expression *1
char symbol; 1* Holds scanned char from infix expression *1
-.top = -1; 1* Stack is empty *1
s[++top] = '#'; 1* Initialize stack to # *1
j =0; 1* Points to first char of prefix expression *1
strrev(infix); 1* Reverse the infix expression *1
fore i = 0; i < strlen(infix); i++)
{
symbol = infix[i]; 1* Scan the next symbol *1
while (F(s[top]) > G(symbol) )
{
prefixjj] = s[top--]; 1* Pop from stack and place *1
j++; 1* into prefix *1
}

if ( F(s[top]) != G(symbol) )
s[++top] = symbol; 1* push the input symbol *1
else
top-«; 1* discard '(' from stack *1
}
while ( s[top] != '#')
{
prefix [i++] = s[top--];
}

prefixjj] = '\0'; 1* Attach NULL char at the end of string *1


strrev(prefix); 1* To obtain the actual prefix expression *1
}
Q Systematic Approach to Data Structures using C - 31

The complete C program to convert a valid infix expression to postfix expression is


shown below:

Example 6.4.3.5: C program to convert from infix expression into prefix expression

#include <stdio.h>
#include <string.h>

l" Include: Example 6.4.3.3: Two functions F and G */

/* Include: Example 6.4.3.4: Function to convert from infix to prefix */

void mainO
{ Input and Outputs
char infix[20];
char prefix[20]; Enter a valid infix expression
((a+b )*c-( d-e»)"(f+g)
printf("Enter a valid infix expression\n"); The prefix expression is
scanf("%s" ,infix); A_*+abc-de+fg

infix~refix( iniix,prefix); Enter a valid infix expression


a Ab *c-d+e/f/ (g+h)
printf("The prefix expression is\n"); The prefix expression is
printf("%s\n",prefix); +-*Aabcd//ef+gh

Note: The precedence values of the operands in functions G and F in example 6.4.2.3
are 7 and 8. The same values are used in example 6.4.3.3. This is because the order
of the operands in the prefix, postfix and infix expressions are same. Only the order of
the operators changes. So, care should be taken while taking the precedence values
for the operators. For example, consider the following expressions:
a+b*c ( Infix expression)
abc*+ ( Postfix expression)
+a*bc ( Prefix expression)

If we look at above expressions, the operands a, band c appear in the same sequence
where as the operators are not is same sequence. So, the precedence value of the
operands is same, but the precedence values of operators are different while
converting from infix to postfix and from infix to prefix.
6. 2 ~ Stacks

6.4.4 Evaluation of Postfix expression

Let us see "What is the problem in evaluatmg the infix expressions? What is the need
for evaluating postfix/prefix expressions?" The evaluation of infix expression is not
recommended because of the following reasons:
. • Evaluation of infix expression requires the knowledge of precedence of
operators and the associativity of operators.
• The problem becomes complex, if there are parentheses in the expression
because they change the order of precedence.
• During evaluation, we may have to scan from left to right and right to left
~ repeatedly thereby complexity of the program increases.

All these problems can be' avoided if the infix expression is converted to its
corresponding postfix or prefix expression and then evaluate. Evaluation of a postfix
expression or prefix expression is yery simple. Now, let us see "How to evaluate the
postfix expression?" The postfix expression can be evaluated using the following
procedure:
• Scan the symbol from left to right
• If the scanned symbol is an operand, push it on to the stack
• If the scanned symbol is an operator, pop two elements from the stack. The
first popped element is operand2 and the second popped element is operand 1.
This can be achieved using the statements
op2 = s[top--]; /* First popped element is operand2 *i
opl = s[top--]; 1* Second popped element is operand l *1

• Perform the indicated operation


res = op 1 o{> op2 1* op is an operator such +, -, I, * etc. :1<1
• Push the result on to the stack.
• Repeat the above procedure till the end of input is encountered.

The algorithm or pseudocode to evaluate the postfix expression is shown below:

Example 6.4.4.1: Algorithm to evaluate the postfix expression

while end of input is not reached do


(
l
symbol = nextcharO
Q Systematic Approach to Data Structures using C - 6.33

If ( symbol is an operand)
push(symbol,top,s); 1* Push the operand *1
else
op2 = pop(top,s); 1* Pop into second operand *1
opt = pop(top,s); 1* Pop into first operand *1
res = opt op op2; 1* Perform the operation *1
push(res,top,s); 1* Push the result *1
endif

The complete program to evaluate the postfix expression is shown below:

Example 6.4.4.2: C program to evaluate the postfix expression

#include <stdio.h>
#include <math.h>
#include <string.h>

1* Function to evaluate *1
double compute( char symbol, double op l, double op2)
{
switch(symbol)
{
case '+': return op 1 + op2; 1* Perform addition operation *1

case '-': return opl - op2; 1* Perform subtraction operation *1

case '*': return opl * op2; 1* Multiply two operands *1

case 'I': return op 1 I op2; 1* Perform division *1

case '$':
case "":return pow(opl,op2); 1* Computer power *1
}

void mairu)
{
double s[20]; 1* Place for stack elements *1
double res; 1* Holds the result of partial or final result */
6.34 Q Stacks

double op1; 1* First operand *1


double op2; 1* Second operand *1
int top; 1* Points to the topmost element *t
int 1; 1* Index to obtain each symbol from the postfix *1
char postfix[20]; 1* Valid input expression *1
char symbol; 1* Scanned symbol of postfix *1

printf("Enter the postfix expression\n");


scanf("%s" ,postfix);

top = -1; 1* Stack is empty *1

for(i = 0; i < strlen(postfix); i++)


.. {
symbol = postfix[i]; 1* Obtain the next character *1

if ( isdigit(symbol) ) 1* If operand insert into the stack *1


s[top++] = symbol-'O';
else
{
op2 = s[top--]; 1* Obtain second operand from stack *1
op1 = s[top--]; 1* Obtain first operand from stack *1

1* Perform the specified operation *1


res = compute(symbol,op1,op2);

s[++top] = res; 1* Push the partial result on the stack *1


}
}
res = s[top--]; 1* Obtain result from the stack *1

printf("The result is %f\n",res);


}

Output
Enter the postfix expression
1 231

The result is 0.666667


Enter the postfix expression
23+
The result is 5.00000
Q Systematic Approach to Data Structures using C - 6.35

6.4.5 Postfix to prefix

A postfix expression can be converted into its equivalent prefix expression. Let us see
"What is the procedure to convert a postfix expression to prefix expression?" The
procedure to be followed is shown along with the example below. Consider the
postfix expression:

ab+

• If the scanned character is an operand, push it on to the stack. For example, in the
above expression a and b are pushed on to the stack

• If the scanned character is an operator, obtain the corresponding two operands


from the stack and obtain the partial prefix expression by prefixing the operator to
the operands. In this example, the next scanned symbol is +. So, the prefix
expression is formed by concatenating the + and the two operands a and b which
are on the stack as shown below:

+ab

Note: The following two functions of push and pop operations are used ill
subsequent sections:

Example 6.4.5.1: C functions implementing push and pop operations

void push( char item[], int *top, char s[][20J)


{
*top = *top + 1; 1* Point top to next location *1
strcpy( s[*top], item);

char *pop(int *top, char s[][20J)


{
char *item;

item = s[*top]; 1* Access the top most item *1


*top = *top - 1; 1* Update the to pointer *1
return item; 1* Return item to the calling function *1
6.36 ~ Stacks

Thus, a postfix expression can be converted into prefix expression and the
corresponding program is shown below:

Example 6.4.5.2: C program to convert a postfix expression to its equivalent prefix


expreSSIOn.
.
#include <stdio.h>
#include <string.h>

1* Include: Example 6.4.5.1: C functions implementing push and pop operations *1

void postfixjirefixrchar postfix[], char prefix[])


{
char s[20][20]; /* Stack to hold the intermediate prefix obtained *1
int top; /* Points to topmost item */
char symbol; /* Symbol scanned from postfix expression */
char temp[2]; /* To convert symbol scanned into a string */
char *opl; /* Holds operand 1 obtained after popping */
char *op2; 1* Holds operand 2 obtained after popping */
int 1; /* Index to scan each symbol from postfix */

top = -1; /* Stack is empty *1

for (i = 0; i < strlen(postfix); i++)


{
symbol = postfix[i]; 1* obtain the next symbol *1

temp[O] = symbol; 1* Convert symbol to string *1


temp[l] = '\0';

switch( symbol)
{
case '+': 1* If the scanned symbol is an operator *1 I
ca e '-':
case '*':
case 'I':
case '''':
op2 = pop(&top,s); 1* Obtain the second operand *1
op1 = pop(&top,s); 1* Obtain the first operand *1
Q Systematic Approach to Data Structures using C - 6.37

I*Build the partial prefix expression: Op op 1 op2 *1


strcpy(prefix, temp); 1* Prefix an operator *1
strcat(prefix,opl); 1* Concatenate first operand *1
strcat(prefix,op2); 1* Concatenate second operand *1

push(prefix, &top, s); I*Push partial prefix obtained *1

break;

default:
push( temp,&top,s); 1* Push the operand on to stack *1
}
}

Note: The array s[20][20] is used as stack of strings. So, two-dimensional array is
used.

void maim)
{
char postfix[20]; 1* Input: has postfix expression *1
char prefix[20]; 1* Output: will have prefix expression *1

printf("Enter the postfix expression\n");


scanf("%s" ,postfix);

postfix ~refix(postfix, prefix); 1* Convert postfix to prefix *1

printf("The prefix expression is %s\n", prefix);

Output! Output2

Enter the postfix expression


Enter the postfix expression
abAc*d-ef/gh/+l+ ab+c=de=fg+"
The prefix expression is
The prefix expression is
+-*Aabcdllef+gh A-*+abc-de+fg
6.38 Q Stacks

6.4.6 Postfix to Infix

A postfix expression can be converted into its equivalent infix expression. The
procedure to be followed is shown along with the example below. Consider the
postfix expression

ab+

• If the scanned character is an operand, push it on to the stack. For example, in the
above expression a and b are pushed on to the stack
• If the scanned character is an operator, build an infix expression by enclosing the
expression within 'C' and ')' as shown below:
a. Copy the symbol '(' into partial infix expression.
b. Concatenate first operand
c. Concatenate the operator
d. Concatenate the second operand
e. Concatenate the string ")"

and the expression obtained is

(a+b)

Thus, a postfix expression can be converted into infix expression and the
corresponding program is shown below:

Example 6.4.6.1: C program to convert a postfix expression to its equivalent infix


expression.

#include <stdio.h>
#include <string.h>

/* Include: Example 6.4.5.1: C functions implementing push and pop operations */

void postfix _infixCchar postfix[], char infix[])


{
char s[20][20]; 1* Stack to hold the intermediate infix obtained *1
1 int top; 1* Points to topmost item *1
char symbol; 1* Symbol scanned from postfix expression *1
char temp[2]; 1* To convert symbol scanned into a string *1
char *opl; 1* Holds operand 1 obtained after popping *1
char *op2; 1* Holds operand 2 obtained after popping *1
int 1; 1* Index to scan each symbol from postfix *1
~ Systematic Approach to Data Structures using C - 6.39

top = -1; 1* Stack is empty *I

for (i = 0; i < strlen(postfix); i++)


{
symbol = postfix[i]; 1* Obtain the next symbol *1

temp[O] = symbol; 1* Convert symbol to string *1


temp[l] = '\0';

switch(symbol)
{
1* If the scanned symbol is an operator *1
case '+':
case '-':
case '*':
case 'I':
case '1\':
op2 = pop(&top,s); 1* Obtain the second operand *1
op1 = pop(&top,s); 1* Obtain the first operand *1

1* Form the partial infix expression, enclose within (,)*1

strcpy(infix, "("); 1* Prefix with left brace *1


strcat(infix, op 1); 1* Concatenate first operand *1
strcat(infix, temp); 1* Concatenate the operator *1
strcat(infix, op2); 1* Concatenate second operand *1
strcat(infix, ")"); 1* Suffix with right brace *1

push(infix, &top, s); I*Push the partial infix obtained *1

break;

default:
push(temp,&top,s); 1* Push the operand on to stack *1
}
}
6.40 Q Stac::.,:k,::s ...!- _
void mairu)
{
char postfix[20]; /* Input: has postfix expression */
char infix[20]; /* Output: will have infix expression */

printf("Enter the postfix expression\n");


scanf("%s" ,postfix);

postfix _ infix (postfix, infix); /* Convert postfix to infix */

printf("The infix expression is %S", infix);


}

Output
Enter the postfix expression
abcde/\*/-
The infix expression is (a-(b/(c*(d/\e))))
Enter the postfix expression
ab+c-
The infix expression is «a+b)-c)

6.4.7 Prefix to Postfix

A prefix expression can be converted into its equivalent postfix expression. The
procedure to be followed is shown along with the example below: Consider the prefix
expression

+ab

• Reverse the prefix expression. In this example, the expression after reversing will
be
ba+
• If the scanned character is an operand, push it on to the stack. For example, in the
above expression b and a are pushed on to the stack
• If the scanned character is an operator, pop two operands into op 1 and op2
ryspectively and concatenate opi, op2 with t e operator. In this example, the two
operands popped from stack are a and b and are concatenated with + symbol to
get the expression
ab+
which is a postfix expression.
~ Systematic Approach to Data Structures using C - 6.41

Thus, a prefix expression can be converted into postfix expression and the
corresponding program is shown below:

Example 6.4.7.1: C program to convert a prefix expression to its equivalent postfix


expression.

#include <stdio.h>
#include <string.h>

/* Include: Example 6.4.5.1: C functions implementing push and pop operations *1

void prefix~ostfix( char prefix[], char postfix[])


{
char s[20][20]; 1* Stack to hold the intermediate postfix obtained *1
int top; 1* Points to topmost item *1
char symbol; 1* Symbol scanned from prefix expression *1
char temp[2]; 1* To convert symbol scanned into a string *1
char *op1; 1* Holds operand 1 obtained after popping *1
char *op2; 1* Holds operand 2 obtained after popping *1
int i; 1* Index to scan each symbol from prefix *1

top = -1; '* Stack is empty *1

strrev(prefix) ;
for (i = 0; i < strlen(prefix); i++)
{
symbol = prefix[i]; 1* Obtain the next symbol *1

temp[O] = symbol; 1* Convert symbol to string *1


temp[l] = '\0';

switch( symbol)
{

case '+': 1* If the scanned symbol is an operator *1


case '-':
case '*':
case 'I':
case '1\':
6.42 Q Stacks

opl = pop(&top,s); 1* Obtain the first operand *1


op2 = pop(&top,s); 1* Obtain the second operand *1

strcpy(postfix, op 1); 1* Concatenate first operand *1


strcat(postfix, op2); 1* Concatenate second operand *1
strcat(postfix, temp); 1* Suffix operands with operator */

push(postfix, &top, s);


break;

default:
push(temp,&top,s);
- }
}
-}

void maint)
{
char prefix[20]; /* Input: Has prefix expression *1
char postfix[20]; !* Output: Will have postfix expression */

printf("Enter the prefix expression\n");


scanf("%s" ,prefix);

prefix yostfix(prefix, postfix);

printf("The postfix expression is %s\n", postfix);


}

Output
Enter the prefix expression
-a/b=c+de
The postfix expression is
abcdeA'~/-
.1

Enter the prefix expression


-+abc
The postfix expression is
ab+c-
~ Systematic Approach to Data Structures using C - 6.43
6.4..8Prefix to Infix

A prefix expression can be converted into its equivalent infix expression. The
procedure to be followed is shown along with the example below. Consider the prefix
expression

+ab

• Reverse the prefix expression. In this example, the expression after reversing will
be
ba+

• If the scanned character is an operand, push it on to the stack. For example, in the
above expression b and a are pushed on to the stack
• If the scanned character is an operator, build an infix expression by enclosing the
expression within '(' and ')' as shown below:
a. Copy the symbol '(' into partial infix expression.
b. Concatenate first operand
c. Concatenate the operator
d. Concatenate the second operand
e. Concatenate the string ")"

andthe expression obtained is

(a+b)

whichis an infix expression.

Thus, a prefix expression can be converted into infix expression and the
corresponding program is shown below:

Example 6.4.8.1: C program to convert a prefix expression to its equivalent infix


expression.

#include<stdio.h>
#include<string.h>

/* Include: Example 6.4.5.1: C functions implementing push and pop operations *1


6.44 Q Stacks

void prefix _infix( char prefix[], char infix[])


{
char s[20][20]; 1* Stack to hold the intermediate infix obtained *1
int top; 1* Points to topmost item *1
char symbol; 1* Symbol scanned from prefix expression *1
char temp[2]; 1* To convert symbol scanned into a string *1
char *opl; 1* Holds operand 1 obtained after popping *1
char *op2; 1* Holds operand 2 obtained after popping *1
int 1; 1* Index to scan each symbol from prefix *1

top = -1; '* Stack is empty *1

strrev(prefix) ;
for (i = 0; i < strlen(prefix); i++)
{
symbol = prefix[i]; 1* Obtain the next symbol *1

temp[O] = symbol; 1* Convert symbol to string *1


temp[l] = '\0';

switch( symbol)
{
1* If the scanned symbol is an operator *1
case '+':
case '-':
case '*':
case 'I':
case '1\':
opl = pop(&top,s); 1* Obtain the first operand *1
op2 = pop(&top,s); 1* Obtain the second operand *1

1* Bui d an infix expression *1


strcpy(infix,"("); 1* Prefix with left brace *1
strcat(infix, op 1); 1* Concatenate first operand *1
strcat(infix, temp); * Concatenate the operator *1
strcat(infix,op2); * Concatenate second operand *1
strcat(infix, ")"); 1* Suffix with left brace *1

push(infix, &top, s);I* Push partial infix on stack *1


break;
,!;l Systematic Approach to Data Structures using C - 6.45

default:
push( temp,&top,s);
}
}

void maim)
{
char prefix[20]; /* Input: Has prefix expression */
char infix[20]; /* Output: Will have infix expression */

printf("Enter the prefix expression\n");


scanf("%s" ,prefix);

prefix _infix(prefix, infix);

printf("The infix expression is %s\n", infix);

Output

Enter the prefix expression


-a/b*c"de
The infix expression is
(a-(b/( c*( d"e))))
Enter the prefix expression
-+abc
The infix expression is
«a+b)-c)

6.4.9Other useful algorithms and solutions

Example 6.4.9.1: Write an algorithm to determine if an input character string is of the


form
xCy

wherex is a string consisting of the letters 'A' and 'B' and y is the reverse ofx. (i.e.,
ifx = 'ABABBA',
.
y will be 'ABBABA') by reading only one character at a time. ,
6.46 Q Stacks

Design: In the given string xCy note that the string y is reverse of x. During scanning
of a symbol, let us keep on pushing all A's and B's onto the stack till we encounter C.
If symbol C is not encountered, the string is not of the form x C y and the function
should return 0_ The equivalent code is shown below:

for i = 0 to strlen( str)-l


{
if (str[i] = 'A' II str[i] == 'B') 1* Keep pushing A's and B's *1
s[++top] = str[i];
else if (str[i] = 'C') break; 1* If C, come out ofloop *1
}

-if (i = strlen(str)) return 0; 1* Not in the form xCy *1

If C is encountered, for every subsequent input symbol, there should be an equivalent


symbol on the' stack. If so, the string is of the form x C y. If the input symbol and the
symbol on top of the stack are different, the given string is not of the form x C y. The
corresponding code for above activity is shown below:

i++; I*Point one character beyond C*/

while ( i < strlen(str))


{
stk_item = s[top--]; 1* Pop an item from stack *1

if (str[i] != stk_item)
return 0; 1* Not in the form xCy *1

i++; 1* To read the next character *1


}

Once control comes out of the loop, if stack is empty, the string is of the form xCy. If
stack has some elements, definitely the string is not of the form xCy. The equivalent
statements are shown below:

1 if (top = -1) return 1; 1* The string is of the form xCy */

return 0; 1* Stack not empty. So, not of the form xCy *1

The complete program to check whether the string is of the form x C y where y is the
reverse of x is shown below:
Q Systematic Approach to Data Structures using C - 6.47

#include <stdio.h>
#include <string.h>
int isyalindrome( char str[])
{
int t:, 1* Index to access each character */
int top = -1; 1* Points to topmost element */
char s[30];
char stk_item; 1* Item deleted from the stack */
for (i = 0; i < strlen(str); i++) 1* Keep pushing A's and B's *1
{
if (str[i] = 'A' II str[i] = 'B')
s[++top] = str[i];
else if (str[i] = 'C') break; 1* If C, come out of loop */
}
if (i = strlen(str)) return 0; /* Not in the form xCy */
i++; /*Point one character beyond C*/
while ( i < strlen(str))
{
stk_item = s[top--]; 1* Pop an item from stack *i
if (str[i] != stk_item) return 0; /* Not in the form xCy *1
i++; /* To read the next character */
}
if (top = -1) return 1; 1* The string is of the form xCy *"1
return 0; 1* Stack not empty So, not of the form xCy */

void rnaint)
{
char str[20];
printf("Enter strings of A's and B's with C at the center\n");
scanf("%s" .str);
if (isyalindrome(str))
printf("The string is of the form xC y \n");
else
printf("The string is not of the form x C yvn'');
6.48 Q Stacks

Example 6.4.9.2: Write a program to check whether a given string is a palindrome or


not using stack.

#include <stdio.h>
#include <string.h>
int isyalindrome( char str[])
{
int 1·, 1* Index to access each character *1
int top = -1; 1* Points to topmost element *1
char s[30]; 1* Used for stack operations*1
char stk_item; 1* Item deleted from the stack *1
;* Push all the characters of given string *1
for (i = 0; i < strlen(str); i++)
{
s[++top] = str[i];
}
* Check
whether the string is a palindrome or not *1
for (i = 0; i < strlen(str); i++)
{
stk_item = s[top--]; 1* Pop an item from stack *1

if (str[i] != stk_item) return 0; 1* i/p not equal to stack symbol *1


}

return 1; 1* The string is a palindrome *1


}

void maint)
{
char str[20];
printf("Enter strings of A's and B's with C at the center\n");
scanf("%s" ,str);
if (isyalindrome(str))
printf("The string is a palindrome");
else
printf("The string is not a palindrome");
}
Q Systematic Approach to Data Structures using C - 6.49

Example 6.4.9.3: Show how to implement a stack -of integers using C language by
using an array of integers s[STACK_SIZE], where s[O] is used to store the index of
the topmost element of the stack and s[l] through s[STACKSIZE-l] contain the
elements on the stack. Write a declaration and routines push, pop, empty, popandtest,
stacktop and pushandtest functions.

Note: If s[STACK_SIZE]is an array of integers ranging from 0 to STACK_SIZE-l,


we have already learnt how a stack can be implemented. The functions shown in
example 6.2.1 to 6.2.8 are implemented by assuming empty stack is denoted by top =
-1. Now, empty stack is represented by placing 0 in s[O] so that stack starts from 1
onwards. The necessary functions along with complete program is shown below:

#include <stdio.h>
#include <process.h>

#define STACK SlZE 5

/* Function that returns whether the stack is empty or not *1


int empty(int sm
{
if (s[O] = 0) return 1; 1* Stack is' empty *1

return 0; 1* Stack is not empty *1

/* Function to insert an item into the stack *1


void push(int item, int sm
{
1* Increment top and then insert an item *1
s[++s[O]] = item;

* Function to insert
an item into the stack and check for overflow *1
void pushandtest(int item, int sm
{
if (s[O] = STACK_SIZE -1)
{
printf("Stack overflow\n");
return;
}
6.50 Q Stacks

1* Increment top and then insert an item *1


s[++s[O]] = item;
}

1* Function to delete an item from the stack */


int pop(int sm
{
int item_deleted; 1* Holds the top most item of stack *1

item_deleted = s[s[O]--]; 1* Delete the item from the stack *1

return item rleleted; 1* Send the item deleted to the calling function *1
}

1* Function to delete an item from the stack *1


int popandtest(int sm
{
int item_deleted; 1* Holds the top most item of stack *1

if (empty(s)) return 0; 1* Stack is empty *1

item_deleted = s[s[O]--]; 1* Delete the item from stack *1

return itern_deleted; 1* Send the item deleted to the calling function *1


}

1* Function to return the topmost item *1


int stacktop(int sm
{
if (empty(s)) return 0; 1* Stack is empty *1

return s[s[O]]; 1* Return the topmost item *1


} 1

1* F.unction to dispJay the contents of the stack *1


void display(int s[])
{
int i;
Q Systematic Approach to Data Structures usingC - 6.51

if (emptyfs)
{
printf("Stack is empty\n");
return;
}

/* Display contents of stack*/


printf("Contents of the stack\n");
for (i = 1; i <= s[O]; i++)
{
printf("%d\n", sri]);
}

Example 6.4.9.4: C Program to check for validity of an infix expression


,
The program along with various functions with necessary comments is shown below:

#include <stdio.h>
#include <string.h>

lnt check_valid( char infix[])


{
char s[20]; /* Holds only left brackets */
char symbol; /* Holds scanned symbol */
char stk_symbol; /* Holds the symbol deleted from stack */
/* It will be left parenthesis */
iot 1·, /* Index variable to scan the infix expression */
iot top = -1; /* Holds the position of topmost element */

.for (i = 0; i < strlen(infix); i++)


{
symbol = infix[i];

switch (symbol)
{
case '(I:
case '(':
case '{I:
6.52 Q Stacks

s[++top] = symbol;
break;

case')':
case ']':
case I}':
if (top = -1) return 0; 1* No matching left brace */

stk_symbol = s[top--]; 1* Delete item from stack */

I*Input brackt & bracket on stack are different *1


if (stk_symbol = '(I && symbol != I)' II
stk_symbol = '['&& symbol != ']' "
stk_symbol = '{'&& symbol != '} ') return 0;
}
}

if (top != -1) return 0; 1* Extra left bracket on the stack *1

return 1;
}

void maint)
{
int valid; 1* Holds 1, if the expression is correct *1
1* Holds 0, if the expression is not correct *1
char infix[20]; 1* Expression to be checked *1

printf("Enter the infix expression\n");


scanf("%s" .infix);

valid = check_ valid(infix);

if (valid)
l printf("Expression is perfectly paranthesied\n");
else
printf(,'Parantheses rnismatch\n");
}
Q Systematic Approach to Data Structures using C - 6.53

6.5 Stacks using structures

Now, let us see "What is the disadvantage of implementing stacks using arrays? How,
it can be overcome?" So far we have seen how a stack is implemented using an array
and various applications of stacks. In this approach whenever a function puslu) is
called, we have to pass three parameters namely item, top and S, where item is the
element to be pushed, top is an integer value which is the index of the top most
element in the array S. But, as the number of parameters increases, the overhead of
passing parameters in programming also increases and efficiency decreases.
In such cases, we group all related items under a common name using a
structure and pass structures as parameters, which eventually reduces the burden and
increases the efficiency. In our stack implementation, instead of passing two
parameters top and S, we can pass only .one parameter if we use a structure. So, a
stack can be declared as a structure containing two objects viz., an array to store the
elements of the stack and an integer indicating the position of the topmost elem~nt in
the array. The declaration can take the following form:

#define STACK SIZE 5

struct stack
{
int items[STACK_SIZE];
int top;
};

typedcf struct stack STACK;

Oncethis definition is done, we can use a variable s to access the contents of the stack
and to obtain the position of the top most element. The declaration for this can take
theform

STACKs;

Theposition of the top most element and the element itself can be accessed (using the
'.' operator) by specifying

s.top 1* Access the position of topmost element *1


and
s.items[s.top]; 1* To access the top most element *1
6.54 !it Staeks
If the declaration is of the form

STACK '8;

the position of the top most element and the top most element can be accessed by
~ifyiDs

s->top 1* Access the position of topmost element *1


and
s->items[s->top]; 1* To access the top most element *1
.
Let us implement stacks using structures also. We know that the stack is empty, if the
position of the top most element is -1 .. The function is_ emptyt) which returns true
whenever the stack is empty and returns false whenever the stack is not empty is'
shown below:

Example 6.5.1: Function to check whether the stack is empty or not

int is_etnpty(STACK·s)
{
If(s->top=-l) retum-t: 1* Stackempty+/

return 0; 1* Stack is not empty *1


}

The function is MIO retUrns true if stack is full and returns false if the stack is not
full. This function is shown below: .

Example 6.5.2: Function to check whether the stack is full or not

int is_ful1(STACK =s)


{
·1*. Stack is full *1

return 0; 1* Stack is not full *1


}

The function to insert an integer item into the stack is shown below:
Q Systematic Approach to Data Structures using C.- 6.55

Example 6.5.3: Function to insert an integer item into the stack

void push(int item, STACK *s)


{
if (is_full(s) )
{
printflvStack Overflowin");
return;
}

s->top++; /* Update top to point to next item */


s->items[ s->top] = item; /* Insert the item into the stack* /

The function to insert a character item into the stack is shown below:

Example 6.5.4: Function to insert a character item into the stack

void push(char item, STACK *s)


{
if (is_full(s) )
{
printf(tlStack Overflowm");
return;
}

s->top++; /* Update top to point to next item */


s->items[ s->top] = item; /* Insert the item into the stack'v

The function to delete an integer item from the stack is shown below:

Example 6.5.5:Function to delete an integer item from the stack

intpop(STACK *s)
{
iot item;
6.56 Q Stacks

if ( is_ empty( s) )
{
printf("Stack Underflow\n");
return 0;
}

item = s->items[s->top]; 1* Access the top element *1


s->top--; 1* Update the pointer to 'point to previous item */

return item; 1* Return the top item to the calling function */


}

The function to delete a character item from the stack is shown below:

Example 6.5.6: Function to delete a character item from the stack

char pop(STACK *s)


{
char item;
if (is_empty(s) )
{
printf("Stack Underflow\n");
return 0;
}

item = s->items[s->top]; 1* Access the top element *1


s->top--; 1* Update the pointer to point to previous item *1

return item; 1* Return the top item to the calling function *1


.}

The program to display the contents of stack is shewn below:

Example 6.5.7: Function to display the contents of the stack

void display(STACKtfsf
{
lnt i;
,!;l Systematic Approach to Data Structures using C - 6.57

if (is_empty(&s) )
{
prtntf(t'Stack is emptym'');
return;
}
printf("The contents of the stack\n");

for (i = 0; i <= s.top; i++)


{
printf("%d\n",s.items[i]);
}

The C program to simulate the working of a stack using structures is shown below:

Example 6.5.8: C program to simulate the stack operations using structures

#include <stdio.h>
#include <process.h>

#define STACK SIZE 5

struct stack

int items[STACK SIZE];


int top;
};

typedef struct stack STACK;

1* Include: Example 6.5.1: Check for empty stack */

1* Include: Example 6.5.2: Check for stack full or not */

1* Include: Example 6.5.3: To insert an item on the stack */

1* Include: Example 6.5.5: To delete an item from the stack */

/* Include: Example 6.5.7: To display the contents of the stack */


6.58 Q Stacks

void maim)
{
iot item; 1* Item to be inserted *1
int choice; 1* Push, pop, display or quit *1
STACK s; 1* To store items *1

s.top = -1; /* Stack is empty initially */

for (;;)
{
priotf(" 1:Push 2:Pop\n");
priotf("3:Disply 4:Exit\n");
priotf("Enter the choice\n");
scaof("%d" ,&choice);

switch( choice)
{
case 1:
priotf("Enter the item to be inserted\n");
scaof("%d" ,&item);
push(item,.s );
break;

case 2:
item = pop(as);
if (item != 0)
{
priotf("Item deleted = %d\n",item);
}
break;

case 3:
display(s);
break;
1

default: exit(O);
}
}
}
Q Systematic Approach to Data Structures using C - 6.59

The function to convert an infix expression to its corresponding postfix expression


using structures is shown below:

Example 6.5.9: Function to convert infix to postfix using structures

void infix""'postfix(char infix[], char postfix[])


{
int i,j; /* To access infix and postfix expressions respectively */
STACKs; /* Storage for stack elements */
char symbol; /* Holds the next symbol scanned */

s.top = -1;
push('#',&s);

for ( i = j = 0; i < strlen(infix); i++ )


{
symbol = infix[i]; . .
while (F(s.items[s.top]) > G(symbol) )
{
postfix[j++] = pop(&s); .
}

if( F(s.items[s.top]) != G(symbol))


push(symbol;&s);
else
pop(&s);
}

while ( s.items[s.top] != '#')


{
postfix[j++] = pop(&s);
}

postfix[j] = '\0';
6.60 Q Stacks

The complete program to convert a given infix expression to its equivalent postfix
expression is shown below:

Example 6.5.10: C Program to convert infix to postfix using structures

#include <stdio.h>
#include <string.h>

#define STACK SIZE 10

struct stack
{
- int items[STACK_SIZE];
int top;
};

typedef struct stack STACK;

1* Include: Example 6.5.4: Function to insert an item into the stack *1


1* Include: Example 6.5.6: Function to delete an item from the stack *1
1* Include: Example 6.4.2.3: Input & stack precedence functions G & F *1
1* Include: Example 6.5.9: To convert infix to postfix expression*1

void maint)
{
char ihfix[30], postfix[30];

priotf("Enter the infix expression\n");


scaof("%s" ,infix);

infix ""'postfix(infix, postfix);

l priotf("The postfix expression is %s\n",postfix);


}

The program to evaluate the postfix expression using structures is shown below:
Q Systematic Approach to Data Structures using C - 6.61

Example 6.5.11: C Program to evaluate postfix expression (stack is implemented


using structures)

#include <stdio.h>
#include <math.h>
#include <string.h>

#define STACK SIZE 10

struct stack

int top;
double items[STACK_SIZE];
};

typedef struct stack STACK;

1* Function to insert an item of type double *1


void push(double item, STACK *s)
{
s->top++; 1* Update top to point to next item *1

s->items[ s->top] = item; 1* Insert the item into the stack* I

1* Function to delete an item of type double from stack *1


double pop(STACK *s)
{
double item;

item = s->items[s->top]; 1* Access the top element *1

's-:>top--; 1* Update the pointer to previous item *1

return item; 1* Return the top item *1


6.62 Q Stacks

1* function to evaluate *1
double op(char symbol, double opl, double op2)
{
switch( symbol)
{
case '+': return opl + op2;

case '-': return opl - op2; .

case '*': return opl * op2;

case 'I': return op 1 I op2;

case '$':
case '/\I: return pow(opJ,op2);
}
}

void maint)
{
int i;
double res,opl,op2;
~STACKs;
char symbol,postfix[20];

printf("Enter the postfix expression");


scanf("%s" ,postfix);

for ( i = 0; i < strlen(postfix); i++ )


{
symbol = postfix[i];
if ( isdigit(symbol) )
push(symbol-'O',&s);
else
{
1
op2 = pop(&s);
opl = pop(&s);
res = op(symbol,opl,op2);
push(res,&s);
}
}
~ Systematic Approach to Data Structures using C - 6.63

res = pop(&s);
printf("The result is %f\n",res);

Output
Enter the postfix expression
23/
The result is 0.666667
Enter the postfix expression
23+
The result is 5.00QOO

Example 6.5.12: Give the tracing to evaluate the following postfix expression
AB C-D*+E$ F+
corresponding to the infix expression ( ( A + ( B - C ) * D ) $ E + F ) with following
values assigned: A = 6, B = 3, C= 2, D = 5, E = 1, F = 7

Solution: After substituting the given values, the resulting postfix expression is:
632-5*+1$7+
The tracing of the above algorithm is shown below:

Postfix Expression Symbol Op2 Opl Result = Stack


Scanned Opl op op2 Contents
632-5*+11\7+ 6 6
32-5*+11\7+ 3 6 3
2-5*+11\7+ 2 632
-5*+11\7+ - 2 3 3 -2 =1 6 1
5*+11\7+ 5 615
*+11\7+ * 5 1 1*5=5 6 5
+11\7+ + 5 6 6+5=11 11
11\7+ 1 11 1
1\7+ 1\ 1 11 111\1=11 11
7+ 7 11 7
+ + 7 11 11 + 7 = 18 18

The postfix expression is a sequence of characters. So, when an operand is pushed on


to the stack, its ASCII value will be pushed. But, we want to push the corresponding
integer value. This is achieved by subtracting '0' which is 48 in decimal (Ox30 in
6.64 Q Stacks

hexadecimal) from an operand i.e., if '6' is an operand its integer value is '6' -'0' i.e.,
6. This integer value will be pushed on to the stack. The assumption is that the input
consists of only non-negative, single digit integer numbers and the expression is valid.

Example 6.5.13: Apply the evaluation algorithm and trace for the valid postfix
expression
ABC+*CBA-+*

for given value A = 1, B = 2, C = 3 is shown below.

Solution: Substituting the values for the variables we have the following postfix
expression:
123+*321-+*

and the complete tracing is shown in table below:

+-,
Postfix Expression Symb Op Op Result = Stack
01 2 1 Op1 op Contents
Scann op2
ed
123+*321-+* 1 1
23+*321-+* 2 12
3 + * 3 2 1 -+ * 3 123
+*321-+* + 3 2 2+3=5 15
*321-+* * 5 1 1*5=5 5
321-+* 3 53
21-+* 2 532
1-+* 1 - 532 1
-+* 1 2 2-1=1 531
+* + 1 3 3+1=4 54
* * 5 4 4*5= 20
20
--

So, after evaluation of the postfix expression


ABC + * C B A - + * for given value A = 1, B = 2, C = 3,

result = 20
I • e
Q Systematic Approach to Data Structures using C - 6.65
Example 6.3.17: Apply the evaluation algorithm discussed in section 6.3.13 and trac
for the valid postfix expression

AB+C-BA+C$-

for given value A = 1, B = 2, C = 3 is shown below .

.Solution: Substituting the values for the variables we have the following postfi
expression:

1 2 +3 - 2 1 + 3 $ -
and the complete tracing is shown in table below:

Postfix Expression Symbol Op2 Opl Result = Stack


Scanned Op l op op2 Contents
12+3-21+3$- 1 1
2+3"":21+3$- 2 12
+3-21+3$- + 2 1 1+2=3 3
3-21+3$- 3 33
-21+3$- - 3 3 3-3=0 0
21+3$.- 2 02
1+3$- 1 021
+3$- + 1 2 2+1=3 03
3$- 3 033
$- $ 3 3 3 $ 3 = 27 027
- - 27 0 0-27 = -27 -27

So, after evaluation of the postfix expression A B + C - B A + C $ - for given value


A = 1, B = 2, C = 3,

I result = -27 I
Exercises
1. What is a stack? Mention the operations that are performed to put an element on
to a stack and remove an element from a stack. Using C language implement the
above functions. (VTU-July/Aug 2004)
6.66 Q Stacks

2. Given the following expressions give their postfix and prefix forms
i. (A +B)*(D-C)
u. X$Y * Z - M + N + PI Q I (R+S)
(VTU-July/Aug 2004)
3. Obtain the prefix expressions and postfix expressions for the following.
a) A+B-C*D
b) (A+B)*(C+D)$(A+B)
c) ((6+(2-3)*2$4$2)+8)
d) A+B*C-D/E*H
e) (A+B"C"D)*(E+F/D)
4. Convert the following prefix expressions to corresponding infix expressions.
a) -A+*$CDB/-FE*GHI
b) "-*+ABC-DE+FG
c) -+ABC
5. Convert the following postfix expressions to corresponding infix expressions.
a) AB"C*D-EF/GH+/+
b) AB+C*DE-FG+"
. c) EDBCA-+"*AB-*
6. Write a C program to implement a stack of character strings.
7. What is a stack? Discuss the applications of stacks.
8. Write an algorithm for converting infix expression to postfix expression. Trace the
algorithm indicating content of stack for expression (a-b) / (c*d) + e
(VTU July/Aug 2004)
9. What are the advantages of converting an infix expression to postfix expression
10. Write an algorithm for evaluating a valid postfix expression. Trace the same on
i. A B +C- B A +C $-
ii. ABC + * C B A - + *
for given value A=l, B=2, C=3 (VTU Jan/Feb 2004)

11. What are the applications of stacks? Using stack write an algorithm to determine
if a given string is palindrome and print suitable message as output.
(VTU July/Aug 2004)
12. Write a C program to convert an infix expression to its equivalent prefix
expression
13. V{rite a C program to convert prefix expression to infix expression
14. Write a C program to convert a prefix expression to its postfix expression
15. Write a C program to convert a postfix expression to its equivalent prefix
expression
16. Write a C program to convert a postfix expression to its equivalent infix expression
Chapter 7: Recursion
I What are we studying in this chapter? I
• Recursive definition and processes
• Recursion in C
.• Writing recursive programs
• Simulating recursion
'. Efficiency of recursion" - 4 hours
(

7.1 Introduction
Recursion is a powerful tool but least understood by most novice students. It is an
important facility that is available in most of the programming languages such as
Pascal, e, Cf+ etc. In this chapter, let us discuss the meaning of recursion; how a
recursive definition for a problem can be obtained, the designing aspects and how
they are implemented in e language. Finally we compare the iterative technique with
recursion, their merits and demerits along with properties of recursive functions. First,
let us see "What is recursion?"

Definition: Recursioni s a technique for defining a problem in terms of one or more


versions of the same problem. A function, "which contains a call to itself or a call to
another function, which eventually causes the first function to be called, is known as a
recursive function. In recursion, the calling function and called function are same.
The solution to the recursive problem is built from the results obtained from smaller
versions.
For example.computation of factorial of a number is the classic and simple
example which uses recursion.

To understand and write efficient programs, it is necessary for us to know various


methods of representing the solutions for a given problem. Let us compute n! (read as
n factorial) using two different techniques: "
• Iteration _
• Recursion

and then compare iterative version of the program and recursive version of the
program.
7.2 Q Recursion

7.1.1 Iterative version to compute faetorlal gf n


Now, let us see "What is iterative definition to compute factorial of n?" The factorial
of a number n is the product of integer values from 1 to n. The iterative definition to
compute n! is shown below:

1 ifn = 0
Fact(n) =
{ n x (n-1) x (n-2) x (n-3) x 3x2x1 ifn>O

Design: Let us design the program to compute factorial of a number. According to the
definition, if n >0, n! can be computed as shown below:

1*2 * 3 * ....n
The above series can be multiplied as shown below:

1 * 2 * 3 * ....n
Initial: fact =
y 1
Step 1: fact =
Step 2: fact =
~
, fact
v
*
1
2/
Step 3: fact = Jact *
v

"---y----J
Step n: fact = fact * n

From the above figure we can write the following steps

Initial: fact =1 ----.;....,-.... fact = 1;


Step 1: fact = fact *1
Step ~: fact = fact *2
Step 3: fact = fact * 3 --+ fact = fact * i; for i = 1, 2 , 3 , 4 , to n
~------------~---------~
Step n: for (i = 1; i <= n; i++)
fact = fact "n
{
fact = fact * i;
}
Q Systematic Approach to Data Structures using C - 7.3

The function to.compute factorial of n is shown below:

Example 7.1.1.1: C function to compute factorial ofn

int factorial (int n)


{
int fact, i;

fact = 1; 1* factorial ofn when n = 0 *1

for (i = 1; i <= n; i++) 1* factorial ofn when n > 0 *1


{
fact= fact* i;
}

return fact; 1* Return factorial of n *1

The main program (calling program) to compute factorial of n is shown below:


I

Example 7.1.1.2: C program to compute factorial ofn

#include <stdio.h>

1* Include: Example 7.1.1.1: C function to compute factorial of n *1

void maint) I
{
int n·,
I
I
I Input
printf ("Enter the value ofN\n"); Enter the value ofN
scanf ("%d",&n); I 5
I Output
printf("Factorial (%d) = %d\n", n, factorial(n)); I Factorial 5 = 120

t.
I I
7.4 Q Recursion

7.1.2 Recursive version to compute factorial of n

Now, let us see"What is recursive definition 0 compute factorial of n?' The factorial
of a number n is the product of integer values from 1 to n. The recursive definition to
compute n! is shown below:

l ifn = 0
fact(n) =
{ n x fact(n-l) ifn> 0

Now, let us see"How to compute factorial of 5 using recursion?" We can compute 5!


as shown below:

5! = 5 * 4!
Decompose the
----------------~-!-_~4 *3~! = 3 * 2' problem from
-----------~---2 ,.= 2 * l' top to bottom
-----------:-- 1;= 1 * 0'.
................

O! = 1 } Arrive at the solution

.> ··--··-·2-;-:-;-·~ I!l! = 21 * O!


=
= 1
Compute the
~..-.·--··-·--3·i = 3 * 2! 6=
solution from
"-,,,-'--"'4! = 4 * 3! = 24
bottom to top
5! = 5 * 4! = 120

Note: Thus, it is clear from the above computations that, the recursive solution for a
problem involves a two-way journey with a stop at the middle:
• Decompose the problem from top to bottom which involves reducing the problem
into smaller problems of same type
• Arrive at the solution which does not involve any recursion (Base case)
• Compute the solution from bottom to top using the previous solutions.
J.
Observation: It looks like recursive calculations are difficult and take more time.
This is true if we do the calculations using pen and paper. But, using computers it is
easier to write the solution. and looks more elegant. So, let us see "How to write the
recursive function to compute factorial of n?" Using recursive definition, the function
can be written as shown below:
~ Systematic Approach to Data Structures using C - 7.5

Example 7.1.2.1: C function to find the factorial ofN

int fact(int n)
{
if ( n == 0 ) return 1; 1* factorial ofn when n = 0*1
return n*fact(n-l); 1* factorial of n when n > 0*1

In the recursive version, we let the function fact call itself, each time with a different
set of parameters. Observe that recursive solution does not need a loop. Because,
recursion is itself repetition. The main program to compute factoria] is shown below:

Example 7.1.2.2: C Program to find the factorial of N

#include <stdio.h>

/* Include: Example 7.1.2.1:Function to compute factorial ofn *1

void mainf)
{
int n;
I Input
printf(t'Enter nxn''): I Enter n
scanf(If%dlf,&n); I 5
I Output
printft'The factorial of %d = %d\nlf, n, fact(n)); I Factorial of 5 = 120
I

Note: Comparing iterative function (example 7.1.1.1) and recursive function


(example 7.1.2.1), we know that
• Recursive function is much simpler.
• No loops are present. Only simple if statement which returns either 1 or product
of two values using recursion.

7.1.3 How recursion works

Let us visualize how the control glows from one function call to another call. The
figure 7.1 shows exactly what happens when recursive function factt) gets called. The
execution sequence for the above factorial function is shown below.,
7.6 Q Recursion

void maint)
{
int n;

n = ~act (3); Q
l' printfl:d\n", ---2--'
nlr-;
1 o
int fact(int n) int fact(int n) int fact(int n) int fact/int n)
{ { { {
if ( n = 0 )
return 1; b
if ( n = 0 )
return 1; c
if ( n = 0 )
return 1; G) if(n=O) 1
return 1; -..;;......,
return n* fact(n-l); return n* fact(n-l); return n* fact(n-l); return n* fact(n-l)
3*2 } 2*1 } 1*1}

~=-~t__ ~2~ __ 1 t~__ ~I~ __


G) G) CD
Fig 7.1 Ste sin executin a recursive function
a. The first time when function factt) is called, 3 is passed to n.
b. Since n is not 0, the if statement is skipped and facn) is called again with
argument n-l i.e., 2.
c. Since n is not 0, the if statement IS skipped and factt) IS called agam with
argument n-I i.e., l.
d. Since n is not 0, the if statement IS skipped and factt) IS called again with
argument n-I i.e., O.
e. Since n is 0, control goes previous call with value 1 and 1* 1 = 1 is computed and
sent to the previous point of invocation.
f. The resulting value 1 is passed to the point of previous invokation and 2* 1 = 2 is
computed and sent to the previous point of invokation.
g. The resulting value 2 is passed to the point of previous invokation and 3*2 = 6 is
computed and sent to the previous point of invokation.
h. The resulting value 6 is passed to the point of previous invocation and 6 is copied
into variable n in the main program.
Now,llet us see "How recursion works?" When a function is called, C allocates the
memory space in the stack (called stackframe) and stores the following items in the
stack:
• The parameters passed to the recursive function
• Local variables of the calling function
~ Systematic Approach to Data Structures using C - 7.7

• The return address so that after executing the function, control should be returned
back to the calling function
• The variable that receive the value from the recursive function.

For each call of the function, the corresponding stackframe consisting of above items
is placed on top of the stack and then removed from the stack when the execution of
the called function is completed as shown below:

Step 1: Stack empty

Calls
framel
Step 2:

D Step 7: Stack empty

Stack after 1st call

framel
frame21
1
Returns
Stack after 1st call is executed

framel
Step 3:

Stack after znd call


Step 6:
D
Stack after 2nd call is executed

framel Calls
frame21
framel
frame31
Step 4: Step 5: frame21

Rerrns ~L......-__ ---I

Stack after 3rd call '-- __ ....J After 3rd call is executed

Fig 7.1 Sequence of events that take place during function execution

Once we know how recursion works, the next question is "How to design recursive
functions?" Observe the following points from the factorial function:
7.8 Q Recursion

+ Each time the function fact is called, the size of the problem is reduced. Here, the
value of n is reduced by 1. This is often called general case.
+ Finally, we solve the problem by returning the value 1 to the calling function. This
is called base caseor base/terminal condition.

otc: Every recursive call must solve one part- of the problem using base case or
reduce the size of the problem using general case. Now, let us see "What is base case?
What is a general cease?"

Dcfinition: A base case is a special case whose solution can be obtained without
using recursion. This is also called base/terminal condition. Each recursive function
must have a base case. A base case serves two purposes:
+_ It acts as terminating condition.
+ The recursive function obtains the solution from the base case it reaches.
For example, in the function factorial, fact of 0 is 1 is the base case or terminal
condition.

Definition: In any recursive function, the part of the function except base case is
called general case. This portion of the code contains the logic required to reduce the
size of the problem so as to move towards the base case or terminal condition. Here,
each time the function is called, the size of the problem is reduced.
For example,in the function fact, n*fact(n-l) is general case. By decreasing
the value of n by 1, the function fact is heading towards the base case.

Once we reached the base case, the solution begins. We know one part of the answer
and can return that part of the answer to the more general case. As we solve each
general case, we are able to solve the next higher general case and move towards the
most general case which is the original problem as shown below:

Decompose the
problem from top
to bottom

r-- ....
iL.-, B_a_s_e_c_a_s_e --,..;-~~;:;..~~-::.--o-!
__ -_--~---
.•• _=_1---,} Arrive at the solution

~~., •• #'###
--------------U = 1 * O! = 1
_--------- 2! = 2 * I! = 2 Compute the
_------------3! = 3 * 2! = 6
.-------------4! = 4 * 3! = 24 General rase
solution from
bottom to top
5! = 5 * 4! = 120
~ Systematic Approach to Data Structures using C - 7.9

ote: In our factorial program, base case is fllCt(()) and general case is n*fact(n-l).
So, the general rules that we are supposed to follow while designing any recursive
algorithm are:
• Determine the base case. Careful attention should be given here, because: when
base case is reached, the function must execute a return statement without a call to
recursive function.
• Determine the general case. Here also careful attention should be given and see
that each call must reduce the size of the problem and move it towards base case.
• Combine the base case and general cascinto a function.

otc: A recursive function should never generate infinite sequence of calls on itself.
An algorithm exhibiting this sequence of calls will never terminate. If a base case
does not exist, no recursive function can ever be computed.

7.2 Fibonacci series

Now, let us see "What are Fibonacci numbers?"

Definition: The Fibonacci numbers are a series of numbers such that each number is
the sum of the previous two numbers except the first and second number. These
numbers are named after an Italian mathematician "Leonardo Fibonacci" who lived in
earlythirteenth century. The Fibonacci numbers are shown below:

0, 1, 1,2,3, 5, 8, 13, .

Now, let us see "What is the base case and general rase to compute Fibonacci
numbers?"To write a recursive defmition we should know the base case and general
case.
Base casc:
Fib(O) = O} These numbers are given. Since the solution already exists it
Fib(l) = 1 is the base case

General case:
NthFibonacci number = N-l thFibonacci number + N_2"d Fibonacci number
i.e., Fib(n) = Fib(n-l) + Fib(n-2)

ow, we know "What is the recursive definition to compute a Fibonacci number?"


Therecursive definition to find nthFibonacci number can be written shown below:
7.10 Q Recursion

o ifn = 0
Fib(n) = 1 ifn = 1
{
fib(n-l) + fib(n-2) ifn > 2

The way to find fib(4) is shown below: The thick arrows represent either a call to
function fibt) or to the value. The dotted arrows point to the result after computation.
The iterative technique for this is much more efficient than the recursive technique.

fib(5) = 3

! ? .

fib(4) + fib(3) .........


.....

fib(3) +
/* I fif(2)
~+
fib(2)
1

fib(1)
=
·""""""""1
3

+ +
1 1.•......
" ...,1 = 2 1 0 = 1
fib(2) + fib( 1) I
+ + 1
1 0 = 1

The C function to fmd the nth Fibonacci number using recursive definition is below:

Example 7.2.1: C Function to fmd nth Fibonacci number

int fib(int n)
{
if ( n = 0 ) return 0; /* Base case: l" number */

if ( n = 1 ) return 1; /* Base case: 2nd number */

return fib(n-l) + fib (n-2); /* General case: Computation of */


} /* subsequent Fibonacci numbers */

The C program to display nth Fibonacci number is shown below:


Q Systematic Approach to Data Structures using C - 7.11

Example 7.2.2: C program to display nth Fibonacci number

#include <stdio.h>

1* Include: Example 7.2.1: To compute nth Fibonacci number *1

void maint)
{
I
int n; I
I Input
printf("Enter n\n"); I Enter n
scanf("%d",&n); I 6
I Output
printf("fib(%d) = %d\n",n,fib(n)); I Fib(6) = 8
I.

Example 7.2.2: C program to display n Fibonacci numbers

#include <stdio.h>

1* Include: Example 7.2.1: To compute nth Fibonacci number *1

void maint)
{
int .i, n;
I Input
printf("Enter n\n"); I Enter n
scanf("%d",&n); I 6
I Output
printf("%d Fibonacci numbers are\n", n); I 6 Fibonacci numbers are
for (i = 0; i < n; i++) I fib(O) = 0
{ fib(l) = 1
printf("fib(%d) = %d\n",i,fib(i)); I fib(2) = 1
}
I fib(3) = 2
I fib(4) = 3
I fib(5) = 5
7.12 Q Recursion

7.2 GCD - ~reatest ~ommoll ~ivisor of two numbers (Euclid's algorithm)

Now, let us see "What is GeD 0 r two numbers?" What is the recursive definition to
compute GCD of two numbers?"

Definition: TheGCD of two given numbers is the largest integer that divides both of
them, GCD of two numbers is defined only for positive integers but, not defined for
negative integers and floating point numbers.
For example, GCD of two numbers 6 and 10 can be computed as shown
below:

M N Description
Remainder
6-· ....10 ........
6
Given two numbers 6 and 10, R = 6 % 10 = 6
10k'" ....6.c"....4 M (-- 10 and N (-- 6, R = 10 % 6 = 4
6k" 44:"
......
2 M(-- 6 and N (-- 4, R = 6 % 4 = 2
v
4k' / 2ot::
M(-- 4 and N (-- 2, R = 4 % 2 = 0
" 0
,/ M (-- 2 and N (-- O. Since N = 0 the GCD will be
2/ 0 0 the value of M which is 2
'---y-----J
GCD = 2. Note that GCD = M = 2, whenever N = O. We know one part of the
answer. In general, we stop computing GCD of two numbers when N = O.When N =
O. M is the GCD of two Ilumh, Now , let us see "What is the base case" The base
case to compute GCD of two numbers is shown below:

Base case:
GCD (M, N)=M whenever N = 0

Now, let us see HI low (0 0111, uc the gene' I case'!" Note the following points from
the table:


I III
GCD(6, 10) = GCD(10, 6). This can be written in general, as shown below
1 I I I I
i.e., GCD(M,N) = GCD(N, M) whenever M < N

I' t J
Q Systematic Approach to Data Structures using C - 7.1~

I l
• GCD(IO, 6) = GCD (6, 4). This can be written in general, as shown below:
I I I
GCD(10, 6) = GCD (6, 10 % 6) whenever M > N .
.J. .J. .J..J..J.
GCD(r'~ = GCD(N, M % N) whenever M > N
_I t J
General case:
GCD(M,N) = GCD( ,M) whenever M <
GCD(M,N) = GCD(N, M % N) whenever M > N

So, "What is the recursive definition to compute GCD of two numbers?" The
recursive definition to compute GCD of two numbers M and N using EUCLID's
algorithm is shown below:

GCD(n, m) ifm<n
GCD(m, n) m ifn = 0
{
GCD(n, m mod n) ifm > n

The C function to compute GCD of two numbers for the above recursive definition
can be written as shown below:

Example 7.2.1: C function to compute GCD of two numbers (Euclid's algorithm)

int gcd(int m, int n)


{
if(n = 0) return m; 1* Base case *1

if(m < n) return gcd(n, m); 1* General case *1

return gcd(n, m mod n); 1* General case *1

The main program to compute GCD of two numbers is shown below:


7.14 g Recursion

Example 7.2.2: C Program to compute GCD of two numbers (Euclid's algorithm)

#include <stdio.h>

/* Include: Example 7.2.1: To compute gcd of two numbers */

void maim)
{
int m, n, res;
Input
printf("Enter the value of m and n\n"); Enter the value of m and n
, scanf("%d %d" ,&m , &n)·, 106

res = gcd(m, n); res = 2


Output
printf("gcd(%d, %d) = %d\n", m, n, res); gcd(10, 6) = 2
}

7.3 Tower of Hanoi

Let us see, "What is tower of Hanoi problem?" In this problem, there are three
needles say A, Band C. There are n discs of different diameters in the needle A and
are placed one above the other such that always a smaller disc is placed above the
larger disc. The two needles Band C are empty. All the discs from needle A are to be
transferred to needle C using needle B as temporary storage. The rules to be followed
while transferring the discs are
• Only one disc is moved at a time from one needle to another needle
• Smaller disc is on top of the larger disc at any time.
• Only one needle can be used to for storing intennediate disks

The initial set up of the problem is shown below.

source A B temp C destination

After transferring all discs from A to C we get the following setup.


~ S stematic A roach to Data Structures usin C - 7.15

source A B temp C destlnation

Base Ca e: Now , let us see ' What


. is the base case?" This case occurs when there is
only one disk. In that case move the disk from source to destination. So,

Move disk n from source to destination if n = 1

General case. Now , let us see "What is the general case?" This case occurs if there
are more than two disks to be transferred from source to destination. If there are n
disks, then all n disks from source to destination using the specified constraints can be
transferred recursively using following three steps:
• Move 0-1 discs recursively from source to temp .
• Move nth from source to destination.
• Move n-I discs from temp to destination.

The C function to implement tower of Hanoi problem is shown below:

Example 7.3.1: C function to implement tower of Hanoi problem

void tower(int n, int source, int temp, int destination)


{
if (n = 1) 1* Base case */
{
priotf("Move disc %d from %c to %c\n",n, source, destination);
return;
}

1* Move n-I discs from source to temp *1


tower(n-l, source, destination, temp);
/* Move nth disk from source to destination *1 General
printf("Move disc %d from %c to %c\n",n,source, destination); case

1* Move n-I discs from temp to destination */


tower(n-l,temp,source,destination);
7.16 Q Recursion

The complete program to implement tower of Hanoi problem is shown below:

Example 7.3.2: C Program to implement tower of Hanoi problem


~
#include <stdio.h>

1* Include: Example 7.3.1: C function to transfer disks from source to destination *1

void maint)
{
int n;

printf("Enter the number of discs\n");


scanf("%d" ,&n);

1* Transfer n disks from needle A to needle C *1


tower(n ,'A' ,'B' ,'C')·,
}

7.4 Multiplication of two natural numbers

Let us write an algorithm to evaluate m*n by repetitive addition where m and n are
non-negative integers.

Design: The product of m*n can be obtained by adding m to itself n times. Here, n
can be used as a counter. For example, 4*3 can be achieved by adding 4 to 4 three
times. The iterative C function to implement this is shown below:

Example 7.4.1 An iterative algorithm to evaluate m*n using repetitive addition

int evaluate(int m, int n)


{
int sum = 0;

II Add m to itselfn times to get m*n


for (i = 1; i <= n; i++)
{
sum+= m;
}

return sum; 1* Return the product ofm and n *1


}
Q Systematic Approach to Data Structures using C - 7.17
The recursive definition to multiply two numbers m and n is shown below:

0 if m = 0 or n = 0 1* Base case *1
mul (m, n) = m if n = 1 1* Base case *1
{
mul (m, n-1) + m Otherwise 1* General case *1

The recursive function for the above recursive definition is shown below:

Example 7.4.2: C function to multiply two natural numbers

int mul (int m, int n)


{
if ( m = 0 II n == 0) return 0; 1* Base case *1

if (n = 1) return m; 1* Base case *1

return mul(m, n-1) + m; 1* General case of adding m to itself n-1 *1


1* times recursively *1

The C program to multiply two numbers m and n is shown below:

Example 7.4.3: C program to multiply two natural numbers using recursion

#include <stdio.h>

1* Include: Example 7.4.2: Recursive function to multiply m and n *1

void rnairu)
{
int m, n;
I Input
printf("Enter the value ofm and n\n"); I Enter value of m, n
scanf("%d %d",&m, &n); I 4 3
I Output
printf("Prod(%d, %d) = %d\n", m, n, mul(m, nj); I Prod( 4,3) = 12
I
7.18 Q Recursion

7.5 Binary search

Now , let us see "What is binary search? What is the concept used in binary search?"

Deflnltlon.z, binary search is a simple searching technique which can be applied if


the items to be compared are either in ascending order or descending order.
. The general idea used in binary search is similar to the way we search for the
telephone number of a person in the telephone directory. Obviously, we do not use
linear search. Instead, we open the book in the middle and the name is compared with
the element at the middle of the book. If the name is found, the corresponding
telephone number is retrieved and the searching has to be stopped. Otherwise, we
search either the left part of the book or right part of the book. If the name to be
searched is less than the middle element, search towards left otherwise, search
towards right. The procedure is repeated till key item is found or the key item is not
found.
Once we know the concept of binary search, the next question is "How to
search for key in a list of elements?"Now, let us see how to search for an item. The
procedure is shown below:
Design:The program can be designed as follows. Let us see, "How to determine the
base case?" The base case is the condition where searching stops. The search stops
when key item not found or when key item is present. So, for these two cases, let us
find the base case.

Base, case (Item not found):We assumed that low is the position of the first element
and high is the position of the last element. So, whenever low is greater than high it
means there are no items present and search definitely fails. The equivalent code for
this can be written as shown below:
if ( low> high) return -1; 1* Key item not found *1

Base case (Item found): If low is considered as the position of the first element and
high as the position of the last element, the position of the middle element can be
obtained using the statement

mid =( low + high) 12;


l
The key to be searched is compared with middle element. If key found, then search
stops and can be considered as the base case. This is achieved using the statement:

1* Item found at mid position *1


if ( key = a[mid]) return mid; 1* Base case *1
Q Systematic Approach to Data Structures using C - 7.19

Now, let us see "1low to obtain the general case?"

Genera c s . If key item is not present at mid position, the key may be in the left
part of the array or in the right part of the array. If key is less than the middle element,
the elements in the left part of the table have to be compared ranging from low to
mid-I. Otherwise, the right part of the array has to be compared from mid + 1 to
high. This can be achieved recursively using the following statements:

if ( key < a[mid] ) /* Search in the left part of array */


return search (key, a, low, mid-I);

else /* Search in the left part of array */


return search (key, a, mid + 1, high);

The recursive function for binary search is shown below:

Example 7.5.1: C function to search for an item us.ing binary search

int search(int key, int a[], int low, int high)


{
int mid; /* contains position of the mid element *1

if ( low> high) return -1 ; /* Base case: Item not found */

mid = (low + high) /2; /* compute the position of middle item */

if (key = a[mid]) return mid; /* Base case: Item found */

1* General case: to search left or right part */

if (key < a[mid]) /* Search in the left part of array */


return search(key, a, low, mid-I);
else 1* Search in the left part of array */
return search(key, a, mid+ 1, high);

Thecomplete C program to search for an item using binary search is shown below:
7.20 Q Recursion

Example 7.5.2: C program to search for an key using binary search (recursive search)

#include <stdio.h>

1* Include: Example 7.5.1: Function to search for an item recursively *1


void maint)
{
int n, i, a[20], item, pos;

printf("Enter the number of elements\n");


scanf("%d", &n);

_ printf("Enter %d items\n",n);
for (i = 0; i < n; i++)
{
scanf("%d",&a[i]);
}

printf("Enter the item to be searched\n");


scanf("%d",&item);

/* 0 - position of 151 item and n-l is the position of last item */


pos = search(item, a, 0, n-l);

if (pos = -1)
printf("Item not found\n");
else
printf("Item found at %d position\n", pos);
}

7.6 Find maximum of n elements


The algorithm to find maximum of n elements using recursion is very simple and
straight forward.
Design: Let us see, "How to determine the base case?"The base case is reached when
n is and element at a[O] is returned which will be considered as the largest element
to start with. This is achieved using the statement:
if (n = 0) return a[n]; /* Base case *1

Now, let us see, "How to determine the general case?" The item found using base
case has to be compared with all the elements starting from 1 to n-l recursively.
I;l Systematic Approach·to Data Structures using C - 7.21

Using recursion, we can access all the elements starting from 1 to n-I by executing
the statement:

big = large( a, n-l) /*Recursively find all values of big */

Keep comparing the all the elements from 1 to n-I with big as shown below:

if (a[n] > big)


return a[n];
else
return big;

The above statement is repeatedly executed for the values ranging from 1 to n-I. The
corresponding c function is shown below:

Example 7.6.1: C functionto find largest ofn elements in an array(Recursion)

int large(int a[]', int n)


{
int big;

if (n = 0) return a[n]; /* Base case: Return 1st item as big */

/* General case: */
big = large(a, n-I); /* Recursively find big */

if (a[n] > big) return a[n]; /* Keep comparing all the items */
return big; 1* Return the largest number */

The complete program to read n elements and displaying biggest element is shown
below:

Example 7.6.2: C function to find largest ofn elements in an array(Recursion)

#include <stdio.h>

1* Include: Example 7.6.1: To compute the largest ofn numbers */


void rnaint)
{
int n,i,a[ 1O],big;
7.22 Q Recursion

printf("Enter the numbers to sort\n"); Enter the number of elements


scanf("%d" ,&n); 5
printf("Enter n items\n"); Enter n items
for (i = 0; i < n; i++) 10,50,100,25,35
scanf("%d" ,&a[i]);

big = large(a, n-1);

printf("Largest = %d\n",big); Largest = 100


}

7.7 Find minimum ofn elements


Design: The function is same as previous recursive function. But, instead of greater
than symbol use less than symbol while comparing. The variable big should be
replaced by small. Rest of the code remains same.

Example 7.7.1: C function to find minimum ofn elements in an array(Recursion)


int minimum(int a[], int n)
{
int small;
if (n = 0) return a[n]; /* Base case: Return 1st item as big */
/* General case: */
small = minimum(a, n-1); /*Recursively find small */
if (a[n] < small) return a[n]; /* Keep comparing all the items */
return small; /* Return the smallest number */
}

The C program to read n elements, compute minimum of n elements and display


minimum element is shown below:

Example 7.7.2:C Program to find minimum ofn elements in an array(Recursion)


#inclllde <stdio.h>

1* Include: Example 7.7.1: Function to find minimum ofn elements */


void maim)
{
int n,i,a[lO],small;
Q Systematic Approach to Data Structures using C - 7.23

printf("Enter the numbers to sort\n"); I Enter the number of elements


scanf("%d",&n); I 5

printC("Enter n items\n"); I Enter n items


for (i = 0; i < n; i++) SCanf("%d",&a[i]);: 10,50, 100,5,35

small = minimum(a, n-l); I


I
printf("Smallest = %d\n",smaU); I Smallest = 5

7.8 Sum of n elements of array

Each item should be accessed and added recursively as shown below:

Example 7.8.1: C Program to find sum of elements of the given array

#include <stdio.h>

int sum(int a[], int n)


{
if (n = 0) return a[n]; 1* Terminal condition to terminate */
return a[n] + sum(a,n-l);

void maim)
{
int n,i,a[l O],res; I
I
printf("Enter the number of items to add\n"); I Enter number of items to add
scanf("%d" ,&n); I 5
printf("Enter n items\n"); I Enter n items
for (i = 0; i < n; i++) .. I 10 20 30 40 50
scanf("%d",&a[i]); I
res = sum(a, n-1); I
I
printf("Sum = %d\n",res); I Sum = 150
I
7.24 Q Recursion

7.9 product of n elements of array

As in previous algorithms, each item should be accessed and mul.iplied recursively.


The complete program is shown below:

Example 7.9.1: C Program to fmd sum of elements of the given array


#include <stdio.h>
int prod(int a[], int n)
{
if (n = 0) return a[n]; * Base case: Return first item */
return a[n] * prod(a,n-l);* General case: Multiply recursively v/
}
void rnaint)
{
int n,i,a[lO],res;
printf("Enter the number of items to multiply\n");
scanf("%d" ,&n);
printf("Enter n items\n");
for (i = 0; i < n; i++) scanf("%d",&a[i]);
res = prod(a, n-l);
printf("Product = %d\n",res);
}

7.10 Print a given number in reverse order .


Any number can be printed in reverse order and the corresponding program is shown
below:
E.xamplc 7.10.1: C Program to print a given number in reverse order
#include <stdio.h>
void reverse(int n)
{ 1

printf("%d", n % lO);
if (nil 0 = 0) return;
reverse(nllO);
}
Q Systematic Approach to Data Structures using C - 7.25

void maim)
{
int n;
t
I
I Input
printf("Enter the number to be reversed\n"); Enter the number to rerverse
scanf("%d",&n); I 12345
I Output
reverse(n); I 54321
printf("\n"); I
I

7.11 Print array elements in reverse order

The array elements can be printed in reverse order using the program shown below:

Example 7.2.12: C Program to print array elements in reverse order

#inc1ude <stdio.h>

void reverse(int n, int a[D


{
if(n = -1) return;

printf("%d\n", ajnj);

reverse(n-l, a); .

void maint)
{
int i,n,a[IO];

printf("Enter the number of elements\n");


scanf("%d",&n);

printf("Enter n elements\n");
for (i = 0; i < n; i++) scanf("%d",&a[i]);

printf("The reversed array is\n");


reverse(n-l, a);
7.26 Q Recursion

7.12 Efficiency of recursion


Here, first let us see "Why non-recursive programs are efficient?" A non recursive
functions are more efficient in terms of execution time and space utilization when
compared to a recursive version because of following reasons:
• There is no overhead involved while entering the function and when the function
is terminated .
• . Stacking activity (ex: inserting local variables on to the stack) can be eliminated.
But, this is not true always. There are majority of the cases where, it is not possible to
write good non-recursive programs. In such situations, we have to go for recursive
functions. Now, let us see "What are the advantages of using recursion?" The various
advantages of recursion are:
• - Clearer and simpler versions of recursive functions can be created.
• Recursive definition can be easily translated into a recursive function
• Lot of "bookkeeping" activities such as initialization etc., required in iterative
solution can be avoided .
• Many functions are easier to implement recursively and are very efficient. (In
trees chapter we study still more recursive functions)
Now, let us see "What are the disadvantages of using recursion?" There are quite a
few problems associated with recursion that do not occur in non-recursive functions.
So, let us' list the various disadvantages of recursion:
• When a function is called from outside or called from within, the function
saves formal parameters, local variables and return address to ensure its proper
functioning. Apart from this, separate copy of the function variables are
created for each call and definitely consumes lot of memory
• Once the base condition is met, the function should restore the most recently
saved parameters, local variables and return addresses and thus most of the
time is spent in pushing and popping the necessary items from the stack and so
consumes more time to compute the result.
• They often execute slowly when compared to their iterative counterparts
because of the overhead of the repeated function calls.
Note: Recursion is expensive in terms of processor time and memory usage
Note: The efficiency of a recursive function depends on depth of recursion. The depth
of rec~rsion is the number of times the function is called recursively to achieve a
desired task. The depth of recursion to find fact(n) is n where n is the number of
recursive calls used to find factorial of n. As the depth of recursion increases, the
program has large number of recursive calls - and we may run out of memory.
Problems of this nature will even challenge most powerful computers.
Q Systematic Approach to Data Structures using C - 7.27

Now, let us "Compare iterative and recursive functions?" and discuss why the
programmer choose one approach over the other in a particular situation.

Iteration Recursion
1.
repetrtron structures such as selection structures such
loop, while-loop or do-while statement, if-else or
statement

Iteration 2. Involve repetition: I" ecursion


explicitly uses repetition structure achieves repetition by calling the
same function repeatedly.

3. teration is 3. Terminal condition: " ecursion IS


terminated when the loop condition terminated when base case IS
fails. satisfied

4. his occurs if 4. Can occur infinitely: I" ecursion IS


condition never fails infinite if there is no base case or if
base case never reaches

5. There are many situations in which 5. There are many situations in which
iteration is not best suited for recursion is best suited for
problems such as tower of Hanoi algorithmic descriptions while
or tree traversals etc. Even though solving problems such as Tower of
these can be solved using iterative Hanoi, or tree traversal techniques
functions, they are difficult to (Refer Trees chapter 10). In these
design, take more programmers' cases, recursive functions are more
time and are more error prone. efficient and can be understood
easily.
6. Iterative functions execute much 6. In recursion, every time the
faster and occupy less memory and function is called, all the local
can be designed easily. variables, formal parameters and
~ return address will be pushed on to
the stack. So, it occupies more
stack and most of the time is spent
in pushing and popping. Thus,
recursion is expensive in terms of
processor time and memory usage.
7.28 Q Recursion

ote: There is a conflict between the machine efficiency and programmer efficiency.
Sometimes recursive programs are recommended and sometimes non-recursive
programs are recommended. This depends on whether we want machine efficiency or
programmer efficiency.

7.13 Properties of recursive functions

The various properties of recursive defmitions or algorithms are:


• A recursive function should never generate infinite sequence of calls on itself. An
algorithm exhibiting this sequence of calls will never terminate.
• There should be at least one base case or terminal condition which will not
involve a call to the same function i.e., there must be a condition to stop recursion.
If a terminal condition like this does not exist, no recursive function can ever be
computed.

EXERCISES

1. What is recursion? What are its applications? (VTU July/Aug 2003)


2. What is recursion? Explain with an example (VTU July/Aug 2004)
3. What are the properties of recursion? (VTU July/Aug 2004)
4. Compare recursive and iterative algorithms (VTU Jan/Feb 2005)
5. Write a recursive routine to search for a given key
6. Write a recursive 'function to find the factorial of a number
7. Write a recursive function to generate n Fibonacci numbers
8. What is recursion? Write a recursive function to compute nth term of a fibonacci
series. Give the trace along with stack contents for n = 4 (VTU JanlFeb 2004)
9. Write a recursive function to find GCD of two numbers
10. Write a recursive function to fmd the product of two numbers and print numbers
in reversing order. (VTU July/Aug 2004)
11. Write a recursive function to search for an item using binary search
12. Write recursive function to print the numbers in reverse order

1
Chapter 8: Queues
I What are we studying in this chapter? I
• Queue and its sequential representation
• Definition and various types of queues .
• Implementation of ordinary queue using arrays
• Implementation of Circular queue using arrays
• Implementation of Double ended queue using arrays
• Implementation of Priority queue using arrays
• Implementation of ordinary queue using structures
• Implementation of Circular queue using structures
• Implementation of Double ended queue using structures
• Implementation of Priority queue using structures
- 4 hours

8.1Introduction
This chapter deals with an important data structure namely queue. The term queue is
very familiar to us in day to day life, as we see people standing in a queue to board
the bus, or we see people standing in a queue near cinema hall to purchase the tickets
etc., In any situation a person who just arrives will stand at the end of the queue and
the person who is at the front of the queue is the first person to board the bus or to get
the ticket etc., The same concept, of queue is used in the field of computer science
also.
For example, if a number of print jobs are given from various computers to
take printout from a network printer, all the print jobs are diverted to a queue and are
stored in the order of their arrivaL So, a new print job will be at the end of queue and
so, the print job, 'which is at the front of the queue, gets the services of the network
printer. There are so many such instances, where the queue concept is used in the
field of computer science. First, let us see "What is a queue? What are the various
operations that can be performed on queues?

Definition(A queue is defined as a special type of data structure where elements are
inserted from one end and elements are deleted from the other end. The end from
where the elements are inserted is called rear end and the end from where elements
are deleted is called front end. Since the first item inserted is the first item to be
8.2 Q Queues

deleted from queue, queue is also called Eirst !n first Out (FIFO) data structure. In
a queue, elements are always inserted from the rear end and elements are deleted from
the front end. The pictorial representation of the queue is shown in tigure 8.1.

f r
o 1 2 3 4
delete +--1 10 20 I 30 J~ I +-- Insert
Front end Rear end

Fig 8.1 Pictorial representation of queue

Here, the front end is denoted by f and rear end is denoted by r. So, the first item
inserted into the queue is 10, the second item inserted is 20 and the last item inserted
is 30. Any new element to be inserted into this queue has to be inserted towards right
of 30 and that item will be the last element in the queue. The first item to be deleted
from the queue is the item, which is at the front of the queue i.e., 10. So, it is very
clear from the operations performed on queues that First item Inserted is the First
item to be deleted Out from the queue. So, queue is also called First In First Out
(FIFO) data structure.
This data structure is useful in time-sharing systems where many user jobs will
be waiting in the system queue for processing. These jobs may request the services of
CPU, main memory or external devices such as printer etc. All these jobs will be
given a fixed time for processing and are allowed to use one after the other. This is
the case of an ordinary queue where priority is same for all the jobs and whichever
job is submitted first, that job will be processed. Now, let us see "What are the
various operations that can be performed on queues?" The various primitive
operations that can be performed on queues are

Operations on queues -f Insert an item into queue


Delete an item from queue
Display the contents of queue

8.2 Different types of queues

Note: Sometimes, based on the preference, jobs may have to be processed. Such a
queue where a job is processed based on the priority is called a priority queue. Now,
let us see "What are the different types of queues?"
Q Systematic Approach to Data Structures using C - 8.3

The different types of queues are shown below:

Queue (Ordinary queue)


Circular queue
Types of queues
Double ended queue
Priority queue

8.2.1 Queue (Ordinary queue)

Let us see "What is a queue?"

Definition: A queue is defined as a special type of data structure where elements are
inserted from one end and elements are deleted from the other end. The end from
where the elements are inserted is called rear end and the end from where elements
are deleted is called front end. Since the first item inserted is the first item to be
deleted from queue, queue is also called .first !n ,Eirst Out (FIFO) data structure.

Here, first element inserted is the first element to go out of the queue. A queue
can be represented using an array as shown in fig.8.2. The operations that can be
performed on these queues are

Operations on queues -E Insert an item into queue


Delete an item from queue
Display the contents of queue

Letus discuss how these operations can be designed and implemented.

8.2.1.1 Insert at the rear end

Now, let us see "How to implement insert operation using arrays (static allocation
technique)?"

Design: Before inserting any element, we should ask the question "Where and how
the item has to be inserted?" If we know the answer for this question we have the
8.4 Q Queues

insert function ready. So, let us consider the situation where four elements 10, 20, 30
and 40 are already inserted into queue as shown in figure 8.2.a. with f = a and r = 3.

Before insert After insert


(a) (b)

Fi2.8.2 To insert an item 50

Suppose, we have to insert an element say item. Now, let us ask "Where this item has
to be inserted?" We know that it has to be inserted at r = 4. For this to happen, we
have to-increment r by 1 (Fig. 8.2.b). This is achieved using the statement:

r = r + 1; 1* Increment r by 1 *1

Then we ask "How item has to be inserted at rear end?" This is achieved by copying
item to q[r] (Fig 8.2.b) using the following statement:

q[r] = item; 1* Insert into stack *1

But, as we insert an item, we must ask "When we can not insert item into the queue?"
We can not insert any item when r has already reached QUEUE_SIZE - l(Fig. 6.2.b).
In such situation, we have to display appropriate message as shown below:

1* Check for overflow of queue *1


if (r = QUEU-,-SIZE -1)
{
printf("Queue overflow\n");
return;
}
1

Here, QUEUE_SIZE should be #defined (preprocessor directive) and is called


symbolic constant. If the above condition fails, the item has to be inserted. Now, the
complete C function for this can be written as shown below:
,!;!. Systematic Approach to Data Structures using C - 8.5

Example 8.~.1.1.1: C function to insert an integer item (Using global variables)

void insertrean)
{
1* Check for overflow of stack *1
if (r =QUEUE_SIZE - 1)
{
printf("Queue overflow\n");
return;
}

r=r+ 1; 1* Increment top by 1 *1 }


q[r] = item; 1* Insert into queue *1 q[++r] = item;

Note: The array q, the variable r and the variable item are global variables and should
be declared before all the functions. As far as possible let us avoid the usage of global
variables in this book.

Let us re-write the above code by passing parameters. It is clear from the above code
that as the item is inserted, the contents of the queue identified by q and r changes.
So, the variables q and r should be passed as parameters (pass by reference) as shown
below:

Example 8.2.1.1.2: C function to insert an integer item (by passing parameters)

void insertrear (int item, int *r, int q[])


{
1* Check for overflow of stack *1
if (*r = QUEUE_SIZE - 1)
{
printf("Queue overflow\n");
return;
(.
*r = *r + 1; 1* Increment top by 1 *1 } q[++(*r)] = item;
q[*r] = item; 1* Insert into queue *1
8.6 Q Queues

Note: Inserting an element at the rear end of queue IS called enqueue. So, to
implement enqueue is same as the above function.
8.2.1.2 Delete from the front end
Now, let us see "How to implement delete front operation using arrays (static
allocation technique)?" Consider the following situation where 3 items are already
inserted into queue and one item is deleted at a time. The sequence of operations are
shown below:

o 3 4

r
After inserting 3 items After deleting 1st item
(a) (b)

f, r r
nd
After deleting 2 item After deleting 3rd item
(c) (d)

Fig.8.2 Queue showing delete operation

Design: Item has to be deleted from the front end inaqueue. This can be achieved by
accessing the front element q[f] as shown below:
printf("Item deleted = %d\n", q[f]); /* Access and print first item */

and then incrementing f by one as shown below:


f= f+ 1 /* Update position of front item */

The above two statements can also be written using single statement as shown below:
.
1 printf("Jtem deleted = %d\n", q[f++]); /* Access and update queue */

Observe that as each item is deleted, the index variable f is incremented so that it
always contains the position of first item (see figure 8.2). Finally, when the queue is
empty the value of f will be greater than r. Once f is greater than r (see Fig. 8.2.d) , it
is not possible to delete any item. This condition is called underflow of queue. Hence,
Q Systematic Approach to Data Structures using C - 8.7

the above statement has to be executed only if queue is not empty and the code to
delete an item from queue can be written as shown below:

Example 8.2.1.2.1: C function to delete an integer item (using global variables)

void delete_frontO
{
if( f> r)
{
printf("Queue underflow\n");
return;
}
printfC"The element deleted is %d\n",q[(f)++]);

if(f>r)f=O,r=-l; 1* Initialize to queue empty conditions *(

Note: After deleting an item, it may so happen that queue may be empty. So,
immediately after deleting an element, if queue is empty, it is better to initialize f = 0
and r = -1 as shown in the above function. This is the initial status of queue when no
items are inserted and it indicates that queue is initially empty.
Now, let us write the above function without using global variables and by passing
appropriate parameters. Note that f and r contents changes as we delete the items. So,
they should be declared as pointers. The complete C function (by passing parameters)
is shown below:
Example 8.2.1.2.2: C function to delete an integer item (by passing parameters)

void delete_front(int q[], int *f, int *r)


{
if ( *f> *r)
{
printf("Queue underflow\n");
return;
}

printf("The element deleted is %d\n",q[(*f)++]);


if (*f> *r) *f= 0, "r = -1;
I
8.8 ~ Queues

8.2.1.3 Display queue contents

In the display procedure, if the queue already has some items, all those items are
displayed one after the other. If no items are present, the appropriate error message is
displayed. Let us design the display function.

Design: Consider the following situation where 4 items were inserted and first item
has already been deleted.

Usually, the contents of the queue are displayed from the front end and moving
towards right till we get the rear end. So, first item to be displayed is 20, next item to
be displayed is 30 and final item to be displayed is 40. This can be achieved using the
following statements:

Design Output
printf("%d\n"'!IDl ); 20
printf("%d\n", [2); 30
printf("%d\n", 3); 40

In general, we can use printf("%d\n",


!
q (iJ ); I Note: i = 1 to 3
, i = fto r
. I

Note: Please note how the value of i change from f to r (i = 0 to r is wrong). Now, the
code takes the following form:

for (i = f; i <= r; i++)


{
printf("%d\n", q[i]);
}

But, the above statement should not be executed when queue is empty i.e., when f is
greater than r. So, the above code can be modified to include this error condition and
can be written as shown below:
Q Systematic Approach to Data Structures using C - 8.9

Example 8.2.1.3.1: C function to display the contents of queue (using global


variables)
void displayt)
{
int i;

1* If queue is empty */
if(f>r)
{
printf("Queue is empty\n");
return;
}

/* Display contents of queue */


printf("Contents of the queue\n");
for (i = f; i <= r; i++)
{
printf("%d\n", q[i]);
}

By passing parameters, the function above function can be written as shown below:

Example 8.2.1.3.2: Function to display the contents of queue (using parameters)

void display(int q[], int f, int r)


{
int i;

if ( f> r)
{
printf("Queue is empty\n");
return;
}

printf("Contents of queue is\n");


for ( i = f; i <= r; i++)
printf(" %d\n",q[i]);
8.10 Q Queues

The complete C program to implement different operations on an ordinary queue is


shown below:

Example 8.2.1.3.3: C program to implement queue operations (static/array


implementation) using global variables

#include.<stdi~.h>
#include <process.h>

#define QUEUE_SIZE 5

int choice,item,f,r,q[1 0]; /* Global variables */

/* Include: Example 8.2.1.1.1: Function to insert an item (Using global variables) */


/* Include: Example 8.2.1.2.1: Function to delete an item (using global variables) */
/* Include: Example 8.2.1.3.1: To display contents of queue (global variables) */
void maim)
{
/* Initially queue is empty */
f= 0; /* Front end of queue */
r = -1; /* Rear end of queue* /

for (;;)
{
printf("1 :Insert 2:Delete\n");
printf("3:Display 4:Exit\n");
printf("Enter the choice\n");
scanf("%d':" &choice);

switch ( choice)
{
case 1:
printf("Enter the item to be inserted\n");
scanf("%d", &item);
insert_rear(item, q, &r);
. break;

case 2:
delete_front(q, &f, &r);
Q Systematic Approach to Data Structures using C - 8.11

break;

case 3:
display( q, f, r);
break;

default:
exit(O);
}
}

Example 8.2.1.3.4: C program to implement queue operations


by passing parameters

#include<stdio.h>
#include<process.h>

#defineQUEUE_SIZE 5

1* Include: Example 8.2.1.1.2: Function to insert an integer (passing parameters) */


1* Include: Example 8.2.1.2.2: Function to delete an item (by passing parameters) */
1* Include: Example 8.2.1.3.2: Function to display the contents of queue */
void maim)
{
int choice,item,f,r,q[ 10];

/* Initially queue is empty */


f=O; /* Front end of queue */
r = -1; /* Rear end of queue* /

for (;;)
{
printf("1 :Insert 2:Deiete\n");
printf("3:Display 4:Exit\n");
printf("Enter the choice\n");
scanf("%d", &choice);
8.12 Q Queues

switch ( choice)
{
case 1:
printf("Enter the item to be inserted\n");
scanf("%d", &item);
insert_rear(item, &r, q);
break;
case 2:
delete_front(q, &f, &r);
break;
case 3:
display( q, f, r);
break;
default:
exit(O);
}
}
}

8.2.2 Double ended queue (Dequeue)


In this section, let us concentrate on another queue called double ended queue. In
short, it is also called dequeue. Now, let us see "What is a double ended queue (or
dequeue)? and "What are the various operations that can be performed on dequeues?"
Definition: A Dequeue is a special type of data structure in which insertions are done
from both ends and deletions are done at both ends. The operations that can be
performed on deques are
Insert an item from front end
Insert an item from rear 'end
Operations performed on dqueues --+--+ Delete an item from front end
Delete an item from rear end

1
Display the contents of queue
Note: The three operations insert rear, delete_front and display operations have
already been discussed in section 8.2.1. In this section, other two operations i.e., insert
an item at the front end and delete an item from the rear end are discussed.
.Q Systematic Approach to Data Structures using C - 8.13

8.2.2.1 Insert at the front end

Now, let us see "How to implement insert front function using arrays (static allocation
technique)?"

Design: Before inserting any element, we should ask the question "Where and how
the item has to be inserted?" If we know the answer for this question we have the
insert front function ready. So, let us consider various situations shown in figure
below:

Case 1: Queue empty: Note that queue is empty. Here, an item can be inserted at the
front end first by incrementing r by 1 and then insert an item.

-1 o 1 2 3 4 -1

r f

Before insert After insert


(a) (b)

The equivalent code for this can be written as shown below:

/* Insert at front end if queue is empty: Case 1 */


if(f=O&&r=-l)
{
q[++r] = item;
return;
}

Case 2: Some items are deleted: Consider the following situation where 10, 20 and
30 were inserted earlier and 10 and 20 have been deleted from the front end. Now,
there is only one item in queue. Here, an item can be inserted by decrementing the
front index f by 1 and then inserting an item at that position as shown below:

f, r
After deleting 2 items After inserting 20
(a) (b)
8.14 Q Queues

The equivalent code for this can be written as shown below:


/* Insert at the front end if possible: Case 2 */
if ( f!= 0 )
{
q[ --f] = item;
return;
}

Case 3: Some items are inserted (not deleted): Consider the following situation
where 10, 20 and 30 were inserted into queue.

o 1 2 3 4
I 10 I 20 I 30 I I I
f r
Q after inserting 10, 20, 30

Now, Observe that, it is not possible to insert an any item at the front end and we
should display the appropriate message:
printf("Front insertion not possible\n");
I
The complete C function to insert an item at the front end is shown below:

Example 8.2.2.1.1: Function to insert an item at the front end (using global variables)

void insertfrontt)
{
if (f= 0 && r = -1) '/* Case 1: Insert when Q empty */
{
q[++(r)] =item;
return;
}

if (f!= 0) /* Case 2: Insert when items are present */


{
q[ --(f)] = item;
1 return;
}
printf("Front insertion not possible\n");
} /* Case 3: Insertion not possible at front end */
Q Systematic Approach to Data Structures using C - 8.15

By passing parameters, the above function can be written as shown below:

Example 8.2.2.1.2: Function to insert an item at the front end (by passing parameters)
void insert_front(int item, int q[], int *f, int *r)
{
if (*f= 0 && *r = -1) 1* Case 1: Insert when Q empty *1
{
q[++(*r)] = item;
return;
}
if ( *f!= 0) 1* Case 2: Insert when items are present *1
{
q[--(*f)] = item;
return;
}
printf("Front insertion not possible'n'');
1* Case 3: Insertion not possible at front end *1

8.2.2.2 Delete from the rear end

Now, let us see "How to implement delete rear operation using arrays (static
allocation technique)?" Consider the following situation where 3 items are already
inserted into queue and one item is deleted.

o 1 2 3 4 o 1 2 3 4
I 10 I 20 I 30 I I I I 10 I ·20 I I I I
f r f r

After inserting 3 items After deleting from rear


(a) (b)

Design: Item has to be deleted from rear end. This can be achieved by accessing the
rear element q[r] as shown below:
printf("ltem deleted = %d\n", q[r]); 1* Access and print rear item *1
and then decrementing r by one as shown below:
8.16 Q Queues

r=r-1; 1* Update position of rear item *i


The above two statements can also be written using single statement as shown below:
printf("Item deleted = %d\n", q[r--]); 1* Access and update queue *1
. Observe that as each item is deleted, the index variable r is decrementd so that it
always contains the position of last item (see figure). Finally, when the queue is
empty the value of f will be greater than r. Once f is greater than r, it is not possible
to delete any item because queue is empty. This condition is called underflow of
queue. Hence, the above statement has to be executed only if queue is not empty and
the code to delete an item from rear end of queue can be written as shown below:
"
Example 8.2.2.2.1: Function to delete an item from the rear end of queue (Using
global variables)
void delete JearO
{
if(f >r)
{
printf("Queue underflow\n");
return;
}
printf("The element deleted is %d\n",q[(r)--]);
if (f> r) 1* Reset to initial state of empty queue *1
{
f=O,r=-l;
}
}

The above function can be written by passing the parameters as shown below:

Example 8.2.2.2.2: Function to delete an item from the rear end of queue (By passing
parameters)
void drlete Jear(int q[],int *f, int *r)
{
if (*f > *r)
{
printf("Queue underflow\n");
return;
}
Q Systematic Approach to Data Structures using C - 8.17
printf("The element deleted is %d\n",q[(*r)-- J);

if (*f> *r) 1* Reset to initial state of empty queue */


{
*f= 0, *r = -1;
}

The complete C .code to implement double-ended queue using global variables is


shown below

Example 8.2.2.2.3: C program to implement double-ended queue usmg global


variables

#include <stdio.h>
#include <process.h>

#define QUE~ _ SIZE 5


int choice,item,f,r,q[lO]; /* Global variables */
"
1* Include: Example 8.2.1.1.1: Function to insert an itemat the rear end */
1* Include: Example 8.2.1.2.1: Function to delete an item at the front end */
1* Include: Example 8.2.2.1.1: Function to insert an item at the front end */
* Include: Example 8.2.2.2.1: Function to delete an item at the rear end */
1* Include: Example 8.2.1.3.1: To display contents of queue */
void maim)
{
/* Initially queue is empty */
f= 0; /* Front end of queue */
r = -1; 1* Rear end of queue*/
for (;;)
{
printf("l :Insert_front 2:Insert_rear\n");
printf("3:Delete _front 4:Delete Jear\n");
print.f("5:Display 6:Exit\n");
printf("Enter the choice\n");
scanf("%d" ,&choice);
8.18 Q Queues

switch ( choice)
{
case 1:
printf("Enter the item to be inserted\n");
scanf("%d ,&item);II

insert _fronn);
break;

case 2:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
insert JearO;
break;

case 3:
delete _ fronu);
break;

case 4:
deleterean);
break;

case 5:
displayt);
break;

default:
exit(O);
}
}
}

I Example 8.2.2.2.4:
parameters.
C program to implement double-ended queue by passing

#include <stdio.h>
#include <process.h>

#define QUEUE_SIZE 5
Q Systematic Approach to Data Structures using C - 8.19

/* Include: Example 8.2.1.1.2: Function to insert an item at the rear end */


/* Include: Example 8.2.1.2.2: Function to delete an item at the front end */
1* Include: Example 8.2.2.1.2: Function to insert an item at the front end */
1* Include: Example 8.2.2.2.2: Function to delete an item at the rear end */
'* Include: Example 8.2.1.3.2: To display contents of queue *1
void maint)
{
int choice,item,f,r,q[ 10];

f=O;
r = -1;

for (;;)
{
printf(" 1:Insert _front 2:Insert Jear\n");
printf("3 :Delete _front 4:Delete Jear\n");
printf("5:Display 6:Exit\n");
printf("Enter the choice\n");
.s~anf("%d" ,&choice);

switch ( choice)
{
case 1:
printf("Enter the item to be inserted\n");
scanf("%djl,&item);
insert_front(item, q, &f, &r);
break;

case 2:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
insertrearutem, &r, q);
break;

case 3:
deletefronuq, &f, &r);
break;
8.20 Q Queues

case 4:
delete_rear(q, &f, &r);
break;

, case 5:
• display( q, f, r);
break;

default:
exit(O);
}
". }
}

8.2.2.3 Disadvantage of queue

We know that queue is a data structure where elements are inserted from one end and
elements are deleted at the other end. Now, let us see "What is the disadvantage of
representing a queue using array?" Consider the queue shown below:

o 1 2

f r
This situation will arise when 5 elements say 10, 20, 30, 40 and 50 are inserted and
then deleting first two items 10 and 20. Now, if we try to insert an item we get the
message
"Queue overflow"

This is because, in our function insertrear (see example 8.2.1.1.1) before inserting r
is compared with QUEUE_SIZE - 1. Since r is same as QUEUE_SIZE -1, insertion
not possible. Note that "Rear insertion is denied in a queue even if room is available
at the front end". Thus, even if free memory is available, we can not access these
memory locations. This is a disadvantage. This disadvantage can be overcome by
moving the item at the front end of the queue to the very first location of queue and
then shifting the remaining element from second location onwards. But; shifting the
data is costly in terms of computer time if the data being stored is very large. S , this
method is not recommended. Let us see, how these disadvantages and difficulties can
be overcome using "Circular queue represented as an array".
Q Systematic Approach to Data Structures using C - 8.21

8.2.3 Circular queue

Now, we shall see "What is a circular queue?"

Definition: In circular queue, the elements of a given queue can be stored efficiently
in an array so as to "wrap around" so that end of the queue is followed by the front of
queue. The pictorial representation of a circular queue and its equivalent
representation using an array are given side by side in figure shown in next page. This
circular representation allows the entire array to store the elements without shifting
any data within the queue. This is an efficient way of implementing a circular queue
usmg arrays. .
Assume that circular queue contains only one item as shown in fig. 8.6.a. Note
that the value of f = r = O. We know that item is inserted only at the rear end. So,
before inserting the value of r should be -1.

Note: So, initially when stack is empty, f = 0 and r = -1

The configuration shown in fig.8.6.b is obtained after inserting 20 and 30. To insert
an item, the rear index r has to be incremented first. For this, any of the two
statements shown below can be used.

r=r+1 or r = (r + 1) % QUEUE_SIZE

Both statements will increment r by 1. But, we prefer the second statement. Let us
see, why we consider the second approach. The queue shown in fig.8.6.c is obtained
after inserting 40 and 50. Note that at this point, the queue is full. Suppose we delete
two items 10 and 20 one after the other. The resulting queue is shown in fig.8.6.d.
Now, try to insert an item 60. If the statement

r=r+1

is used to increment rear pointer, the value of r will be 5. Since it is it circular queue r
shouldbe O.This can be achieved using the statement

r = (r + 1) % QUEUE_SIZE

After execution of the above statement, r will be O. If this approach is used, to check
foroverflow or underflow, we use a variable count that contains the number of items
in the queue at any instant. So, as an item is inserted, increment count by 1 and as an
item is deleted, decrement count by 1. By this it is ensured that at any point of time,
count always contains the total number of elements in the queue. So, if queue is
empty, count will be 0 and if queue is full, count will be QUEUE_SIZE.
8.22 Q Queues

,2

4
@ 1
o
1 ~
o

f, r
1 2 3 4

(a)
f,r

2r

@
o 1 2 3 4

4' 20 1 ~
f r
10
o (b) After inserting 20 & 30
f

2
4 0
o 1 2 3 4

r 4 5 2 1 ~
f r
~ 10
o (c) After inserting 40 & 50
f

@ 4 0 f o 1 2 3 4

4 5 1 ~
r f r

o After Deleting 10 & 20


(d)

@ 4 0 f o 1 2 3 4

4 5 1 ~
1
6 r f

o
r (e) After inserting 60

Fig.8.6 Pictorial representation of a circular queue


Q Systematic Approach to Data Structures using C - 8.23

Note: As usual, the various operations that can be performed on circular queues are:
+ Insert rear
• Delete front
• Display

Let us see, "How to implement circular queue- operations?"

8.2.3.1 To insert from the rear end

Now, let us see ''What are the various steps to be followed while inserting?" The
following steps are followed:

Step 1: Check for overflow: Now, let us see "How to check for overflow?" This is
achieved using the following statements:

if (count = QUEUE_SIZE)
{
printf("Queue is ful1\n");
return;
}

Step 2: Insert item: This is achieved by incrementing r by 1 and then inserting as


shownbelow: -
r = (r + 1) % QUEUE_SIZE;
q[r] = item;

Step 3: Update count: As we insert an element update count by 1. This is achieved


using the following statement:
count++;

So,the complete function to insert an item at the end of circular queue is shown
below:

Example 8.2.3.1.1: Function to insert an item at the rear end

voidinsertrearfint item, int q[], int *r, int *count)


{
if ( *count = QUEUE_SIZE) /* Check for overflow */
{
printf("Overflow of queue\n");
return;
}
8.24 Q Queues

*r = (*r + 1) % QUEUE_SIZE; 1* increment rear pointer *1

q[*r] = item; 1* Insert the item *1

*count += 1; 1* update the counter *1


}

8~2.3.2To delete from the front end

Now, let us see "What are the various steps to be followed while deleting an
element?" The following steps are followed:
Step 1: Check for undeflow: Now, let us see "How to check for underflow?" This is
achieved using the following statements:
if (count = 0)
{
printf("Queue is empty\n");
return;
}
Step 2: Delete item: This is achieved by accessing the element using index f and then
incrementing f by 1 (As we did in other queues). The equivalent statements can be
written as shown below: incremeriting r by 1 and then inserting as shown below: '

printf("The deleted element is %d\n",-q[f]);


f= (f+ 1) % QUEUE_SIZE;

Step 3: Update count; As we insert an element update count by '1: This is achieved
using the following statement:
count++;

So, the complete function to delete an item from the front end of circular queue is
shown below:

Example 8.2.3.2.1: Function to delete an item from the front end of circular queue
; .
void delete _front(int q[], int *f, int *count)
{ ~
if( *count = 0)
{
printf("Underflow of queue\n");
return;
}
Q Systematic Approach to Data Structures using C - 8.25

printf("The deleted element is %d\n",q[*f]); 1* Access the item *1


*f = (*f + 1) % QUEUE_SIZE; 1* Point to next first item *1
*count -= 1; 1* update counter *1

8.2.3.3 To display queue contents


Now, let us see "What are the various steps to be followed while displaying the
elementsof circular queue?" The following steps are followed:
Step 1: Check for undeflow: Now, let us see "How to check for underflow?" This is
achievedusing the following statements:
if (count = 0)
{
printf("Queue is empty\n");
return;
}
Step 2: Display: Display starts from the front index f. After displaying q[f] we have
to update f by 1 (as we did for r). The procedure is repeated for count number 'of
times. This is because, count contains the number of elements in queue. The
equivalentcode for this can be written as:
for (i = 1; i < = count; i++)
{
printf("%d\n", q[f]);
f= (f+l) % QUEUE_SIZE;
}
So,the complete function to delete an item from the front end of circular queue is
shownbelow:

Example 8.2.3.3.1: Function to display the contents of circular queue


void display(int q[], int f, int count)
(
int i;
if ( count = 0 ) 1* Check for queue empty *1
{
printf("Q is empty\n"); ,
return;
}
8.26 Q Queues

printf("Contents of queue is\n"); /* Print count number of times */

for ( i = 1; i <= count; i++)


{
printf("%d\n",q[f]); /* access the item */
f= (f + 1) % QUEUE_SIZE; /* Point to next item */
}
}

The complete C program to implement circular queue using arrays is shown below:

Example 8.2.3.3.2: C program to implement circular queue

#include <stdio.h>
#include <process.h>

#define QUEUE_SIZE 5

/* Include: Example 8.2.3.1.1: Function to insert an item at the rear end */

/* Include: Example 8.2.3.2.1: Function to delete an item from the front end */

/* Include: Example 8.2.3.3.1: Function to display the contents of circular queue */

void maint)
{
int choice,item,f,r,count,q[20];

f=O;
r = -1;
count = 0; /* queue is empty */
for (;;)
l {

printf(" 1:Insert . 2:Delete\n");


printf("3 :Display 4:Exit\n");
printf("Enter the choice\n");
scanf("%d" ,&choice);
Q Systematic Approach to Data Structures using C - 8.27

switch ( choice)
{
case 1:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
insertrearfitem.q.ecr.eccount);
break;

case 2:
delete_front(q, &f, &count);
break;

case 3:
display( q, f, count);
break;

default:
exit(O);
}
}

8.2.4 Priority queue


In this section, let us see another variation of queue called priority queue. Let us see
"Whatis priority queue? What are the various types of priority queues?"
Definition.r;.he priority queue is a special type of data structure in which items can
beinserted or deleted based on the priority. Always an element with highest priority
isprocessed before processing any of the lower priority elements. If the elements in
thequeue are of same priority, then the element, which is inserted first into the queue,
isprocessed. Priority queues are used in job scheduling algorithms in the design of
operatingsystem where the jobs with highest priorities have to be processed first.

Thepriority queues are classified into two groups:


• Ascending priority queue: In an ascending priority queue elements can be inserted
in any order. But, while deleting an element from the queue, only the smallest
element is removed first.

• Descending priority queue: In descending priority also elements can be inserted in


any order. But, while deleting an element from the queue, only the largest element
is deleted first.
8.28 Q Queues

Now, let us see "How to implementation of priority queues?" There are vanous
methods of implementing priority queues using arrays.

Design 1: One of the methods is to implement an ascending priority queue where


elements can be inserted in any fashion and only the smallest element is removed.
Here, an element is inserted from the rear end of the queue but an element with least
value should be deleted. After deleting the smallest number, store a very large value
in that location, indicating the absence of an item. The variable count can be used to
keep track of number of elements in the array. The three functions useful for this
purpose are:
• insert JearO - which inserts the item at the end of the queue.
• remove _ smallt) - which returns the smallest item from the queue and at the
- same time store maximum number in that location indicating an item has been
deleted.
• displayr) - which displays the contents of queue.

It is left as an exercise to the reader to implement this. Now, let us implement priority
queues using another technique.

Design 2: The second technique is to insert the items based on the priority. In this
technique, we assume the item to be inserted itself denotes the priority. So, the items
with least value can be considered as the items with highest priority and items with
highest value can be considered as the items with least priority. So, to implement
priority queue, we insert the elements into queue in such a way that they are always
ordered in increasing order. With this technique the highest priority elements are at
the front end of the queue and lowest priority elements are at the rear end of queue.
Hence, while deleting an item, always delete from the front end so that highest
priority element is deleted first. The function to insert an item at the appropriate place
is shown below:

Note: To insert an element into appropriate place so that elements are arranged in
ascending order, we use the insertion sort technique.

Example 8.2.4.1: Function to insert an item at the correct place in priority queue
l

void insert_item(int item, iat q[], int *r)


{
int J;
Q Systematic Approach to Data Structures using C - 8.29

if ( *r = QUEUE _ SIZE-l ) 1* Check for overflow *1


{
printf("Q is full\n");
return;
}

j = *r; I*Compare from this initial rear point *1

1* Find the appropriate position to make room for inserting


* an item based on the priority *1
1* Item to be inserted is less than q[j] *1
while (j >= 0 && item < q[j])
{
q[j-H] = q[j]; 1* Move the item at q[j] to its next position *1
j--;
}

q[j+ 1] = item; 1* Insert an item at the appropriate position *1

*r = *r + 1; 1* Update the rear pointer *1

Note: To implement priority queue, insert an item such that items are arranged in
ascending order. But, always delete an item from the front end. The functions
delete_front{) and display{) remains unaltered. The complete program to implement
priority queue is shown below:

Example 8.2.4.2: C Program to implement priority queues

#include <stdio.h>
#include <process.h>

#define QUEUE_SIZE 5
/

/* Include: Example 8.2.1.2.2: C function to delete an integer item *1

/* Include: Example 8.2.1.3.2: Function to display the contents of queue *1

/* Include: Example. 8.2.4.1: Function to insert item at the correct place in queue *1
8.30 Q Queues

void maint)
{
int choice,item,f,r,q[10];

f= 0;
r = -1;

for (;;)
{
printf(" 1:Insert 2:Delete\n");
printf("3 :Display 4:Exit\n");
printf("Enter the choice\n");
scanf("%d" ,&choice);

switch (choice)
{
case 1:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
insert_item(item, q, &r);
break;

case 2:
delete_front(q, &f, &r);
break;

case 3:
display( q,f,r);
break;

default:
exit(O);
}
}
}

Note: We can input in any order. But, the items are inserted at the appropriate
position and are arranged in ascending order. The item at Oth position is having
highest priority; the item at 15t position is having next highest priority and so on.
Finally, the item at the end of the queue is having the least priority. So, if we remove
from front, an item with highest priority is removed.
,!;l Systematic Approach to Data Structures using C - 8.31

Note: The priority queue need not have the numbers or characters. They can represent
complex structures and elements can be ordered based on some common property. In
this sense, a stack can be considered as a priority queue. If we take the time as an
ordering on the elements, an element that is inserted first has to spend more time in
the stack where as the element which is inserted recently will spend less time in the
stack. This is because stack is a last in first out data structure. So, while deleting, the
element that has spent less time is removed first.
Even an ordinary queue can also be considered as a priority queue where the
priority is based on the order in which they are inserted. Here, the first element
inserted into queue is the first element to go out of the queue. So, an item that is
inserted first can be considered as the item with highest priority and so it is removed
first from the queue.

8.3 Dequeues using structures

Double ended queue has already been discussed. Here, let us see "How to implement
deques using structures?" Here, we need two index variables front and rear and one
more variable q to store the elements of the queue. Instead of passing front, rear, a
and item to the function insertreart) as discussed earlier, we can pass only two
parameters item and a. Here, the variable a is of type structure with three fields front,
rear and q where
• froat is an integer field which contains the index of the first item in the queue.
• rear is an integer field which contains the index of the last item in the queue.
• q is an array and is used to store the elements of the queue.

The declaration can take the following form:

#defIne QUEUE_SIZE 5

typedef struct
{
int q[QUEUE_SIZE];
int front;
int rear;
} QUEUE;

Note:The reader is advised to refer chapter 4 for further information on structures. If


there is a declaration of the form
QUEUE a;
8.32 Q Queues

the value of each member can be obtained using'.' operator as shown below:
a.front
a.rear
a.q

The item at the front end can be accessed using


a.q[ a.front]

and the item at the rear end can be accessed using


a.q[a.rear]

If there is a declaration of the form


QUEUE *a;

the value of each attribute can be obtained using' ->' operator as shown below:
a->front
a->rear
a->q

The item at the front end can be accessed using


a->q[ a->front]

and the item at the rear end can be accessed using


a->q[ a->rear]

Note: We know that initial values of front and rear are 0 and -1 respectively. Queue
is empty whenever front is greater than rear.

Example 8.3.1: C function to insert an item at the front end of queue

void insert_front(int item, QUEUE *a)


{
if (a->front = 0 && a->rear = -1 )
a->q[ ++(a->rear)] = item; /* Case 1: of section 8.2.2.1 */
else if ( a->front != 0 )
a->q[ --(a->front)] = item; /* Case 2: of section 8.2.2.1 */
else
printff'Tront insertion not possible\n"); /* Case 3: of section 8.2.2.1 */
}
,!;l Systematic Approach to Data Structures using C - 8.33

Note: The design aspects of dequeue are provided in the section 8.2.2.

The function to insert an item at the rear end of the queue is shown below:

Example 8.3.2: C function to insert an item at the rear end of queue

void insertrearfint item, QUEUE *a)


{
if ( a->rear = QUEUE _ SIZE-l ) 1* Is right insertion possible *1
{
printf("Rear insertion not possible\n");
return;
}

a->q[++(a->rear)] = item; 1* Increment rear and insert item *1

The function to delete an item from the front end of the queue is shown below:

Example 8.3.3: C function to delete an item from front end of queue

void delete_front(QUEUE *a)


{
if ( a->front > a->rear ) 1* Check for underflow *1
{
printf("Queue is empty\n");
return;
}

!* Access first item and delete *1


printf("The element delted is %d\n",a->q[a->front++]);

if (a->front> a-> rear) 1* Queue empty *1


{
a->front = 0; 1* Reset to initial values *1
a->rear = -1;
}
8.34 Q Queues

The function to delete an item from the rear end of the queue is shown below:

Example 8.3.4: C function to delete an item from rear end of queue

void delete Jear(QUEUE *a)


{
if ( a->front > a->rear ) 1* Check for underflow *1
{
printf("Queue is empty\n");
return;
}

" 1* Access the last it m and delete *1


printf("The deleted element is %d\n",a->q[a->rear--]);

if (a-c-Iront > a-> rear) 1* Queue empty *1


{
a->front = 0; 1* Reset to initial values *1
a->rear =. -1;
}
}

The function to display the contents of the queue is shown below:

Example 8.3.5: C function 10 display the contents of queue

void display(QUEUE *a.)


{
int i;

if ( a->fiont > a.->rear) 1* Check for queue empty *1


{
prtntf(t'Queee is emptyvn'');
return;

prinff(lfThe coni nts of queue\:n"); 1* Display Q contents *1


for ( i = a->fiont; i <= a->rear; i++)
printf("%d\n":a->q[i]);
}
Q Systematic Approach to Data Structures using C - 8.35

The main function to implement double-ended queue is shown below:

Example 8.3.6: C program to implement dequeue using structures

#include <stdio.h>
#include <process.h>
#define QUEUE_SIZE 5

typedef struct
{
int q[QUEUE_SIZE];
int front;
int rear;
}QUEUE;

/* Include: Example 8.3.1: C function to insert an item at the front end of queue */
/* Include: Example 8.3.2: C function to insert an item at the rear end of queue */
/* Include: Example 8.3.3: C function to delete an item from front end of queue */
/* Include: Example 8.3.4: C function to delete an item from rear end of queue */
/* Include: Example 8.3.5: C function to display the contents of queue*/

void maim)
{
QUEUE a;
int item.choice;

a.front = 0;
a.rear = -1;

for (;;)
{
printf(" 1:Insert front 2:Insert rear\n");
printf("3:Delete front 4:Delete rear\n");
printf("S:Display 6:Exit\n");
printf("Entcr the choice\n");
scanf("%d" ,&choice);
8.36 Q Queues

switch ( choice)
{
case 1:
printf("Enter the item to be, inserted\n");
scanf("%d", &item);
insert_front(item, &a);
break;

case 2:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
insert_rear(item, &a);
break;

case 3:
delete _front( &a);
break;

case 4:
delete_rear(&a);
break;

case 5:
display( &a);
break;

default:
exit(O);
}
}
}

8.4 Circular queue using structures


l

The design detail of circular queue is already discussed in section 8.2.3. The various
attributes associated with circular queue are: front end identified by f, the rear end
identified by r, the number of elements in queue identified by count and the storage
for the items inserted which is identified by q. The structure declaration for this can
be of the form:
Q Systematic Approach to Data Structures using C - 8.32

typedef struct
{
int f,
int r:,
int q[QUEUE _ SIZE];
int count; ,
} QUEUE;

Note: If there is a declaration of the form

QUEUE a;

the value associated with each attribute of the structure can be obtained using' .'
operator and if there is a declaration of the form

QUEUE *a;

the value associated with each attribute of the structure can be obtained using' :->'
operator as discussed in the previous section.

The C function to insert an item into circular queue is shown below:

Example 8.4.1: Function to insert an item at the rear end

void insert_rear(int item, QUEUE *a)


{
if ( a->count = QUEUE_SIZE) /* Check for overflow */
{
printf("Overflow of queue\n");
return;
}

a->r = (a->r + 1) % QUEUE_SIZE; /* increment rear pointer */


a->q[a->r] = item; . /* Insert the item */
(a->count )++; /* update the counter */

Thefunction to delete an item from circular queue is shown below:


8.38 ~ Queues

Example 8.4.2: Function to delete an item from th front end of circular queue

void delete_front(QUEUE *a)


{
if ( a->count = 0 ) /* Check for underflow */
{
printf("Underflow of queue\n");
return;
}

/* Access the item */


._printf("The deleted element is %d\n",a->q[a->f]);

a->f= (a->f + 1) % QUEUE_SIZE; /* Point to next first item */


(a->count)--; /* update counter */
}

The function to display contents of circular queue is shown below:

Example 8.4.3: Function to display the contents of circular queue

void display(QUEUE *a)


{
int i;

if ( a->count =0 ) /* Check for queue empty */


{
printf("Q is empty\n");
I return;

printf("Contents of queue is\n");


for ( i = 1; i <= a-c-count; i++) /* Print count number of times */
{
printf("%d\n",a->q[f]); /* access the item */
f= (f+ 1) % QUEUE_SIZE; /* Point to next item */
}
}

The complete program to implement circular queue using structures is shown below:
Q Systematic Approach to Data Structures using C - 8.39

Example 8.4.4: C Program to implement circular queues using structures

#include <stdio.h>
#include <process.h>

#define QUEUE_SIZE 5

typedef st ruet
{
jut f,
int r:,
int q[QUEUE_SIZE];
int count;
} QUEUE;

/* Include: Example 8.4.1: Function to insert an item at the rear end *1

/* Include: Example 8.4.2: Function to delete an item from circular queue *1

/* Include:ExampJe 8.4.3: Function to display the contents of circular queue */

void maint)
{
int choice, item;
QUEUE a;

a.f= 0;
a.r=-l;
a.count = 0; I" quen ·1 em *1

for (;;)
{
printf(" 1:lnse t c: lcl 1 J ");
printtC'3:D'splay ~.:"xit\n' .
priDtf("Entu the c. ice\ ").
scan .(" fod", "ell rc e);
8.40 Q Queues

switch ( choice)
{
case 1:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
insert ..:..rear(item,&a);
break;

case 2:
delete _front( &a);
break;

case 3:
display( &a);
break;

default:
exit(O);
}
}
}

8.5 Priority queue using structures

Each item is inserted at the appropriate position based on the priority and the item is
always deleted from the front end. The design details are provided in section 8.2.4. In
this section, the priority queue is implemented using structures. The structure
declaration for this can be of the form:

typedef struct
{
int f',
int r:,
int
} QUEUE;
1

Note: If there is a declaration of the form

QUEUE a;
Q Systematic Approach to Data Structures using C - 8.41

the value associated with each attribute of the structure can be obtained using' .'
operator and if there is a declaration of the form

QUE~ *a;

the value associated with each attribute of the structure can be obtained using' ->'
operator as discussed in the previous section.

The function to insert an item into priority queue is shown below:

Example 8.5.1: Function to insert item into priority queue

void insert_item(iot item, QUEUE *a)


{
int J;

if ( a->f> a->r) 1* Check for overflow *1


{
printf(nQ is full'n");
return ;
}

j = a->r; I*Compare from this initial point *1

1* Find the appropriate position to make room for mserting


* an item based on the priority *1
* Item to be inserted is less than a[j] *1
while (j >= 0 && item < a->q[j])
{
a->q[j+ 1] = a->q[j]; 1* Move the item at a[j] to its nex position *i

J--;
}

a->q[j+ 1] = item; 1* Insert an item at the appropriate position *1

a->r++; 1* Update the rear pointer *1


8.42 Q Queues

The function to delete an item from priority queue using structures is shown below:

Example 8.5.2: Function to delete an item from priority queue

void delete _front(QUEUE *a)


{ -
if ( a->f> a->r ) 1* Check for underflow *1
{
printf("Queue underflow\n");
return;
}

.. 1* Access the item and remove from front end *1


printf("The element deleted is %d\n",a->q[a->f++]);

if (a->f> a->r) 1* Queue empty *1


{
a->f= 0, a->r = -1; 1* Reset to initial values *1
}
}

The function to display the contents of priority queue using structures is shown
I below:

Example 8.5.3: Function to display contents of priority queue

void display(QUEUE *a)


{
int i;

if ( a->f> a->r ) 1* Check for underflow *1


{
printf("Queue is empty\n");
return;
l }

printf("Contents of queue is\n"); 1* Display the contents queue *1 .


for ( i = a->f; i <= a->r; i++)
printf(" %d\n",a->q[i]);
}
Q Systematic Approach to Data Structures using C - 8.43

The complete program to implement priority queue using structures is shown below:

Example 8.5.4: C Program to implement priority queues using structures

#include <stdio.h>
#include <process.h>

#define QUEUE_SIZE 5

typedef struct
{
int f·,
int r:,
int
}QUEUE;

void maint)
{
int choice,item;
QUEUE a;

a.f=O;
a.r = -1;

for (;;)
{
printf(" 1:Insert 2:Delete\n");
printf("3 :Display 4:Exit\n");
prtntf(t'Enter the choice\n");
scanf("%d", &choice);

switch (choice)
{
case 1:
printf("Enter the item to be inserted\n");
scanf("%d", &item);
insert _item(item, &a);
break;
8.44 Q Queues

case 2:
delete _front( &a);
break;
case 3:
display( &a);
break;
default:
exit(O);
}
}
}

Note: In this program the input can be in any order. But, the items are inserted at the
appropriate position and are arranged in ascending order. The item at Oth position is
having highest priority; the item at 1st position is having next highest priority and so
on. Finally, the item at the end of the queue is having the least priority.

8.6 Input restricted queue

Now, let us see "What is input restricted dequeue?"

Definition: An input restricted dequeue is a variation of double ended queue which


.support only the following operations:
• Delete front
• Delete rear
• Insert front
• Display

Note: Input is restricted only to front end. Here, rear insertion is not permitted. Hence
the name input restricted queue. If rear insertion is permitted then front insertion
should not be permitted. The C program to implement input restricted queue is shown
below:

Example 8.6.1: C program to implement input restricted queue


1 .

#include <stdio.h>
#include <process.h>

#define QUEUE_SIZE 5
.Q Systematic Approach to Data Structures using C - 8.45

/* Include: Example 8.2.1.2.2: Function to delete an item at the front end */


/* Include: Example 8.2.2.1.2: Function to insert an item at the front end */
." Include: Example 8.2.2.2.2: Function to delete an item at the rear end */
/* Include: Example 8.2.1.3.2: To display contents of queue */
void maint)
{
int choice,item,f,r,q[l 0];
f=O;
r = -1;
for (;;)
{
printf(" 1:Insert_front \nil);
printf("2:Delete_front 3:DeleteJear\n");
printf("4:Display 5:Exit\n");
printf("Enter the choice\n");
scanf("%d" ,&choice);
switch ( choice)
{
case 1:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
insert_ front(item, q, &f, &r);
break;
case 2:
. delete_front(q, &f, &r);
break;
case 3:
delete_rear(q, &f, &r);
break;
case 4:
display(q, f, r);
break;
default:
exit(O);
}
}
8.46 Q Queues

8.7 Output restricted queue


Now, let us see "What is output restricted dequeue?"

Definition: An output restricted dequeue is a variation of double ended queue which


support only the following operations:
• Delete front
. • Insert front
• Insert rear
• Display

Note: Output is restricted only to front end. Here, rear deletion is not permitted.
Hence the name output restricted queue. If rear deletion is permitted then front
deletion should not be permitted. The C program to implement output restricted queue
is shown below:

Example 8.7.1: C program to implement output restricted queue

#include <stdio.h>
#include <process.h>

#define QUEUE SIZE 5

/* Include: Example 8.2.1.1.2: Function to insert an item at the rear end */


/* Include: Example 8.2.1.2.2: Function to delete an item at the front end */
/* Include: Example 8.2.2.1.2: Function to insert an item at the front end */
/* Include: Example 8.2.1.3.2: To. display contents of queue */
void mainC)
{
int choice,item,f,r,q[l 0];

f= 0;
r = -1;

l for (;;)
{
printf(" 1:Insert _front 2:Insert_rear\n");
printf("3:Delete front \nil);
printf(II4:Display 5:Exit\n~I);
~ Systematic Approach to Data Structures using C - 8.47

printf("Enter the choice\n");


scanf("%d" ,&choice);

switch ( choice)
{
case 1:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
insert_front(item, q, &f, &r);
break;

case 2:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
insertrearfitem, &r, q);
break;

case 3:
delete_front(q, &f, &r);
break;

case 4:
display(q, f, r);
break;

default:
exit(O);
}
}

EXERCISES

1. What is a queue? What are the various operations that can be performed on
queues?
2. What are the different types of queues?
3. Explain an ordinary queue and write a C program to implement the same
(VTU Jul/ Aug 2004)
8.48 Q Queues

4. What is the disadvantage of an ordinary queue? How you can overcome this
disadvantage?
5. What is a circular queue? How it is different from an ordinary queue?
(VTU Jan/Feb 2004)
6. Write a C program to implement circular queues using arrays
(VTU JullAug 2003)
7.. Write a C program to implement circular queues using structures
8. What is a double ended queue or deque? What are the operations that can be
performed on double-ended queues?
9. Write a C program to implement deques using arrays
10. Write a C program to implement deques using structures
11. What is a priority queue? How, it is different from an ordinary queue?
<. (VTU Jan/Feb 2003)
Explain how a priority queue can be implemented? (VTU Jul/Aug 2005)
13. Write a C program to implement priority queues using arrays
14. Write a C program to implement priority queues using structures
15. Define input restricted queue and output restricted queue with suitable diagrams
(VTU July/Aug 2006)
16. If we define an input-restricted deque as a queue which performs the operations
delete_front, delete Jear and insert_front, how we can implement a stack and how
we can implement a queue?
17. If we define an output-restricted deque as a queue which performs the operations
delete_front, insert front and insert right, how a stack can be implemented? How
a queue can be implemented?
18. How a stack of queues can be implemented?
19. How a queue of stack can be implemented?
20. How a queue of queues can be implemented?
21. A Circular queue the size of which is 5 has 3 elements 10,40,25, where F = 2 and
R = 4. After inserting 50,60, what is the value of F and R? Trying to insert an
element 30 at this stage what will happen? Delete 2 elements from the queue and
insert 100. Show the sequence of steps with necessary diagrams with the value of
F and R.
22. What is an ascending priority queue and descending priority queue?
23. Implement an ascending priority queue using arrays
24. Implement an ascending priority queue using structures
25. Explain how elements can be arranged in ascending order in priority queue while
inserting? After arranging them in ascending order, what other functions are
necessary to implement priority queues?
Chapter 9: Linked Lists
What are we studying in this chapter?

• Advantages and disadvantages of arrays and linked lists


• Singly linked list and various operations such as
• Insertion at the front/rear end
• Insertion and deletion at the specified position
• Reverse a list
• Concatenate two lists
• Implementation of stacks and queues using linked lists
• Creating an ordered linked list
• Merging of two ordered linked lists
• Search for an item
• Priority queues and other problems
• Non-homogenous lists
• Implementation of linked lists using arrays
• Circular singly linked lists
• Doubly linked lists
• Applications of linked lists such as
• Addition of long positive numbers
• Evaluation of a polynomial
• Addition of two polynomials -12 hours

9.1 Introduction
In the previous chapters, we have seen various types of linear data structures such as
stacks, queues and their representations and implementations using sequential
allocation technique i.e., using arrays. Let us see, "What are various advantages of
usingarrays?" The advantages of using arrays in implementing various data structures
areshown below:
• Data accessing is faster: Using arrays, the data can be accessed very efficiently
just by specifying the array name and the index of that item. For example, we can
access ith item in the array A by specifying A[i]. The time taken to access a[O] is
same as the time taken to access [10000].
• Simple: Arrays are simple to understand and use.
9.2 Q Linked Lists

Now, let us see "What are the disadvantages of arrays?" Even though arrays are very
useful in implementing various data structures, there are some disadvantages:
• The size of the array is fixed: A fixed amount of memory is allocated before the
start of execution for static arrays and during execution for dynamic arrays. The
memory required for most of the applications often cannot be predicted while
writing a program. If more memory is allocated and the application requires less
. memory, it results in wastage of memory space. If less memory space is allocated
and if the applications require more memory space during execution, it is not
possible to allocate extra memory for arrays during execution. .
• Array items are stored contiguously: Some times enough contiguous memory
locations may not be available. There are situations where a number of chunks of
contiguous memory locations are available. Even though the total free memory
space is sufficient, this space cannot be used since arrays require contiguous
storage space.
• Insertion and deletion operations involving arrays is tedious job: Consider an
array consisting of more than 100 or 200 elements. If we have to insert an item in
the ithposition, all the elements from (i+ l)'h position have to be moved to the next
subsequent locations to make room for the item to be inserted. Only after this
movement, item can be inserted into ithlocation. Similarly, to delete an ith item, all
elements from (i+ l)'h position, should be moved to their corresponding previous
locations. So, if the applications require extensive manipulation of stored data, in
the sequential representation, more time is spent only in the movement of data.

9.2 Linked list

All the disadvantages just now listed can be overcome using linked lists. First, let us
see "What is a linked list?"

Definition: A linked list is a data structure which is collection of zero or more nodes
where each node has some information. The pictorial representation of the node is
shown below:

u:ya-
Node = info + link
r A .•••.•
"

Address of the next node


l

info link
Note that a node in a list consists of two fields namely info and link:
• info - This field is used to store the actual data or information to be manipulated
Q Systematic Approach to Data Structures using C - 9.3
I
• link -A link basically contains address of the next node. So, given address of a
node, we can easily obtain addresses of subsequent nodes. Thus, the adjacency
between the nodes is maintained by means of links.

Now, let us see "What are the different types of linked list?" The linked lists are
classified as shown below:

Singly linked lists


Doubly linked lists
Types of linked lists
Circular singly linked lists
Circular doubly linked lists

9.2.1 Singly linked list

Now, let us see "What is a singly linked list?"

Definition: A singly linked list is a linked list, where each node has designated field
called link field which contains address of the next node. If there exists only one link
field in each node of the list, the linked list is called singly linked list. A singly linked
list may have a collection of nodes with various fields. But, each node should have
onlyone link field which contains the address of the next node.
The pictorial representation of a singly linked list consisting of the items 50,
20, 45, 10 and 80 is shown below:

1004 1020 1012 1008 1016


I

I
1r-50---'~ 20 ~ 45 ~
I 10 ~ 80 ~
L

~nfO link info link info link info link info link

Node = info + link


first
I
<. Fig. 9.2.1.a Pictorial representation of linked list

first ~

Fig. 9.2.1.bAn empty linked list


9.4 Q Linked Lists

The pointer first contains the address of the first node of the list. So, first itself can be
considered as the name of the list. Using the pointer first, we can access any node in
the list. But, pointer first in Fig. 9.2.1.b, contains \0 (null) and it is called empty list.
Now, let us "Defme an empty linked list"

Definition: An empty linked list is a pointer containing a null pointer. This indicates
that list does not exists. Ex: Pointer first in Fig.9.2.1.b. is an empty list.

The following points are observed from the linked list shown in Fig. 9.2.1.a.
• This list contains 5 nodes and each node consists of two fields, info and link.
• The first field of each node i.e., info contains the data. In this list, the items 50, 20,
45, 10 and 80 represent the data.
• The second field i.e., link of each node contains address of the next node. Note
the arrow originating from link field of each node. This arrow indicates that the
address of the next node is stored. So, using link field, any node in the list can be
accessed. Note: The link field of a last node contains \0 (null). The null (\0) in
the link field indicates that it is the last node in the list.
• Nodes that are physically adjacent need not be logically adjacent in the list. For
example, the nodes identified by the addresses 1004, 1020, 1012, 1008 and 1016
they are physically not adjacent but they are logically adjacent. Note: In the
figure, it appears as if the nodes with addresses 1004, 1020, 1012, 1008 and 1016
are physically adjacent. But, by observing the addresses, we know that they are
physically far apart. But, logically adjacent.

The nodes in a linked list are self-referential structures. So, let us see "What are self-
referential structures? How to define a node in C language?"

Definition: If the type of a member in a structure is same as the header of the


structure definition (identified by struct tagname), then that structure is called self-
referential structure. All the nodes in a linked list are self-referential structures
For example, let us define a node in C language. Since each node has two
fields info and link both are of different data type, we can think of a structure with
following syntax:

SYntax
Note: Here, struct is keyword
struct node and node is tagname.
{
type1
type2
info;
*link;
,.
};
~ Systematic Approach to Data Structures using C - 9:5

Let us see, "What is the type of members?" The members of the above structure can
be declared as shown below:
• info - Since it contains the information, it can be of type int, float, char, double
etc. Let us assume this field is of type into So, it can be declared as:
int info;
• link - It contains address of the next node. So, link field must be a.pointer to a
node which can be declared as shown below:
struct node *link;
"---v----'
type of pointer link

Thus, a node with two fields can be defined as shown below:

header of structure definition ~--"""'


t
I

I struct nod~ same


{
int" info;
I struct node I *link;
}; L.- -++~ type of link

typedef struct node *NODE; ,

Note: The header of the structure defmition and type of a member shown in
rectangular box are same. So, it is a self-referential structure

Now, let us see "How to declare a variable? and How to access the members of
structure?"

Example 9.2.1.1: Structure defmition of a node along with declaration


- /

/* Structure defmition for a node */


struct node
{
int info;
struct node *link
};
typedef struct node *NODE;
9.6 Q Linked Lists

A pointer variable first can be declared as shown below:

Method 1: NODE first;


or
Method 2: struct node * first;
1'-- --+ same because of typedef

Both the declarations are same, since NODE and struct node * can be
interchangbly used because of typedef. So, while programming one of the
two declarations can be used. The info field and link fields can be accessed
using the following notations:
Notation 1: Using -> operatior
first->info 1* Access info field *1
first->link 1* Access link field *1

Notation 2: Using * operator


(*first).info 1* Access info field *1
(*frrst).link 1* Access link field *1

Note: In the text book, let us use method 1 for declaring pointer variables
and notation 1 for accessing the members of structure. But, remember
any method or notation mentioned here can be used.

Note: We just now saw that using arrow operator -> or using * operator we can
access members of a structure. The following notations are used to access the
members of a structure while writing the algorithms:

info(first) 1* Access info field *1


link( first) 1* Access link field *1

So far we have seen, what is a linked list, how to represent a node and how to access
various fields of a node. Most important thing is creating a list and manipulating the
list. To create a list, we require nodes. Now, we have too many questions:
• Where the required number of nodes are present? Answer is available list
• How to· get these nodes? Answer is using getnodet)
• When nodes are not required, how to return back? Answer is using freenodet)
Q Systematic Approach to Data Structures using C - 9.7

Now, let us answer the question "What is available list?"

Definition: The free memory space available which is not used by any program is
considered a pool of empty nodes. Since free memory space is finite, we have a finite
pool of empty nodes. This list of free available nodes is called available list. The
available list is pictorially represented as shown below:

AVAIL

Fig. 9.2.2.a Free available nodes (available list)

EQ] AVAIL

Fig. 9.2.2.b Empty available node (Available list is empty)

The nodes in the available list can not be accessed by the programmer directly. Then
how to get these nodes to store the information. This is where the functions getnodet)
and freenodet) makes their existence. Using getnode and freenode, the user can
access the available list.

First,let us see "What is getnode?"

Definition: The getnodeO is a function which removes the first node from the
available list and makes it available for the user. The getnode operation can be treated
as a machine that manufactures nodes. Each time the getnode is invoked, it gives a
new node from the available list. Once a node is obtained from the available list, the
user can use this node to store information,

Now, let us see "How does getnode work when available list has more free nodes?"
The syntax to use getnode function is shown below:

NODEp; 1* Declare a pointer variable p *1

p = getnodet); 1* Get a node from available list *1


9.8 Q Linked Lists ?

The following actiyities take place after executing the above statement:
• Memory is allocated for pointer variable p. The memory does not contain valid
address. So, it is a dangling pointer and can be represented pictorially as shown
below:
p~ invalid address

. The availability list before executing getnode is shown below:

AVAIL

t G4----iG--1_~ .
1000 1040 1020

• The function getnode obtains the first free node from the available list pointed to
by AVAIL. The address of the empty node thus obtained is copied into pointer p
as shown below:
1000

p~----iD
Now, pointer p contains valid address and now, it is not a dangling pointer.

• The pointer AVAIL points to the next free node (avail = linktavail) as shown
below:

AVAIL

-i-~""""""'"

1000 1040 1020

Note: The node shown in dull- color represent that it has been removed from the
available list and given to the user. Now, removed node is not part of the available list
What to do next? Once the node is obtained, it is the responsibility of the user to store
the information by accessing info and link fields. For example, suppose it is required
~ Systematic Approach to Data Structures using C - 9.9

to store only one item 10. Since our list has only one item, info field should contain
10and the link field of this node should contain \0 (null) indicating it is the last node
inthe list. The equivalent code for this can be written as shown below:

Algorithm notation C notation


info(p) = 10 p->info = 10; 1* Store lOin info field *1
link(p) = \0 p->link = NULL; 1* make node as last node *1
The pictorial representation of the new node thus created after storing the necessary
information is shown below:

pG-110 GJ
Now,let us see "How does getnode work when available list is empty?"

Theempty available list is shown in figure 9.2.2.b. Note that pointer AVAIL points
to\0 (null) which indicates that the available list is empty and there are no free nodes
tobe given to the user. If the user request a free node using the getnode function, the
getnodefunction returns \0 (null). This means that all free nodes are currently in use
by various programs and memory is used to full extent resulting overflow condition.

Now,we can easily know "How getnodet) function is implemented?"

Thegetnodet) function is implemented based on whether the available list is empty or


notas shown below:
• If the available list is empty, getnode function should display appropriate error
message and then it should return NULL. This is achieved using the following
statements:

if (AVAIL = '\0') Note: In place of '\0' we can use NULL


{
printf("Overflow of memory\n"):
return '\0';
}

• If the available list is not empty, get node function returns the free node pointed to
by AVAIL using the statement:

p = AVAIL;
9.10 Q Linked Lists

• The pointer AVAIL points to the next free node using the statement:

AVAIL = link (AVAIL);

Thus, complete implementation of getnodetjfunction IS implemented as shown


below:

Example 9.7.1.2: Algorithm to implement the function getnode

Algorithm getnodet)
{
- if(AVAIL==NULL) 1* If available list does not exist, it is overflow */
{
printf("Overflow of memory\n");
return '\0';
}

x = AVAIL; 1* Get a free node from available list *1

AVAIL = link(A VAIL); 1* Point to next free node of available list *1

return x; 1* Return the free node to the user program *1


}

Now, let us see "How to implement the function getnodet) in C language?"

In C language, we can use malloct) to allocate memory explicitly as and when


required and exact amount needed during execution (Refer section 2.9.2.1, page 2.85
for details)
• On successful allocation, the function returns the address of first byte of allocated
memory. Since address is returned, the return type is a void pointer. By type
casting appropriately we can use it to point to any desired data type
• I specified size of memory is not available, the condition is called "overflow of
memory". In such case, the function returns NULL.

Note: It is the responsibility of the programmer to check whether the sufficient


memory is allocated or not as shown below:
Q Systematic Approach to nata Structures using C - 9.11

ptr = (data_type *) malloc(size);


if (ptr = NULL)
{
printf("Insufficient memory\n");
exit(O);
}

/* Memory has been successfully allocated */

Thus, in C language getnode function is implemented as shown below:

Example 9.2.1.3: C Function to get a new node from the availability list

NODE getnodet)
{
NODE x;

/* Try to allocate the required size of memory */


x = (NODE) malloc(sizeof(struct node));

if(x=NULL) /* Free nodes don't exist */


{
printf("Out of memory\n"); /* Allocation failed */
exit(O); 1* Terminate the program */
}

/* allocation successful and return the address */


return x;

ote: The return type of getnodet) is NODE and its type definition is available in
example 9.2.1.1 (see this example for details on NODE)

Note:The prototype ofm~l1ocO is defmed in header file "stdlib.h"


9.12 Q Linked Lists

First, let us see "What is freenode?"


Definition: A node which is no longer being used can be returned to available list so
that when a next getnode is called, the node can be re-used. For this purpose, free
node is used. So, a freenodet) is a function which returns unused node to the
available list. The node thus returned is added at the beginning of the available list.
Now, let us see "How does freenode work?" The syntax to use freenode function is
shown below:
{
NODEp; 1* Declare a pointer variable p *1

p = getnodet); 1* Get a node from available list *1

freenode(p) ; 1* Return a node to the available list *1


}
Consider the following availability list before executing freenodet):

AVAIL

t G-1"------1~ .
1040 1020
Assume the variable p points to a node as shown below and it is no longer used. So, it
is required to return this node back to the available list.
1000

p~

The following activities take place after executing the freenodet):


• After executing the function freenode(p), the node pointed to by p is returned to
the available list. The pictorial representation of pointer p after executing the
function freenodet) is shown below:

p invalid address
~ Systematic Approach to Data Structures using C - 9.13
Now, the pointer p does not contain valid address. So, pointer p is now a
dangling pointer.

• The returned node is thus added at the beginning of the available list as shown
below:

AVAIL

~-~ .
1000 1040 1020

It is clear from above figure that link(p) should contain address of the first node of the
available list. This is achieved using the following statement:
link(p) = AVAIL;

Then make the new returned itself as the starting address of the available list by
executing the statement:
AVAIL =p;
So, the final available list is shown below:

AVAIL

t 1000
~1..--G-1L.-G--+"""""'"'' ~L.-0
1040 1010

Now, let us see "How to implement the function freenodet) III the form of an
algorithm" The corresponding algorithm is shown below:

Algorithm freenode(p)
{
link(P) = AVAIL;
AVAIL=p;
}
9.14 Q Linked Lists

The corresponding C function to de-allocate or free a node is shown below:

Example 9.2.1.4: C Function to free a node to the availability list

void freenode(NODE x)
{
free(x);
}

So far we learnt how to get a node from the available list and how to return that node
to the available list whenever it is not being used.

9.2.2 Operattons on singly linked lists

Now, let us see "What are the various operations that can be performed on singly
linked lists?" The basic operations that can be performed on a linked list are shown
below:

Inserting a node into the list


Deleting a node from the list
Various Operations of linked lists
Search in a list
Display the contents of list
9.2.2.1 Insert a node at the front end

In this section , let us see "How to insert a node at the front end of the list?"

Design: To design the function easily, let us consider a list with 4 nodes. Here,
pointer first contains address of the first node of the list. Let us try to insert the item
50 at the front end of the list. The sequence of steps to be followed are shown below

Step 1: Obtain a free node from the availability list and -identify the node with
variable temp using the following statement:
1
temp = getnode();

Step 2: Copy item = 50 to the info field of temp using the following statement:

info(temp) = item;
Q Systematic Approach to Data Structures using C - 9.15

Step3: Attach pointer first to the link field of temp using the statement:

link( temp) = first;

Step4: Now, a node temp has been inserted and observe from the figure that temp is
thefirst node. Let us always return address of the first node using the statement:

return temp;

Thesesteps and the changes made as per these steps are shown in figure below:

Fig.9.2.2.1.1 To insert an item at the front end (called function)

Thealgorithmic function to insert an item at the front of the list is shown below:

Example9.2.2.1.1: Algorithm to insert an item at the front of list

Algorithminsert_fropt(item, first)
{
temp = getnodei); /* Get a node from the availability list */

info(temp) = item; /* Insert the item */

link(temp) = first; /* Attach to the existing first node of the list */

. return temp; /* Make temp as new first node */

ote: in the calling function (say main), let us use first always to point to the first
node of the list. This can be achieved by calling the function insert _ frontt) as shown
below
9.16 Q Linked Lists

first = insert_front(item, first);

After executing this statement, we know that function insertfrontt) returns temp
which is the address of the first node in that function. This returned value is copied
into first in the calling function. The entire linked list as seen in calling function is
shown below:

..., .
1 llir.,t
~.":".:

Fig.9.2.2.1.2 After inserting 50 at the front end (calling function)

ote: The variable first in the calling function (say main) always points to the first
node. The previous node which was pointed to by first before executing insert _ frontt)
is shown in gray color.

Note: The algorithm insert_frontO has been designed by assuming that the list already
exists. Assume now that the list is empty i.e., the pointer variable first contains
NULL. Now try to insert an item into the empty list and see that the function
insertfrontt) works for this case also.

Just now, we have inserted one node at the front end of the list. Now, the question is
"How to create a linked list?" The answer is very simple. Consider the following
statement:
first = insert _front(item, first);

• If first is NULL and the above statement is executed, a linked list with only one
node is created.
• If it is executed for the second time, a new node is inserted at the front end and
there by number of nodes' in the list is 2
• If it is executed for the third time, the number of nodes in the list will be 3. Thus,
if the function insert _ fronn) is called n times, we have a list with n nodes.

ote: Thus, repeated inserting an element at the front end of the list we can create a
linked list. The C function to insert an item at the front end of the list is shown below:
~ Systematic Approach to Data Structures using C - 9.17

Example 9.2.2.1.2: C Function to insert an item at the front end of the list

NODE insert_front(int item, NODE first)


{
NODE temp;
temp = getnodet); /*obtain a node from the available list*1
temp->info = item; 1* Insert an item into the newly created node */
temp->link = first; /* Attach new node at the front end of list *1
return temp; 1* return the new first node *1

9.2.2.2 Display singly linked list

Now, let us see "How to display the contents of list?" Consider the list shown in
fig.9.2.2.2. Here, first contains address of the first node. Instead of updating first
from left to right to access each node, let us use another pointer temp which initially
points to the first node of the list. By pointing temp to each subsequent nodes and
printing the info field of each node, entire contents of list can be displayed.

~
. ..
----------~----
temp
Fig. 9.2.2.2 Singly linked list to be displayed

Now,let us see "How to point temp to point to next node?" Note that link(temp) is
1004. If we copy this value to temp, now temp has the address 1004 which is the
addressof the second node. Thus, using the statement:
temp = link( temp)
wecan point temp to next node. Now, the items to be displayed are 20, 45, 10 and 80.
This is achieve by repeatedly printing info field of temp and updating temp to point
tonextnode as shown below:
9.18 Q Linked Lists

Output
write (info(temp)) 20 45 10 80
temp = link(temp)
[

After displaying 80, note that temp points to NULL, indicating all the nodes in the
list have been displayed. Now, there is no need to go back and execute those
statements i.e., those two statements have to be repeatedly executed, as long as temp
is not NULL. So, the next version of the algorithm can be written as

temp = first
while ( temp != NULL)
{
write (info(temp))
temp = link( temp)
}

Note that all these statements have to be executed only if the list is existing. If first is
NULL, display the message "List is empty" The algorithmic function to display the
list is shown below:

Example 9.2.2.2.1: Algorithm to display the contents of the list

Algorithm displaytfirst)
{
if (first = NULL) 1* Check for empty list *1
{
write('List is empty')
return;
}
write('The contents of the list')
temp = first 1* Holds address of the first node *1
while ( temp != NULL) 1* As long as no end oflist *1
{
write (info(temp)) 1* Display the info field of a node *1
temp = link( temp) 1* Update to point to next node *1
}
}

TheC function to display the contents of the list is shown below:


Q Systematic Approach to Data Structures using C - 9.19

Example 9.2.2.2.2: C function to display the contents oflinked list

void display(NODE first)


{
NODE temp;

if ( first = NULL) 1* Check for empty list *1


{
printf("List is empty\n");
return;
}

printf("The contents of singly linked list\n");

temp = first; 1* Holds address of the first node *1


while (temp!= NULL) 1* As long as no end of list *1
{
printf("%d ",temp->info); 1* Display the info field of node *1
temp = temp->link; 1* Point to the next node *1
}
printf("\n");

The complete C program to create a list and to display the contents of list is shown
below:

Example 9.2.2.2.3: C program to create a list and to display the contents oflist

#include <stdio.h>
#include <alloc.h>
#include <process.h>

struct node

int info;
struct node *link;
};

I typedef struct node* NODE;


9.20 Q Linked Lists

1* Include: Example 9.2.1.3: C Function to get a new node from availability list */
/* Include: Example 9.2.2.1.2: C Function to insert an item at the front end of list */
1* Include: Example 9.2.2.2.2: C function to display the contents oflinked·list */
void maim)
{ . NODE first = NULL; /* To start with list is empty. */
int choice, item;

for (;;)
{
printf(" 1:Insert front 2:Display\n");
printf("3 :Quit\n");
printf("Enter the choice\n");
scanf("%d" ,&choice);

switch ( choice)
{
case l:
" printf("Enter the item to be inserted\n");
scanf("%d" ,&item);

first = insert _ fronuitem.first);

break;

case 2:
displaytfirst);
break;

default:
exit(O);
}
}
}

9.3 Other operations on linked lists

This section describes the implementation of stacks, queues and dequeues using
linked representation and various operations that can be performed on linked lists
along with design aspects.
Q Systematic Approach to Data Structures using C - 9.21

9.3.1 Delete a node from the front end

Now, let us see "How to delete a node from the front end of the li t?"

Design: To design the function easily, let us consider a list with 5 nodes. Here,
pointer first contains address of the first node of the list. Let us try to delete an item
from the front end of the list. The sequence of steps to be followed are shown below:

first (b)

Fig.9.3.1 To delete an item from the front end

Step 1: An auxiliary pointer temp should point to the first node of the list using the
following statement
temp = first;
9.22 Q Linked Lists

Step 2: Update the pointer temp to point to the next node. This is achieved using the
statement:
temp = link( temp);

Step 3: Note that first points to first node of the list and temp points to the second
node of the list. Using the pointer first, the first node can be deleted as shown below:

freenode( first);

The node pointed to by first is deleted and is returned to the availability list. The
resulting linked list is shown in fig.9.3.l.c.

Step 4: Once the node first is deleted, the node temp will become first node. So,
return temp as the first node to the calling function using the statement:

return temp;

Note that all these statements have to be executed, only when the list exists. If the list
is empty, display the message "List empty, can not delete" and return NULL. The C
function to delete an item from the front end of the list is shown below:

Example 9.3.1: C function to delete an item from the front end of the list

NODE delete_front(NODE first)


{
NODE temp;

if ( first = NULL) 1* Check for empty list *1


{
printf("List is empty can not delete\n");
return first;
}

temp = first; 1* Retain address of the node to be deleted *1


temp = temp->link; 1* Obtain address of the second node *1
printf("Item
..• deleted = %d\n",frrst->info); 1* access first node *1
freenode( first); 1* delete the front node *1

return temp; 1* return address of the first node *1


}
Q Systematic Approach to Data Structures using C - 9.23
1ote: Now, onwards let us write only C functions. Algorithmic functions can be
writtenas shown in earlier examples.

9.3.2Insert a node at the rear end

Now,let us see "How to insert a node from the rear end of the list?"

Design:To design the function easily, let us consider a list with 5 nodes. Here,
pointer first contains address of the first node of the list. Let us try to insert an item at
the rear end of the list. The sequence of steps to be followed are shown below:

tempe!)

(a)

temp

,
--!-----..:....
(b)

9 first 0 9 temp

150 G-{20 ~ 45 G1""'-10-&[80 I~


(c) dJ cur ®
Fig.9.3.1 To insert an item at the rear end of the list
9.24 Q Linked Lists

Step 1: Create a node to be inserted and insert the item using the following
statements:
temp = getnodet);
temp->info = item;
temp->link = NULL;

,Step 2: If the node temp is inserted into the list for the first time (i.e., into the empty
llist), then return temp itself as the first node using the following code.

if(first = NULL) return temp;

Step 3: The moment control comes here, we have an existing list. We need to obtain
the address of the last node. This is possible only if we start from the first node. So,
we use pointer cur which initially points to the first node using the statement:

cur = first;

Step 4: Now, we should obtain the address of the last node. This is possible by
repeatedly updating cur till last node is reached.

I cur; cur->link;

Note: if cur->link contains \0 (null) then cur points to the last node. So, keep
updating cur as long as cur->link is not NULL. This is achieved using the following
statement:
while ( cur->link != NULL)
cur = cur->link;

Step 5: Once cur points to the last node, we can easily insert temp at the end of the
list. This is achived by copying temp to link field of cur using the statement:

cur->link = temp;

Step 6: After updating always return address of the first node of the list using:

return first;

The complete C function to insert an item at the rear end of the list is below:
Q Systematic Approach to Data Structures using C - 9.25

Example 9.3.2: Function to insert an item at the rear end of the list

NODE insertrear/int item, NODE first)


{
NODE temp; 1* Points to newly created node *1
NODE cur; 1* To hold the address of the last node *1
temp = getnodet); 1* Obtain new node, insert the item into node *1
temp->info = item;
temp->link = NULL;

1* If list is empty return new node as the first node* I


if ( first = NULL) return temp;

1* Iflist exists, obtain address of the last node *1


cur = first;
while ( cur->link != NULL)
{
cur = cur->link;
}

cur->link = temp; 1* Insert the node at the end *1


return first; 1* return address of the first node *1

9.3.3Delete a node from the rear end


Now,let us see "How to delete a node from the rear end of the list?"
Design: To design the function easily, let us consider a list with 5 nodes. Here,
pointerfirst contains address of the first node of the list. Let us try to delete an item
fromthe rear end of the list. The sequence of steps to be followed are shown below:

Step 1: It is not possible to delete an item from the empty list. Appropriate error
messagecan be displayed as shown below:

if (first = NULL)
{
printf("List is empty can not delete\n");
return first;
}
9.26 Q Linked Lists

Step 2: Consider a list with single node shown in figure 9.3.3.a. After deleting this
node, the list should be empty. The code for this case is shown below.
I*If only one node is present, delete it *1
if ( first ->link = NULL)
{
printf ("The item to be deleted is %d\n",first->info);
freenode(first); 1* Delete and return to availability list */
return NULL; /* return empty list */
}

first cv
50 After deleting first = NULL

(a) only one node

first

--- ---
-.z..
r---....,...- ....•

prev
Note: cur and prev points to last and last but one node (final dotted lines)
(b)

9firSl0 ~cur 4

\50 ~20
~ 45 ~ 10 r;:] , -;;-~\O-·
.L ~ node deleted
~ prey

(c) Deleting the last node


~ Systematic Approach to Data Structures using C - 9.27

Step 3: Once control comes to this step, the list has more than one node. To delete the
last node, we need to find the address of the last node and address of the last but one
node. For this reason, we use two pointers: cur and prev,

Initially, cur points to the first node and prey points to \0 (null). Now, let us
point cur to point to last node and prey to last but one node. This is possible by
repeatedly updating cur and prey as long as link field of cur is not NULL. Just
before updating cur, assign cur to prey so that prev->link always contains address of
cur node. This can be achieved by using the following sets of statements.

prev=NULL;
cur = first;

while( cur->link != NULL )


{
prey = cur;
cur = cur->link;
}

After executing the above statements, cur points to the last node and prey points to
last but one node as shown in figure 9.3.3.b.

Step 4: To delete the last node pointed to by cur, the function freenodet) is used as
shownbelow: (gray color in 9.3.3.c)

printf("The item deleted is %d\n",cur->info);


freenode( cur);

Step 5: Once the last node is deleted, the node pointed to by prey should be the last
node.This is achived by copying NULL to link field of prey as shown below:

prev->link = NULL; 1* Node pointed to by prey is the last node *1

Step 6: Finally return address of the first node.

return first; 1* return address of the first node *1

Thecomplete C function to delete a node from the rear end of the list is shown below:
9.28 Q Linked Lists

Example 9.3.3: Function to delete an item from the rear end of the list

NODE delete _rear(NODE first)


{
NODE cur,prev;

if (first = NULL) 1* Check for empty list *1


{
printf("List is empty can not delete\n");
return first;
}

if ( first ->link = NULL ) I*Only one node is present and delete it *1


{
printf ("The item to deleted is %d\n",first->info);

freenode(first) ; I*·return to availability list *1

return NULL; 1* List is empty so return NULL *1


}

1* Obtain address of the last node and just previous to that *1


prev = NULL;
cur = first;
while( cur->link != NULL)
{
prev = cur;
cur = cur->link;
}

1* delete the last node and return to available list* I


printf("The item deleted is %d\n",cur->info);
freenode( cur);

prev->link = NULL; 1* Make last but one node as the last node *1

return first; 1* return address of the first node *1


}
.d Systematic Approach to Data Structures using C - 9.29

9.3.4 Implementation of queues using linked lists

Now, "How to implement queues using linked lists?" We have discussed the concept
.of queues in chapter 8. It is a FIFO data structure. Here, insertion is done from one
end and deletion is done from the other end. So, we can utilize the functions
• insert_rearO
• delete_ frontt)
• displayt)

to implement queues using linked list. The complete C program to implement queues
is shown below:

Example 9.3.4: Program to implement gueues using singly linked lists

#include <stdio.h>
#include <stdlib.h>
#include <process.h>

struct node
{
int info;
struct node *link; .
};

typedef struct node* NODE;

1* Include: Example 9.2.1.3: C Function to get a new node from availability list */

./* Include: Example 9.2.1.4: C Function to free a node to the availability list */

1* Include: Example 9.2.2.2.2: C function to display the contents of linked list */

1* Include: Example 9.3.1: C function to delete an item from the front end oflist */

1* Include: Example 9.3.2: Function to insert an item at the rear end of the list */

void maint)
{
NODE first = NULL;
int choice, item;
9.30 Q Linked Lists

for (;;)
{
printf(" 1:Insert rear 2:Delete front \nil);
printf("3:Display 4:Exit\n");
printf("Enter the choice\n");
scanf("%d" ,&choice);

switch ( choice)
{
case 1:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
first = insert Jear(item,first);
break;

case 2:
first = delete_front(first);
break;

case 3:
display(first);
break;

default:
exit(O);
}
}
}

Note: Using the functions insertfrontt), delete_rearO and displayt) also, we can
implement queues.

9.3.5 Implementation of stacks using linked lists

Now, "How to implement stacks using linked lists?" We have discussed the concept
of stacks in chapter 6. It is a LIFO data structure. Here, insertion is done from one end
and deletion is done from same end. So, we can utilize the functions
• insert _frontt) • insert _rearO ,.
• delete _frontt) or. delete JearO .
• displayt) • displayt)
~ Systematic Approach to Data Structures using C - 9.31

to implement stacks using linked list. The complete C program to implement stacks is
shownbelow:

Example 9.3.5: Program to implement stacks using singly linked lists

#include <stdio.h>
#include <stdlib.h>
#include <process.h>

struct node

int info;
struct node *link;
};

typedef struct node* NODE;

1* Include: Example 9.2.1.3: C Function to get a new node from availability list */

1* Include: Example 9.2.1.4: C Function to free a node to the availability list */

1* Include: Example 9.2.2.1.2: C Function to insert an item at the front end of list */

/* Include: Example 9.2.2.2.2: C function to display the contents of linked list */

1* Include: Example 9.3.1: C function to delete an item from the front end of list */

voidmaint)
{
NODE first = NULL;
int choice, item;

for (;;)
{
printf("1 :Insert front 2:Delete front \n");
printf("3 :Display 4:Exit\n");
printf("Enter the choice\n");
scanf("%d" ,&choice);
9.32 Q Linked Lists

switch ( choice)
{
case 1:
printf(t'Enter the item to be insertedm'');
scanf(tI%dtl ,&item);
first = insert _front(item,first);
break;
case 2:
first = delete_front(first);
break;
case 3:
display(first);
break;
default:
exit(O);
}
}

9.3.6 Implementation of double ended queues using linked lists


Now, "How to implement dequeus using linked lists?" We have discussed the concept
of dequeues in chapter 8. It is a special type of data structure where insertion and
deletion operations are p .formed on both ends. So, we can utilize the functions
• insert _ frontt) • insert JearO
• delete _ frontt) • delete JearO
• displayt)
to implement deques using linked list. The complete C program to implement de que!
is shown below:
Example 9.3.6: Program to implement deques using singly linked lists
#include <stdio.h>
#include <stdlib.h>
#inclu~e <process.h>
struct node
{
int info;
struct node *link;
};
Q Systematic Approach to Data Structures using C - 9.33

typedef struct node* NODE;

1* Include: Example 9.2.1.3: C Function to get a new node from availability list */

1* Include: Example 9.2.1.4: C Function to free a node to the availability list */

1* Include: Example 9.Z.2.1.2: C Function to insert an item at the front end oflist */

1* Include: Example 9.2.2.2.2: C function to display the contents oflinked list ~/


1* Include: Example 9.3.1: C function to delete an item from the front end of list */

1* Include: Example 9.3.2: Function to insert an item at the rear end of the list */
1* Include: Example 9.3.3: Function to delete an item from the rear end oflist */

void maim)
{
NODE first = NULL;
int choice, item;

for (;;)
{
printf("l :Insert front 2:Jnsert rear\n");
printf("3:Delete front 4:Delete rear\n");
printf(" 5 :Display 6:Exit\n");
printf("Enter the choice\n");
scanf("%d" ,&choice);

switch ( choice)
{
case 1:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
first = insertfronuitem.first);
break;
case 2:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
first = insert Jear(item,first);
break;
9.34 Q Linked Lists

case 3:
first = delete _ front(first);
break;

case 4:
first = delete. reanfirst);
break;

case 5:
display(frrst);
break;

default:
exit(O);
}
}
}

9.3.7 Creating an ordered linked list

Now, let us see "What is an ordered linked list?"

Definition: A linked list in which the items are stored in some specific order is an
ordered linked list. The elements in an ordered linked list can be in ascending or
descending order or based on key information. A key is one or more fields within a
structure that are used to identify the data. For example, an ordered linked list shown
in fig.9.3.7.a.

Now, let us see "How to create an ordered linked list?"

Design: To design the function easily, let us consider a list with 4 nodes. Here,
pointer first contains address of the first node of the list. After inserting any item into
this existing list, the order of list should be maintained i.e., the items in the list should
be arranged in ascending/descending order only. The pointer first, contains the
address of the first node of the list. To insert an item into the list, the sequence of
steps to be followed are:

Step 1: Create a node to be inserted and insert the item usmg the following
statements:
temp = getnodet);
temp->info = item;
temp->link = NULL;
Q Systematic Approach to Data Structures using C - 9.35

Step 2: If the node temp is inserted into the list for the first time (i.e., into the empty
llist), then return temp itself as the first node using the following code.

if (first = NULL) return temp;

Case 1: Insert at front end

Case 2: Insert at the middle

(e)
Fig.9.3.1 To create an ordered linked list

Case 1: Inserting an item at the front end of the list: Let the item to be inserted be 5.

Step 3: Consider the list with 4 nodes having 10, 20, 30, 40 as the info of each
node. The item 5 is less than i0 which is the info of first node of the list. To
maintain the order, the created node temp should be inserted at the front of the
list as shown in fig.9.3.7.b. The code corresponding to this is shown below.
9.36 Q Linked Lists

CD temp->link = firs~; /* Insert the node at the front end of the list */

Step 4: Once the node temp is inserted at the front end, let us return temp
indicating temp itself is the first node of the list using:

.0 return temp; /* Make new node as the first node */

Case 2: Inserting an item at the middle/end: Let the item to be inserted is 35

Step 5: Find the appropriate position (Fib 9.3.1b or Fib 9.3.1c): The node
temp containing item 35 should be inserted between two nodes prey and cur.
So, it is required to find appropriate positions so that the node temp is inserted
maintaining the order. This is possible if traversing is done from the first node of
the list. Let us use two pointers cur and prey with cur pointing to first node and
prey pointing NULL as shown below:

prev = NULL;
cur = first;

Then, as long as the item to be inserted is greater than info of cur, keep updating
the cur and prey to point to their successor nodes one after the other. The code
to find the appropriate position is shown below.

while ( cur != NULL && item> cur->info )


{
prev = cur; Note: While updating cur and prey, we
cur = cur->link; should see that cur should never be NULL
}

Note: The moment we find the appropriate place, control comes out of the while
loop. Now, we have cur and prey between which node temp has to be inserted.

Step 6: Insert at middle/end: The corresponding code is shown below:

prev->link = temp; /* connect node prey with node temp */


temp->link = cur; /* connect new node temp with next node cur */

Step 7: Always we return the address of the first node as shown below:

return first; /* return address of the first node */


~ Systematic Approach to Data Structures using C - 9.37

The complete C function to insert an item into an ordered linked list is below:

Example 9.3.7: Cfunction to create an ordered linked list

NODE insert(int item, NODE first)


{
NODE temp, prey, cur;

1* obtain a node to be inserted *1 STEPl


temp = getnodet);
temp->info = item;
temp->link = NULL;

1* Inserting the node for the first time *1 STEP 2


if ( first = NULL) return temp;

1* Inserting the node in the beginning of the list *1 STEP 3 and 4


if ( item < first->info )
{
temp->link = first;
return temp;
}

1* find prey and cur locations so that node temp has to be inserted *1
prey = NULL; STEP 5
cur = first;

while ( cur != NULL && item> cur->info )


{
prey = cur;
cur = cur->link;
}

1* Insert the node between prey and cur *1 STEP 6


prev-c-link = temp;
temp->link = cur;

1* return the first node *1 STEP 7


return first;
9.38 Q Linked Lists

9.3.8 Search for an item in a list

Before writing the algorithm/program for searching, let us see "What is searching?"

Definition: More often we will be working with large amount of data. It may be
necessary to determine whether a particular key or item is present in the large amount
of data. This process of finding a particular key or item in the large amount of data is
called searching.

Now, let us see "How to search for an item in a linked list?" Searching for a key item
is very simple and straight forward technique. We know how to display info of each
node. The partial code can be written as: .

" cur = first;


while (cur!= NULL) 1* As long as no end oflist */
{
1* Display the info of a node */
1* point cur to the next node */
} Note: Replace printf by the if
r------------------L~
if (key = cur->info) break;

Note: Replacing the printf by the above statement our searching is over. The partial
code for searching can be written as shown below:

cur = first;
while (cur!= NULL) 1* As long as no end oflist */
{
if (key = cur->info) break; /* If found go out of the loop *1
cur = cur-c-link; /* point cur to the next node */
\

if (cur -= NULL) 1* If end of list, key no.t found *1


(
l
pri t ("Search is unsuccessful\n");
l
return;
}

printf("Serach is successfu1\n"); 1* Yes, key found */


The complete C function to search for a key item is shown below:
Q Systematic Approach to Data Structures using C - 9.39

Example 9.3.8.1: Function to search for key item in the list

void search(int key, NODE first)


{
NODE cur;

if ( first = NULL) /* Search for empty list */


{
printf("List is empty\n");
return;
}

/* Compare one after the other */


cur = first;
while (cur != NULL) /* As long as no end of list */
{
if (key = cur->info) break; /* If found go out of the loop of< /
cur = cur->link; /* point cur to the next node */
}

if (cur = NULL) /* If end of list, key not found */


{
printf("Search is unsuccessful\n");
return;
}

printf("Serach is successful\n"); 1* Yes, key found *1

9.3.9 Delete a node whose information field is specified

This section gives a more general way of deleting a node based on the information
given. This involves traversing the list for the specific information. If the item is
present, the corresponding node is deleted. Otherwise, appropriate message is
displayed. The main aim is to search for the specified item in the list and delete the
corresponding node.

ow, let us see "How to delete a node whose info field is specified?"
Design: To design the function easily, let us follow the sequence of steps shown
below:
9.40 Q Linked Lists

Step 1: Check for empty list. The equivalent code can be written as shown below:
if (first = NULL)
{
printf("List empty, Search fails\n");
return NULL;
}
Let us compare key with info field of the first node in the list. If there is a
match, the node at the front end of the list has to be deleted as shown below:

G Save the address of first node into cur using the statement:
cur = temp;

@ Update first to point to the next node using the statement:


first = first -> link

G) Delete the first node pointed to by cur using the statement: .


freenode(cur); 1* Deleted node is shown in Gray color *1
@ Return address of the first node using the statement:
return first;

25

The code corresponding to this is shown below.


if ( key = first->info )
{
cur = first; 1* Save the address of the first node *1
first = first->link; 1* Point first to second node in the list *1
freenode( cur); , 1* Delete the first node *1
return first; , 1* Return second node as the first node *1
r
~ Systematic Approach to Data Structures using C - 9.41

Step 3: Control comes to step 3, if key is not present in the first node of the list. It
may be present or may not be present. So, we have to search for key in the list. The
code can be written as shown below:
prev=NULL;
cur = first;

while (cur != NULL) 1* As long as no end of list *1


{
if (key = cur->info) break; 1* If found go out of the loop *1

I pre v -
cur; I 1* Save the address of cur node *1
cur - cur-e-link; 1* point cur to the next node *1
}

if (cur == NULL) 1* If end of list, key not found *1


{
printf("Search is unsuccessful\n");
return first;
}

printf("Serach is successful\n"); 1* Yes, key found *1

Step 4: Once search is successful, the node pointed to by cur has to be deleted. Also,
observe that if cur is the node to be deleted, prev is the predecessor of the node to be
deleted. Assume key = 30. Now, to delete the node pointed to by cur consider the
figure shown below:
9.42 Q Linked Lists

Now, to delete the node pointed to by cur, we have to establish a link between the
successor and the predecessor of the node to be deleted. This can be done using the
following statement:

CD prev->link = cur->link;
Step 5: Once a link has been established, the node pointed to by cur is isolated and it
can be deleted by calling the function freenodet)

o freenode( cur);

Step 6:_ Finally return the address of the first node. The code for this is shown below.

o return first;

The complete C function to delete a node whose information field is specified is


shown below:

Example 9.3.9.1: Function to delete a node whose info field is specified

NODE delete_info(int key, NODE first)


{
NODE prev, cur;
if ( first = NULL ) 1* Check for empty list *
{
printf'(t'List is emptyin");
:I return NULL;
}
if (key = first-s-info )
{
cur = first; 1* Save the address of the first node *1
first = first-c-link; 1* Point first to second node in the list ~I
freenode( cur); 1* Delete the first node ~.I .'
return first; 1* Return second node as the first node *1
}
prev=NULL;
cur = first;
Q Systematic Approach to Data Structures using C - 9.43

while (cur != NULL) 1* As long as !I0 end Of list */


{
if (key = cur-e-info) break; 1* If found go out of the loop *1

prev = cur; 1* Save the address of cur node *1


cur = cur->link; 1* point cur to the next node *1
}

if (cur = NULL) 1* If end oflist, key not found *1


{
printf("Search is unsuccessful\n");
return first;
}

1* Search successful. So, delete the node *1


prev->link = cur->link; 1* Establish link between the
predecessor and successor *1
freenode(cur); 1* Delete the node with info key *1

return first; 1* Return address of first node *1

9.3.1 0 Delete a node at the specified position

Thisproblem is similar to the previous method. Instead of deleting a node whose info
fieldis specified, we obtain a node at the specified position and then delete from that
position. If the specified position is 1, the node at the front end of the list has to be
deleted as shown in fig.9.11.a. The code corresponding to this can be

Now,let us see "How to delete a node at the specified position?"


Design: To design the function easily, let us follow the sequence of steps shown
below:

Step 1: Check for empty list. The equivalent code can be written as shown below:
if (first = NULL II pos <= 0)
{
printf("Invalid position\n");
return NULL;
}
9.44 ~ Linked Lists

Step 2: This step is exactly similar to step 2 of previous problem. But, instead of
comparing key with first node of the list, we compare whether the node to be deleted
is at position 1. The code corresponding to this is shown below.
if( pos = 1 )
{
cur = first; /* Save the address of the first node */
first = first->link; /* Point first to second node in the list */
freenode( cur); /* Delete the first node */
return first; /* Return second node as the first node */
}
Step <3: This step is also exactly similar to the previous problem. But, instead of
comparing key with each node, we compare the position. If specified position is
obtained come out of the loop. Only the difference is that we have to keep track to
find whether the specified position is reached or not. For this we have to keep track of
count. The corresponding code is shown below:
prev = NULL;
cur = first;
count = 1; /* Start from the first node */
while (cur != NULL) /* As long as no end oflist */
{
if (count = pos) break; /* If found go out of the loop */
prev = cur; /* Save the address of cur node *1
cur = cur-c-link; 1* point cur to the next node */
}

if (count != pos) /* If end of list, invalid position *1


{
printf("Invalid position\n");
return first;
}
Step ,14, 5, 6: These steps are exactly same as the. previous problem: The
corresponding code is shown below:
prev->link = cur->link;
freenode( cur);
return first;
Q Systematic Approach to Data Structures using C - 9.45

The complete C function to delete a node whose information field is specified is


shown below:

Example 9.3.10.1: Function to delete a node at the specified position


NODE delete ---'pos(intpos, NODE first)
{
NODE cur; 1* Address of the node to be deleted *1
NODE prey; 1* Address of the previous node *1 •
int count; 1* Update till desired node is found *1
if ( first = NULL II pos <= 0 ) 1* Check for empty list or pos <= 0 *1
{
printf("Invalid position\n");
return NULL;
}
if( pos = 1 )
{
cur = first; 1* Save the add! of the first node *1
first = fust->link; 1* Point first to second node in the list *1
freenode( cur); 1* Delete the first node *1
return first; 1* Return second node as the first node *1
}
prey = NULL;
cur = first;
count = 1; 1* Start from the first node *1
while (cur!= NULL) 1* As long as no end oflist *1
{
if (count = pos) break; 1* If found go out of the loop *1

pre v = cur; 1* Save the address of cur node *1


cur = cur->link; 1* point cur to the next node *1
}
if (count != pos) 1* If end of list, invalid posi tion *1
{
printf("Invalid position\n");
return first;
}
9.46 Q Linked Lists

if ( count l= pos ) 1* Invalid position *1


{
printf("Invalid position specified\n");
return first;
}

1* Position found. So, delete the node *1


prev->link = cur->link; 1* Establish link between the
predecessor and successor *1
freenode( cur); 1* Delete the node with info key */
return first; 1* Return address of first node *1
}

9.3.11 Concatenate two lists

Now, let us see "What is concatenation of two lists?"

Definition: Concatenation of two lists is nothing but joining the second list at the end
of the first list.

Design: Concatenation of two lists is possible if two lists exist. If one of the lists is
empty, return the address of the first node of the non-empty list as shown below:
if (first = NULL) return second;
if (see = NULL) return first;

If both lists exist, obtain the address of the"last node of the first list and attach this to
the first node of the second list as shown in figure 9.3.1l. The code to obtain address
of the last node of the first list is shown below:
cur = first;
while (cur->link != NULL) I*Traverse till the end *1
{
cur ~ cur->link;
}
Once control comes out of the loop, pointer cur contains address of the last node of
the first list (see the figure below). Now, attach address of the first node of the second
list identified by second to cur node as shown in red line. The code corresponding to
this can be written as
cur->link = second;
Q Systematic Approach to Data Structures using C - 9.47

Now, first contains the address of the first node of the concatenated list and return
this node to the calling function using the statement:

return first;

Fig. 9.3.11 Concatenation of two lists

Thecorresponding C function is shown below:

Example 9.3.11.1: Function to concatenate two lists

ODE concat (NODE first, NODE see)


{
NODE cur; /* holds the address of the last node of first list"

if (first == NULL) return second;

if (see = NULL) return first;

/* Obtain address of the last node of first list*/


cur = first;
while ( cur->Iink != NULL)
{
cur == cur->link;

cur->Iink = sec; /* Attach first node of second list to end of 1irst list */

return first; /* Return the first node of the concatenated list ~/


9.48 Q Linked Lists

9.3.12 Reverse a list without creating new nodes


Let us concentrate on another operation namely reversing a linked list. Consider the
list shown in figure 9.3.12.a. After reversing, the first node becomes the last node,
second node becomes the last but one node and so on. Finally, the last node becomes
the first node. All existing links of the list shown in figure 9..3.12.a are reversed to
01?tainthe reversed list as shown in figure 9.3.12.b.

(a) before reversing

(b) After reversing


Fig. 9.3.12 Linked list before and after reversing

The C function to reverse a linked list is shown in example 9.23.


Example 9.3.12.1: Function to reverse a list
NODE reverse ( ODE first)
{
ODE cur, temp;
cur = ULL; /* Initial reversed list */
while (first != NULL)
{
temp = first; /* Hold part of the list not yet reversed*/
first' = first->link; /* The node marked in above step will be reversed*/
/* So it is updated to point to the list to be reversed */
temp->link = cur; /* The node marked for reversing is */
/* linked to the partial reversed list */
cur = temp; /* Points to the partial revered list */

return cur; /* Contains address of the reversed list */


Q Systematic Approach to Data Structures using C - 9.49

9.3.13Insert a node at the specified position


In an ordered linked list an item is inserted at the appropriate position so that the list
remains in ascending order. If item to be inserted is less than the first element, the
item is inserted in the beginning of the list. If item to be inserted is larger than all
items present in the list, that item will be inserted at the end of the list. Otherwise,
somewhere in the middle at the appropriate position the item is inserted with the
condition that the list remains ordered. For details, the reader can refer section 9.3.7
(page9.34) for creating an ordered list. The same logic with minor modifications can
be used to insert an item at the specified position. The C function to insert an item at
thespecified position is shown below:

Example 9.3.13: Function to insert an item at the specified position


NODE insertposfint item, int pos, NODE first)
{
NODE temp; 1* Node to be inserted *1
NODE prey, cur; 1* A node is inserted between these two nodes *1
int count; 1* To find the exact position to insert an item *1
temp = getnodet); r obtain a node to be inserted *1
temp->info = item;
temp->link = NULL;
if ( first = NULL && pos = I) 1* Inserting the node for the first time *1
return temp;
if (first = NULL) 1* Check for empty list *1
{
printf("Invalid position\n");
return first;
}
if (pos == 1 ) 1* Insert the node at the front of the list *1
{
temp->link = first;
return temp;
}
1* Find the appropriate position *1
count = 1;
prev = NULL;
cur = first;
9.50 Q Linked Lists

while ( cur != NULL && count != pos )


{
prev.= cur;
cur = cur->link;
count++;
}
if ( count = pos ) /* If valid position, insert the node */
{
prev->link = temp;
temp->link = cur;

return first;
}
printf(" Invalid position\n");
return first;
}

9.3.14 Priority queue using linked lists

A priority queue can be implemented by using an unordered linked list and an ordered
linked list as well. Using an unordered linked list, an ascending priority queue can be
implemented by selecting a node with least value and then deleting it from the list. To
implement a descending priority queue, select a node with highest item and delete that
node.
A priority queue can also be implemented using an ordered linked list. If the
elements of the list are in ascending order, deleting a node from the front end results
in ascending priority queue. Here, a node containing a least item is considered to be a
node with the highest priority and that is the node to be deleted first. To implement a
descending priority queue, create an ordered ·list in descending order and delete from
the front end. Here, a node with highest item is considered to be a node with the
highest priority and that is the node to be deleted first.

9.3.15 Non-homogenous lists

Let us see "What is non-homogenous list?"

Definition: A linked list with two or more fields with different data types IS
considered as non-homogenous list.
Q Systematic Approach to Data Structures using C - 9.51

For example, in the linked lists so far we have seen, the type of info field of each node
in the list was integer. But, the data type can be float? double or array of characters of
real or any other complex entity. For example, to store the student names,
corresponding id's and semester using a linked list, we can have the following
declaration

struct student
{
char name[lO];
int id;
int sem;
struct student * link;
};

typedef struct student * STUDENT;


Here, the student details such as name, id and semester are the inputs. Let us provide
the facilities to:
• Enter the student details and insert a node at the front end/rear end/at the
specified position.
• Delete all the details of a student based on a given id.
• Search a node based on student id and update the information content.
• To display full details of a student after searching for a given id.

By looking at the problem description, the operations to be supported are


• insert front( char name[], int id, int sem, STUDENT first) i.e., to insert
student details from the front end
• insert rearrchar name[], int id, int sem, STUDENT first) i.e., to insert student
details from the rear end
• insertpostchar name[], int id, int sem, int pos, STUDENT first) i.e., to insert
student details at the specified position.
• delete_student (int id, STUDENT first) i.e., to delete the student details given
an id
• search(int id, STUDENT first,) i.e., to search for the existence of a student
based on id and update
• display(STUDENT first) i.e., to display all the student details

The pointer variable first points to the first node of the list where each node of the list
contains unique information of a student. All the basic operations of this problem are
already discussed and the code for this is shown below:
9.52 Q Linked Lists

Example 9.3.15.1:Function to get a node from the availability list

STUDENT getnode(void)
{
STUDENT x;

x = ( STUDENT) malloctsizeoflstruct student));


if(x = NULL )
{
printf("Out of memory\n");
exit(O);
}
'- return x;
}

Example 9.3.15.2:Function to return node to availability list

void freenode(STUDENT x)
{
freetx);
}

Example 9.3.15.3:Function to insert at the front end

STUDENT insert_front(char name[], int id, int sem, STUDENT first)


{ .
STUDENT temp;

temp = getnodet); 1* Obtain a node *1

1* Insert the student information into the node *1


strcpy( temp->name,name);
temp->sem=sem;
temp->id = id;
temp->link = first;

1* Created node is made the first node *1


first = temp;
return first;
Q Systematic Approach to Data Structures using C - 9.53

Example 9.3.15.4: Function to insert at the rear end

STUDENTinsertJear(char name[], int id, int sem, STUDENT first)


{
STUDENT temp; /* Node to be inserted */
STUDENT cur; /* To hold the address of the last node */

1* Obtain the node to be inserted and copy the item*/


temp = getnodet);
strcpy(temp->name, name);
temp->id = id;
temp->sem = sem;
temp->link = NULL;

1* Return new node created as the first node iflist is empty *1


if ( first = NULL) return temp;

1* If list exists, obtain address of the last node *1


cur = first;
while ( cur->link != NULL)
{
cur = cur->link;
}

cur->link = temp; /* Insert the node at the end *1

return first; 1* return address of the first node *1

Example 9.3.15.5: Function to insert item into specified position linked list

STUDENT insertpost char name[], int id, int sem, int pos, STUDENT first)
{
STUDENT temp; 1* Node to be inserted */
STUDENT prey, cur; 1* A node is inserted between these two nodes *1
int count; 1* To find the exact position to insert an item *1

1* obtain a node to be inserted */


temp = getnodet);
9.54 Q Linked Lists

1* Insert the student information into the node *1


strcpy( temp->name, name);
temp->id = id;
temp->sem = sem;
temp->link = NULL;
if ( first = NULL && pos = 1) 1* Inserting the node for the first time *1
return temp;
if (first = NULL)
{
printf("Invalid position\n");
return first;
.-}

if (pos = 1 ) 1* Inserting the node in the beginning of the list *1


{
temp->link = first;
return temp;
}
count = 1; 1* Find the appropriate position */
prev = NULL;
cur = first;
while ( cur != NULL && count != pos) 1* Find the valid position *1
{
prey = cur;
cur =cur->link;
count++;
}
if ( count = pos ) 1* If valid position, insert node *1
{
prev->link =temp;
temp->link = cur;

l
return first;
}
printf("Invalid positionvn");
return first; 1* return the first node *1
}
Q Systematic Approach to Data Structures using C - 9.55

Example 9.3.15.6: Function to delete student details of an id specified

STUDENT delete_student(int id, STUDENT first)


{
STUDENT prev,cur;

if ( first = NULL)
{
printf("No students in the organization\n");
return NULL;
}

1* Compare one after the other *1


prev=NULL;
cur = first;
while ( cur != NULL && id != cur->id )
{
pre v = cur;
cur = cur->link;
}

if ( cur = NULL) 1* id specified is invalid *1


{
printf("Student Id not found\n");
return first;
j}

Of( prey = NULL) 1* to delete the first student *1


first = first->link;
else
prev->link = cur->link; 1* to be deleted is in middle or end *1

free(cur);

return first; .
9.56 Q Linked Lists

Example 9.3.15.7: Function to search for the student details based on id

STUDENT search(int id, STUDENT first)


{
STUDENT cur;
ehar name[20];
int sem;

if (first = NULL)
{
printf("No students in the organization\n");
return NULL;
}

1* Compare one after the other *1 .


cur = first;
while ( cur != NULL)
{
if (id = cur->id) break;
cur = cur->Iink;
}

if ( cur = NULL) 1* Student id not four, ~/


{
printf("Student with id %d not found\n",id);
retu rn first;
}

printf("Student found with following informationin'');


printf("Name: %s\nJD : %d\n Sem: %d\n", cur-e-name, cur->id, cur->sem);

printf("Name : "); seanf(" %[/\\n]",name);


1 printf "Jd : "); seanf("%d" ,~id);
printf("Sem : "); seanf("%d",&sem);
Q Systematic Approach to Data Structures using C - 9.57

/* Update the student information */


strcpy( cur->name, name);
cur->id = id;
cur->sem = sem;

return first; /* Return address of the first node */

Example 9.3.15.8: Function to display the information of a student

void display(STUDENT first)


{
STUDENT temp;

if ( first = NULL)
{
printf("No students in the organization\n");
return;
}

printf("Student Name Student 10 Semester\n");


prln. tf'("
l' -------------------------------------------- \n")',

for ( temp = first; temp != NULL; temp = temp->iink)


printf("%10s %4d %4d\n",temp->name, temp->id, temp->sem);

printf("\n");

Example 9.3.15.9: C Program to add/delete/search student information

f1inciullc <stdio.h>
flindlldc <alloc I -.
/Ii,lclllcle <proeess.h>
I!incillclc (.Sir'io8,11 .

/
9.58 Q Linked Lists

struct student
{
char name[20];
int id;
int sem;
struct student* link;
}~
typedef struct student* STUDENT;

:::,...tncludc:Example 9.3.15.1: Function to get a node from the availability list */

* Include: Example 9.3.15.2: Function to return node to availability list */

::v1nc1ude:Example 9.3.15.3: Function to insert at the front end */

"<Include: Example 9.3.15.4: Function to insert at the rear end*/ r

"<lnclude: Example 9.3.15.5: Function to insert item into specified position */

/':o1ilc1ude:Example 9.3.15.6: Function to delete student details of an id specified */

*(1nclude: Example 9.3.15.7: Function to search for the studen 0 0 ril based on id*/

/* Include: Example 9.3.15.8: Function to display the information of a student*/

void maint)
{
0-

STUDENT first = NULL; i'

int choice, id, sem, pos;


char name[lO];

for (;;)
{
prtntf'("l .Insert front 2: Insert Rearm");
printf(lf3:Insert at position 4: Delete'n");
printf(lf5:Search 6: Displayvn");
printf(lf7:Exit\nlf);
printffEnter the choicein'');
scanf(If%dlf ,&choice);
Q Systematic Approach to Data Structures using C - 9.59

if (choice = 1 /I choice = 2 /I choice = 3)


{
printf("Name : "); scanf(" %["\n:]",name);
printf("Id : "); scanf("%d" ,&id);
printf("Sem : "); scanf("%d" ,&sem);
}

switch( choice)
{
case 1:
first = insert_front(name,id,sem,first);
break;

case 2:
first = insert reartnamc.id.sem.first);
break;

case 3:
printf("Enter poistion to insert the entry\n");
scanf("%d" ,&pos);

first = insertyos(name,id,sem,pos,first);

break;

. case 4:
printf("Delete student details for ID :");
scanf("%d" ,&id);

first = delete_student(id, first);

break;

case 5:
printf("Search with ID :");
scanf("%d" ,&id);

search(id,first);
.', .' break;
9.60 Q Linked Lists

case 6:
display( first);
break;
default:
exit(O);
}
}
}

9.3.16 Implementation of lists using arrays

The previous sections describe how a singly linked list can be represented in C and in
othersections we have seen how lists can be traversed(i.e., visiting each node) and
manipulated using links between the nodes. This section describes the way to
represent a linked list using an array. In this case, an array is considered to be a
collection of nodes. Each node-has two fields, info and link as discussed earlier.
Consider the list shown in fig.9.3.16.a. This list can be stored in an array L as
shown in fig. 9.3.16.b. Note that each location in this array has two fields, info and
link. The variable first is used as an index variable from which different nodes can be
accessed. In fig. 9.3.16.b, the initial value of index variable first is 2. The first item
20, in this location can be accessed using L[2].info. The index of the next item is
stored in L[2].link which in this case is O. Using this index value 0, the next item
L[O].info i.e., 45 can be obtained. The next item can be accessed by the index
obtained li'OI11 L[O].link i.e., 4. L[4].info gives 10 and so on. Proceeding this way all
the items 20, 45, 10; 80 and 50 can be accessed.

first
~mJ3-[@]3--~~
(a)

index info link


45 4

first -m~
L 3
4
50 -I
20 0
80 I
10 J

(b)
Figure. 9.3.16 Array representation of a linked list
Q Systematic Approach to Data Structures using C - 9.61

index info link

avair-,c+O
I
2
first =-1 3
indicates user list is empty L ~

BE
initially.

(a) 99 -I

index info link


index info link

fi,,' ~
m
0
-0 30 I
I
I 40 2 2
, 2 avail
20 -I 3
,
.
L ,
i
!

(b)
99 EfB -I

first ---:... 0

x--:..
.
avail
~.....
....
index info link

'
1
30
40
20
I
2 .....................................
-I .... avail--+'~3
L
o
1
-................ 2

i
.r !
c=ho
(c) 99 CIIJ
index info link

first_o
index info link
~
'0
1 Bp
I~ avail_~

L
2
3 BE ,
,
cJ98l
99 CIIJ
(d)
Fig.9.3.17 Array representation of linked list
9.62 Q Linked Lists

In general, given an index i, L[i].info gives the actual data and L[i].link gives the
index of the next item. If L[i].link has the value -1, then end of list is reached. If an
index variable i has-the value 1, L[i].link has the value -1 indicating it is the last node
and the last item 50 can be accessed using L[i].info. An availability list L, which is an
array of free nodes can have the following structure:

typedef int NODE;

struct node
{
int info;
NODE link;

.where info field contains the actual information and link field contains the index of
the next node and is of type NODE (since index is an integer, NODE is defined as int
using typedef). We use an array L to represent the availability list and the index
variable avail, which contains 0; the index of the first free node in the list L. Assume
L and avail are global variables. Assume the size of the availability list is
MAX_SIZE. The initial organization of the availability list is

avail = 0;

fore i = 0; i < MAX_SIZE-l; i++)


{
L[i] = i+1;
}

L[MAX_SIZE-l].link = null;

Note that null can be defined as -1. If L[i].link is null i.e., -1, then the node
corresponding to the index i is the last node. The pictorial representation of the
availability list is shown in fig.9.3.17.a.
To insert an item, a node has to be obtained from the availability list. Note that
initia value of the global index variable avail is O. So, the node at the index 0 is
returned if there is a request from the user. Once the node is returned, avail should
point to the next free node. This can be achieved by accessing the link field of avail
and assigning this back to avail. In linked list representation this can be achieved by
specifying avail = avail->link. But, using an array representation, this can be
achieved by the following statements.
Q Systematic Approach to Data Structures using C - }:?~

x = avail;
avail = L[avail].link;
return x;

In the linked list while updating the pointer variable, it may point to NULL, indicating
last node in the list is reached. In this representation, while updating avail, this may
point to null, which in this case is -1. If avail has the value -1, it indicates that
availability list is empty and memory cannot be allocated. The function to allocate
memory is shown below:

Example 9.3.16.1: Function to allocate memory to implement linked lists usrng


arrays

NODE gctnode(void)
{
NODE x;

if ( avail = null )
{
printf(tlOut of memoryvn");
cxit( 1);

x = avail;
avail= L[avail].link;

return x;

Suppose3 items 30, 40 and 20 are inserted into the list in the same order. The user list
anti the availability list is shown in fig.9.3.17.b. Note that the index variable first
containsthe index of the first item i.e., 30.
To delete a node and to return this to the availability list, consider the array
shown in fig.9.3.17.c. Suppose x is the node to be returned to the availability list-
Then, the node x should be the first node in the availability list and avail should point
tox, so that when a new node is requested, the node just returned to the availability
listcan be re used. This can be achieved by assigning avail to link field of the noele to
be deleted i.e., x and then assigning x to avail. After deleting the node x, the resulting
9.64 Q Linked Lists

user list and the availability list is shown in fig.9.3.17.d. The C function to return a
node to the availability list is shown below:

Example 9.3.16.2: Function to return a node to the availability list using arrays

void freenode(NODE x)
{,
L[x].link = avail;
avail = x;

return;

'-

Given an array representation of a linked list, we see how to implement deques. The
algorithm remains same. But, in the program, instead of using pointers and dynamic
variables, we use an array representation. Note that to access info field of a node x, in
linked representation we use the notation x->info where as in the array representation
we use the notation L[x] .info. The complete program to implement deques using an
array representation of a linked list is shown below:

Example 9.3.16.3: Deque using an array representation of a linked list

#inc1ude <stdio.h>
#inc1ude <process.h>

#defme MAX SIZE 100


#define null -1

typedef int NODE;

struct node
{
int info;
NODE link;
};
1

struct node L[100]; 1* Global variables *1


NODE avail;
,!;l Systematic Approach to Data Structures using C - 9.65
void freenode(NODE x)
{
L[x].link = avail;
avail = x;

return;

void initialize( void)


{
NODE i;

avail = 0;

for (i = 0; i < MAX_SIZE-I; i++)


{
, L[i].link = i+ 1;
}

L[MAX SIZE-I] .link = null;

NODE getnode(void)
{
NODE x;

if ( avail = null )
{
printf("Out of memory\n");
exit(1);
}

x = avail;
avail = L[avail].link;

return x;
9.66 Q Linked Lists

void display(NODE first)


{
NODE tcmp;

if ( first =-~null )
{
printf("List is cmpty\n");
return;
}

printf("Contents of dcque is\n");


temp = first;
.. while (tcmp != null)
{
printf("%d ",L[tcmp].info);
;,-temp = L[temp ].link;
}
printf("\n");

1* function to insert item at the rear end *1


NODE inscnjcartint item, NODE first)
{
NODE cur,temp;

temp = gctnoder);
L]temp]. info = item;
L[temp].link = null;

if ( first == null) return temp;


cur = first;
while ( L[ cur].link != null )
{
cur = L[cur].1ink;
}

L[cur].link = temp;

return first;
}
Q Systematic Approach to Data Structures using C - 9.6~

1* function to delete an item from the rear end */


NODE delete_Jcar(NODE first)
{
NOD}~ cur, prey;

if ( first == null )
{
printf("List is empty\n");
return first;
}

prey = null;
cur = first;
while (L[ cur].link != null)
{
prcv = cur;
cur = L[cur].link);
}

printf("The item deleted is %d\n",L[cur].info);


freenodet cur);

if ( prey = null )
first = null;
else
L[prcv].link = null;

return first;

'*ODE
function to delete an item at the front end */
dcletc_1i"ont(NODE first)
{
NODE temp;

if ( first == null )
{
printf("List is empty\n");
retu rn first;
9.68 Q Linked Lists

temp = first;
first = L[ first].link;
printf("The item deleted is %d\n",L[temp].info);
freenode( temp);
return first;
} .
/*function to insert item at the front end */
NODE insert_front(int item, NODE first)
{
NODE temp;
.. temp = getnodet);

L[temp].info = item;
L[temp].link = first;
return temp;
}

void maim)
{
NODE first = null;
int choice, item;
initializet);

for (;;)
{
printf("l:Insert front 2:Insert rear\n");
printf("3:Delete front 4:Delete rear\n");
printf("5:Display 6:Exit\n");
printf("Enter the choice\n");
scanf("%d",&choice);
switch ( choice)
{
case 1:
printf("Enter the item to be inserted\n");
scanf("%d",&item);
first = insert_front(item,first);
break;
Q Systematic Approach to Data Structures using C - 9.69

case 2:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
first = insert_rear(item,first);
break;
case 3:
first = delete _front(first);
break;

case 4:
first = deletereanfirst);
break;
case 5:
display(first);
break;
default:
exit(O);
}
}

Note: Compare this program with the program given in example 9.11. All statements
are same. The only difference is that, if x is the address of the node then in the linked
representation link (x) and info(x) can be accessed using the statements

x->link and x->info

In an array representation the corresponding fields can be accessed using

L[x].link and L[x].info

It is left to the reader to implement rest of the programs on linked lists using an-array
representation.

Now, we should be in a position to answer the question "What are the drawbacks of
using sequential storage (arrays) to represent stacks and queues?". The various
drawbacks are listed below:
• A fixed amount of storage is allocated: The compiler allocates only specified
number of memory locations for stacks and queues. If more memory is allocated
9.70 Q Linked Lists

but using only small amount of memory results in wastage of memory space. II'
less memory is allocated when we insert more items, there is possibly of ovcrl1ow
• Items are stored contiguously: Some times enough contiguous memory locations
may not be available. There are situations where a number of chunks 01
contiguous memory locations are available. Even though the total free memory
space is sufficient, this space cannot be used since stack items and queue items
. require contiguous storage space.

Now, let us see "What are the drawbacks of representing a stack or a queue using
linked list?"The various drawbacks are listed below:
• A node in a linked list may have two or more tields and naturally occupies more
storage space than the corresponding element in the array.
• Accessing the data related to stack or a queue is much slower using linked list
since additional time is spent in managing the available list. Only when required
memory is allocated. So, time is required to get a node ti"OI11 the available list.
When a node is returned using free, the unused node has to be added to the
beginning of available list. Thus, each addition and deletion of an clement
involves corresponding deletion and addition in available list.

9.4. Static allocation Vs Linked allocation

Now, let us see "What are the differences between static allocation and linked
allocation?"The differences are listed below:

Static allocation technique Linked allocation technique


l. Memory IS allocated during 1. Memory IS allocated during
compilation time execution time

2. The size of the memory to be 2. As and when memory is required,


allocated IS fixed during memory can be allocated. Ir not
compilation time and can not be required, memory can be de-
. altered during execution time allocated. The size or the memory
required may vary during execution
time.
-
3. Used only when the data size IS 3. Used only for unpredictable
fixed and known in advance before memory requirement.
processing
.~ I
Q Systematic Approach to Data Structures using C - 9.7l

4. Execution is faster, since memory is 4. Execution is slower since memory


already allocated and data has to be allocated during run time.
manipulation IS done on these Data manipulation is done onl y
allocated memory locations after allocating the memory.

5. Memory is allocated either in stack 5. Memory is allocated only in heap


area (for local variables) or data area
area (for global and static
variables).
6. Data accessing is very fast and is 6. Data accessing is very slow. Data
done by specifying the array name stored in the beginning of the list
along with index. Time take to can be accessed very fast. But, to
access a[O] and a[ 1000], in general access any other data, the list has to
a[i] is same. be traversed and definitely requires
more time
7. It is difficult to insert or delete the 7. The data can be inserted anywhere
data in the beginning or middle of in the list. Addition or deleting of a
the array. First, we have to make a node is done just by manipulating
room by copying the items into the links.
successive locations and then insert.
While deleting an item, the
subsequent elements should he
copied into previous locations.
8. If we can predict the size of the data 8. If the size of the data can not be
or if the size of the data is known in predicted or number of items to be
advance, then it is better to go for inserted is not known in advance,
static allocation then it is better to go for linked
allocation
9. For n items only n memory 9. For n items, apart from n memory
locations are allocated locations extra memory required for
each node to store the addre~f the
next node. So, more memory space
is used for n items when compared
with arrays.

ote: For certain operations and applications linked allocation is more useful ail I
efficientand for some other operations and applications sequential allocation is mor.:
usefuland efficient. So, it is the responsibility of the programmer to choose the cI~![;!
structuresproper! y for the efficient utilization of the resources.
9.72 Q Linked Lists

EXERCISES

1. Write a C function which will perform an insertion to the immediate left of the klh
node in the singly linked list.
2. Write a C function to count the number of nodes' in a singly linked list. . - '
3•. Write a C function to change theinfo field of the k" node to the value given by X.
4. Write a C function to concatenate two lists into a single list.
5. Write a C function to reverse a given. singly linked list without creating new
nodes.
(l. Write a C function search(p,x) that accepts a pointer p to a list of integers and an
integer x and .rctums a pointer to a node containing x, if it exists, and the NULL
pointer otherwise.
7. Write a C function srchinsrt(p,x) that adds an item x to the list pointed-to by p,
provided x is not in the list. Insertion can be done at the front end or rear end.
8. Write a C function to delete a node from the front end and insert it at the-end of
the list.
9. Write a recursive program to implement the following functions.
a. To insert an item into an ordered singly linked list
b. To insert an item into an ordered doubly linked list
c. To display the contents of singly linked list
d. To display the contents of doubly linked list
e. To search for a specific node.
f. To find the union of two linked lists
g. To find the intersection of two linked lists
h. To delete a node in a singly linked list whose position is specified

1
Q Systematic Approach to Data Structures .uslag C.,. 9;7~

Chapter 9: Other List structures' :.;~


..
9.5 Circular sib-gly linked list, .

Note: IQ singly linked .list that we have discussed earlier, note that link field of las
node contains \0 (null) indicating there are no more nodes from this point onwards.

Now, let us see "What are the disadvantages of singly linked lists?" The variou:
disadvantages of singly linked lists are listed below: ,
• In a singly linked list, there is only one link field and hence traversing (visitin]
each node) is done only in one direction. So, given the address of a node x, onh
those nodes which' follow x are teachable but, the nodes 'that precede x are nr
reachable. To reach the nodes that precede x, it is required to preserve a pointe
first which contain the address of the first node of the list. .

Note: Since traversing is only in one direction, singly linked lists are also caller
one W~ly lists. '

• To delete a designated node cur, address of the first node of the list should b
provided. This is necessary because, to delete node cur, the predecessor of thi:
node has to be found. For this, search has to begin from the first node ofthe list.

These disadvantages can be overcome using special type of list called circular list
Now, let us see "What is circular list?"

Definition: In singly linked list, the link field of the last node contains \0 (null)
Instead of storing \0 in the link field. of last node, a number of advantages can be
gained if link field of the last node contains starting address of the first node. Such l
list is called circular list. In general, a circular list is a variation of ordinary linked Ii:
in which link field of the last node contains address of the first node.

This list is primarily used in structures that allow access to nodes in the middle
of the list without starting from the first node. The' pictorial representation of l
circular list is shown below:
9.7~ Q Linked Lists

Fig. 9.5.1 Circular singly linked list

Now.Jet us see "What are the advantages of circular lists?" The various advantages of
circular list are shown below: . . -
• Every node is accessible from agiven node by traversing successively using the
link . field .
• To delete a node cur, the address of the first node is not necessary (but it is
•. • •• ." •• < J

necessary in singly linked list). Search tor the predecessor of node cur, can be
initiated from cur itself.
• Certain operations on circular lists such as concatenation and splitting of lists etc.
will be more efficient

Now, let us see "What is the disadvantage of circular list?"

In singly linked list, the link field of last node contains \0 (null) designating end of
list. But, in circular list, this \0 is replaced by the address of the first node of the list.
There is no special indication to find which is the last node. So, some care has to be
taken during processing. The disadvantage 0 f these circular lists is that if proper care
is not taken it is possible that we may end up in an infinite loop unless we detect the
end ofthc list. In circular list, it is very important to detect the end of tile list.

Since the list is circular, any node can be considered as first node and its predecessor
is considered as last node. The following two conventions can be used: .
• Approach 1: A pointer variable first can bc used to designate the starting point of
the list. Using this approach, to getthe address of the last node, the entire list has
to be traversed from the first node. The pictorial representation of the circular list
using this approach is shown in figure. 9.5.1 (see top of this page)
Q Systematic Approach to Data Structures using C- 9.75

• Approach 2: In the second technique,' a pointer variable last can be used to


designate the last node and the node that follow last, can be designated as the first
node of the list. The pictorial representation of the circular list using this approach
is shown below: .'

Fig. 9.5.1 Circular singly linked list.

Observe from the above figure that, given pointer last which points to last node, by
using link field of last node, i.e, last->link, we can get the address of the first node.

Note: link field oflast gives address of first node. So, we use the second approach in
our discussions for convenience.

Whatever operations are possible using singly linked lists, all those operations can be
performed using 'circular lists also. .

A circular list can be used as a stack, queue or a dequeue (double ended queue). To
implement these data structure we require the following functions:
• insel·t_fron~- To insert an clement at the front end of the list
• lnsertjrear - To insert an element at the rear end of the list
• delete_front _. To delete an clement from the front end of the list
• dclete_rear - To delete an' element from the rear end of the list
• display - To display the contents of the list

9.5.1 Insert a node at the front end

Now,let us see "How to insert a node at the front end of the list?"
Design: To design the function easily, let us consider a list with 4 nodes. Here,
pointer last contains address of the last node of the list. Let us try to insert an item at
thefront end of the list. The sequence of steps to be followed are shown below:
9.76 Q Linked Lists

(a)
last@

(b)
Fig. 9.5.1.1 To insert at the front end

Note: The modifications are shown in gray color

Step 1: To insert an item 50 at the front of the list, obtain a free node temp from the
available list and store the item in info field as shown in figure (gray color). This can
be accomplished using the following statements
temp = getnodet);
temp-e-info = item;
.
Step 2: Copy the address of the first node(i.e., last->Iink) into link field of newly
obtained node temp and the statement to accomplish this taskis
temp->link = last->Iink;

Step 3: Establish a link between the node temp and the last node. This is achieved
by copying the address of the node temp into link field of node last. The
corre ponding code for this is
last->link = temp;

Step 4: Finally, we return address of the last node using the statement:
retu rn last;
~ Systematic Approach to Data Structures using C - 9.7'

The above steps have been designed by assuming that the list is already existing. I
the list is empty, make temp itself as the node last and establish a link between th:
first node and the last node. The C function to insert an item at the front of thl
circular linked list is shown below:

Example 9.5.1.1 Function to insert an item at the front end of the list

NODE insert _front(int item, NODE last)


{
NODE temp;

temp = getnodet); /* Create a new node to be inserted *1


temp->info = item;

if ( last = NULL) 1* Make temp as the first node *1


last = temp;
else
temp->link = last->link; 1* Insert at the front end *1

last->link = temp; 1* link last node to first node *1

retu rn last; 1* Return the last node *1

9.5.2 Insert a node at the rear end

Now, let us see "How to insert a node at the rear end of the list?"
Design: To design the function easily, let us consider a list with 4 nodes. Here,
pointer last contains address of the last node of the list. Let us try to insert an item at
the rear end of the list. The sequence of steps to be followed are shown below:

Let us insert the item 80 at the end of this list. Follow the steps shown below to insert
an item at the rear end of the list.

Step 1: Obtain a free node temp from the availability list and store the item in info
field as shown in figure below. This can be accomplished using the following
statements

temp = getnodei);
temp->info = item;
9.78 Q Linked Lists

(b)
Fig. 9.5.2.1 To insert at the rear end

Step 2: Copy the address of the first node(i.e., last->link) into link field of newly
obtained node temp and the statement to accomplish this task is

temp->link = last->link;

Step 3: Establish a link between the newly created node temp and the node last. This
is achieved by copying the address of the node temp into link field of node last. The
corresponding code for this is

last->link = temp;

Step 4: The new node is made as the last node using the statement:
return temp;

These steps have been designed by assuming the list is already existing. If the list is
empty make temp itself as the first node as well as the last node. The C function for
this is shown below:
Q Systematic Approach to Data Structures using C - 9.79

Example 9.5.2.1: Function to insert an item at the rear end of the list

NODE insert_rear(int item, NODE last)


{
NODE temp;

temp = getnodet); 1* Create a new node to be inserted *1


temp->info = item;

if ( last - NULL) 1* Make temp as the first node *1


last = temp;
else
temp->link = last->link; 1* Insert at the rear end *1
last->link = temp; 1* link last node to first node *1
return temp; 1* Make the new node as the last node. *1

Note:Compare the functions insert_frontO and insertreart). All statements in both


the functions are same except in return statement. In insert_ frontt), address of last
node is returned and in the function insert _rearO address of the new node is returned.

9.5.3 Delete a node from the front end


Now, let us see "How to delete a node from the front end of the list?"
Design: To design the function easily, let us consider a list with 5 nodes. Here,
pointer laft contains address of the last node of the list. Let us try to delete an item at
thefront end of the list. The sequence of steps to be followed are shown below:

fil'StG)

Fig. 9.5.3.IDelettng at the front end


9.80 ~ LinkedLists

Step 1: first = last->link; 1* obtain address of the first node *1


Step 2: last->link = first->link; 1* link the last node and new first node *1
Su p 3: printf ("The item deleted is %d\n", frrst->info);
freenode(first); I*delete the old first node *1

Now, the node first is deleted. These steps have been designed by assuming the list is
already existing. If there is only one node, delete that node and assign NULL to last
indicating the list is empty. The code corresponding to this is can be

1* If there is only one node, delete it *1


if ( last->link = last)
{
printf("The item deleted is %d\n", last->info);
freenode(last) ;
last = NULL;
return last;
}

All these steps designed so far have to be executed provided. the list is not empty. If
the list is empty, display the appropriate message. The complete code to delete an
item from the front end is shown below:

Example 9.5.3.1: Function to delete an item from the front end

NODE delete _front(NODE last)


{
NODE temp, first;

if ( last =. NULL ) 1* Check for empty list *1
{
printf("List is empty\n");
return NULL;
}

if ( last->link = last) 1* Delete if only one node *1


1 {

printf("The item deleted is %d\n", last->info);


freenode(last) ;
return NULL;
}
Q Systematic Approach to Data Structures using C - 9.81

1* List contains more than one node *1


first = last->link; 1* obtain node to be deleted *1
last->link = first-c-link; I*Store new first node in link of last *1
printf("Item deleted is %d\n", first->info);

freenode( first); 1* delete the old first node *1


return last; 1* return always address oflast node *1

9.5.4 Delete a node from the rear end


Now, let us see "How to delete a node from the rear end of the list?"
Design: To design the function easily, let us consider a list with 5 nodes. Here,
pointer last contains address of the last node of the list. Let us try to delete an item at
the rear end of the list. The sequence of steps to be followed are shown below:

Fig. 9.S.4.1Deleting at the rear end

Step 1:Obtain the address of the predecessor of the node to be deleted. This can be
accomplished by traversing from the first node till the link field of a node contains
address of the last node. The code corresponding to this is
prey = last->link;
while (prev->link != last)
{
prey = prev->link;
}
9.82 Q Linked Lists

Step 2: The first node and the last but one node( i.e., prev) are linked. This can be
accomplished using the statement
prev->link = last->link;
Step 3:The last node can be deleted using the statement
freenode(last );
Step 4: Return prey itself as the last node of the result using the statement:
return(prev);

All these steps have been designed by assuming that the list is already existing.
• If there is only one node, delete that node and assign NULL to the pointer variable
last indicating that the list is empty. The equivalent statements are:
if ( last->link = last) 1* Delete if only one node ./
{
printf("The item deleted is %d\n", last->info);
freenode(last) ;
return NULL;
}
• If the list is empty in the beginning display the appropriate message.
The C function to delete an item from the rear end of circular list is shown below:

Example 9.5.4.1: Function to delete an item from the rear end ; ..•.

NODE delete Jear (NODE last)


{
NODEprev;
if ( last = NULL) ,. Check if list is empty ./
{
printf("List is empty\n");
return NULL;
}

1if ( last->link = last) 1* Delete if only one node */


{
printf("The item deleted is %d\n", Iastc-info);
freenode(last);
return NULL;
}
Q Systematic Approach to Data Structures using C -
'C
prey = last->Iink; '* Obtain address of previous node */
while( prev->Iink != last)
{
prev = prev->Iink;
}

prev->link = last->Iink; /* prey node is made the last node */


printf("The item deleted is %d\n", last->info);
freenode(last); /* delete the old last node */
return prey; /* return the new last node *'

The C function to display the contents of circular list is shown below: The read
required to understand how the function is working.

Example 9.5.4.2: Function to display the contents of the circular queue

void display(NODE last)


{
NODE temp;

if ( last = NULL) /* Check for empty list */


{
printf("List is empty\n");
. return;
}

printf("Contents of the list is\n"); /* Display till we get last node 4

temp = last->Iink; .
while (temp != last)
{
printf("%d ",temp->info);
temp ~ temp->link;
}

printf("%d\n", temp->info); /* Display last node */


9.84 Q Linked Lists

The C program to implement deque using circular linked list is below:

Example 9.5.4.3: Program to implement deque using circular list

#include <stdio.h>
#include <alloc.h>
#include <process.h>

struct node
{
int info;
struct node * link;
};

typedef struct node" NODE;


! .

1* Include: Example 9.2.1.3: Function to get new node from the availability list *1
1* Include: Example 9.2.1.4:C Function to fi:ee a node to the availability list *1
1* Include: Example 9.5.1.1:Function to insert item at front end of the list *1
1* Include: Example 9.5.2.1:Fullction to insert item at rear end of the list *1
1* Include: Example 9.5.3.1:Function to delete an item from the front end *1
1* Include: Example 9.5.4.1:Function to delete an item from the rear end */.
1* Include: Example 9.5.4.2: Function to display the contents of the circular queue *1

void maint)
{
NODE last;
int choice, item;

last = NULL;

for (;;)
{
printf("l :Insert_Front 2:Insert_Rear\n");
printf("3:Delete _Front 4:Delete _Rear\n");
printf("5:Display 6:Exit\n'.');
printf("Entei the choice\n");
scanf("%d", &choice);
Q Systematic Approach to Data Structures using C - 9.85

switch( choice)
{
case 1:
printf("Enter the item to De inserted\n");
scanf("%d", &item);
last = insert_front (item, last);
break;
case 2:
printf("Enter the item to be inserted\n");
scanf("%d", &item);
last = insert_rear (item, last);
break;
case 3:
last = delete _front(1ast);
break;
case 4:
last = delete Jear(1ast);
break;
case 5:
display(last);
break;
default:
exit(O);
}
}

9.6Header Node
Before seeing what is a header node, let us ask one question ourselves "Have we
faced any problem when we manipulate the singly linked lists?" To answer this
question, consider the program to delete a node whose information field is specified
insection 9.3.9. Observe that during programming we have to take too many extreme
casessuch as:
• If list is empty what to do?
• If item to be deleted is present in the first node what to do?
• Otherwise what to do?

Wehave written the code for all these cases. If we have too many cases like this, the
lengthof the program will increase and naturally it will be difficult to read and
9.86 Q J :nked Lists

understand. So, it is better to minimize the number of checking for various cases like
this. This is possible with a special type of node called Header node. Now, we shall
see' \\'hat is a header node?"

lrefluitlon: A header node in a linked list is a special node whose link field always
contains address of the first node of the list. If list is empty, then link field of header
node contains \0 (null). The header node may have one or more links pointing to
di fferent types of linked lists. Using header node, any node in .the list can be accessed.
The info field of such a node usually does not contain any information and such a
node does not represent an item in the list. Sometimes, useful information such as,
n urn her 0 f nodes in the list can be stored in the info field.
For example, consider the list with a header node shown in figure below:

!:pHead~1 ---I0 (a)

I 13-1 G4 G4 [3-4 0 20 4S 10 80

(b)

Number of
nodes in list (c)

Fig. 9.6.1 Sin 1 linked list with header nodes

Observe the following points with respect to lists shown in above figure:
• Since the link field of the header node shown in figure 9.6.1.a contains \0, it
represent an empty list. .
• In figure 9.6.l.b, link field of a node contains address of the first node of the list
which has 4 items.
• The info field of header node in figure 9.6.1.c contains 4, which represents the
total number of nodes present. in the list. In such a case, there is an overhead of
altering the info field of this node. Each time a node is added or deleted, the count
in this field must be readjusted so as to contain actual number of nodes to be
accessed in the list.
Q Systematic Approach to Data Structures using C - 9.87

Now, let us see "What are the advantages of a list with a header node?" The
advantages of a header node are shown below:
• Simplifies Insertion and deletion operations
• Avoid the usage of various cases such as "if only one node is present what to do"
• Designing of program will be very simple (compare the program in section 9.3.9
and section 9.6.2 )
• Circular lists with header node are frequently used instead of ordinary linked lists
because many operations can be easily implemented

9.7 Circular list with a header node

Note: Given a header node, there is no need of a pointer variable that points to the
firstnode of the list or the last node of the list.

Now, let us see "What is circular singly linked list with header node?" In a circular
list with a header node, the link field of the last node contains address of the header
node and the link field of the header node contains the address of the first node.
Usually the info field of a header node does not contain any information. Sometimes,
some useful information such as number of nodes in the list can be stored.
Fore example, consider the list shown in fig.9. 7.l.a. The info field of this
header node contains 4, which is the number of nodes that can be accessed from the
header node. An empty circular list with a header node is shown in fig.9.7.l.b. When
the list is empty, the link field of a header node contains the address of itself.

(a)

(b)
Fig. 9.7.1 Circular singly linked list
9.88 Q Linked Lists

Let us see "What are the advantages of circular singly linked list with a header node?"
A circular list with a header node is very useful since some of the problems can be
solved very easily and efficiently.
For example, problems such as addition of long positive numbers, merging of
two ordered lists into a single ordered list etc. are much easier to design. In this
section let us concentrate on some problems that can be solved using a circular list
with a header node.
9.7.1 Insert a node at the front end

Now, let us see "How to insert an item at the front end?" Consider the circular list
with a header node shown in fig.9.7.1.1. Following the sequence of steps shown in
fig.9.7.1.1, an item 50 can be inserted at the front end of the list.
- -

Fig. 9.7.1.1. Insert item at the front of list

Step 1: Obtain a node from the availability list and store the item. The following
statements will do this job.
temp = getnodet);
temp->info = item;
Step 2: Establish a link between the newly created node pointed to by temp and the
first node. The corresponding code to accomplish this tusk is
temp->link = head->link;
Step 3: The newly created node pointed to by temp is made the first node by
establishing a link between header node and temp using the following statement.
head->link = temp;
Step 4: Finally return the address of the header node using the following statement:
return head;
Q Systematic Approach to Data Structures using C - 9.89

The complete C function is shown below:

Example 9.7.1.1: Function to insert at the front end of the list


NODE insert _front(int item, NODE head)
{
NODE temp;

temp = getnodet); 1* Create a node, insert the item *1


temp->info = item;
temp->link = head->link; 1* Insert at the front end *1
head->link = temp;
return head; 1* Return the header node */

9.7.2 Insert a node at the rear end

Now, let us see "How to insert an item at the rear end?" To insert an item at the rear
end of the list, it is necessary to obtain the address of the last node. This can be
achieved by traversing the list from the first node. An auxiliary pointer variable cur,
which initially points to the first node, can be used to traverse till the end. The
statements to accomplish this task are:
cur = head->link;
while ( cur->link != head)
{
cur = cur->link;
}
Once the address of the last cur is known, the node pointed to by temp can be easily
inserted by following the sequence of steps shown in figure 9.7.2.1. The steps to be
followed are shown below:
Step 1: Establish a link between the last node cur and the node to be inserted at the
end temp. This can be accomplished using the following statement
cur->link = temp;
Step 2: Establish a link between the new last node temp and the header node. This
canbe achieved by using the following statement.
temp->link = head;
Step 3: Finally return address of the header node using the following statement:
return head;
9.90 Q Linked Lists

Head

IPG)

Fig. 9.7.2.1 Insert an item at the rear

Note:" All these steps have been designed by assuming the address of the node to be
inserted i.e., temp is known. So, just before these steps, obtain the node to be inserted
and store the item.

The C function to insert an item at the rear end of the circular linked list is shown
below:

Example 9.7.2.1: Function to insert at the rear end of the list

NODE insert reartint item, NODE head)


{
NODE temp, cur;

temp = getnodet); 1* node to be inserted *1


temp->info = item;

cur = head->link; 1* obtain address of the last node *1


while ( cur->link != head)
{
cur = cur->link;
}

.• cur->link = temp; 1* inscrt at the end *1


temp->link = head;

retu rn head; 1* Return the address of the header */


}
Q Systematic Approach to Data Structures using C - 9.9!.
9.7.3 Delete a node whose info field is specified

Note: Refer section 9.3.9 for the details. As we discussed earlier in section 9.3.9, it is
required to search for the node whose info field is specified and obtain the address of
the node to be deleted along with its predecessor. So, two auxiliary pointer variables
prey pointing to the predecessor of the node to be deleted and cur pointing to the
node to be deleted are used. The search starts from the first node of list (head->link).
So, point cur to the first node and prey to header node initially. When cur finally
points to the header node, stop searching and indicate that the specified item is not
there in the list. Otherwise, delete the node. The C function for this is shown below:

Example 9.7.3.1: Function to delete a node whose info field is specified


NODE delete _item(int item, NODE head)
{
NODE prev,cur;
if ( head->link = head) 1* Check for empty list *1
{
printf("List is empty\n");
return NULL;
}
prey = head; 1* search for the item *1
cur = head->link;
while ( cur != head)
{ if (item = cur->info) break;
prey = cur;
cur = cur->link;
}

if ( cur = head) 1* Item not found *1


{
printf("Item not found\n");
return head;
}
prev->link = cur->link; 1* (kklc the node *1
freenode( cur);

return head; 1* Rctui n the header node *1


9.92 Q Linked Lists

9.7.4 Insert a node at the specified position


Note: Already discussed in section 9.3.13. But, because we are using header node, the
design becomes simple and more efficient. Now, let us see "How to insert an item at
specified position end?" Follow the sequence of operations:

Step 1: As in the previous problem, obtain the address of the cur node and prey
based on the position. We have to keep track of count to find the exact position. The
equivalent statements are shown below:

prey = head;
cur = head->link;
count = 1;
".while (cur != head)
{
if (count = pos) break;
prey = cur;
cur = cur->link;
count++;
}

Step 2: Check for the appropriate position. This IS done usmg the following
statement:
if (count != pos)
{
printf("Invalid position\n");
return head;
}

Note: If count is same as pos, it is valid position and it is required to insert a newly
created node between cur and prey as shown in figure 9.7.4.1

Step 3: /* obtain the node and insert the item */


temp = getnodet);
temp->info = item;

" Step 4 and 5: /* insert the newly created node between prey and cur */
temp->link = cur;
prev->link = temp;

Step 6: Finally, return the address of the first node of the list.
retu rn head;
Q Systematic Approach to Data Structures using C - 9.93

At 3rd position insert the node

Fig. 9.7.1.1. To delete a node at the specified position

The complete C function to insert an it~m at the specified position is shown below:

Example 9.7.4.1: Function to insert an item at the specified position

NODE insert ~osition(int item, int pos, NODE head)


{
NODE prev, cur, temp;
int i;
prev = head; /* find the appropriate position*/
cur = head->link, count = 1;
while (cur != head)
{
if (count = pos) break;
prev = cur, cur = cur->link;
count++;
}

if (count != pos) /* Invalid position */


{
printf("Invalid position\n");
return head;
}
9.94 Q Linked Lists

temp = getnodet); 1* obtain a node and insert item*'


temp-e-info = item;

. n \
prev->link = temp; /* Insert between prev an /
temp->link = cur;

return head;
}

9.7.5 Delete a node at the specified position

Note: Already discussed in section 9.3.10. But, because we are using header node, the
design becomes simple and complexity of the program will be simple.

Follow the sequence

Step 1: Check for empty list and display the appropriate messages usmg the
following code:
if (head->link = head)
{
hi
printf("List is empty\n");
return head;
3001'
}

Step 2: As in the previous problem, obtain the address of the cur node-to be deleted
along with its prev node (predecessor of cur node). For this we have to keep track of
counter to find the exact position. The equivalent statements are shown below:

prev = head; , . 10 ')li


cur = head->link; r ,f'Jlq
count = 1; r IJOJ

while (cur l= head)


{ I ,u li
if (count = pos) break;
prev = cur;
cur = cur->link;
count++; {
}
Q Systematic Approach to Data Structures us in C - 9.95

Step 3: Check for the appropriate position. This IS done usmg the following
statement:

if (count != pos)
{
printf("Invalid position\n");
return head;
}

Note: If count is same as pos, it is valid position and using cur node can be deleted
asshown below:

Let pos = 3. So, third node is deleted.

Fig. 9.7.1.1. To delete a node at the specified position

Step 4: Isolate the node pointed to by cur by establishing the link between the
predecessor and successor of the node to be deleted using the statement:

prev->link = cur->link;

Step5: Delete the node pointed to by cur using the statement:

freenode (cur);

Step6: Finally return address of the header node.

return head

TheC function to delete at the specified position is shown below:


9.96 Q Linked Lists

Example 9.7.5.1: Function to delete an item at the specified position

NODE delete ~osition(int pos, NODE head)


{
NODE prev,cur;
int i;

if ( head->link = head) 1* Check for empty list *1


{
printf("List is empty\n");
return head;
}

prey = head; 1* Find the appropriate position */


cur = head->link;
count = 1;
while (cur != head)
{
if (count = pos) break;
prey = cur;
cur = cur->link;
count++;
}

if (count != pos) 1* Position is invalid *1


{
printf("Invalid position\n");
return head;
}

prev->link = cur->link; 1* Delete at specified position */


freenode( cur);

return head;
}

The C function to display the contents of circular list with a header node is shown
below:
Q Systematic Approach to Data Structures using C - 9.97

Example 9.7.5.2: Function to display the contents of circular list with header node

void display(NODE head)


{
NODE temp;

if (head->link = head)
{
printf("List is empty\n");
return;
}

printf("Contents of the list is\n");


temp = head->link;
while(temp != head)
{
printf("%d ",temp->info);
temp = temp->link;
}

printf("\n");

The complete C program to implement insert_front/rear or delete based on item and


pas is shown below:

Example 9.7.5.3: Program to insert_front/rear or delete based on item and pos

#include <stdio.h>
#include <alloc.h>
#include <process.h>

struct node

int info;
struct node *link;
};

typedef struct node* NODE;


9.98 .Q Linked Lists
, t ) f L 21£ (J n il')f U

1* Include: Example 9.2.1.3: Function to get new node from the availability list *1
1* Include: Example 9.2.1.4: C Function to free a node to tOOa ai t list.>!<
L

1* Include: Example 9.7.1.1: Function to insert at the front end of the list *1
1* Include: Example 9.7.2.1: Function to insert at the rear end of the list k/( II
1* Include: Example 9.7.3.1: Function to delt node whose info field is specified *1
1* Include: Example 9.7.4.1: Function to insert an item at tlle speBiJ1ea po 'itidn *1
1* Include: Example 9.7.5.1: Function to deletean item at the specified position *1
1* Include: Example 9.7.5.2: Function to display the cbrhcnts of it ular *1
.n ut 1
void maim)
{
" t' I f
"NODE head;
int choice, item, pos;

head = getnodet);
head-s-info = 0;
head-c-link = head; 1* Empty header node *1

for (;;)
{
printf(" 1:Insert_front 2:Insert_At_Position\n");
printf{"3:Delete item 4:Delete_At_Position\n");
printf("S:Display 6:Exit\n");
printf("Enter the choice\n");

scanf("%d" ,&choice);

switch( choice)
{
case 1:
printf("Enter the item to be inserted\n");
rIh
scanf("%d" ,&item);
head = insert_front(item, head);
tni
break;
')U1.
case 2:
printf("Enter the item to be inserted\n");
scanf("%d ,&item);
II

printf("At position = ");


Q Systematic Approach to Data Structures using C - 9.99

scanf("%d",&pos);
head = insert ---'position(item, pos, head);
break;
case 3:
printf("Enter the item to be deleted\n");
scanf("%d" ,&item);
head = delete_item(item,head);
break;
case 4:
printf("Positon of node to be deleted = ");
scanf("%d",&pos); .
head = delete ---'position(pos,head);
break;
case 5:
displaytheadj. II
break;
default:
exit(O);
}
}

Note: Whatever operations are possible using ordinary linked list, the same
operations can be performed using linked list with a header node. Also observe that

elegant programs.
.
using a list with ,a header node simplifies the design and we can write simple and
.

' .
, r

Now, let us see "What are the disadvantages of singly linked lists whether circular or
with or without the header?" Some of the disadvantages of singly linked lists/circular
lists are: 'I J' "I ~ t:

• Using singly linked lists and circular lists it is not possible to traverse the list
backwards. Two way traversing is not possible.
• Insertion/Deletion to the left of a designated node x is difficult. This requires
finding the predecessor of x which takes more time.
r u J

• Given a node x, it is difficult to fmd the predecessor ofx. To fmd the predecessor,
it is required to traverse the list from the first node in case of singly linked list. In
case of circular list, -the predecessorcan be obtained by traversing the whole list
from the node specified. For example, if the position of the current node is 15, to
find the position of node 14, the whole list has to be traversed. All these
disadvantages can be overcome by using doubly linked lists. "
9.100 Q Linked Lists

9.8 Doubly linked lists

ow, let us see "What is a doubly linked list?"

Definition: One of the most powerful variations of linked lists is the doubly linked
list. A doubly-linked list is a linear collection of nodes where each node is divided
into,three parts:
• info - This is a field where the information has to be stored
• llink - This is a pointer field which contains address of the left node or
previous node in the list
• rlink - This is a pointer field which contains address of the right node or next
node in the list

Using such lists, it is possible to traverse the list in forward and backward directions.
Such a list where each node has two links is also called a two way list. The pictorial
representation of a doubly linked list is shown in figure 9.8.l.a. In this list, observe
that the llink field of the leftmost node and rlink field of rightmost node points to
NULL. The two variations of doubly linked lists are:
• Circular doubly linked list
• Circular doubly linked list with a header node

Let us see "What is circular doubly linked list?"

Definition: A circular doubly linked list is a variation of doubly linked list in which
• rlink (right link) of the last node contains address of the first node
• llink (left link) of the first node contains address of the last node
The pictorial representation of circular doubly linked list is shown in figure 9.8.l.b

Now, let us see "What is circular doubly linked list with a header?"

Definition: A circular doubly linked list (can also be called doubly linked circular
list) is a variation of doubly linked with a header node in which:
• Ilink of header contains address of the last node of the list
• rlink of header contains address of the first node of the list.
• llink of last node contains the address of last but one node of the list
• rlink of last node contains the address of the first node of the list

The pictorial representation of circular doubly linked list with a header node is shown
in figure 9.8.l.c. This list is primarily used in structures that allow access to nodes in
both the directions. For example, addition of long positive numbers (discussed in the
next section). .
~ Systematic Approach to Data Structures using C - 9.H

Note: An empty list with a header node can be represented as shown in fig.9.8.I.I
where llink and rlink of a header node points to itself.

(b)
head

t
(c)

(d)
Fig. 9.8.1 Variations of doubly linked lists

Note: All the problems that can be solved using singly linked lists can also be solve
using doubly linked lists. It is left to the reader to implement all the problems solve
so far, using doubly linked lists and doubly linked circular list. Given any problem It
us implement them using doubly linked lists and with a header node. Using a heade
node, problems can be solved very easily and effectively.
9.102 Q Linked Lists

9.8.1 Insert a node at the front end

Now, let us see "How to insert an item at the front end of the list" Consider the list
shown in fig.9.8.1.1. To insert a node pointed to by temp at the front of the list,
address of the first node i.e., pointed to by cur should be known. This can be
accomplished by using the statement
cur = head->rlink;

The node pointed to by temp can be easily inserted between head node and the node
pointed to by cur (follow the dotted lines). This can be accomplished by using the
following statements.
head->rlink = temp;
temp->llink = head;
temp->rlink = cur;
cur->llink = temp;

Figure 9.8.1.1 To insert a node at the front end

The C function to insert at the front of a doubly linked circular list with a header node
is shown in example 9.8.1.1.

Example 9.8.1.1: Function to insert a node at the front end of the list

NODE insert_front(int item, NODE head)


{
NODE temp, cur;
Q Systematic Approach to Data Structures using C - 9.103

temp = getnodet); 1* Node to be inserted *1


temp->info = item;

cur = head->rlink; 1* obtain address of first node *1

head->rlink = temp; 1* Insert between header node and first node *1


temp->l1ink = head;
temp->rlink = cur;
cur->llink = temp;

return head; 1* return the header node *1

9.8.2 Insert a node at the rear end

To insert a node at the rear end of the list, consider the list shown in fig.9.8.2.1 and
try to write the corresponding code. After writing the code compare this with the
function insert _ frontt). Note that the two functions are same except that llink and
rlinkhave been exchanged.

Note: The reader should know the simplicity of the code using double linked circular
list with header node. The C function to insert an item at the rear end of the list is
shownbelow:

Figure 9.8.2.1 To insert a node at the rear end


9.104 Q Linked Lists

Example 9.8.2.1: Function to insert an item at the rear end

NODE insertrearunt item, NODE head)


{
NODE temp, cur;

temp = getnode 0; 1* Node to be inserted *1


temp->info = item;

cur = head->llink; 1* obtain address of the last node *1

head->llink = temp; 1* Insert at the end of the list *1


0. temp->rlink = head;
temp->llink = cur;
cur->rlink = temp;

return head; 1* return the header node *1


}

9.8.3 Delete a node from the front end

Consider the list shown in fig.9.8.3.l. Find the address of the first node to be deleted
using the statement:
cur = head->rlink;

Also obtain the successor of the node to be deleted using the statement:
next = cur->rlink;

Figure 9.8.3.1 To delete a node at the front end

Once the addresses of the node to be deleted, its predecessor and successor are
known, following the sequence of numbers shown in fig.9.8.3.1, the node at the front
end can be deleted. The steps to be followed are shown below.
~ Systematic Approach to Data Structures using C - 9.105

Step 1, 2: Establish a link between the header node and successor of the node to be
deleted i.e., next in both directions. This can be accomplished using the statement
head ->rlink = next;
next->llink = head;

Step 3: Once these statements are executed, the node to be deleted namely cur is
isolated and it can be deleted. The corresponding statements are:
printf("The item deleted is %d\n",cur->info);
freenode( cur);

Finally return the address of the header node. Note that all these steps have been
designed by assuming list is already existing. If list is empty display the appropriate
message. The C function to delete an item from the front end of the list is shown
below:

Example 9.8.3.1: Function to delete a node from the front end

NODE delete_front(NODE head)


{
NODE cur, next;

if ( head->rlink = head) 1* Check for empty list *1


{
printf("Deque is empty\n");
return head;
}

cur = head->rlink; 1* Obtain the first node *1


next = cur->rlink; 1* Obtain the second node*1

head->rlink = next; 1* adjust pointers and delete the node *1


next->llink = head;

printf("The node to be deleted is %d\n",cur->info);

freenode( cur); 1* Delete the first node *1

return head; 1* Return the address of the last node *1


9.106 Q Linked Lists

9.8.4 Delete a node from the rear end


To delete a node at the rear end of the list, consider the list shown in fig.9.8.4.1 and
try to write the corresponding code. After writing the code compare this with the
function deletefrontt), Note: The two functions are same except that llink and rlink
have been exchanged. The pointer variable next is replaced by the pointer variable
pr;ev.

Figure 9.8.4.1 To delete a node at the rear end

The C function to insert an item at the rear end of the list is shown below:

Example 9.8.4.1: Function to delete a node from the rear end


NODE delete _rear(NODE head)
{
NODE cur,prev;
if ( head->llink = head)
{
printf("Deque is empty\n");
return head;
}
cur = head->llink; 1* obtain address of the last and last but one node *1
prey = cur->llink;
head->llink = prey; 1* adjust links in both directions *1
lprev->rlink = head; 0 CD
printf("The node to be deleted is %d\n",cur->info);
freenode(cur); 1* delete the node */0
return head;
}
~ Systematic Approach to Data Structures using C - 9.107

9.8.5 Delete a node whose information field is specified


This problem has already been discussed in section 9.7.3 using a singly linked
circular list. Here, the address of the node to be deleted is obtained in the beginning
using the statements:
cur = head->rlink;
while ( cur != head)
{
if (item = cur->info) break;
cur = cur->rlink;
}
If the item specified is not there in the list, the pointer variable cur points to the
header node and so, display the appropriate message. The code for this can be
if ( cur = head)
{
printf("Item not found\n");
return head;
}
If item is present in the list, the address of the node to be deleted i.e., cur is known.
Its predecessor can be obtained from the left link and its successor can be obtained
from the right link using the statements:
prev = cur->llink; /* address of the predecessor */
next = cur->rlink; /* address of the successor */
Now, consider the linked list shown below:

Figure 9.8.5.1 To delete a node whose information field is specified


9.108 Q Linked Lists

The node pointed to by cur is the node to be deleted, the node pointed to by prey is
the predecessor and the node pointed to by next is the successor of the node to be
deleted. Once the addresses of these nodes are known, establish the link between
predecessor and successor nodes and delete the node pointed to by cur. Following the
sequence of steps shown in fig.9.8.5.!, the node cur can be deleted. The
corresponding statements are:

prev->rlink = next;
next->llink = prev;

freenode( cur);

Finally, return the address of the header node. All these steps have been designed by
assuming list is present. If list is not present, display the appropriate message. The C
function to delete a node whose information field is specified is shown below:

Example 9.8.5.1: Function to delete a node whose info is provided

NODE delete_item(int item, NODE head)


{
NODE prev, cur, next;

if ( head->rlink = head)
{
printf("List is empty\n");
return head;
}

cur = head->rlink; /* find the address of node to be deleted */


while ( cur != head)
{
if (item = cur->info) break;
cur = cur->rlink;
}

if ( cur = head)
{
printf("Item not found\n");
return head;
}
Q Systematic Approach to Data Structures using C - 9.109

prev = cur->llink; /* Obtain the address of the predecessor */

next = cur->rlink; /* Obtain the address of the successor */

prev->rlink = next; /* Adjust the pointers and delete */


next->llink = prev;

freenode( cur);

return head; /* Return the header node */


}

9.8.6 Delete all nodes whose information field is specified as key

The procedure for this problem is same as discussed in previous section. But,
immediately after deleting the specified node, search for the key specified again from
successor node onwards. If the key is found, delete the node and repeat the process.
The modified C function to delete all nodes whose information is same as the key
specified is shown below:

Example 9.8.6.1: Function to delete all nodes whose info is same as key item

NODE delete_all(int item, NODE head)


{
NODE prev, cur, next;
int count;

if ( head->rlink = head)
{
printf("List is empty\n");
return head;
}

count = 0; /*assume key initially not present */

cur = head->rlink; /* find the address of node to be deleted */


9.110 Q Linked Lists

while ( cur != head)


{
if (item != cur->info)
cur = cur->rlink;
else
{
count++; 1* Update the number of occurrences *1
prev = cur->llink; I*Obtain the address of the predecessor*1
next = cur->rlink; 1* Obtain the address of the successor *1
prev->rlink = next; 1* Adjust the pointers and delete the node*1
next->llink = prev;
freenode( cur);

cur = next; 1* seach for key from this point *1


}
}

if( count = 0)
printf("Key not found\n");
else
printf("Key found at %d positions and are deleted'n't.count);

return head;
}

In this function the variable count is used to find the number of occurrences of the
key in the list. If key is found, the variable count is incremented by one and the
corresponding node is deleted and search for the key from the next node onwards and
repeat the process. Even after searching the entire list, if count is zero, it means that
key is not there in the list.

9.8.7 Insert a node after the key and before the key

Search for the specified key as explained in the section 9.7.5. Insert the specified item
towards right of the node whose info is same as the key. Similarly an item can be
inserted to the left of a designated node. The C functions, to insert an item towards
right of a node and towards left of a.node are shown in examples 9.48 and 9.49
respectively. The reader is supposed to write the appropriate figures and trace these
functions. The code is straightforward and simple.
Q Systematic Approach to Data Structures using C - 9.111

Example 9~8.7.1: Function to insert to the right of a specified node

NODE insertrighuint item,NODE head)


{
NODE temp,cur,next;

if ( head->rlink = head) /* Check for empty list */


{
printf("List is empty\n"); -
return head;
}

cur = head->rlink; /* search for the key */

while ( cur != head)


{
if (item = cur->info ) break;
cur = cur->rlink;
}

if ( cur = head) /* Key information not found */


{
printf("Key not found\n");
return head;
}

/*A node with key is found */


next = cur->rlink; /*obtain the address of the successor */
. ---
printf("Enter the item to insert towards right of %d = ",item);
temp = getnodet);
scanf("%d" ,&temp->info);

cur->rlink = temp; /* insert this new node between cur and next */
temp->llink = cur;
next->llink = temp;
temp->rlink = next;

return head; /* Return the header node */


9.112 Q Linked Lists

Example 9.8.7.2: Function to insert to the left of a specified node

NODE insert_left(int item,NODE head)


{
NODE temp, cur, prey;

if ( head->r1ink = head) 1* Check for empty list */


{
printf("List is empty\n");
return head;
}

cur = head->r1ink; 1* search for the key *1


while (cur != head)
{
if (item = cur->info ) break;
cur = cur->r1ink;
}

if ( cur = head) 1* Key not found *1


{
printf("Key not found\n");
return head;
}

I*A node with key is found *1


prey = cur->l1ink; 1* Obtain the prdedessor *1

printf("Enter the item to inser towards left of%d = ",item);

temp = getnodet);
scanf("%d" ,&temp->info);

prev-e-rlink = temp; 1* insert between prey and cur *1


temp-xllink = prey;
cur->1link = temp;
temp->r1ink = cur;

return head; 1* Return address of header *1


} .
Q Systematic Approach to Data Structures using C - 9.11~

TheC program to implement all these operations discussed in this section, is shown
below:

Example 9.8.7.3: Program to implement insert at front/rear/before/after a node, to


deletefront/rearlbased on i,m/all nodes etc.

#include<stdio.h>
#include<alloc.h>
#include<process.h>

struct node

int info;
struct node *llink;
struct node *rlink;
};
typedef struct node* NODE;

1* Include: Example 9.2.1.3: Function to get new node from the availability list */

1* Include: Example 9.2.1.4: C Function to free a node to the availability list */


I /
1* Include: Example 9.8.1.1: Function to insert a node at the front end of the list */

1* Include: Example 9.8.2.1: Function to insert an item at the rear end */

1* Include: Example 9.8.3.1: Function to delete a node from the front end */.

1* Include: Example 9.8.4.1: Function to delete a node from the rear end */
/
1* Include: Example 9.8.5.1: Function to delete a node whose info is provided */ /

1* Include: Example 9.8.6.1: Function to delete all nodes after searching for key *1,

1* Include: Example 9.8.7.1: Function to insert to the right of a specified node */


f
1* Include: Example 9.8.7.2: Function to insert to the left of a specified node */ /'
9.114 Q Linked Lists

/* function to display the contents of the list */


void display(NODE head)
{
NODE temp;

if ( head->rlink == head)
{
printf("Deqye is empty\n");
return;
}

.. printf("Contents of the deque is\n");


temp = head->rlink;
while (temp != head)
{
p rin tf("%d ",temp->info );
temp = temp->rlink;
}
printf("\n");
}

void maim)
{
NODE head;
int choice, item;

head = getnodet);
head->rlink = head;
head->l1ink = head;

for (;;)
{
printf(" 1:Insert_ front 2:InsertJear\n");
printf("3:Delete _front 4:Delete _rear\n");
printf("5:Display 6:Delete _info\n");
printf("7:Delte_keys 8:Insert after\n");
printf("9:Insert before lO:Exit\n");
printf("Enter the choice\n");

scanf("%d" ,&choice);
Q Systematic Approach to Data Structures using C - 9.115

switch( choice)
{
case 1:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
head = insert_ front(item,head);
break;
case 2:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
head = insertrearutem.head);
break;
case 3:
head = delete_front(head);
break;
case 4:
head = delete Jear(head);
break;
case 5:
display(head);
break;
case 6:
printf("Enter the item to be deleted\n");
scanf("%d" ,&item);
head = delete_item(item,head);
break;
case 7:
printf("Enter the key to be delted\n");
scanf("%d" ,&item);
head = delete _ all(item,head);
break;
case 8:
printf("Enter the key\n");
scanf("%d" ,&item);
head = insert _right(item,head);
break;
case 9:
printf("Enter the key\n");
scanf("%d" ,&item);
9.116 Q Linked Lists

head = insert_Ieft(item,head);
break;
default: exit(O);
}
}
}

'9.8.8 Singly Vs Doubly linked lists

Now, let us see "What is the difference between singly linked and doubly linked list?"

Singly linked list Doubly linked list


1. Traversing is only in one direction 1. Traversing can be done m both
"

directions
2. While deleting a node, its predessor is 2. While deleting a node x, it
required and can be found only after predecessor can be obtained using
traversing from the beginning of list llink of node x. No need to traverse
the list
3. Occupy less memory 3. Occupy more memory
4. Programs will be lengthy and need 4. Using circular linked list with header, .
more time to design efficient and small programs can be
written and hence design is easier
5. Care is taken to modify only one link 5. Care is taken to modify both links of a
ofa node node

Now, let us see "What are the advantages of doubly linked lists?" The advantages of
doubly linked lists are shown below:
• Using doubly linked lists with a header node most of the problems can be
solved very easily and effectively.
• The doubly linked lists are extensively used in trees. The hierarchical structure
of the tree can be easily represented using a doubly linked list.
• Graphs can be represented using doubly linked list.

Now, let us see "What are the disadvantages of doubly linked lists?" Some of the
disadvantages of doubly linked lists are:
• Each node in the list requires two links one is forward link and the other
backward link requiring additional storage for each field.
• While manipulating the lists extra care should be taken to manipulate both
links.
.Q Systematic Approach to Data Structures using C - 9.117

Exercises

1. Write a C function to check whether a given string is a palindrome using a doubly


linked list.
2. Mention few advantages of a header node.
3. What are the advantages and disadvantages of dynamic data structures?
4. Compare and contrast static data structures with dynamic data structures.
5. Explain the advantages and disadvantages of representing a groups of items as an
array versus a linear linked list.
6. What are the shortcomings of a singly linked list? How these are eliminated in
circular list?

9.9 Application of linked lists

In this section, let us see "What are the applications of linked lists?" The various
applications of linked lists are shown below:
Arithmetic operations on long positive numbers
Manipulation of polynomials I
Applications of
linked lists Evaluation of polynomials
In symbol table construction (Compiler design)

9.9.1 Addition of two long positive numbers

Now, Ietus see "Why very large numbers can not be added using + operator?" Some
applications may require various operations on very large numbers. But, all the
computers have a certain maximum number of bits required for representing an
integer, float etc. If the size of the numbers exceed this limit, ordinary arithmetic
operations can not be performed. Using linked lists, we can represent these large
numbers and any arithmetic operation can be performed on these large numbers.

Now, let us see "How to write algorithm/function to add two long positive numbers?"
This achieved by splitting the program into various modules based on activity
performed as shown below:
• Reading a long positive number
• Writing a long positive number
• Adding tw9 long positive numbers

Now, let us see "How to read a long positive number using linked list?"
9.118 Q Linked Lists

Design: Let us design by taking the number 6698274. This number can be split into
groups of one digit each as shown below from the most significant digit to least
significant digit.
6,6,9,8,2,7,4

Since there are 7 digits, a singly linked list with seven nodes can be used to store each
digit in each node. Consider the way the numbers are displayed on the display portion
of the calculator. If the number 6698274 is typed, display portion of the calculator
may look like as shown below.
6
66
669
6698
66982
669827
6698274

Note that as the new digits are typed, old digits will be shifted one digit left thereby
making room for the most recently typed digit. Thus the first digit typed will be the
leftmost digit of the number and the last digit typed will be the right most digit of the
number. Ifthe position of the least significant digit i.e., right most digit of a number is
considered as the front end, the digits that are typed will be inserted at the front end.
The linked representation for the number typed i.e., 669827 using circular
singly linked list with a header node is shown in fig.9.9.1.1. The next digit typed i.e.,
4 will be the new least significant digit and has to be inserted immediately after the
header node. Inserting immediately after the header node is considered as inserting an
element from the front end. Inserting temp, a node containing the digit 4 at the front
end of the list is shown using gray lines in fig.9.9.1.1. The resultant integer stored in
the result will be 6698274.

~)<Jo
..•. ~......... 1£.•.••.•••.•.•••.• head

CJIJ
temp

Figure 9.9.1.1 To insert an item at the front end

To accomplish this task the function insertfrontt) (example 9.5.1.1 in section 9.5.1)
can be used. Using the function insertfrontt), a function read_numberO to read a
long positive number can be obtained and is shown below:
.!;1,Systematic Approach to Data Structures using C - 9.119

Example 9.9.1.1: Function to read a long positive number

NODE read_number(NODE head)


{
char c;

while ( ( c = getchet) ) != '\r' )


{
if ( isdigit( c) )
head = insert _ front( c - '0', head);
else
{
printf("Invalid integer\n");
exit(l);
}
}
printf("\n");

return head;

Note: In this function the characters are read from the keyboard and if the character
typed is a digit, it is inserted into the list. Otherwise, appropriate message is
displayed.

Now, the next question is "How to display the number stored in a linked list?" Note
that the digits have to be displayed not from the first node, but from the last node to
the first node. This is the point where doubly linked list will be useful while
traversing backwards. This is not possible in singly linked list. So, to display the
linked list in reverse order, traverse the list in forward direction, copy the digits from
each node into an array and finally display the array items in reverse order. The code
corresponding to this is shown below:

Example 9.9.1.2: Function to display a long positive integer

void display_number(NODE head)


{
int k, n, *a;
NODE cur;
9.120 Q Linked Lists

if ( head->link = head) 1* Check for empty number *1


{
printf("Number does not exist\n");
return;
}

n = head->info; 1* number of digits in the number *1

a = (int *) malloc( n * sizeof(int) );1* allocate memory for n digits *1

cur = head->link, k = 0; 1* Copy the number into array a *1

while (cur != head) 1* Copy the number into an array *1


{
a[k++] = cur->info;
cur = cur->link;
}
while (--k != -1 ) printf("%d",a[k]); 1* display the result in reverse form *1

printf("\n");
}

Now, we know the method of reading and displaying a number. Now, let us see "How
to add two numbers using linked list?" Suppose the two numbers to be added are 987
and 86. These two numbers can be represented using circular linked list with a header
node as shown below:

~14--- --IETIJ----IEb Hl

dTIJ~-----1ETIJ------1Eb H2

Figure 9.9.1.2 Two numbers represented as linked lists

These two numbers should be added digit by digit from right to left i.e., from least
significant digit to most significant digit. A pointer variable c1 can be used to access
the digits from the first list and a pointer variable c2 can be used to access the digits
Q Systematic Approach to Data Structures using C - 9.121

fromthe second list. The corresponding digits along with a carry (initial carry 0 ) are
added. From the result obtained say sum, extract the digit using:
digit = sum % 10;

and carry by dividing sum by 10 i.e.,


carry = sum / 10;

In this case when we add 7 and 6, the sum obtained is 13.


digit = 13 % 10 = 3
carry = 13 / 10 = 1

Add the resulting digit at the end of the partial result obtained so far. So, function
insertrear shown in example 9.5.2.1 section 9.5.2 can be used. Move on to the next
digit in both the numbers by updating c1 and c2 and repeat the process. When the end
of one of the list is encountered, add the carry to the remaining digits of the other list.
The C function to add two long positive numbers is shown below:

Example 9.9.1.3: Function to add two long positive numbers

ODE add_long(NODE hI, NODE h2, NODE h3)


{
NODE c,c 1,c2,h;
int sum, carry, digit;

carry = 0; /*Initial carry is zero */


cl = hl->link; /* Points to the first digit of the first number */
c2 = h2->link; /* Points to the first digit of the second number */

/* add the two numbers digit by digit along with carry */


while (cl != hI && c2 != h2 )
{
sum = c 1->info + c2->info + carry;
digit = sum % 10; /* Extract the result */
carry = sum / 10; /* Extract the carry */

h3 = insert Jear( digit,h3); /* add the result to the partial output */

cl = cl->link; /* Point to the next digit of 1st number */


c2 = c2->link; /* Point to the next digit of ~nd number */
}
9.122 Q Linked Lists

1* Obtain the address of the remaining digits of bigger number *1


if( cl !=hl)
c=cl,h=hl;
else
c =c2, h=h2;
1* Add the carry to the remaining digits of bigger number *1
while ( c l= h )
{
sum = c->info + carry;
digit = sum % 10;
carry = sum I 10;
h3 = insertreartdigit.h'I);
c = c->link;
}
1* If carry add at the end of the result *1
if ( carry = 1 ) h3 = insertreartcarry.hs);
return h3;
}
The complete structure of C program to add two long positive numbers is shown
below:
Example 9.9.1.4: C program to add two long positive numbers
#include <stdio.h>
#include <alloc.h>
#include <process.h>
#include <conio.h>
#include <ctype.h>
struct node
{
int info;
struct node *link;
};
typedef struct node* NODE;

1* Include: Example 9.2.1.3: Function to get new node from the availability list *1
1* Include: Example 9.9.1.1: Function to read a long positive number *1
~ Systematic Approach to Data Structures using C - 9,]

/* Include: Example 9.9.1.3: Function to add two long positive numbers */


/* Include: Example 9.5.1.1: Function to insert an item at the front end of the list *
/* Include: Example 9.5.2.1: Function to insert an item at the rear end of the list */
/* Include: Example 9.9.1.2: Function to display a long positive integer */
void maint)
{
NODE hl,h2,h3;
hl = getnode/);
h2 = getnodei);
h3 = getnodet);
h 1->link = hl ;
h2->link = h2;
h3->link = h3;
hl->info = h2->info = h3->info = 0;
Input
printf("Enter the first number\n"); Enter 1st number
hl = read_number(hl); 99999
printf("Enter the second number\n"); Enter 2nd number
h2 = read_number(h2); 99999
h3 = add_long(hl,h2,h3);
Output
printf("Numl = "); display _number(h 1); Numl = 99999
printf("Num2 = "); display _number(h2); Nurn2 = 99999
printf("Sum = "); display _number(h3); Sum = 199998

9.9.2 Evaluation of a polynomial


Before evaluating, let us see "How to represent a polynomial using linked list?"
us assume we have a polynomial consisting of only two variables x and y. Here,
need to store co-efficient, power of x and power of y. So, a polynomial can be ear
represented using a .linked list where each term can be considered as a node consist
of four fields as shown below:
• cf - to store the coefficient
• px - to store the power of x
• py - to store the power of y
• link - which contains the address of the next term(node).
9.124 Q Linked Lists

The declaration for a node can be written as shown below:

struct node
{
float cf;
float px;
float py;
struct node *link;
};

typedef struct node* NODE;

Now'; let us see "How to represent a polynomial 5x\,z + 3x2 + 4x3y -5 using a
linked?" The following figure shows how the given polynomial is stored in a linked
list. .

cf px py link
~---------------~---------------~
term
(a)

5xlj -5
(b)

Figure 9.9.2.1 Representing a polynomial using linked list

Since there are four terms in the polynomial, it is represented as. a linked list
consisting of four nodes. To design the algorithm, for the sake of simplicity we
assume each term in the polynomial is unique i.e., each term has different powers ofx
and y. Each term in the polynomial can have the same or different coefficient. We use
a singly linked circular list with a header node.
The pointer variable poly is used which contains address of the header node.
1
Each term of the polynomial can be inserted into the list from the rear end as .
discussed in section 9.5.2. The C function to add a term from the rear end of the list is
shown below:
~ Systematic Approach to Data Structures using C - 9.125

Example 9.9.2.1: Function to insert a term at the rear end

NODE insertreartfloat cf, float x, float y ,NODE head)


{ .
NODE temp,cur;

temp = getnodet); 1* create a node and write polynomial */


temp->cf = cf;
temp->px = x;
temp->py = y;

cur = head->link; , 1* Obtain the address of the last node */


while ( cur->link != head)
cur = cur-c-link;

cur->link = temp; 1* insert at the end of the list *1


temp->link = head;

return head; 1* return the header of a polynomial */


}

By repeatedly invoking the function insertreari), while adding a term, a linked list
representing a polynomial can be created. Once the co-efficient of term is -9999,
stop adding the term to the list. If the co-efficient of a term is not equal to -9999, it is
end of the polynomial and address of the header node is returned. The C function to
read a polynomial is shown below:

Example 9.9.2.2: Function to read a polynomial

NODE read yoly(NODE head)


{
int i;
float px; 1* to hold power of x */
float py; 1* To hold power ofy *1
float cf; /* To hold the co-efficient */

printf("Enter the coefficient as -999 to end the polynomial\n");


9.126- Q Linked Lists

for(i = 1; ; i++)
{
printf("Enter the %d term\n",i);
printf("Coeff= "); scanf("%f',&cf);
if ( cf = -999 ) break;
printf("pow x = "); scanf("%f' ,&px);
printf("pow y = "); scanf("%f' ,&py);

head = insert_rear(cf,px,py,head);
}
return head;
}
Now, let us see "How to evaluate the polynomial?" To evaluate the polynomial we
should know the values of the variables x and y. Once these values are known,
substitute these values for the corresponding variables in each term and by adding all
the terms, the result is obtained. The function to evaluate the polynomial is shown
below:
Example 9.9.2.3:Function to evaluate a polynomial with two variables
float evaluate(NODE head)
{
float x,y,sum = 0;
NODE poly;
printf("Enter the value ofx and y\n");
scanf("%f %f' ,&x,&y);
poly = head->link; /* Access each term, substitute x and y */
while (poly != head)
{
sum += poly->cf * pow(x,poly->px) * pow(y,poly->py);
poly = poly->link;
}
return sum;
1
}

Now, let us see "How to display a polynomial represented as a linked list?" The
function to display the polynomial represented as a circular linked list with a header
node is shown below:
Q Systematic Approach to Data Structures using C - 9.127

Example 9.9.2.4: Function to display a polynomial


void display(NODE head)
{
NODE temp;
if ( head->link = head)
{
printf("Polynomial does not exist\n");
return;
}
temp = head->link;
while (temp != head)
{
printf("+%5.2fxl\%3.1fyl\%3.1f",temp->cf,temp->px,temp->py);
temp = temp->link;
}
printf("\n");

The main program to evaluate the polynomial is shown below:

Example 9.9.2.5: C Program to evaluate a given polynomial


#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <math.h>
struct node

float cf;
float px;
float py;
struct node *link;
};
typedef struct node* NODE;

1* Include: Example 9.2.1.3: Function to get new node from the availability list */
1* Include: Example 9.9.2.4: Function to display a polynomial */
1* Include: Example 9.9.2.3: Function to evaluate a polynomial with two variables */
'* Include: Example 9.9.2.2: Function to read a polynomial */
1* Include: Example 9.9.2.1: Function to insert a term at the rear end */
9.12& Q Linked Lists

void mairu)
{
NODE head;
float res;

head = getnodet);
head->link = head;

printf("Enter the polynomial'n");


head = readpolyihead);
res = evaluate(head);
printf("The given polynomial is\n");
display(head);
printf("The result = %f\n",res);
}
Note: The polynomial 5x\,z + 3x2 + 4x3y - 5 with value x = 1 and y = 2 can b
entered as shown below:

Output
Enter the polynomial
Enter the co-efficient as -999 to end the polynomial
Enter the 1stterm
Coeff = 5 pow x = 3 pow y = 2

Enter the 2nd term


Coeff= 3 pow x = 2 pow y=O

Enter the 3rd term


Coeff= 4 pow x = 3 pow y = 1

Enter the 4th term


Coeff= -5 pow x = 0 pow y= 0

Enter the 5th term


Coeff= -999

Enter the value of x and y


12
The given polynomial is
+5.00xI\3.0yI\2.0 + 3.00xI\2.0yI\0.0 + 4.00x/\3.0y/\1.1 + -S.OOxI\O.Oy/\O.O
The result = 26.00000
~ Systematic Approach to Data Structures using C - 9.129

9.9.3 Addition of two polynomials


Once we know the method of reading, displaying and evaluating a polynomial, now
the next question is "How to add two polynomials?"

Design: Let use circular list with a header node to represent a polynomial as
discussed in previous section. The pointer variable h I contains address of the header
node of the first polynomial and pointer variable h2 points to the header node of the
second polynomial. The first polynomial can be accessed from link of h l and the
second polynomial can be accessed from link of h2. The procedure to be followed
while adding two polynomials is shown below.

• Search for the next term of first polynomial in the second polynomial

• if found then
add the coefficients of both terms.
If the result is not zero add the result to the resulting polynomial.
else
add the term of first polynomial to the resulting polynomial
endif

This process has to be repeated until all the terms of the first polynomial are over. So,
the first version of the algorithm can be

pI = link(hI)
while p l !=hI
{
Search for the next term of first polynomial in the second polynomial
if found then
add the coefficients of both terms. If the result is not zero i.e., two
terms can not be cancelled, add the result to the resulting polynomial.
else
add the term of first polynomial to the resulting polynomial
endif
p l = link(pl);

Let us discuss how to search for the next term of the first polynomial in the second
polynomial. The first term of the first polynomial can be obtained using the
statements
9.130 Q Linked Lists

xl = px(PI);
yl = py(pI);
cfl = cf(PI);
provided the pointer variable p l contains the address of the first term in the
polynomial. To obtain the successive terms using the above sets of statements, point
the
, pointer variable p l to successive nodes one after the other. This term should be
compared with each term of the second polynomial. This can be done using the
following set of statements
p2 = link(h2);
while (p2 != h2 )
{
x2 = px(P2);
y2 = py(P2);
cf'2 = cf(P2);
if(xl =x2&&yl =y2) break;
p2 = link(p2)
}

After executing these statements, if p2 and h2 are same, it means that the term of the
first polynomial is not present in the second polynomial. Otherwise, the term is
present. Searching for the next term in the first polynomial is over. After searching,
the following statement has to be executed.
if found then
add the coefficients of both terms.
If the result is not zero add the result to the resulting polynomial.
else
add the term of first polynomial to the resulting polynomial
endif
The code for the above statement can be written as
if (p2 != h2) 1* term is present */
{
cf= cfl + cf'2
if ( cf!= 0) h3 = insertreartcf.x l.y l.hf);
}
else
h3 = insert Jear( cfl,x 1,yl ,h3);
Q Systematic Approach to Data Structures using C - 9.131
The complete algorithm to add two polynomials is shown below:

pl = link(bl)
while (p l != h l )
{
/* obtain the current term */
xl = px(pl)
yl = py(pl)
cfl = cf(Pl)

/* search for the term in the second polynomial */


p2 = link(h2)

while ( p2 != h2 )
{
x2 = px(P2)
y2 = py(p2);
cf2 = cf(P2);

if (xl = x2 && yl = y2 ) break;

p2 = link(p2)
}

if( p2 != h2)
{
/* if found add the co-efficients and the result to the
resultant polynomial */

cf= cfl + cf2


if ( cf!= 0) h3 = insert_rear(cf,xl,yl,h3);
}
else
/* add the first term to the resultant polynomial */
h3 = insertreartcft.x l.yl.hj);

/* point the pointer variable p l to point to the next term */


p l = link(pl);
9.132 Q Linked Lists

When all the terms in the first polynomial are compared with the second polynomial,
the remaining terms of the second polynomial can be simply inserted into the
resultant polynomial.
To check for the remaining terms of the second polynomial, one more field
called flag can be added. Initially, flag field of each node in the second polynomial is
zero. Once the coefficients of two terms are added make flag field of the current term
in. the second polynomial as 1. So, the flag field of each node in the second list
corresponding to the second polynomial may be 1 or 0. If flag field is 0, it means that
the corresponding term is not there in the first polynomial. The code to copy the
remaining terms of the second polynomial is

p2 = link(h2)

while (p2 != h2 )
{
if ( flag(p2) = = °)
{
h3 = insert_rear(cf(p2),px(p2),py(p2),h3);
}

p2 = link(p2)
}

Finally address of the header node of the resultant polynomial IS returned. The
function to add two polynomials is shown below:

Example 9.9.3.1: Function to add two polynomials

NODE add .....


ooly(NODE hI, NODE h2, NODE h3)
{
·~uJJ.I!, 1.p2;
in l x i ,Al,y 1,y2,ct1 ,c12,ct;

p l = h i -;-1:1li(;
while (pI !=h1)
{
1* obtain the next term of the first polynomial *1
xl = p1->px;
y1 = p1->py;
cfl = p l->cf;
Q Systematic Approach to Data Structures using C - 9.1

1* seach for this term in the second polynomial *1


p2 = h2->link;
while ( p2 != h2 )
{
x2 = p2->px;
y2 = p2->py;
cfl = p2->cf;

if (xl = x2 && y1 = y2 ) break;

p2 = p2->link;
}

if (p2 != h2) 1* if term of 1st polynomial is present */


{
cf = cfl + cf2; 1* add the coefficients *1

p2->f1ag = 1; 1* insert into resultant polynomial */


if( cf!= 0) h3 = insertreartcf.x l.y l.h.l);
}
else 1* insert 1st term into resultant polynomial */
h3 = insert rearfcflx I.y l.h'I);

p l = p1->link; 1* obtain the next term of 1st polynomial *1


}

)* Add the remaining terms of second polynomial to the result *1


p2 = h2->link;
while (p2 1=h2 )
{
if ( p2->f1ag == 0 )
{
h3 = insertJear(p2->cf,p2-:>px,p2->py,h3);
}
p2 = p2->link;
}
return h3;

The complete C program to add two polynomials is shown below:


9.134 Q Linked Lists

Example 9.9.3.2: Program to add two polynomials


#include <stdio.h>
#include <alloc.h>
#include <process.h>
#include <math.h>
struct node
{
float cf;
float px;
float py;
int flag;
struct node *link;
};
typedef struct node* NODE;
/* Include: Example 9.2.1.3: Function to get new node from the availability list */
/* Include: Example 9.9.2.4: Function to display a polynomial */
/* Include: Example 9.9.3.1: Function to add two polynomials */
/* Include: Example 9.9.2.2: Function to read a polynomial */

NODE insertreartfloat cf, float x, float y ,NODE head)


{
NODE temp, cur;
temp = getnodet);
temp->cf = cf; temp->px = x; temp->py = y; temp->flag = 0;
cur = head->link; /* Obtain the address of the last node */
while ( cur->link != head)
cur = cur->link;
cur->link = temp; /* insert at the end of the list */
temp->link = head;
return head;
}

void maint)
{
NODE hI,h2,h3;
Q Systematic Approach to Data Structures using C - 9.13!

h l = getnodet);
h2 = getnodet);
h3 = getnodet);
hl->link = hl ; h2->link = h2; h3->link = h3;

printf("Enter the first polynomial\n");


hl = read polythl );

printf("Enter the second polynomial\n");


h2 = read polythz);

h3 = add--'poly(hl,h2,h3);

printf("The first polynomial is\n");


displayfhl );
printf("The second polynomial is\n");
display(h2);
printf("The sum of two polynomials is\n");
display(h3);

ote: Consider the two polynomials: 5x\,2 + 6xy + 3xy + 5 and 10x3y + 4x3 + 3xl
+ lO~ + 7. The sum of these two polynomials will be 5x\,2 + 9xy + 3xy + 12 +
10x3~ + 4x3 + 101. The polynomials should be entered as shown below:

Output
Enterthe first polynomial
Enterthe co-efficient as -999 to end the polynomial
Enterthe I5t term
Coeff= 5 pow x = 3 pow Y = 2
Enterthe 2nd term
Coeff= 6 pow x = I pow y = 3
Enterthe 3rd term
Coeff= 3 pow x = I pow Y = I
Enterthe 4 tit. term
Coeff= 5 pow x = 0 pow y = 0
Enterthe s" term
-999
Enterthe second polynomial
9.136 Q Linked Lists

Enter the co-efficient as -999 to end the polynomial


Enter the 1SI term
Coeff = 10 pow x = 3 pow y = 3
Enter the 2nd term
Coeff = 4 pow x = 3 pow y = 0
Enter the 3rd term
Coeff = 3 pow x = 1 pow Y = 3
Enter the 41h term
Coeff = 10 pow x = 0 pow y = 3
Enter the 5th term
Coeff = 7 pow x = 0 pow y = 0
Enter'the 6th term
Coeff= -999
The first polynomial is '..
+5.00x"3.0y"2.0 + 6.00x"1.0y"3.0 + 3.00x<"l.Oy"1.0 + 5.0Ox"0.Oy"0.O
The second polynomial is
+1O.00x"3.0y"3.0 + 4.00x"3.0y"0.0 + 3.00x"1.0y"3.0 + 10.00x"0.Oy"3.0 +
7.OOx"0. Oy"O.0
The sum of two polynomials is
+5.00x"3.0y"2.0 + 9.00x"1.0y"3.0 + 3.00x"l.Oy"1.0 + 12.00x"O.Oy"0.0 +
1O.OOx"3.0y"3.0 + 4.00x"3.0y"0.0 + 10.00xl"0.Oy"3.0

Exercises

1. How long positive numbers can be represented using linked lists? Explain with an
example
2. Write a C program to subtract two long positive numbers using circular singly
linked lists
3. Write a C program to add two long positive numbers using doubly linked list.
4. Write a C program to subtract two long positive numbers using doubly linked list.
5. How a polynomial with 3 variables x, y and z can be represented using linked
lists. Explain with an example
6. Modify the program given in example 9.61 to add two polynomials with 3
variables x, y and z.
7. Write a program to subtract two polynomials with 2 variables.
\

n
Chapter 10: Trees
I What are we studying in this chapter? I
• Definition of a tree and related terminologies
• Array and linked representation of a tree
• Traversal techniques
• Insert an element
'. Delete an element
• Copy the tree
• Search for a specified item
• To find the height of a tree
• To find the number of nodes
• To find the number ofleaves
• To find maximum and minimum in a tree
• Implementation of a priority queue
• Conversion and evaluation of expressions
• Iterative traversal techniques
• Threaded binary trees -12 hours

10.1 Introduction

Sofar we have discussed the data structures where linear ordering was maintained
usingarrays and linked lists. For some of the problems it is not possible to maintain
thislinear ordering using linked lists. Using non-linear data structures such as trees,
graphs,multi-linked structures etc., more complex relations can be expressed. In this
chapteron trees, we begin with some definitions, the various operations that can be
performedon trees along with various applications. In the previous chapter, we have
seena doubly linked list with two link fields.
Now, we concentrate on a tree which is also a doubly linked list, but the field
lIink does not point to predecessor and field rlink does not point to successor, instead
theypoint to some other trees. A tree is a data structure which is collection of zero or
morenodes and finite set of directed lines called branches that connect the nodes. The
firstnode in the tree is called root node and remaining nodes are partitioned into
varioussubtrees. Trees are normally divided into two groups: General trees and
Bmarytrees
10.2 Q Trees

Note: The number of branches associated with each node is called degree of a node.
When a branch is directed towards the node, we say it has indegree branch and when
a branch is directed away from the node, we say it has outdgree branch.

In this chapter, let us concentrate on binary trees. First we shall see "What is a binary
tree?"

Definition: A binary tree is a tree which is collection of zero or more nodes and finite
set of directed lines called branches that connect the nodes. A tree can be empty or
partitioned into three subgroups namely root, left subtree and right subtree.
• Root - If tree is not empty, the first node is called root node.
• left sub tree - It is a tree which is connected to the left of root. Since this tree
comes under root, it is called left subtree.
• right subtree - It is a tree which is connected to the right of root. Since this tree
comes under the root, it is called right subtree.

Note: In general, a tree in which each node has either zero, one or two subtreesis
called a binary tree. If any node has more than two subtrees, then it is not a binary
tree. The pictorial representation of a typical node in a binary tree is shown below:
Node = llink + info + rlink

Address of ~ ._ Address of
left subtree right subtree
llink info rlink
Note that a node in a tree consists of three fields namely llink, info and rlink:
• llink - basically contains address of left subtree
• info - This field is used to store the actual data or information tobe manipulated
• rlink - basically contains address of right subtree.

The pictorial representation above node takes more space. So, to minimize the space,
we can represent the above node as shown below:

info info
~.
-~,
Ilinr - '{.link lIiny . ",ink
left subtree right subtree left subtree right subtree
(a) (b)
Fig 10.1: A node in a binary tree
Q Systematic Approach to Data Structures using C - 10.3
Thefigure 10.1.a is shown with directions to left and right subtrees. But, the second
figureshows without directions. In the text book, we show without directions. But, it
is implied that directions are present moving away from root. The following figure
showssome of the binary trees:

Empty tree Tree with 1 node Tree with 2 nodes Tree with 3 nodes
(a) (b) (c) (d)

Fig 10.2: Binary trees

ote: An empty tree is also a binary tree. Binary here means at most two i.e., zero,
one or two subtrees are possible. But, more than two subtrees are not permitted.
Considerthe trees shown below: Are they binary trees? No.

(a) (b) (c)

Fig 10.3: Not Binary trees

Letus see "Why they are not binary trees?"


• The tree shown in Fig 10.2.a is not binary tree. This is because, it has more than
two subtrees.
• The tree shown in Fig. 10.2.b is not a binary tree. The node 100 has subtree 200.
Node 200 has subtree 300, node 300 has sub tree 100 and cycle repeats. There
should not be any cycles. So, it is not a binary tree.
• The node 100 has subtree 10 and 10 has the subtree 100. If 10 is subtree of 100,
then 100 can not be the subtree of 10. So, it is not a binary tree.
10.4 Q Trees

Now, let us see "What are the various terminologies normally associated 'with trees?
Define each of them" The various terminologies that are associated with a tree shown
below:
• Root node: A node with indegree 0 is called root node. It is the first node in the
tree. For example,
• node 100 is the root of the tree (shown in Fig. lOA)
• Child: The nodes, which are all reachable from a node x using only one edge are
called children of node x and node x is the parent for all those children. The
word son can also be used in place of child. [Let use the word child, otherwise
daughters may feel bad]. for the tree shown in Fig. lOA
• 50 and 60 are children of 100
• 80 and 40 are children of 60
• 70 is child of 50
• 35 and 30 are children of 80
• Siblings: Two or more nodes having the same parent are called siblings. For
example, for the tree shown in Fig. lOA
• 50 and 60 are siblings since they have same parent 100
• 80 and 40 are siblings since they have same parent 60
• 35 and 30 are siblings since they have same parent 80
• Ancestors: The nodes in the path from root to the specified node x, are all
ancestors of node x. For example, for the tree shown in Fig. 10.4
• 100 is the ancestor of 50
• 60 is the ancestor of 100
• 50 and 100 are the ancestors of 70
• 60 and 100 are the ancestors of 80 and 40
• 80, 60 and 100 are the ancestors of 100 and 30
• Descendents: The nodes in the path below the parent are called descendents.In
other words, the nodes that are all reachable from a node x are all called
descendents ofx. For example, for the tree shown in Fig. 10.4
• All the nodes below 100 are descendents of 100
• All the nodes below 50 are descendents of 50 and so on.
• Left descendents: The nodes that lie towards left subtree of node x are calledJeft
descendents. For example, for the tree shown in Fig. 10.4
• 50 and 70 are left descendents of 100
• 80, 35 and 30 are the left descendents of 60
• 35 and 80 are left descendents of 60
,!;lSystematic Approach to Data Structures using C - 10.5

.Lex.el

Len:l1.. _ _____ 60 Hei.&!tU

Level 2 Hei ht 2

Level 3

Maximumlevel of the tree = 3 Maximum height/depth of the tree = 3

Fig. 10.4: Binary tree with all terms used

• Right descendents: The nodes that lie towards right subtree of node x are called
right descendents. For example, for the above tree
• 60, 80, 40, 35 and 30 are right descendents of 100
• 30 is the right descendent of 80
• 40 is the right descendent of 60

• Leftsubtree: All the nodes that are all left descendents of a node x form the left
subtree of x. For example, for the above tree
• 50 and 70 form the left subtree of 100
• 80, 35 and 30 form the left subtree of 60

• Right subtree: All the nodes that-are all right descendents of a node x form the
right subtree of x. For example, for th'f above tree
• 60, 80,40,35 and 30 are right descendents of 100
• 30 is the right descendent of 80
• 40 is the right descendent of 60

• Parent: A node having left subtree or right sub tree or both is said to be a parent
node for the left subtree and/or right subtree. The word father also used in place of
parent. [Let us use the word parent, otherwise mothers may feel bad]. For
example, for the above tree
10.6 Q Trees

• 100 is the parent for 50 and 60


• 50 is the parent for 70
• 60 is the parent for 80 and 40
• 80 is the parent for 35 and 30
• Leaf: A node in a tree that has an outdegree of zero is called a leaf node. In other
words, a node with an empty left child and an empty right child is called a leaf
node. It is also called a terminal node or external node. For example,
• 70,35,30 and 40 are the leaf nodes

• Internal nodes: The nodes except leaf nodes in a tree are called internal nodes.
For example,
• 100, 50, 60 and 80 are the internal nodes

• External nodes: The leaf nodes in a tree are called external nodes. For example,
• 70,35, 30 and 40 are the external nodes

• Level: The distance of a node from the root is called level of the node. In a tree,
the root has a level 0 (zero) and level of any other node is one more than the level
of its father. For example,
• level of each node is shown in Fig. 10.4

• Height (Depth): The height of the tree is defined as the maximum level of any
leaf in the tree. For example,
• height of tree shown in Fig 10.4 is 3

10.2 Types of binary trees

Once we know the terminologies or nomenclature used for trees, now let us see
"What are the different types of binary trees?" The binary trees are classified as
shown below:

Strictly binary tree


Complete binary tree
Types of binary trees ---f-~.Almost complete binary tree
An expression tree (section 10.6.3)
Binary search tree (section 10.5)
Q Systematic Approach to Data Structures using C - 10.7

(a) (b) (c)


Fig. 10.5: Binary trees

First,let us see "What is strictly binary tree?"

Definition:If the outde~~ of every ~de in a tree is either 0 or 2, then the tree is
saidto be strictI binary tree i.e., each node can have maximum two children or no
children(no children indicate empty left and empty right child).
For example, the trees shown in fig.1O.5.b and fig.l 0.5.c are strictly binary
treeswhereas the tree shown in figure 10.5.a is not strictly binary tree (because, the
node5 should have two children or no children. But, it has one child)

Now,let us see "What is complete binary tree?"

Definition:A strictly binary tree in which the number of nodes at any level i is z', is
saidto be a complete bina tree. The trees shown in fig.10.6 are all complete binary
trees.

(a) (b) (c)


Fig. 10.6:Complete binary trees (at levels 0, 1 and 2)
10.8 Q Trees

Example 10.2.1: Show that n, = 2d+1 - 1 and nL = 2d - 1 where n, represent total


number of nodes and d is the depth(height) of the tree and nnLrepresent total number
of non-lean nodes.

Solution: Observe the following factors from the complete binary tree:
,Number of nodes at level 0 = 1 = 2°
Number of nodes at level 1 = 2 = 21
Number of nodes at level 2 = 4 = 22
Number of nodes at level 3 = 8 = 23

Number of nodes at level d = 2d•

Total number of nodes in the complete binary tree = 2° + 21 + 22 + i.


Summation of this series is given by S = a ( r" - 1) / ( r - 1)
where a = 1, n = d+ 1 and r = 2

So, total number of nodes n, = a (rn - 1) / (r - 1)


=1 (2d+1-1)/(2-1)
=2d+1_1

Therefore, total number of nodes I fit = 2d+l - 11


Number of non-leaf nodes = total number of nodes + leaf nodes
d d
= n, + 2 (where 2 = number of leaf nodes at level d)
d 1 d
= 2 + -1- 2
= 2d-l

Therefore, total number of non-leaf nodes I nnL = 2 d


- 1

First, let us see "What is almost complete binary tree?"

Definition: A tree of depth d is an almost complete binary tree if following two


properties are satisfied: .
• If the tree is complete up to the level d-l, then the total number of nodes at the
level d-I should be 2d-1•
Q Systematic Approach to Data Structures using C - 10.9

• The total number of nodes at level d may be equal to 2d• If the total number of
nodes at level d is less than 2d, then the number of nodes at level d-l should be
2d-1 and in level d the nodes should be present only from left to right.

For example, the trees shown in fig.l0.7.a to fig.lO.7.d are almost complete binary
trees and the rest are not. The nodes in an almost complete binary can be numbered
level by level from left to right as shown in fig.l 0.7 .d.

(a) (b) (c)


Fig. 10.7: Almost complete binary trees at level 2

(d) (e)
Fig. 10.7: Almost complete binary tree Fig. 10.7: Not almost complete binarytre

10.3Storage representation of a binary tree

Now, let us see "What is the storage representation of binary trees?" The storage
representation of binary trees can be classified as shown below:
• sequential allocation technique (using arrays)
• Linked allocation technique (using dynamic allocation)
10.10 Q Trees

Now, let us see "How a tree is represented using linked allocation technique?" In a
linked allocation technique a node in a tree has three fields:
• info - which contains the actual information
• lIink - which contains address of the left subtree
• rlink - contains address of the right sub tree.

So, a node can be represented using structure as shown below:

struct node
{
int info;
struct node *llink;
struct node *rlink;
};

typedef struct node* NODE;

A pointer variable root can be used to point to the root node always. If the treeis
empty, the pointer variable root points to NULL indicating the tree is empty. The
pointer variable root can be declared and initialized as shown below:

NODE root = NULL;

Memory can be allocated or de-allocated using the functions getnodet) and freenode)
as we discussed in linked lists in chapter 9. Now, let us see "How a tree is represented
using static allocation(using arrays) technique?"

A tree can also be represented using an array, which is called sequential


representation (array representation). Consider the trees shown in fig. IO.8.a and
fig. 10.8. b. and observe the following points:
• The nodes are numbered sequentially from O.
• The node with position 0 is considered as the root node.
• If an index i is 0, it gives the position of the root node.
• Given the position of any other node i, 2i+ 1 gives the position of the left child
and 2i+2 gives the position of the right child.
• If i is the position of the left child, i+ 1 gives the position of the right child
• If i is the position of the right child, i-I gives the position of the left child.
• Given the position of any node i, the parent position is given by (i-I) / 2. Ifiis
odd, it points to the left child otherwise, it points to the right child.
Q Systematic Approach to Data Structures using C - 10.11

(b)
Figure 10.8: Sequential representation of a tree

Atree can be represented using arrays in two different methods as shown below:

Method 1: In the first representation shown below, some of the locations may be
usedand some may not be used. For this, a flag field namely, used is used just to
indicatewhether a memory location is used to represent a node or not. If flag field
used is 0, the corresponding memory location is not used and indicates the absence of
nodeat that position. So, each node contains two fields:
• info where the information is stored
• used indicates the presence or the absence of a node

The structure declaration for this is shown below:

#define MAX SIZE 200


struct node
{
int info;
int used;
};
typedef struct node NODE;
10.12 Q Trees

An array a of type NODE can be used to store different items and the declaration
for this is shown below:
NODE a [MAX_SIZE];

Method 2: An alternate representation is that, instead of using a separate flag field


used to check the presence of a node, one can initialize each location in the array to 0
. indicating the node is not used. Non-zero value in the location indicates the presence
of the node. In section 10.7, a program is shown to create the tree and traverse it in
different orders using this approach.

10.4 Various operations on binary trees using linked representation

Now, let us see "What are the various operations that can be performed on binary
trees?" The various operations that can be performed on binary trees are shown
below:
Insertion (Insert a given item into a tree)
Traversal (Visiting the nodes of the tree one by one)
Operations on __ -+-_~
Search (Search for the specified item)
binary trees
Copying (To obtain exact copy of the given tree)
Deletion (To delete a node from the tree)

10.4.1 Insertion

Suppose the node pointed to by temp has to be inserted whose information field
contains the item'!' as shown in fig.10.9.

.•...
(j")
...... temp
Figure 10.9: To insert an item I
~ Systematic Approach to Data Structures using C - 10.13

Let'd' be an array, which contains only the directions where the node temp has to be
inserted.If 'd' contains 'LRLR', from the root node, first moves towards left(L), then
right(R),then left(L) and finally move towards rightrR). Finally if the pointer points
toNULL, at that position, node temp can be inserted otherwise, node temp can not
be inserted. To achieve this, one has to start from the root node. Let us use two
pointersprev and cur where prey always points to parent node and cur points to
childnode. Initially cur points to root node and prey points to NULL. To start with,
onecan write the following statements.

prev=NULL
cur = root

Now,keep updating the node pointed to by cur towards left if the direction is ('L')
otherwise,update towards right. The pointer variable prey always points to the parent
nodeand cur points to the child node. Once all directions are over, if cur points to
NULL, insert the node temp towards left or right based on the last direction.
Otherwise,display an error message. In the following algorithm, an index variable i is
usedto access the directions. The C function to insert a node is shown below:

Example 10.4.1.1: Function to insert an item into a binary tree based on direction

ODE insert(int item, NODE root)


{
NODE temp; 1* Node to be inserted *1
NODE cur; 1* Child node *1
NODE prev; 1* Parent node *1

char direction[lO]; 1* Directions where the node has to be inserted *1


int i; 1* Maximum depth where a node can be inserted *1

temp = getnodet); 1* Obtain a node from the availability list *1


temp->info = item; 1* Copy the necessary information *1

temp->llink = temp->rlink = NULL;

if ( root = NULL) return temp; 1* Node is inserted for the first time *1

printf("Give the directions where you want to insert\n");


scanf("%s" ,direction);
10.14 Q Trees

toupper( direction); 1* Convert the directions to upper case *1

prev=NULL;
cur = root;

1* find the position to insert *1


for ( i = 0; i < strlen(direction); i++)
{
if (cur = NULL) break;

prev = cur; 1* Parent *1

if ( direction[i] = 'L') 1* If direction is (L) move towards left */


cur = cur->llink;
else 1* Otherwise move towards right *1
cur = cur->rlink;
}

if ( cur != NULL II i != strlentdirection)


{
printf("Insertion not possible\n");
free( temp);
return root;
}

1* insert the node at the leaf level *1


if ( direction[i-l] = 'L') 1* Attach the node to the left of the parent */
prev->llink = temp;
else
prev->rlink = temp; 1* Attach the node to the right of the parent */

return root;
}

10.4.2 Traversals
1

Now, let us see "What is the meaning of traversing a tree?"

Definition: Traversing is a method of visiting each node of a tree exactly once in a


systematic order based on the order. During traversal, we may print the info field of
each node visited.
Q Systematic Approach to Data Structures using C - 10.15

Now, let us see "What are the different traversal techniques of a binary tree?" The
various traversal techniques of a binary tree are shown below:

Binary tree
traversals -E Pre order
Inorder

Postorder
Now, let us see "What is preorder traversing of a binary tree?"

Definition: The pre order traversal of a binary tree can be recursively defmed as
follows:
1. Process the root Node [NJ
2. Traverse the Left subtree in preorder [LJ
3. Traverse the Right subtree in preorder [RJ

The C function to traverse the tree in pre order can be recursively defined as shown
below:

Example 10.4.2.1 :Display the contents of the tree in preorder

voidpreorder(NODE root)
{
if ( root = NULL) return;

printf("%d ",root->info); /* visit the node */


preorder( root->llink); /* visit left subtree in preorder*/
preorder( root->rlink); /* visit right sub tree in preorder*/

Now,let us see "What is inorder traversing of a binary tree?"

Definition:The inorder traversalof a binary tree can be recursively defined as


follows:
1. Traverse the Left subtree in inorder [LJ
2. Process the root Node [NJ
3. Traverse the Right subtree in inorder [RJ

TheC function traverse the tree in inorder is shown below::


10.16 Q Trees

Example 10.4.2.2: Function traverse the tree in inorder

void inorder(NODE root)


{
if ( root = NULL) return;

inorder(root->l1ink); /* visit left-subtree in inorder */


printf("%d ",root->info); /* visit the node */
inorder(root->rlink); /* visit right-subtree in inorder */
}

Now, let us see "What is postorder traversing of a binary tree?"

Definition: The postorder traversal of a binary tree can be recursively defined as


follows:
1. Traverse the Left subtree in postorder [L]
2. Traverse the Right subtree in postorder [R]
3. Process the root Node [N]

The C function traverse the tree in postorder is shown below:

Example 10.4.2.3: Function traverse the tree in postorder is shown below:

void postorder(NODE root)


{
if ( root = NULL) return;

rxrtoracrtroot-c-llink); /* visit leftsubtree in postorder*/


r'0sto~'~~',l"ot-orlinkv /* visit rightsubtree in postorder*/
print \..''1J/od ",root->illtO); /* visit the node */
}

Example 12.4.2.4: Traverse the following tree in preorder

Solution: Easiest method of writing pre order traversal is to start from innermost
square and visit each node in the sequence specified as shown below:
.Q Systematic Approach to Data Structures using C - 10.17

2 3 '---..r---'
D G H E I F

The above tree now can be written as shown below:

B D G H C ElF

The above tree can be now written as shown below:

ABDGHCEIF
10.18 Q Trees

The preorder traversal by observing the tree and following the numbers in sequence is
shown below:

A B ID
1 2
G HI
3
\0 c I E \0 I I F

1 3 \..1
\.. 2
V
.J
2
V
3
2 3
Example 12.4.2.5: Easiest method of writing inorder traversal is to start from
innermost square and visit each node in the sequence specified as shown below:

G D H E I F
The above ee now can be written as:

G D H B E I C F
Q Systematic Approach to Data Structures using C - 10.1
Theabove tree can be now written as shown below:

In order traversal is G D H B A E I C F

The inorder traversal by observing the tree and following the numbers in sequence
shownbelow:

tG
: HI: 3
C
2 3
F

I
I 2 3
Example 12.4.2.6: Easiest method of writing postorder traversal is to start frc
innermost square and visit each node in the sequence specified as shown below:

1 2

-
G H DIE F

'ryl~above tree now can be written as:


=1'
\
Q Systematic Approach to Data Structures using C - 10.21

if (root = NULL) return;

display(root->rlink, level + 1);

for (i = 0; i < level; i++) printf(" ");

printf("%d\n", root->info);

display(root->llink, level + 1);


}

10-4.3 Searching

Now, let us see "How to search for a key in a binary tree?" By traversing the tree in
any of the order one can visit each node. As we visit the node we can compare the
information field of each node with the key to be searched. If found, display
successful search, otherwise display unsuccessful search. Here, we use inorder
traversal technique. The equivalent C function is shown below:

Example 10.4.3.1: Function to search for an item using inorder traversal

void search(int item, NODE root, int *flag)


{
if ( root = = NULL) return;

search(item, root->llink, flag); /* Traverse left subtree */

if ( item = root->info ) /* Visit the node */


{
*flag = 1;
return;
}

search(item, root->rlink, flag); /* Traverse right subtree */

Note: In the above function, apart from item and root the other parameter passed is
flag which is a pointer to an integer. If an item is present in the tree, its value is set to
1 and the control is returned to the calling function. So, just before invoking the
function searcht), the flag should be set to 0 and should be invoked as shown below:
10.22 Q Trees

flag = 0;
search(item, root, &flag);

if (flag = 1)
printf("Search successful");
else
printf("Unsuccessful search");

Note: .The program to search for an item using preorder is shown below:

Example 10.4.3.2: Function to search for an item using preorder traversal

void search(int item, NODE root, int *flag)


{
if ( root = NULL) return;

if (item = root->info ) 1* Visit the node *1'


{
*flag = 1;
return;
}
search(item, root->llink, flag); 1* Traverse left subtree *1
search(item, root->rlink, flag); 1* Traverse right subtree *1
}

Note: The program to search for an item using postorder is shown below:

Example 10.4.3.3: Function to search for an item using postorder traversal

void search(int item, NODE root, int *flag)


{
if ( root = NULL) return;

search(item, root->llink, flag); 1* Traverse left subtree *1


search(item, root->rlink, flag); 1* Traverse right subtree *1
Q Systematic Approach to Data Structures using C - 10.23

if ( item = root->info ) 1* Visit the node *1


{
*flag = 1;
return;
}

The complete C program for creating a tree, traversing the tree and searching for a
specified item in the tree is shown below:

Example 10.4.3.4: C Program to create a tree, traverse and search for an item

#include <stdio.h>
#indude <stdlib.h>
#include <process.h>
#include <string.h>

struct node

int info;
struct node *llink;
struct node *rlink;
};

typedef struct node* NODE;

1* Include: Example 9.2.1.3:C Function to get a new node from availability list *1
1* Include: Example 10.4.2.1: Display the contents of the tree in preorder *1
1* Include: Example 10.4.2.2: Function traverse the tree in inorder *1
1* Include: Example 10.4.2.3: Function traverse the tree in postorder *1
1* Include: Example 12.4.2.7: C function to print the tree in tree form *1
1* Include: Example 10.4.3.1/2/3: Function to search for item *1
1* Include: Example 10.4.1.1: Function to insert item into tree based on direction *1

void maim)
{
NODE root = NULL;
int choice, item, flag;
~ Systematic Approach to Data Structures using C - 10.25

case 4:
if ( root = NULL)
printf("Tree is empty\n");
else
{
printf("The given tree is\n");
display(root, 1);

printf("Postorder traversal is\n");


postorder( root);
printf("\n");
}
break;

case 5:
if ( root = NULL)
printf("Tree is empty\n");
else
{
printf("The given tree is\n");
display(root, 1);

printf("Enter item to search\n");


scanf("%d", &item);
flag = 0;
searchiitem, root, &flag);
if (flag = 1 )
printf("Seach successful\n");
else
printf("Unsuccessful search\n");
}
break;

default: exit(O);
}
}

ote:Let us create the tree shown in figure 10.5.a. The sequence of input to be
providedto create the tree is shown below:
Q Systematic Approach to Data Structures using C - 10.27
10-4.4 Copying a tree

The C function to obtain the exact copy of the given tree using recursion is shown
below: It is self-explanatory. In this function address of the root node is given and
after copying, it returns address of the root node of the new tree.
,

Example 10.4.4.1: Function to get the exact copy of a tree

NODE copy(NODE root)


{
NODE temp;

if ( root = NULL) return NULL; 1* Tree does not exist *1

temp = (NODE) malloc(sizeof(struct node»; I*Create a new node */

temp->info = root->info; I*copy the information *1


temp->lptr = copy(root->lptr); /*Copy the appropriate links */
temp->rptr = copy(root->rptr);

retu rn temp; 1* return address of the new root *1

10-5Binary search tree (RST)

Now, let us see "What is a binary search tree?"

Definition: A binary search tree is a binary tree in which for each node say x in the
tree, elements in the left-subtree are less than info(x) and elements in the right subtree .
are greater or equal to info(x). Every node in the tree should satisfy this condition, if
leftsubtree or right subtree exists. Fig. 10.4.4.1 shows some of the binary search trees.

Note: Traversal of a binary search tree is same as traversal of a binary tree as


explainedin see 10-4.2. Other common operations performed on binary search trees
are
.• Insertion - An item is inserted
• Searching - Search for a specific item in the tree
,. Deletion - Deleting a node from a given tree.
10.28 Q Trees

(a) (b) (c)


Figure 10.4.4.1 Binary search trees

10-5.1 Insertion
Now, let us see "How to create a binary search?" Creating a binary search tree is
nothing but repeated insertion of an item into the existing tree. So, we concentrate on
how to insert an item into the tree. In a BST (Binary Search Tree), items towards left
subtree of a node x will be less than info(x) and the items in the right subtree are
greater or equal to info(x). Consider the BST shown below:
l

prev=NULL
root 100 cur

••••
•••
.. ..
-~

{140·:
<:»
t
temp
Figure 10.8: Inserting an item into a binary search tree
Q Systematic Approach to Data Structures using C - 10.29

Suppose the node pointed to by temp (with item 140) has to be inserted. The item 140
is compared with root node 100. Since it is greater, the right subtree of root node has
to be considered. Now compare 140 with 200 and since it is less, consider the left
subtree of the node 200. Now, compare 140 with 150. Since it is less, consider the left
subtree of node 150. Since, left subtree of node 150 is empty, the node containing the
item 140 has to be inserted towards left of a node 150. Thus, to find the appropriate
place and insert an item, the search should start from the root node. This is achieved
by using two pointer variables prey and cur. The pointer variable prey always points
to parent of cur node. Initially cur points to root node and prey points to NULL i.e.,
prev = NULL
cur = root

Now, as long as the item is less than info(cur), keep updating the node pointed
to by the pointer variable cur towards left. Otherwise, update towards right. The
pointer variable prey always points to the parent node and cur points to the child
node. Once cur points to NULL, insert the node temp towards left(prev) if item is
less than info(prev), otherwise insert towards right. The code corresponding to this
canbe

prev = NULL;
cur = root;

1* find the position where to insert *1


while (cur != NULL)
{
prev = cur;
if (item < cur->info )
cur = cur->llink:;
else
cur = cur->rlink;
}

if ( item < prev->info )


prev->llink = temp;
else
prev->rlink = temp;
Note: The above steps can be executed provided the tree exists. If the tree is empty
initially, then make the node pointed to by temp itself as root node. The complete C
function to insert an item into a binary search tree is shown below:
10.30 Q Trees

Example 10.5.1.1: Function to insert an item into a binary search tree (with duplicate
elements)
NODE insert(int item, NODE root)
{
NODE temp,cur,prev;
temp = getnodet); 1* Obtain new node from the availability list */
temp->info = item; 1* Copy appropriate data *1
temp->llink = NULL;
temp->rlink = NULL;
if ( root = NULL) return temp; 1* Insert a node for the first time *1
prev = NULL; 1* find the position to insert *1
cur = root;
while ( cur != NULL)
{
pre v = cur; 1* Obtain parent position *1
if (item < cur->info )
cur = cur->llink; 1* Obtain left child position *1
else 1* or *1
cur = cur->rlink; 1* Obtain right child position *1
}
if ( item < prev->info ) 1* Ifnode to be inserted < parent *1
prev->llink = temp; 1* Insert towards left of the parent *1
else
prev->rlink = temp; 1* else, insert towards right of the parent */

return root; 1* Return the root of the tree *1


}

Note: In the above function, duplicate items are inserted towards ri h1. To avoid
insertion of duplicate elements, the above function can be modified as s own below:

Example 10.5.1.2: Function to insert an item into a binary search tree (No duplicate
items are allowed)

NODE insert(int item, NODE root)


{
NODE temp,cur,prev;
temp = getnodei); /* Obtain new node from the availability list */
Q Systematic Approach to Data Structures using C - 10.31

temp->info = item; 1* Copy appropriate data *1


temp->llink: = NULL;
temp->rlink = NULL;

if ( root = NULL) return temp; 1* Insert a node for the first time *1
prey = NULL; 1* find the position to insert *1
cur = root;
while ( cur != NULL )
{
prey = cur; 1* Obtain parent position *1
if ( item = cur->info ) 1* do not insert duplicate item *1
{
printf("Duplicate items not allowed\n");
free(temp);
return root;
}

if (item < cur->info )


cur = cur->llink; 1* Obtain left child position *1
else 1* or *1
cur = cur->rlink; 1* Obtain right child position *1
}
if ( item < prev->info ) 1* If node to be inserted < parent *1
prev->llink: = temp; 1* Insert towards left of the parent *1
else
prev->rlink = temp; 1* else, insert towards right of the parent *1
return root; 1* Return the root of the tree *1

10-5.2 Searching
Now, let us see "How to search for a key in binary search tree?" Start searching from
the root node and move downward towards left or right based on whether the key lies
towards left subtree or right subtree. This is achieved by comparing this key with root
node of an appropriate subtree (left subtree or right subtree). If two items are same
then search is successful and address of that node is returned. If the key is less than
info(root), search in the left subtree, otherwise search in the right subtree. If key is
not found in the tree, finally root points to NULL and return root indicating search is
unsuccessful. The iterative function to search for the key is shown below:
10.32 Q Trees

Example 10.5.2.1: Function to search for an item in binary search tree using iteration

NODE iterative_search(int item, NODE root)


{
if (root = NULL) return root; 1* empty tree *1

while ( root != NULL) 1* search for the item *1


{
if (item = root->info) break;

if ( item < root->info )


root = root->l1ink;
else
root = root->rlink;
}

if (root = NULL) 1* Key not found *1


{
printf("Item not found\n");
return root;
}

printf("Key found\n"); 1* Key found *1

return root;
}

The recursive function to search for an item is shown below:

Example 10.5.2.1: Function to search for an item in BST using recursion

NODE recursive_search(int item, NODE root)


{
if ( root = NULL II item = root->info ) return root;

if ( item < root->info ) return recursive_search(item, root->l1ink);

return recursive _ search(item, root->rlink);


}
Q Systematic Approach to Data Structures using C - 10.33

10-5.3 Other operations


Various other useful operations are shown below.
• find maximum - to return maximum item in the tree
• find minimum - to return minimum item in the tree
• to find height of the tree
• to count the number of nodes
• to count the leaf nodes
• deletion - deleting a node: from the tree

10-5.3.1 To find maximum value in a tree BST

Let us see "How to fmd maximum value in a binary search tree?" Given a binary
search"tree, a node with maximum value is obtained by traversing and obtaining the
right most node in the tree. If there is no right subtree then return root itself as the
node containing the item with highest value. The corresponding C function is shown
below:

Example 10.5.3.1.1: Function to return the address of highest item in BST

NODE maximum(NODE root)


{
NODE cur;

if (root = NULL) return root;

cur = root;
while ( cur->rlink: != NULL)
{
cur = cur->rlink:; /* obtain right most node in BST */
}

return cur;

10-5.3.2 To find minimum value in a BST


Let us see "How to find minimum value in a binary search tree?" Given a binary
search tree, a node with least value is obtained by traversing and obtaining the left
most node in the tree. If there is no left subtree then return root itself as the node
containing an item with least value. The corresponding C function is shown below:
10.34 Q Trees

Example 10.5.3.2.1: Function to return the address of least item in BST


NODE minimum(NODE root)
{
NODE cur;
if (root = NULL) return root;
cur = root;
while ( cur->llink != NULL )
{
cur = cur->llink; 1* obtain left most node in BST *1
}
return cur;
}
10-5.3.3 Height of tree
Let us see "How to find the height of the tree?"

Height of the tree is nothing but the maximum level in a tree. The recursive definition
to compute the height of the tree is shown below:

-I if root = NULL
Height(root) =
{ 1 + max ( height(root->llink), height(root->rlink )) otherwise

The corresponding C function to find the height of the tree is shown below:
Example 10.5.3.3.1: Function to find the height of the tree
1* function to find maximum of two numbers *1
int max(iot a, int b)
{
return ( a> b ) ? a : b;
}
1* Function to find the height of the tree *1
int height(NODE root)
{
if ( root = NULL) return -1;
return 1 + max( height(root->llink), height(root->rlink) );
}
Q Systematic Approach to Data Structures using C - 10.35

10-5.3.4 Count nodes in a tree

Now, let us see "How to count the nodes in a tree?" The number of nodes in the tree
is obtained by traversing the tree in any of the traversal technique and increment the
counter whenever a node is visited. The variable count can be a global variable and it
is initialed to zero before calling this function. In this example, the inorder traversal is
used to visit each node. The C function to obtain the number of nodes in a tree is
shown below:

Example 10.5.3.4.1: Function to count the number of nodes in a tree

void count_node(NODE root)


{
if ( root = = NULL) return;

count_ node(root->llink);

count++;

count_ node(root->r1ink);

·10-5.3.5 Count leaves in a tree

Now, let us see "How to compute the number of leaves in a tree?" As in the previous
case visit each node in a given tree. Whenever a leaf is encountered update count by
one. A leaf or a terminal node is one, which has an empty left and empty right child.
The variable count can be a global variable and it is initialed to zero to start with. The
function to count the leaves in a binary tree is shown below:

Example 10.5.3;5.1: Function to count the leaves or terminal nodes in a tree

void count_leaf(NODE root)


{
if ( root = NULL) return ;

count_leaf(root->llink); /* Traverse recursively towards left */

/* if a node has empty left and empty right child? */


if (root->llink = NULL && root->r1ink = NULL) count++;

count_leaf(root->r1ink); /* Traverse recursively towards right */


}
10.36 Q Trees

10-5.3.6 Delete a node from the tree

It is very important to remember that once the required node is found and deleted, ina
binary search tree the ordering of the tree should be maintained i.e., even after
deleting a node, elements in the left subtree should be lesser and elements in the right
subtree should be greater or equal. Let us see "What are the activities to be performed
to delete a node?" The various activities to be performed are shown below:

Case 1: An empty left subtree and non empty right subtree or an empty right subtree
and nonempty left subtree Note: A node having empty left child and empty right child
is also deleted using this case.
Consider the figures shown below where cur denotes the node to be deleted
and in both cases one of the subtrees is empty and the other is non-empty. The node
identified by parent is the parent of node cur. The non empty subtree can be
obtained and is saved in a variable q. The corresponding code is:

if (cur->llink = NULL) 1* Ifleft subtree is empty *1


q = cur->rlink; 1* non empty right sub tree is saved*1
else if ( cur->rlink = NULL) 1* If right subtree is empty *1
q = cur->llink; 1* non empty left sub tree is saved*1

parent

Figure 10.5.3.6.1. To delete a node cur from the tree

Case 2: Non empty left subtree and non empty right subtree: Consider the figures
shown below where cur denotes the node to be deleted. In both cases both the
subtrees are non-empty. The node identified by parent is the parent of the node cur.
~ Systematic Approach to Data Structures using C - 10.37

parent parent

Figure 10.5.3.6.1. To delete a node cur from the tree

parent

90 q

••
••
11
o
Obtain right subtree of

•• •• the node to be deleted


••••
+. 70
r:::..... ,,"
\b .
Attach left subtree of
node to be deleted to left
of inorder successor

Fig.10.5.3.6.2: To delete node cur from the tree


10.38 Q Trees

The node can be easily deleted using the following procedure in sequence:

Step 1: Find the inorder successor of the node to be deleted. The corresponding code
is shown below:

suc = cur->rlink; 1* Inorder successor always lies towards right */

while ( suc->llink != NULL) 1* and immediately keep traversing left *


{
suc = suc->llink;
}

Step 2: Attach left sub tree of the node to be deleted to the left of successor of the
node to be .deleted. The corresponding code is:

suc->llink = cur->llink; 1* Attach left of node to be deleted to left of


successor of the node to be deleted */
Step 3: Obtain the right subtree of the node to be deleted. The corresponding codeis:

q = cur->rlink; 1* Right subtree is obtained *1


Attach the node q to parent: Now, after case 1 or case 2, it is required to attachthe
right sub tree of the node to be deleted to the parent of the node to be deleted. If parent
of the node to be deleted does not exist, then return q itself as the root node usingthe
statement:
if (parent = NULL) return q;

If parent exists for the node to be deleted, attach the subtree pointed to by q, to the
parent of the node to be deleted. In this case, attach q to parent based on the
direction. If cur is the left child, attach q to left(parent) otherwise attach q to
right(parent). This can be achieved by using the following statement
1* connecting parent of the node to be deleted to q *1
if ( cur = parent->llink )
parent->llink = q
else
parent->rlink = q;

Once the node q is attached to the parent, the node pointed to by cur can be deleted
and then return the address of the root node. The corresponding statements are:
Q Systematic Approach to Data Structures using C - 10.39

free (cur);
return root;

All these statements have been written by assuming the node to be deleted cur and its
parent node is known. So, just before deleting, search for the specified node, obtain
its parent and then delete the node. The complete function to delete an item from the
tree is shown below:

Example 10.5.3.6.1: Function to delete an item from the tree

NODE delete _item(int item, NODE root)


{
NODE cur ,parent, suc, q;

if ( root = NULL)
{
printf("Tree is empty! Item not found\n");
return root;
}
parent = NULL, cur = root; I*obtain node to be deleted, its parent *1
while (cur != NULL)
{
if (item = cur->info) break;
parent = cur;
cur = ( item < cur->info ) ? cur->llink : cur->rlink;
}
if ( cur = NULL)
{
printf("Item not found\n");
return root;
}
1* Item found and delete it *1
1* CASE 1 *1
if ( cur->llink = NULL) 1* If left subtree is empty *1
q = cur->rlink; 1* obtain non empty right sub tree *1
else if ( cur->rlink = NULL) 1* If right subtree is empty *1,.
q = cur->l1ink; 1* obtain non empty left subtree *1
else
{ 1* CASE 2 *1
suc = cur->rlink; 1* obtain the inorder successor *1
10.40 Q Trees

while (suc->llink != NULL)


sue = suc->llink;
suc->llink = cur->llink; 1* Attach left of node to be deleted to *1
I*left of successor of node to be deleted•
q = cur->rlink; 1* Right subtree is obtained *1
}
if (parent = NULL) return q; 1* If parent does not exist return q as root*
1* connecting parent of the node to be deleted to q *1
if ( cur = parent->llink )
parent->llink = q;
else
parent->rlink = q;
free(cur);
return root;
}
The complete program for creating a tree, traversing and deleting a specified itemis
shown below:

Example 10.5.3.6.2: C program to create a tree, traverse a tree and delete an item
from the tree

#include <stdio.h>
#include <stdlib.h> .
#include <process.h>

struct node
{
int info;
struct node *llink;
struct node *rlink;
};

typedef struct node* NODE;

1* Include: Example 10.5.3.6.1: Function to delete an item from the tree *1


1* Include: Example 10.5.1.2: Function to insert an item into binary search tree *1
1* Include Example 10.4.2.1: Display the c ntents of the tree in preorder *1
· Q Systematic Approach to Data Structures using C - 10.41

* Include: Example 10.4.2.2: Function traverse the tree in inorder */


'* Include: Example 10.4.2.3: Function traverse the tree in post order */
'* Include: Example 12.4.2.7: C function to print the tree in tree form */
* Include: Example 9.2.1.3: C Function to get a new node from availability list */

void maim)
{
NODE root, temp;
int choice, item;

root = NULL;

for (;;)
{
printf(" 1:Insert 2:Inorder 3:Preorder\n");
printf("4:delete 5:Exit\n");
printf("Enter the choice\n");
scanf("%d", &choice);
switch( choice)
{
case 1:
printf("Enter the item to be inserted\n");
scanf("%d", &item);
root = iterative_insert(item, root);
break;
case 2:
if ( root = NULL)
printf("Tree is empty\n");
else
{
printf("The given tree in tree form is\n");
display(root, 1);
printf("Inorder traversal is\n");
inorder(root);
printf("\n");
}
break;
case 3:
if ( root = NULL)
printf("Tree is empty\n");
10.42 Q Trees

else
{
printf("The given tree in tree form is\n");
display(root, 1);
printf("Preorder traversal is\n");
preorder(root);
printf("\n");
}
break;
case 4:
printf("Enter the item to be deleted\n");
scanf("%d" ,&item);
root = delete _item(iten:I, root);
break;
default: exit(O);
}
}
}

10-5.3.7 Binary search tree as a priority queue

Let us see "How a binary search tree can be used as a priority queue?" Binary search
tree can be used as a priority queue. To implement ascending priority queue, create a
binary search tree such that elements in the left subtree of any node say x will be less
than info(x) and elements in the right subtree will be greater than or equal to info(x).
Once the tree is created search for the least item and delete from the tree. All these
functions are already implemented and the C program for this is shown below:

Example 10.5.3.7.1: C program to implement priority queue

#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <string.h>

struct node
{
int info;
struct node *llink;
struct node *rlink;
};
Q Systematic Approach to Data Structures using C - 10.43

typedef struct node* NODE;

1* Include: Example 10.5.3.6.1: Function to delete an item from the tree */


1* Include: Example 10.5.1.2: Function to insert an item into binary search tree */
1* Include: Example 10.4.2.2: Function traverse the tree in inorder */
1* Include: Example 12.4.2.7: C function to print the tree in tree form */
1* Include: Example 9.2.1.3: C Function to get a new node from availability list */
1* Include: Example 10.5.3.2.1: Function to return the address ofleast item in BST */

void mainC)
{
NODE root, temp;
int choice,item;

root = NULL;

for (;;)
{
printf(" 1:Insert 2:Display\n");
printf("3 :delete 4:Exit\n");
printf("Enter the choice\n");

scanf("%d" ,&choice);
switch( choice)
{
case 1:
prlntf(t'Enter the item to be inserted\n");
scanf("%d~' ,&item);
root = insert (item, root);
break; .
case 2:
if ( root = NULL)
printf("Priority que is empty\n");
else
{
printf("Contents of priority que\n");
inorder(root);
printf("\n");
}
break;
10.44 Q Trees

case 3:
temp = minimum(root);
if ( temp = NULL )
printf("Priority que is empty\n");
else
{ -
item = temp->info;
printf("The deleted item is %d\n",item);
root = delete_item(item, root);
}
break;
default:
exit(O);
}
}
}

10-6 Applications

Now, let us see "What are the applications of binary search trees?" Some of the
applications of binary search trees are shown below:
• searching and sorting
• manipulation of arithmetic expressions
• Constructing symbol table.
• The trees are also used in syntax analysis of compiler design and are used to
display the structure of a sentence in a language.

Some applications are discussed in this section.

10.6.1 Searching

In binary tree to search for an item, each node has to be compared. But, if the treeis
binary search tree then the comparison will be restricted to either the left subtree or
the right subtree. Comparison starts from the root node and moves downward towards
the leaves. The number of comparisons can be greatly reduced using binary search
tree. It has been discussed in detail in section 10.5.2

10.6.2 Sorting

Once the binary search tree is created, traversing this tree in inorder, the elements will
be displayed in ascending order.
Q Systematic Approach to Data Structures using C - 10.45

10.6.3 Expression trees

A sequence of operators and operands that reduces to a single value is called an


expression.Let us consider only arithmetic operators such as: +, -, * and /. First, let us
see"What is an expression tree?"

Definition:An expression tree is a binary tree that satisfy the following properties:
t Any leaf is an operand
t, The root and internal nodes and operators
t The subtrees represent sub expressions with root of the subtree as an operator.

Letus see "How an infix expression can be written using expression tree?" An infix
expressionconsisting of operators and operands can be represented using a binary tree
withroot as the operator. The left and right subtrees are the left and right operands of
thatoperator. A node containing an operator is not a leaf where as a node containing
anoperand is a leaf. The tree representation for the infix expression

((6+(3-2)*5) /\ 2 + 3)

isshown in figure below: Let us traverse the tree in preorder and postorder as shown:

Preorder traversal Postorder traversal


+

3
"---y-----/
-3 2 = A 32-=A
10.46 Q Trees

*A5=B A5*=B

+6B=C 6B+=C

$C2=D C2 $ =D
Q Systematic Approach to Data Structures using C - 10.47'

2 3

+ D 3 D 3+
+$C23 C2 $3+
+$+6B23 6B+2$3+
+$+6*A523 6A5*+2$3+
+$+6*-32523 632-5*+2$3+
( Prefix expression) (postfix expression)

Note: In an expression tree, we observe that if the expression tree is traversed in


preorder we get prefix expression and if we traverse in postorder we get postfix
expression.In fact, if we traverse in inorder, we get infix expression without brackets.

10.6.4Create binary tree for the postfix expression

Letus see "What is the procedure to obtain an expression tree from the postfix
expression?" The procedure to be followed while creating an expression tree using
postfixexpression is shown below:
• Scan the symbol from left to right.
• Create a node for the scanned symbol.
• If the symbol is an operand push the corresponding node onto the stack.
• If the symbol is an operator, pop one node from the stack and attach to the
right of the corresponding node with an operator. The first popped node
represents the right operand. Pop one more node from the stack and attach to
the left. Push the node corresponding to the operator on to the stack.
• Repeat through step 1 for each symbol in the postfix expression. Finally when
scanning of all the symbols from the postfix expression is over, address of the
root node of the expression tree is on top of the stack.

Thefollowing C function creates a binary tree for the valid postfix expression.
10.48 Q Trees

Example 10.6.4.1: Function to create an expression tree for the postfix expression

NODE creat_tree(char postfix[])


{
NODE temp, st[20];
int i,k;
char symbol;

for ( i = k = 0; ( symbol = postfix[i] ) != '\0'; i++)


{
temp = getnode(); 1* Obtain a node for each operator *1
temp->info = symbol;
temp->llink = temp->rlink = NULL;

if( isalnum(symbol) )
st[k++] = temp; 1* Push the operand node on to the stack */
else
{
temp->rlink = st[--k]; 1* Obtain 2nd operand from stack */
temp->llink = st[--k]; 1* Obtain 1st operand from stack */
st[k++] = temp; i* Push operator node on to stack */
}
}

return st[--k]; 1* Return the root of the expression tree */


}

10.6.5 Evaluation of expression

Now, let us see "How to evaluate the expression?" In the expression trees, whenever
an operator is encountered, evaluate the expression in the left subtree and evaluate the
expression in the right sub tree and perform the operation. The recursive definition to
evaluate the expression represented by an expression tree is shown below:

Eval(root->llink) op E~al(roo!->rlink) if root ->info is operator


Eval ( root) = .
{ Root->info - '0' ifroot->info is operand

The C function for the above recurrence relation to evaluate the expression
represented by an expression tree is shown below:
~ Systematic Approach to Data Structures using C - 10.49

Example10.6.5.1: Function to evaluate the tree

floateval(NODE root)
I
float nurn;

switch( root->info)
{
case '+': return eval(root->llink) + eval(root->rlink);

case '_I: return eval(root->llink) - eval(root->rlink);

case 'I': return eval(root->llink) I eval(root->rlink);

case '*': return eval(root->llink) * eval(root->rlink);

case '$':
case '''I: return pow (eval(root->llink),eval(root->rlink));

default :
if (isalpha(root->info) )
{
printf("%c = ",root->info);
scanf("%f' ,&nurn);
return num;
}
else
return root->info - '0';
}

Thecomplete C program to evaluate an expression using expression tree is shown


below:

Example 10.6.5.2: C program to create an expression tree and evaluate

#inc!ude<stdio.h>
#include<ctype.h>
#include<process.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
10.50 Q Trees

#defme STACK SIZE 20

struct node
{
char info;
struct node *llink;
struct node *rlink;
};

typedef struct node* NODE;

1* Include: Example 9.2.1.3: C Function to get a new node from availability list */
1* Include: Example 10.6.5.1: Function to evaluate the tree *1
1* Include: Example 10.6.4.1: Function to create expression tree for postfx exprsin*1
void maim)
{
char postfix[40];
float res;

NODE root = NULL; I


I Input
printf("Enter the postfix expression\n"); I Enter postfix expression
scanf("%s" ,postfix); I 632-5*+ 1"7+
root = creat_ tree(postfix); I
res = eval(root); I
I Output
printf("Result = %f\n", res); I Result = 18.00000
} I
Output
Enter the postfix expression
abc-d*+e"f+
e=1
a=6
b=3
c=2
d=5
f=7
Result = 18.0000
Q Systematic Approach to Data Structures using C - 10.51

10.7 Tree operations using sequential representation

Insection 10.3 we have seen as to how a tree can be represented using an array. The
creation of a binary search tree and different traversal techniques using array
representation is ~iscussed in this section. The advantages and disadvantages of
sequentialrepresentation over linked representation is also discussed.

10.7.1 Creation of a binary search tree and traversal techniques

The second approach discussed in section 10.3 to represent a binary tree using
sequential allocation is used. The complete program in C to create the binary search
treeand to traverse the tree in inorder, preorder and postorder is shown below:

Example 10.7.1.1: C Program to create a tree and traverse the tree using array
representation

#inc1ude<stdio.h>
include<process.h>

#defineMAX SIZE 100

typedef int NODE;

/*function to insert an item */


voidinsert(int item, NODE am
{
int i;

i = 0; 1* root node */
while (i < MAX_SIZE && a[i] != 0) /* obtain position where to insert */
{
if (item < a[i] )
i = 2*i + 1; /* Move towards left link */
else
i = 2*i + 2; /* Move towards right link */
}

a[i] = item; /* insert the item */


10.52 Q Trees

void inorder(NODE a[], int i)


{
if ( a[i] = 0) return;

inorder(a, 2*i + 1); 1* Traverse left sub tree *1


printf("%d ",a[i]); 1* Visit the node *1
inorder(a, 2*i + 2); 1* Traverse right subtree *1
}

void preorder(NODE a[], int i)


{
if ( a[i] = 0 ) return;

printf("%d ",a[i]); 1* Visit the node *1


preorder(a, 2*i + 1); 1* Traverse left subtree *1
preorder(a, 2*i + 2); 1* Traverse right subtree *1
}

void postorder(NODE a[], inti)


{
if ( a[i] = 0 ) return;

postorder(a, 2*i + 1); 1* Traverse left sub tree *1


postorder(a, 2*i + 2); 1* Traverse right subtree *1
printf("%d ",a[i]); 1* Visit the node *1
}

void maim)
{
NODE a[MAX_SIZE];
int item,choice,i;

for ( i = 0; i < MAX_SIZE; i++) a[i] = 0;

fore;;)
{ priotf(" 1:Insert 2:Inorder\n");
printf("3:Preorder 4:Postorder\n");
printf(" 5:Exit\n");
printf("Enter the choice\n");
scanf("%d" ,&choice);
Q Systematic Approach to Data Structures using C ~ 10.53

switch( choice)
{ case 1:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
insert(item, a);
break;
case 2:
if( a[O] = 0)
printf("Tree is empty\n");
else
{
printf("The inorder traversal is\n");
inorder( a,O);
printf("\n");
}
break;
case 3:
if (a[O] = 0)
printf("Tree is empty\n");
else
{
printf("The preorder traversal is\n");
preorder(a,O);
printf("\n");
}
break;
case 4:
if( a[O] = 0)
printf("Tree is empty\n");
else
{
printf("The postorder traversal is\n");
postorder(a,O);
printf("\n");
}
break;
default: exiteD);
}
}
10.54 Q Trees

10.7.2 Advantages and disadvantages

The sequential representation is simple and it saves space if the tree is complete or
almost complete as there is no need to have fields such as left-link, right-link etc.If
the tree is not complete or not almost complete binary tree, too much space may be
wasted. The index i used to move downward while doing some operations should not
exceed the array bound i.e., MAX_SIZE. This is advantageous only when the number
of items in the tree is known in advance.
The linked representation is useful most of the time during repeated deletionor
manipulations, which can be easily done by adjusting the links and where the number
of items in the tree is unpredictable.

10.8 Iterative traversals of binary tree

This chapter deals with, mostly of problems involving recursion. In this sectionwe
develop the functions for traversal of trees using iterative technique.

10.8.1 Iterative preorder traversal

We know that in preorder traversal, node is visited first, then the left subtreeis
traversed in preorder and finally right subtree is traversed in preorder. Visiting the
node here is nothing but display the corresponding item in the node. This canbe
achieved using the statement

printf("%d ",cur->info);

only if cur points to root node. So, initially cur points to the root node. Once thenode
is visited, next is to traverse the left subtree in preorder. For this descend the tree
towards left. Once all the nodes in the left subtree are displayed, it may be requiredto
ascend the parts of the tree to display the nodes in the right subtree, To ascend thetree
later, just before descending towards left, push the address of current node cur and
then descend the tree left. This process has to be repeated till end of left subtreeis
encountered. The code corresponding to this can be written as

while ( cur != NULL)


{
printf("%d ",cur->info); 1* Visit the node *1
s[++top] = cur; 1* push(cur, &top, s) *1
cur = cur->1link; 1* traverse left *1
}
Q Systematic Approach to Data Structures using C - 10.55

In the tree shown in figure below, after executing these statements 100,50 and 25 will
be displayed.

Figure 10.8.1 Binary search tree

Once traversing the left subtree in pre order is over, traverse the right subtree in
preorder i.e., ascend the tree by poppipg the address of the node most recently pushed
and descend towards right subtree. This is possible only when the stack is not empty.
If the stack is empty traversing the tree in preorder is complete and the program
terminates. The code corresponding to this is shown below:

if ( top != -1 ) 1* If stack is not empty *1


{
cur = s[top-- ]; 1* Obtain the recent node from the stack *1
cur = cur->rlink; 1* traverse right *1
}
else
return;

After descending the tree towards right, entire right sub tree has to be traversed in
preorder. So, the above set of statements has to be repeated. The complete C function
forthis is shown below:

Example 10.8.1: Function for iterative preorder traversal

void preorder(NODE root)


{
NODE cur, s[20];
int top = -1;
10.56 Q Trees

if ( root = NULL)
{
printf("Tree is empty\n");
return;
}

cur = root;

for (;;)
{
while (cur != NULL)
{
printf("%d ",cur->info); /* Visit the node */
s[++top] = cur; /* push(cur, &top, s) */
cur = cur->llink; /* traverse left */
}

if ( top != -1 ) /* If stack is not empty */


{
cur = s[top--]; /* Obtain the recent node from the stack */
cur = cur-c-rlink; /* traverse right */
}
else
return;
}
}

1 8.2 Iterative inorder traversal

In this traversal technique, first left subtree is traversed in inorder, then the node is
visited and finally the right subtree is traversed. As in iterative preorder traversal,
traverse the left sub tree in inorder by descending the tree towards left until cur which
initially points to root node is NULL. Before updating the pointer cur towards left,
push its address so as to descend towards right subtree later. The code corresponding
to this can be

while ( cur != NULL )


{
s[++top] = cur; /* push(cur,&top,s); */
cur = cur->llink; /* traverse left*/
}
~ Systematic Approach to Data Structures using C - 10.57

Oncethe left subtree is traversed, visit the node by popping the most recently pushed
node on to the stack and then traverse towards right if the stack is not empty. If the
stackis empty, traversing the tree in inorder is over and the procedure is terminated.
Thecode to achieve this can be

if (top !=-1) /* If stack not empty */


{
cur = s[top--]; /* Remove recent node from stack */
printf("%d ",cur->info); /* visit node */
cur = cur->r1ink; /* traverse right */
}
else
return;

Aftertraversing towards right, traverse the tree in inorder and repeat the process. This
canbe achieved by executing all the above statements. The C function to traverse the
treein inorder is shown below:

Example 10.8.2: Function for iterative inorder traversal

'* display the contents of the tree in inorder *1


void inorder(NODE root)
{
NODE cur,s[20];
int top = -1;

if ( root = NULL)
{
printf("Tree is empty\n");
return;
}

cur = root;

for (;;)
{
while ( cur != NULL)
{
s[++top] = cur; /* push(cur,&top,s); */
cur = cur->l1ink; /* traverse left*/
}
10.58 Q Trees

if (top != -1 ) /* If stack not empty */


{
cur = s[top--]; /* Remove recent node from stack */
printf("%d ",cur->info); /* visit node */
cur = cur->rlink; /* traverse right */
}
else
return;
}
}

10.8.3 Iterative postorder traversal

In postorder traversal, traverse the left subtree in postorder, then traverse the right
subtree in postorder and fmally visit the node. Here also stack is used. But, each node
will be stacked twice once during traversing the left-subtree and another while
traversing towards right. Just to distinguish that traversing the right subtree is over,
we set the flag to -1. So, check the flag field of the corresponding node. If flag field
of a node is -ve, right subtree is traversed and one can visit the node. Otherwise
traverse the right subtree. This process is repeated till the stack is empty. The C
function for this is shown below:

1 Example 10.8.3: Function for iterative postorder traversal

void postorder(NODE root)


{
struct stack
{
NODE address;
int flag;
};

NODE cur;
struct stack s[20];
int top = -1;

if ( root = NULL) /* Check for empty stack */


{
printf("Tree is empty\n");
return;
}
Q Systematic Approach to Data Structures using C - 10.59
cur = root;

for (;;)
{
while ( cur != NULL)
{
top++;
s[top].address = cur; /* push(cur,&top,s) */
s[top].f1ag = 1;
cur = cur->llink; /* traverse left */ ,r

/* -ve values on stack indicate right subtree is


* traversed and the node can be visited
*/
while ( s[top ].f1ag < 0 )
{
cur = s[top].address; /* cur = pop(&top,s); *!
top--;

printf("%d ",cur->info); /* visit the node */

if (top = -1 ) return;
}

/* ascend to traverse the right subtree */


cur = s[top].address; /* cur = pop(&top,s); */
cur = cur->rlink;
s[top ].f1ag = -1; /*-ve indicates right subtree is traversed */
}

Thecomplete C program to create the tree and traversing using iterative technique is
shownbelow:

Example 10.8.3: Program to create a tree and to traverse (Iteration)

#include<stdio.h>
#include<stdlib.h>
#include <process.h>
10.60 Q Trees

struct node
{
int info;
struct node *llink;
struct node *rlink;
};

typedef struct node* NODE;

1* Include: Example 10.8.1: Function for iterative preorder traversal *1


1* Include: Example 10.8.2: Function for iterative inorder traversal *1
1* Include: Example 10.8.3: Function for iterative postorder traversal *1
1* Include: Example 10.5.1.1: Function to insert an item into a binary search tree *1
1* Include: Example 9.2.1.3: C Function to get a new node from availability list */

void maint)
{
NODE root = NULL;
int choice, item;

for (;;)
{
printf("l :Insert 2:Preorder\n");
printf("3 :Inorder 4:Postorder\n");
printf("Enter the choice\n");

scanf("%d" ,&choice);
switch( choice)
{
case 1:
printf("Enter the item to be inserted\n");
scan f("%d" ,&item);
root = insert(item,root);
break;

case 2:
preorder( root);
printf("\n");
break;
Q Systematic Approach to Data Structures using C - 10.61

case 3:
inorder(root);
printf("\n");
break;

case 4:
postorder( root);
~ printf("\n");
break;

default:
exit(O);
}
}

10.9Threaded binary trees

Now, let us see "What are the disadvantages of binary trees?" The various
disadvantages of the binary tree are shown below:
• In a binary tree, more than 50% of link fields have \0 (null) values and more
memory space is wasted by storing \0 (null) values
• Traversing a tree with binary tree is time consuming. This is because, the traversal
of a tree either uses implicit stack (in case of recursive programs) or explicit stack
(in case of iterative programs). Whatever it is stack is must. Most of the time is
spent in pushing and popping activities during traversing.
• Computations of predecessor and successor of given nodes is time consuming
• In binary trees, only downward movements are possible

All these disadvantages can be overcome using threaded binary tree. Now, let us
see"What is threaded binary tree?"

Definition: In a binary tree, more than 50% of link fields have \0 (null) values and
more space is wasted by the presence of \0 (null) values. These link fields which
contains \0 characters can be replaced by address of some nodes in the tree which
facilitate upward movement in the tree. These extra links which contains addresses of
somenodes (pointers) are called threads and the tree is termed as threaded binary tree.
In general, a threaded binary tree is a binary tree which contains threads (i.e.,
addresses of some nodes) which facilitate upward movement in the tree.
10.62 Q Trees

Now, let us see "What are the various types of threaded binary trees?" A binary treeis
threaded based on the traversal technique. Since there are three traversal techniques,
threaded binary trees are classified into three types as shown below:

Types of threaded
bi tr
mary ees -f In-threaded binary trees
.
Pos-threaded bmary trees

Pre-threaded binary trees

Now, let us see "What is in-threaded binary trees?"

Definition: In a binary tree, if llink (left link) of any node contains \0 (null) andifit
is replaced by address of the inorder predecessor, then the resulting tree is calledleft
in-threaded binary tree. In a binary tree, if rlink (right link) of a node is NULL andif
it is replaced by address of inorder successor, the resulting tree is called right in
threaded binary tree, An in-threaded binary tree or inorder threading of a binary tree
is the once which is both left in-threaded and right in-threaded. For example, consider
the binary tree shown below:

Fig. 10.9.1 Binary tree with a header node

In the above binary tree, if the right link of a node is NULL and if it is replaced by the
address of the inorder successor as shown using dotted lines in fig. 10.9.2, then the
tree is said to be right in-threaded binary tree.
~ Systematic Approach to Data Structures using C - 10.63

r--------------,
I I
I I
I I

h~

[ _~_- ~~ r I 1
~ ....----I=lllfc:;-r=I:J...----.

! ,,';;~ead 1 t 1
[ZTIIJ ~ j lZJJ'IJ
.~

(b)

Figure 10.9.2: Right in-threaded binary tree

Now, let us see "How to implement right in-threaded binary tree in C language?" To
implement a right in-thread an extra field rthread is used. If rthread is 1 the
corresponding right link represents a thread and if rthread is 0 the right link
represents an ordinary link connecting the right subtree. Thus a node can be defined
as shown below:
struct node
{
int info;
struct node *llink; /* Pointer to the left subtree */
struct node *rlink; /* Pointer to the right subtree */
int rthread; /* 1 indicates the presence of a thread*/
/* 0 indicates the absence of a thread */
};

typedef struct node* NODE;

For a binary tree shown in figure 10.9.1, if the left field of a node is NULL and is
replaced by the inorder predecessor as shown in fig.10.9.3, then the tree is said to be
left in-threaded binary tree.

Here also an extra field [thread is used where 1 indicates the presence of a thread and
o indicatesordinary link connecting the left subtree.
10.64 Q Trees

r-------------------------------------, I
I

lthread ~

rI A 1
I

~ I ~'~"'" 1
~ 1 DIE]
tTI:J2J
Figure 10.9.3 Left in threaded binary tree

r--------------,
I I
I I
r----------------------------------~
I I
I
I
I
I

\ ~head !

1 /,:1 AI!
~!l leil\., 1!
CIJIIJ ~1 \
1
I
o::rr:J
.~

Figure 10.9.4 In-threaded binary tree (inorder threading of binary tree)


Q Systematic Approach to Data Structures using C - 10.65

Thus a node can be defined as

struct node
{
int info;
struct node *llink; 1* Pointer to the left subtree */
struct node *r1ink; 1* Pointer to the right subtree *1
int lthread; 1* 1 indicates a thread else ordinary link */
};
typedef struct node* NODE;

An inorder threading of a binary tree or in-threaded binary tree is one which is left
in-threaded and right in-threaded and is shown in fig. 10.9.4. Here two extra fields
[thread and rthread as defined earlier are used and the structure of the node can be
defined as shown below:

struct node
{
int info;
struct node *llink; 1* Pointer to the left sub tree *1
struct node *r1ink; /* Pointer to the right subtree *1
int lthread; 1* 1 indicate a thread else ordinary link */
int rthread;
};

It is desirable to have a header node so as to solve the problems more easily. In this
case, the header node serves as the predecessor of the first node and successor of the
last node. This imposes a circular structure on the tree. When the tree is empty, the
header node is represented as shown in fig. 10.9.5. The tree is attached always to the
left field of the header node.

head

Fig.10.9.S Empty tree with a header node

Now let us see, "How to find the inorder successor and predece sor?' and "How to
traverse the tree in inorder?"
10.66 Q Trees

10.9.1 Inorder successor for right in-thread

Consider the right in-threaded binary tree shown in fig. 10.9.2. Given a node X, if
rthread is 1, which indicates the presence of thread, its rlink gives the address of the
inorder successor. If rthread is 0, rlink contains the address of the right subtree. Left
most node in the right sub tree is the inorder successor. The C function is shown
below:

Example 10.9.1.1: Function to fmd the inorder successor

NODE inorder_successor(NODE x)
{
NODE temp;

temp = x->rlink;

if (x->rthread = 1 ) return temp;

/*Obtain the left most node in the right subtree */


while ( temp->llink != NULL)
temp = temp->llink;

return temp;
}

10.9.2 Inorder traversal of right in-thread

The C function to traverse the tree in inorder is straightforward and the reader is
required to trace this program. The C function is shown below:

Exa pIe 10.9.2.1: Function to traverse the tree in inorder

void inorder(NODE head)


{
NODE temp;

if ( head->llink = head)
{
printf("Tree is empty\n");
return;
}
Q Systematic Approach to Data Structures using C - 10.67

printf("The inorder traversal of the tree is\n");


temp = head;

for (;;)
{
temp = inorder_successor(temp);

if (temp = head) return;

printf("%d ",temp->info);
}

10.9.3 Insert left and insert right

This function inserts item towards left of node x only if its left child is empty and is
shownbelow:

Example 10.9.3.1: Function to insert towards left of a node

void insert_Ieft(int item, NODE x)


{
NODE temp;

temp = getnodet);

temp->info = item;
x->llink = temp;
temp->llink = NULL;
temp->rlink = x;
temp->rthread = 1;

Thisfunction inserts an item towards right of node x only if its right child is a thread
and is shown below:

Example 10.9.3.2: Function to insert towards right

void insertrightfint item, NODE x)


{
NODE temp,r;
Q Systematic Approach to Data Structures using C - 10.67

printf("The inorder traversal of the tree is\n");


temp = head;

for (;;)
{
temp = inorder_successor(temp);

if ( temp = head) return;

printf("%d ",temp->info);
}

10.9.3Insert left and insert right

This function inserts item towards left of node x only if its left child is empty and is
shownbelow:

Example 10.9.3.1: Function to insert towards left ofa node

void insert_left(int item, NODE x)


{
NODE temp;

temp = getnodet);

temp->info = item;
x->llink = temp;
temp->Hink = NULL;
temp->rlink = x;
temp->rthread = 1;

Thisfunction inserts an item towards right of node x only if its right child is a thread
and is shown below:

Example 10.9.3.2: Function to insert towards right

void insertrightfint item, NODE x)


{
NODE temp,r;
10.68 Q Trees

temp = getnodet);

temp->info = item;

r = x->rlink;
x->rlink = temp;
x->rthread = 0;
temp->llink = NULL;
temp->rlink = r;
temp->rthread = 1;
}

10.9.4 Insert an item to a right threaded binary tree

This function finds the appropriate position to insert an item based on the directions.
. Initially the pointer variable cur points to the root node. If the direction is '1'('L') and
if left child is NULL then the item is inserted towards left of cur, otherwise cur is
updated to point towards left subtree. Similarly if the direction is 'r' and rthread of
cur is 1 indicating a thread, item is inserted towards right at that point, otherwise cur
is updated to point towards the right subtree. The function to insert an item into a right
in-threaded binary tree is shown below:

Example 10.9.4.1: Function to construct the threaded binary tree

NODE insert(int item, NODE head)


{
char direction;
NODE cur;

if ( head->llink = NULL) .
{
insert _left( item,head);
retu rn head;
}

cur = head->llink;
for (;;)
{
printff'Tnsert %d towards left",item);
printf(" or right of%d (l/r) ",item,cur->info);
Q Systematic Approach to Data Structures using C - 10.69

direction = getchet);

printf("\n");

fflush(stdin);

if ( direction = '1')
{
if (cur->llink = NULL)
{
insert_left(item,cur);
return head;
}
else
cur = cur->llink;
}
else
{
if ( cur->rthread = 1 )
{
insert Jight(item,cur);
return head;
}
else
cur = cur->rlink;
}
}

The complete program to create a right in-threaded binary tree and traversing the tree
in inorder is shown below:

Example 10.9.4.2: Construct a threaded tree and traverse in inorder

#include <stdio.h>
#inc1ude<stdlib.h>
#inc1ude<process.h>
#include <conio.h>
10.70 Q Trees

'. struct node


{
int info;
struct node *llink;
struct node *rlink;
int rthread;
};

typedef struct node* NODE;

/* Include: Example 9.2.1.3: C Function to get a new node from availability list */
/* Include: Example 10.9.1.1: Function to find the inorder successor */
/* Include: Example 10.9.2.1: Function to traverse the tree in inorder */
/* Include: Example 10.9.3.1: Function to insert towards left of a node */
/* Include: Example 10.9.3.2: Function to insert towards right */
/* Include:Example 10.9.4.1: Function to construct the threaded binary tree */

void maint)
{
NODE head;
int choice, item;

head = getnodet);
head->rlink = head;
head->rthread = 0;
head->llink = NULL;

for (;;)
{
printf(" 1:Insert 2:Inorder\n");
printf("3 :Exit\n");
printf("Enter the choice\n");
scanf("%d" ,&choice);

switch( choice)
{
case 1:
printf("Enter the item to be inserted\n");
scanf("%d" ,&item);
head = insert(item,head);
break;
Q Systematic Approach to Data Structures using C - 10.71

case 2:
inorder(head) ;
printf("\n");
break;
default:
exit(O);
}
}

10.9.5Inorder predecessor for left in-thread

Itis symmetric to the function inorder_successorO i.e., llink is replaced by rlink and
viceversa and rthread is replaced by lthread. The C function for this is shown below:

Example10.9.5.1: Function to find the inorder predecessor

NODE inorderyredecessor(NODE x)
{
NODE temp;

temp = x->llink;

if (x->lthread = 1 ) return temp;

/*Obtain the right most node in the left subtree */


while (temp->r1ink l= NULL)
temp = temp->r1ink;

return temp;

Now, let us see "What is pre-threaded binary trees?"

Definition:In a binary tree, if llink (left link) of any node contains \0 (null) and if it
isreplacedby address of the preorder predecessor, then the resulting tree is called left
re-threadedbinary tree In a binary tree, if rlink (right link) of a node is NULL and
if itis replaced by address of preorder successor, the resulting tree is called right pre-
hreadedbinary tree. A pre-threaded binary tree or preorder threading of a binary tree
istheonce which is both left pre-threaded and right pre-threaded.
10.72 Q Trees

Now, let us see "What is post-threaded binary trees?"

Definition: In a binary tree, if Ilink (left link) of any node contains \0 (null) and if it
is replaced by address of the postorder predecessor, then the resulting tree is called
left post-threaded binary tree. In a binary tree, if rlink (right link) of a node is NULL
and if it is replaced by address of postorder successor, the resulting tree is called right
post-threaded binary tree. A post-threaded binary tree or postorder threading of a
binary tree is the once which is both left pro-threaded and right pro-threaded.

10.9.6 Advantages and disadvantages

Now, let us see "What are the advantages of threaded binary trees?" The various
advantages of the binary tree are shown below:
• In a binary tree, more than 50% of link fields have \0 (null) values and more
memory space is wasted by storing \0 (null) values. This wastage of memory
space is avoided by storing addresses of some nodes.
• Traversing of a threaded binary tree is very fast. This is because, it does not use
implicit or explicit stack.
• Computations of predecessor and successor of given nodes is very easy and
efficient
• Any node can be accessed from any other node. Using threads, upward movement
is possible and using links downward movement is possible. Thus, in a threaded
binary tree, we can move in either directions. This is not possible in un-threaded
binary trees.
• Even though insertion into a threaded binary tree and deletion from a threaded
binary are time consuming operations, they are very easy to implement.

Now, let us see "What are the disadvantages of threaded binary trees?" The various
disadvantages of threaded binary trees are shown below:
• Here extra fields are required to check whether a link is a thread or not and hence
occupy more memory when compared with un-threaded binary trees.
• Insertion and deletion of a node consumes more time than its counter part because
many fields have to be modified.

EXERCISES

1. What is a tree? What are the various operations that can be performed on trees?
2. Write recursive functions to implement various traversal techniques
3. Write an iterative function to traverse the tree in inorder
Q Systematic Approach to Data Structures using C - 10.73

4. Write an iterative function to traverse the tree in preorder


5. Write an iterative function to traverse the tree in postorder
6. Write an iterative function inseru) to insert an element into a tree
7. Write a recursive function to insert an element into a tree
8. Write a program to create a tree and traverse the tree in preorder, inorder and
postorder using arrays.
9. Obtain a directed tree for the given infix expression (A+B)*(C+DY'E.
10.Write a program to implement priority queues
11.Write a program to implement find maximum and minimum in a tree
12.Show that in a complete binary tree the total number of edges is given by 2(nt - 1),
where n, is the number of leaf nodes.
13.Write a C function to obtain the sum of contents of all the nodes in a given binary
tree of integers.
14.Write a C function that accepts a pointer to a node in a binary search tree and
deletes the smallest/largest item from the tree.
15.Write an iterative C function to obtain the copy of a given binary tree.
16.Write a C function to determine the number of leaves in a threaded binary tree
(right in thread or left in thread)
17.Write a C function to find the kth element in the pre order traversal of an
unthreaded binary tree.

Lab Problem 3: Write a C program, which accepts the Internet Protocol (IP) address
in decimal dot format (ex:153.18.8.105) and convert it into 32-bit long integer
(ex:2568095849) using strtok library function and unions.

Solution: The structure of the IP-ADDRESS is shown below:


1000 1001 1002 1003

LJii4L~Llitl1bJ
(Decimal) 153 18 8 105
(Binary) ~1 ~1 ~ Q2!9 Q9,Q9 t.QQ9 Q1J.9 19.5D
(Hexadecimal) 99 12 08 69
'-----------------v----------------~
2568095849

So, given the string 153.18.8.105, extract 153 and copy into field4, extract 18 and
copy into field3, extract 8 and copy to field2 and extract 105 and copy to fieldl.
Then, print 32-bit long integer as shown in following program.
10.74 Q Trees

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct
{
unsigned field4:8;
unsigned field3:8;
unsigned field2:8;
unsigned field 1:8;
} IP-DOT - FORMAT;

typedef union
{
IP_DOT_FORMAT ip;
long int ip_32_bit;

} IP_ADDRESS;

void maint)
{
char a[13];
IP ADDRESS t:,
char *p; Input

printf("Enter IP address in dot format\n"); Enter IPaddress in dot format


scanf("%s",a); 153.18.8.105

p = strtok(a,".");
i.ip.fieldl = atoi(p);

p = strtok(NULL, ".");
i.ip.field2 = atoi(p);

p = strtok(NULL, ".");
i.ip.field3 = atoi(p);

p = strtok(NULL, ".");
i.ip.field4 = atoi(p); Output

printf("32 bit long int = %lu\n",i.ip-':'32_bit); 32 bit long int = 2568095849


}
/

Chapter 11: Sorting and'Searching


What are we studying in this chapter?

• Bubble sort /

• Selection sort
• Simple merge ~
• Merge sort
• Quick sort
• Tree sorts such as binary tree sort and heap sort

• Priority queue using heap


• Insertion sorts such as simple insertion sort, Shell sort, Address
calculation sort

• Radix sort

11.1 Introduction

Sorting is an important concept that is extensively used in the field of computer


science and in day today life. Suppose we want to search for the telephone number of
a person in the telephone directory. If the telephone directory is not sorted in
alphabetical order, we may have to search for the entire telephone directory just to
know whether the telephone number of a person exists or not. Since the telephone
directory is sorted, we know how easy is to search for telephone number. So, it is
required to arrange the names in alphabetical order. There are so many such
applications in day to day life. Before proceeding further, let us ask the question
"What is sorting? What are the various sorting techniques?"
Definition: More often programmers will be working with large amount of data and it
may be necessary to arrange them in ascending or descending order. This process of
. rearranging the given elements so that they are in ascending order or descending order
is called sorting. For example, consider the unsorted elements:
10,50,25,20, 15
11.2 Q Sorting and searching

After sorting them in ascending order, the elements are rearranged as shown below:
10, 15,20,25,50
After sorting them in descending order, the elements are rearranged as shown below:
50,25,20,15,10

11.2 Bubble sort

Before writing the algorithm or the program let us know the answer for" What is the
concept used in bubble sort (Why it is also called sinking sort)?"
Procedure: This is the simplest and easiest sorting technique. In this technique, the
r two successive items A[i] and A[i+ 1] are exchanged whenever A[i] »= A[i+ 1]. For
example, consider the elements shown below:

40,50,30,20,10

The elements can be sorted as shown in figure 11.2.1. In the first pass 40 is compared
with 50 and they are in order. So, no exchange has been done. Next 50 is compared
with 30 and they are exchanged since 50 is greater than 30. If we proceed in the same
manner, at the end of the first pass the largest item occupies the last position. On each
successive pass, the items with the next largest value will be moved to the bottom and
thus elements are arranged in ascending order.

15t Pass I 2nd Pass I 3rd Pass 14th Pass


Ir A 'I~I/A\I~
A[O] = 4~J 40 40 40 40P 30 30 30P20 20 IJ 10
A[l] = sq 501 30 30 30 401 20 20 30J 10 I 20
A[2] ~ ad 30J 5:J 20 201 20J 40J 101 10 30 I 30

~[[:]]: ~~ 20 2 50<-]101 10 10 401 40 40 1 40


..:.t 10 10 loJ 501 50 50 501 50 50 I 50
Given I 50 sinks to I 40 sinks to 130 sinks to I 20 sinks
array I bottom I bottom Ibottom I to bottom
1 after pass 1 1 after pass 2 1 after pass 31

Note: Observe that after each pass, the larger values sink to the bottom of the array
and hence it is called sinking sort.

The following figure below shows the output of each pass.


Q Systematic Approach to Data Structures using C - 11.3

Original Out put of each pass Note: Observe that at the end of each
Array 1st 2nd 3rd 4th
pass smaller values gradually
"bubble" their way upward to the top
A[O] = 40 40/30/20/10 (like air bubbles moving to surface of
A[I] = 50 30/20/10 20 water) and hence called bubble sort.
A[2] = 30 20/10 30 30
A[3] = 20 10 40 40 40
A[4] = 10 50 50 50 50

Now we concentrate on the designing aspects of this sorting technique. The


comparisons that are performed in each pass are shown below:

Passes -7 Pass-I Pass-2 Pass 3 Pass 4

0-1 0-1 0-1 0-1


1-2 1-2 1-2
Comparing 2-3 2-3
3-4

i
i = 0 to 3
t
i = 0 to 2
i
i = 0 to 1
t
i = 0 to 0
5-2 5-3 5-4 5-5
5-(1+1) 5-(2+1) 5-(3+ 1) 5-(4+1)
n- (j+l) n -0+1) n-(j+ 1) n-(j+ 1)
In general we can say i = 0 to n-(j+ 1) or i = 0 to n - j - 1. Here, j = 1 to 4 represent
pass number. In general j = 1 to n-l. So, the partial code can be written as:

forti = 1; j <= n-I ; j++) 1* same as for (j=1; j < n; j++) *1


{
for (i = 0; i <= n-(j+l); i++) /* same as for (i = 0; i < n-j; i++)*/
{
if (A[i] >= A[i + 1])
{
exchange ( A[i] , A[i+ 1] )
}
}
11.4 Q Sorting and searching

The complete C program is shown below:

Example 11.2.1: Program to arrange numbers in ascending order using bubble sort

#include <stdio.h> TRACING


void maint)
{
int n, i, j, temp, a[20];
Input
the number of items
scanf("%d",&n); 5
printf("Enter the items to sort\n"); Enter the items to sort
for ( i = 0; i < n; i++) 40 50 30 20 10
scanf("%d" ,&a[ i]);
Sort the numbers
for(j = l ; j <n;j++)
{ See page number 13.25 to know
for ( i = 0; i < n - j; i++) how the items 40 50 30 20 and 10
{ are sorted
if ( a[i] >= a[i+ 1] )
{ \
temp = a[i];
a[i] = a[i+l];
a[i+l] = temp;
}
}
}
.outPllt
printf("The sorted items are\n"); The sorted items are
for ( i = 0; i < n; i++) 10 20 30 40 50
printf("%d\n",a[i]);
}
Advantages of bubble sort
~ Very simple and easy to program
~ Straight forward approach
Disadvantages of bubble sort
K It runs slowly and hence it is not efficient. More efficient sorting techniques are
present
oA Even if the elements are sorted, n-l passes are required to sort.
Q Systematic Approach to Data Structures using C - 11.5

11.3 Selection Sort

Before writing the algorithm/program let us know the answer for" What is the concept
used in selection sort?"
Procedure: As the name indicates, we first find the smallest item in the list and we
exchange it with the first item. Obtain the second smallest in the list and exchange it
with the second element and so on. Finally, all the items will be arranged in ascending
order. Since, the next least item is selected and exchanged appropriately so that
elements are finally sorted, this technique is called Selection sort.
For example, let us take the following elements and are sorted using selection
sortas shown below: 45 20 40 5 15

Given items After ass 4


A[O] = 4 5
A[l] = 20 I 20 15 15 115

. : :~J ::J
I I
A[2] = 40
A[3] = 5 1 :~
A[4] = 15 I 15 I 20 40 I 45
I .
pt smallest is 12nd smallest is 13Tdsmallest is 14th smallest is I All elements I
5. Exchange it 115. Exchange 120. Exchange 140. Exchange it I are sorted
withl" item I it with 2nditem I it with 3Tditem I with 4th item I

Design:The smallest element from ith position onwards can be obtained using the
followingcode.
pos = i;
for tj =i+l;j <n;j++)
{
if ( a[j] < a[pos] ) pos = j;
}
Afterfinding the position of the smallest number, it should be exchanged with ith
position.The equivalent statements are shown below: '
temp = a[pos];
a[pos] = a[i];
a[i] = temp;
Theabove procedure has to be performed for each value of i in the range 0 ~ i < n-l.
Theequivalent C program is shown below:
11.6 ~ Sorting and searching

Example 11.3.1: Program to arrange numbers in ascending order (Selection sort)

#include <stdio.h> TRACING

void maim) Execution starts from here


{
int n, i, j, temp, a[20],pos; Non-executable statements;
Input
printf("Enter the number of items"); Enter the number of items
scanf("%d",&n); 5

1* Input elements to sort *1


printf("Enter the items to sort\n"); Enter the items to sort
for ( i = 0; i < n; i++)
{ r? s~u
pfDS~
I

scanf("%d" ,&a[i]); 45 te 40 5 15
} 1 ~ ': \J7<
'ri "(if .: '2
/* Sort the elements */ .J I Sort usine selection sort
for (i = 0; i < n-l ; i++) D(frOS c- ~6
{ I See Page number 13.29 for
pos_= 1; () ~zt)sorting the given numbers using
fot'{j - i +1; j < n; j++) selection sort
{
if ( a[j] < a[pos]) pos = j;
/'

temp = ajpos];
aGJos] ,,; a[i]; ,
a[i] = temp;
}
Output
printf("The sorted items are\n"); The sorted items are
for ( i = 0; i < n; i++)
{
printf("%d\n",a[i]); 5 15 20 40 45
}
}
Q Systematic Approach to Data Structures using C - 11.7

11.4Merge Sort

First,let us discuss the way to merge two sorted vectors and later concentrate on merge sort. The
processof merging of two sorted vectors into a single sorted vector is called simple merge. The
onlynecessary condition for this problem is that both vectors should be sorted (either in
ascendingor descending order).

Design:Suppose we have two sorted vectors A and B. Assume m elements are in vector A and n
elementsare in vector B. To obtain a sorted vector, compare ith item of vector A with t item of
vectorB and copy the lesser item into kthposition of resultant vector C (with 0 as the initial value
forthe variables i, j and k).That is, if A[i] is less than B[j], copy the item A[i] to the resultant
vectorC[k] and update the index variables i and k by 1. Otherwise, copy an item B[j] to C[k] and
updatethe index variables j and k. This process of comparing and copying is repeated, for 0::;; i <
m and0 ~ j < n. When either i or j exceeds its limits, the elements remaining in other vector, can
becopiedinto the vector C. Consider the two sorted vectors A and B shown below.
A B C

~~
i J k
Inthis example, m IS 4 ana n IS j. set l,j ana k to U minauy. Arter comparrng AlIJ ana tlUJ we
knownthat A[i] is less than B[j] (10 < 15). So, copy A[i] to C[k] and increment i and k. Then we
compare20 and 15. Since 20 is greater than 15, copy 15 to C and increment j and k by 1.
Repeatingthis process, we have 10, 15,20, 25 and 30 in the vector C. The complete tracing is
shownbelow:
A B C
10 20 40 50 15 25 30 10 10<15,10is
;,f\ It\: copied to C. Now
:J k
k
update i and k
I J
10 20 40 50 15 25 30 10 15 15 < 20 and so 15 is
/I'\. /I'\. copied to C. Now update
j and k
1 J k
20 < 25 and so 20 is
10 20 40 50 15 25 30 10 15 20
copied to C. Now update
IT\
'" i and k
1 J k
25 < 40 and so 25 is
10 20 40 50 15 25 30 10 15 20 25 copied to C. Now update
JI\ IT\
j and k
1 i k
30 < 40 and so 30 is
10 20 40 50 15 25 30 10 15 20 25 30 copied to C. Now update
JI\ JI\
j and k
1 J k
Copy remaining items
10 20 40 50 15 25 30 10 15 20 25 30 45 50 from A to C
m elements n elements m+n elements
11.8· Q Sorting and searching

The pseudo code to achieve the above task is shown below:

while ( i < m and j < n )


if ( A[i] < B[j] ) then
C[k] ~ A[i] II Copy the lowest element from A to C
k~ k+ 1, i ~ i + 1 II Point to next item in C and A
else
C[k] ~ B[j] II Copy the lowest element from B to C
k~k + l,j~j + 1 II Point to next item in C and B
end if
end while

Since, there are no more elements in B to compare, the remaining elements of A can be
copied into C. Now 10, 15, 20, 25, 30,40, 50 are stored in the vector C. In general, when eitheri
or} exceeds its limits, the elements remaining in other vector, can be copied into the vector C and
the corresponding pseudocode is shown below:

while (i < m) II Copy the remaining items from A to C


C[k] ~ A[i]
k~k+l,i~i+l
end while
while (j < n) II Copy the remaining items from B to C
C[k] ~ B[j]
k~k+l,j~j+l
end while

Thus using simple merge, one can merge two sorted vectors into a single sorted vector. The
algorithm is shown below:

Example 11.4.1: Algorithm to merge two sorted vectors into a single sorted vector(simple
merge)
Algorithm SimpleMerge(A, B, C, m, n)
II Purpose: Merge two sorted arrays into a single sorted array
II Input:
II A is a sorted vector with m elem~nts
liB is a sorted vector with n elements
II Output:
II C is a sorted vector obtained after merging the elements of A and B.

i~j~k~O
while ( i < m and j < n )
if.! A[i] < B[j] ) then
C[k] ~ A[i]. II Copy the lowest element from A to C
i ~ i+ 1 II Point to next item in A d

k e=k+ 1 II Point to next item in C


Q Systematic Approach to Data Structures using C - 11.9

else
C[k] +- Bfj] II Copy the lowest element from B to C
j+-j+l II Point to next item in B
k+- k + 1; II Point to next item in C
end if
end while

while (i < m) II Copy the remaining items from A to C


C[k] +- A[i]
i+-i+l
k+-k+l
end while

while (j < n) II Copy the remaining items from B to C


C[k] +- Bfj]
j+-j+l
k+-k+l
end while

In the above algorithm we have used two sorted arrays A and B with index values of vector A and
vector B starting from O. Now, consider a situation of a single vector which is divided into two
sorted parts as shown below:
Vector A

mid mid+ 1

It is clear from the figure that the elements from low to mid are sorted and elements from mid+ 1
to high are also sorted. But, if we take the elements from low to high the elements are not sorted.
Note that instead of considering the vector A as single, we can assume that there are two arrays
with single name A, but one array starts from low to mid and other array starts from mid+ 1 to
high. Now, if we want to merge the two sorted vectors into a single sorted vector, we can modify
the algorithm shown in example 4.4 by replacing the vector B by A and the limits of the first part
of the array being low and mid whereas the limits of second part of the array being mid+ 1 and
high. The modified algorithm to merge two sorted vectors identified by a single vector between
low to mid and (mid + 1) to high into a single sorted vector is shown below:

Example 11.4.2: Algorithm to merge two sorted vectors (a single array divided into two sorted
arrays) into a single sorted vector

Algorithm SimpleMerge(A, low, mid, high)


IlPurpose : Merge two sorted arrays where the first array starts from low to mid and the
II second starts from mid+ 1 to high .
I/Input : A is a sorted from the index position low to mid
II A is a sorted from the index position mid+ 1 to high
11.10 Q Sorting and searching

IIOutput: A is a sorted from index low to high.

i ~ low,j ~ mid+l, k ~ low

while ( i <= mid and j <= high)


if ( A[i] < AU] ) then
C[k] ~ A[i] II Copy the lowest element from first part of A to C
i~i+ 1 II Point to next item in the left part of A
k~k+ 1 II Point to next item in C
else
,C[k] ~ AU] II Copy the lowest element from second part of A to C
j~ j+1 II Point to next item in the second part of A
k e= k+ 1; II Point to next item in C
end if
end while
while ( i <= mid) II Copy the remaining items from left part of A to C
C[k] ~ A[i]
k ~ k + 1, i ~ i + 1
end while
while (j <= high) II Copy the remaining items from right part of A to C
C[k] ~ A[j]
k~k+l,j~j+l
end while
II Copy the elements from vector C to vector A
for i = low to high
a[i] ~ c[i]
end for
return
II End of the algorithm
Once the merging is over, we can easily arrange the numbers in ascending order using merge sort.
If low and high are lower limit and upper limits in an array, the general procedure to sort the
items using merge sort is shown below:
if ( low < high)
1. Divide the array into equal parts
2. Sort the left part of the array recursively
3. Sort the right part of the array recursively
4. Merge the left part and right part
end if
The complete algorithm to sort the numbers using merge sort is shown below:
Q Systematic Approach to Data Structures using C - 11.11

Example 11.4.3: Algorithm for merge-sort

Algorithm MergeSort(A, low, high)

!/Purpose : Sort the elements of the array between the lower bou~d and upper bound

//Input: A is an unsorted vector with low and high as lower bound and upper bound

IIOutput: A is a sorted vector

if ( low < high)


mid +- (low + high)/2 II Divide the array into equal parts
MergeSort (a, low, mid) II Sort the left part of array
MergeSort (a, mid + 1, high) II Sort the right part of the array
SimpleMerge(a, low, mid, high) II Merge the left part and right part
end if

Themerge sort technique can be easily understood by taking the example. Consider the elements:
60,50,25,10,35,25,75,30

The above elements can be sorted using merge sort and the trace for the same is given using
recursiontree as shown in figure 4.2.
- - - - - - - - - - - - - - =-==-==-===-===-==-==-=-=-='-9
Unsorted vector I 60,5~25, 1~35,25,75,30 I
~ ~
1r--6-0,-5-0-,
2-5-,-1-0
-, ,...--------,

~ ~

Figure 11.4.1 Trace of merge sort


11.12 Q Sorting and searching

Example 11.4.4: C++ Program to sort n elements using merge sort

#include <iostream.h>

const int MAX = 1000;

void simple jncrgetint a[], int low, int mid, int high)
{
int 1 low; II Points to first element of left part of the array
int j = mid+l; II Points to first element of second part of the array
int k = low; II Points to first element of resulting array
int c[MAX]; II Temporarily holds the sorted elements

while ( i <= mid && j <= high)


{
if ( a[i] < a[j] )
{
c[k] = a[i]; II Copy the lowest element from first part of A to C
i=i+l; II Point to next item in the left part of A
k=k+l; II Point to next item in C
}
else
{
c[k] = a[j]; II Copy lowest element from second part of A to C
j=j+l; II Point to next item in the second part of A
k = k + I; II Point to next item in C

while ( i <= mid ) II Copy the remaining items from left part of A to C
{
c[k++] = a[i++];

while (j <= high ) II Copy the remaining items from right part of A to C
{
c[k++] = a[j++];
}

I/Copy the elements from vector C to vector A


for (i = low; i <= high; i++)
{
a[i] = c[i];
Q Systematic Approach to Data Structures using C - 11.13

void merge_sort(int a[], int low, int high)


{
int mid;
if ( low < high)
{
mid = (low + high)/2; 1* Divide the array into equal parts *1
merge_sort (a, low, mid); 1* Sort the left part of array *1
merge_sort (a, mid + 1, high); 1* Sort the right part of the array *1
simple_merge(a, low, mid, high); 1* Merge left part and right part *1

void mainO
(
int a[MAX]; II Elements to be sorted
int n; II Number of elements to sort
int 1; II Used as an index to access the elements

cout « "Enter the number of elements to sort" « endl;


cio »> n,

cout « "Enter the elements to sort" « endl;


for ( i = 0; i < n; i++)
cio » a[i];

merge_sort(a,O , n-1);

cout « "The sorted vector is" « endl;


for ( i = 0; i< n; i++)
cout « a[i] «endl;
)

11.5 Quick sort (partition exchange sort)

Thissorting technique works very well on large set of data. The first step in this technique is to
partitionthe given table into two sub-tables such that the elements towards left of the key element
areless than the key element and elements towards right of the key element are greater than key
element.After this step, the array is partitioned into two sub tables. The elements in the left sub
tableare lesser and elements in the right sub table are greater than the key element. For example,
the array obtained after partition may look like shown below:

36 37 1110 42 72 65 98 88 78
-<4~ -->42-
11.14 Q Sorting and searching

low i j, high
42 37 11 9.8 36 72 65 10 88 78 ( 42> 37 so, increment i)
i
42 37 11 98 36 72 65 10 88 78 ( 42> 11 so, increment i)

42 37 11 98 36 72 65 10 88 78 (Since 42 < 98 stop


incrementing i and
compare 42 with a[j] which is 78)
1 J
42 37 11 98 36 72 65 10 88 78 (42 < 78 so, decrementj)
. .
1 J
42 37 11 9.8 36 72 65 10 88 78 ( 42 < 88 so, decrement j)
i j
42 37 11 98 36 72 65 10 88 78 (since 42 < 10 is false
t 't stop decrementing j)
Since i <}, exchange a[i] with a[j] and repeat the process
i j .
42 37 11 1.0 36 72 65 98 88 78 (42) 10 so, increment i)
. .
1 J
42 37 11 10 36 72 65 98 88 78 (42) 36 so, increment i)
. .'
1 J
42 371110-36.7.2 65 98 88 78(42)72isfalseso
stop incrementing i and
compare 42 with a[j] i.e., 98)
J
42 37 11 10 36 72 65 98 88 78 ( 42 < 98 so, decrement j)
1 J
42 37 11 10 36 72 6~ 98 88 78 (42 < 65 so, decrementj)
sJ ~
42 37 11 10 36 72 65 98 88 78 (42 < 72 so, decrementj)
J 1
42 3711 10 3~ 72 65 98 88 78 (42 < 36 is false.)
t t
Since i exceeds}, exchange a[low] with a[j]' Now, the contents of the array will be

36 37 11 10 42 72 65 98 88 78
- <42 - -->42-

Fig. 11.5.1 Tracing of partitioning the array

Here, the elements towards left of the key item 42 are less than 42 and elements towards right of
it are greater. Now, sort the left sub-table and right-sub-table. After sorting the left and right sub-
tables the position of the key item i.e., 42 is not changed and the entire array is sorted. The same
process is repeatedly applied for the left sub-table and right-sub tables, till the elements in both
the sub tables are in their appropriate positions so that the entire array is sorted.
Q Systematic Approach to Data Structures using C - 11.15
To partition the array into two sub tables, two index variables i and) are used. The index variable
i points to low+ 1 where low points to the first element and the index variable) points to high
which points to the last element. The item a[low] is used as a key element. This key item has to
be placed in a position) such that a[k] <= a[j] for low <= k < j and a[j] >= a[l] for j+ 1 <= I <=
high. This can be achieved by comparing the item key with a[i] and aU]' Keep incrementing the
index i whenever key >= a[i]. Immediately when this condition fails, keep decrementing the
index) whenever key < aU]' At this stage if i is less than), exchange a[i] with a[j] and repeat the
process. Ifi is greater than or equal to) then exchange a[low] with a[j] and return) which gives
the position of the partitioned element. Now the elements towards left of aU] are all less than a[j]
and elements towards right of it are greater. Consider the elements shown below:
3711 98 36 72 65.10 88 78
In a table or sub-table, the leftmost element is considered to be a key element always. In the items
shown above, 42 is the key item. Manipulate this table such that elements towards left of 42 are
lesser and elements towards right of it are greater. The fig.II.5.1 shows how partition can be done
for the above elements. This can be done by keep incrementing i byl whenever key is greater than
or equal to a[i] and while updating i, it should not exceed high and the equivalent statement is
shown below:
while (i < high && key >= a[i]) i++;
Once this condition is false, keep decrementing) by 1 as long as key is less than a[j]' This can be
achieved using the statement
while ( key < a[j] ) j--;
Once the control comes out of this loop, if i is less than), exchange a[i] with a[j]' Otherwise,
exchange a[low] with a[j] and return) as the position of the partitioning item. The complete C
function to partition the array as explained is shown below:

Example 11.5.1: Function to partition the array for quick sort


int partition(int a[],int low,int high)
{ int ij,temp,key;
key = a[low], i = low+ 1, j = high;
while(1)
{
while ( i < high && key >= a[i]) i++;
while ( key < a[j] ) j--;
if ( i < j )
temp = a[i], a[i] = a[j]' a[j] = temp;
else
{
temp = a[low], a[low] = a[j], a[j] = temp;
retumj;
11.16 Q Sorting and searching

After partitioning, the original table is partitioned into two sub tables as shown below:
{36 37 11 10} and {72 65 98 88 78}

The same procedure is applied to each of these sub tables repeatedly until the table is completely
sorted. This method of sorting is called partition exchange sort or quick sort. The divide and
conquer approach is used to sort each of these sub-tables as discussed in merge sort. Using this
approach, after ,partitioning the table into two sub-tables, sort the left sub-table recursively and
then sort the right sub-table recursively. Note that as in merge sort, there is no need of merging
the left sub-table and right sub-table. The C function to sort using quick sort is shown below:

Example 11.5.2: Function to sort the numbers in ascending order using quick sort

void quicksorttint a[], int low, int high)


{
intj;

if ( low < high)


{
j = partition(a,low,high); /* Partition the array into 2 subtables */
quicksort(a,low J-l); /* Sort the left part of the array */
quicksort(aJ+ 1,high); /* Sort the right part of the array */

The complete C program to arrange numbers in ascending order using quick sort is shown below:
Example 11.5.3: C program to sort the numbers in ascending order using quick sort

#include <stdio.h>

/* Include: Example 11.5.1: Function to partition the array for quick sort */
/* Include: Example 11.5.2: Function to sort the numbers in ascending order using quick sort */
void maint)
{
int i,n,a[20];

printf("Entr the value for n\n");


scanf("%d",&n);

printf("Enter the numbers to be sorted\n");


for (i=O; i < n; i++) scanf("%d",&a[i));

quicksort(a,O,n-l );

printf("The sorted array is\n");


for(i=O; i < n; i++) printf("%d\n",a[i));
~ Systematic Approach to Data Structures using C - 11.17

11.6 Tree sorts (Heap sort, binary tree sort)

Thetwo types of tree sorting techniques are


• binary tree sort (Create a binary search tree and traverse it in inorder (section 10.6.2)
• heap sort

A priority queue is a special type of data structure wherein the elements are inserted into the
queuebased on the priority and elements are deleted from the queue based on the priority. While
deleting,a highest priority element has to be deleted. To implement a priority queue efficiently, a
heapis used. Apart from implementing priority queue using a heap, it is also possible to sort the
elements in ascending order or descending order which is often called heap sort. Before
discussingheap sort, let us define a heap.
A heap is a complete binary tree where all the levels are full except possibly the last level
i.e.,if the maximum level in the tree is i, upto (i-1)Ihlevel the tree is complete so that the number
of elements in (i_l)th level should be i-I. In level i, number of nodes can be less than or equal to
i If the number of nodes are less than z' at ilh level, then the nodes in that level should be
completely filled, only from left to right (only right most leaves are missing at the last level).

~
(a) (b) (c)

l\ ~
"0

(d)
d (e)

Figure 11.6

A heajs can either be an ascending heap or a descending heap. In an ascending heap, the root
node contains the least element and each node is less than its left child and the right child as
shown in fig 11.6.a. Observe that the items in the path from the root to a leaf are in ascending
order. In descending heap, the root node contains the largest element and each node is greater
than its left child and right child as shown in fib.ll.6.b and fig.l1.6.c and so the items in the path
11.18 Q Sorting and searching

from root node to a leaf are in descending order. Since a heap is an almost complete binary tree,
the nodes can be numbered from the root, one level at a time. In each level the nodes are
numbered sequentially from left to right as shown in figure II.6.c.
In a heap, for a given node i, the parent position say j is obtained by (i - 1)/2, the position
of left child is given by 2i+ 1 and that of right child is 2i + 2. So, in an ascending heap, each a[j]
is less than or equal to a[i], where a[j] is the parent and a[i] can either be left or right child. The
position of each child varies from 1 to n-l (i.e. 1 ~ i < n) and j = (i-I) I 2. Similarly, in a
descending heap, each a[j] is greater than or equal to a[i] where a[j] is the parent and a[i] is the
child. .
ote: The trees shown in fig.II.6.d and fig.ll.6.e are not heaps.

The heap shown in fig.II.6.c can be represented using an array as shown below:
A[O] [1] [2] [3] [4] [5] [6]
100 75 80 25 50 45 30

To sort the elements the first condition is that, the elements should be in a heap. Let us discuss the
way to obtain a heap given an array of arbitrary elements. The elements in an array can be
represented using a tree. A tree consisting of only one element is a heap (it is a root element). To
this initially created heap, insert an item a[k] at the positions 1 ~ k < n. Here, k is assumed to be
the child's position in the heap and a[k] is the item to be inserted. A heap is created using the
following steps for each a[k] for 1 ~ k < n.
• Assign k to i and a[k] to item initially
• Obtain the position of the parent usingj = (i-I) I 2
• Repeat while parent exists and item is greater than the parent
1. Move the parent down to the position of child.
2. Make parent node as the child node
3. Obtain the position of new parent.
• Insert the item into child's position.

The detailed algorithm to create heap is shown below:


Algorithm Heapify(a,n)
{
Repeat for k = 1to n-I
item = a[k] II Item to be inserted
i =k II at position i
j = (i-l ) /2 II Obtain parent position
while parent exists and item> parent
Move parent down to position of child
Make parent node as child
Obtain the position of the new parent
end while
Insert item into child's position
End for
Q Systematic Approach to Data Structures using C - 11.19

Note:The index i indicates the position of the child and} indicates the position of the parent.

,,
® ~
,,
c] ~ ."'~
k=2 k=3
(a) (b) . (c)

k=4 (d)

(e)

//7
@
k=6 (t)

k=7 (g)

Figure 11.7 To create a heap


11.20 Q Sorting and searching

Now, let us see how to obtain a heap shown in fig.1I.7.c from the elements shown below.

50,25,30,75,100,45,80

Initial heap is the tree, which consists of the first item as shown in fig.1I.7.a. Next items to be
inserted are 25 and 30 and are inserted in positions 2 and 3 respectively and the resulting heaps
are shown in fig. 1I. 7.b and fig.1I.7.c. If an item 75 is inserted at 4th position, the tree is no more
a heap. To make it a heap, compare 75 and 25 and since 75 is greater than 25, move 25 down and
75 up and the resulting tree is shown in fig.1I.7.d. Again compare 75 with 50 and since 75 is
greater than 50, move 50 down and 75 up to form the heap as shown in fig.1I.7d. Similarly, the
items 100,45 and 80 are inserted in the appropriate positions and the corresponding heaps are
shown in fig.l l. 7 .e, fig. 1I. 7.f and fig. 1I. 7 .g.

Note: If child is the root, then i is set to °


and parent does not exist. So, to check for the existence
of the parent, check the value of i. If i has a value 0, it means that parent does not exist otherwise,
parent exists.

The pseudocode for creating a heap is shown below:


Algorithm Heapify(a,n)
{
Repeat for k = 1 to n-I
item = ark]
i= k
j=(i-I)/2

/* While parent exists and item> parent */


while i > °
and item> aU]

/*Move parent down to position of child */


a[i] = aU]

/* Make parent as child */


1 =J

/* Obtain the position of the new parent */


j=(i-I)/2

end while

/*Insert item into child's position*/


a[i] = item ••.
End for

The corresponding C function is shown below:


Q, Systematic Approach to Data Structures using C - 11.21
Example 11.6.1: Function to heapify (i.e, to create a heap)

void heapify(int a[], int n)


{
int ij,k,item;

for (k = 1; k < n; k++)


{
item = a[k]; /* item to be inserted */
i =k; /* at the ith position */
j=(i-l)/2; -/* obtain the position of the parent*/

while ( i > 0 && item> au] )


{ /* while parent exists & i~em>parent */

a[i] = au]; /* Move parent down to child */

/* Make parent as child */

j = (i-l)/2; /* Obtain new parent for child */

a[i] = item; /* Insert item into child's position */

Once the heap is created, then root has the highest value. Next step is to sort the elements in
ascending order. Since the root has the highest value, this value can be exchanged with the last
elementso that the item in the last position is sorted. Now, sort the remaining n-I elements. This
canbe achieved by reconstructing the heap for n-I elements and the formal algorithm for this is:

1. Obtain an item i.e., a[O] to be inserted.

2. Find the largest child for the item

3. If item is less than the largest child


• move largest child to the parent position
• Make largest child as the parent
• Obtain the position of the left child for the new parent
Else
Proper position found and insert the item
End

The steps 2 and 3 are performed repeatedly as long as the child exists or item is greater than the
children.When one of the conditions is failed, insert the item into appropriate position. The next
versionof the formal algorithm is shown below:
11.22 ~ Sorting and searching

Algorithm Adjust(a,n)
{
item = a[O] II node to be inserted to recreate heap
j =0 II and its position ( parent)
obtain left child
. while left child exists do
{
if right child also exists obtain the position of the largest child
if item less than the largest child
move largest child to parent position
Make largest child as parent
Obtain position of the left child for the new parent.
Else Proper position found and insert
}
Insert item into parents position.

Once the heap is created and after exchanging 1st item (at position 0) with nth item (which is at
position n-l), the tree is no more a heap. At this point, the root item i.e., a[O] should be moved
down the tree and should be inserted at the appropriate position to get back a heap for remaining
items. For this reason, j that initially points to root is considered as parent and i its child. The
position of left child is given by 2j+ 1 and right child is given by 2j+2. If i points to left child, i+l
gives the position of right child. When we move down the tree, note that the value of i, should not
exceed n-l. The detailed algorithm for adjusting the heap is shown below:

Algorithm Adjust(a,n)
{
item = a[O] II node to be inserted to recreate heap
j=O II and its position
i = 2*j+1 Ilobtain left child
while i <= n-I do II As long as left child exists do

if ( i + 1 <= n-l ) then l/if right child also exists


if ( a[i] < a[ i+ 1] ) i = i + 1 II Obtain position of largest child
endif
I*if item less than the largest child *1
if ( item < a[i] ) then
au] = a[i] I*move the largest child to parent position */
J =1 I*Make largest child as parent *1
i = 2*j+l I*Obtain position of left child for new parent *f
else break 1* Proper position for item found *1
}

au] = item I*Insert item into parents 'position. *1


Q Systematic Approach to Data Structures using C - 11.23

The C function to adjust the heap is shown below:

Example 11.6.2: Function to adjust the heap or to recreate the heap

void adjust(int a[], int n)


{
int ij,item;

j = 0; /* Parent */
item = afj];
i = 2*j+l; /* Left child */

while (i <= n-l ) 1* As long as left child exists *1


{
if ( i+ 1 <= n-I ) 1* If right child also exists */
if ( a[i] < a[i+ 1] ) i++; /* Obtain position of largest child */
if ( item < a[i] ) /* If item less than largest child */
{
au] = a[i]; /* Move child to parent position */
J = 1; /* Make child as parent */
i = 2*j+l; /* Obtain left child of new parent */
}
else
break; /* Proper position for item found */
}
au] = item; /* Insert item to parent position */

Consider the situation shown in fig.l1.8.a. After exchanging a[O] with a[n-l] i.e., 100 and 45, the
tree shown in fig.l1.8.b is obtained and (n_lyh item is sorted. Now, reconstructing the heap for
remaining n-l elements using the above procedure the tree shown in fig.l1.8.c is obtained. We
see that the item 45 is moved down the tree and is inserted at the appropriate position so as to get
the heap for n-l elements.

(a) (b) (c)


Figure 11.8 To show how a heap can be reconstructed
11.24 ~ Sorting and searching

Using the two functions i.e., to create a heap and reconstructing the heap the elements can be
easily sorted and the heap sort algorithm is shown below.

1. Call heapify to create the heap.

2. Once the heap is created, the root has the highest value and exchange root with the nill
element. Now the nth item is sorted and we have to sort the remaining n-I elements. This is
achieved by reconstructing the heap by calling the function adjusu) for n-I elements. Then
the root is exchanged with (n-I yh element. Now last two elements are sorted. Recreate the
heap for the remaining n-2 elements by calling the function adjusu) for n-2 elements. By
repeating this process, fmally all the elements will be arranged in ascending order.

The fig.l1.9. clearly shows how the elements are sorted. Initially, using the function heapify(a,n)
create the heap as in fig.l1.9.a. Exchange a[l] with a[7]. The last item is sorted. Recreate the
heap for remaining 6 elements. Exchange a[l] with a[6]. Now last two items are sorted. Then
recreate the heap for 5 elements. Repeating this way all the items are arranged in ascending order.

Exchange
==>
a[O],a[6]

Initial heap sorted


part

Exchange a[O],a[5]
c::=:======~

sorted part

Exchange a[O],a[ 4]

sorted part
Q Systematic Approach to Data Structures using C - 11.25

Exchange a[O],a[3]

sorted part

25

Exchange a[O],a[2]
4

art ~

Exchange a[O],a[1] The entire array sorted


====~~ L- ~

Fig.ll.9 Trace for Hea sort

Example 11.6.3: Function for heap sort

Algorithm HeapSort(a,n) void heapsort(iot a[], int n)


{ {
Heapify(a,n); int i, temp;
Repeat for i = n-l down to 0 heapify(a,n);
Exchange a[O], a[i] . for ( i = n-l ; i > 0; i--)
Adjust(a,i); {
End for temp = a[O], a[O] = a[i], a[i] = temp;
} adjust(a,i);
}
}
11.26 Q Sorting and searching

The figures (fig.ll.9) on the left hand side, shows the heap after reconstructing and the
figure on the right hand side shows the sorted part shown using rectangular region. The elements
outside the region, indicates the tree elements for which the heap has to be created. The trace for
the algorithm heap sort is shown in fig.ll.9. The algorithm to sort items and the C function is
shown in the example 1l.6.3. The complete C program to arrange numbers in ascending order
using heap sort is shown below:

Example 11.6.4: Complete C program to sort n numbers using heap sort

#include <stdio.h>

/* Include: Example 11.6.1: Function to heapify (i.e, to create a heap) */


/* Include: E ample 11.6.2: Function to adjust the heap or to recreate the heap */
/* Include: Example 11.6.3: Function for heap sort */

void maint)
{
int a[20],n,temp,i;

printf("Enter no. of elements to sort\n");


scanf("%d",&n);
printf("Enter the elments to sort\n");
for ( i = 0; i < n; i++) scanf("%d",&a[i]);

heapsort( a,n);

printf("The sorted array is\n");


for ( i = 0; i < n; i++)
{
printf("%d\n" ,a[i]);

11.6.3 Priority queue using heap

This can be achieved by creating a heap. The function heapifyt) creates an ascending heap. Delete
the root node after creating a heap. Now, recreate the heap by calling the function adjustt) forthe
remaining elements. This way, one can easily implement an ascending priority queue. Similarly,a
descending priority queue can also be implemented.

11.7 Insertion sorts(Simple insertion sort, Shell sort)

The insertion sort works very well when the input elements are partially ordered and the numbers
to be sorted are very less. The different techniques using this method are:

• Simple Insertion sort (discussed in section 1.12 )


• Shell sort
,!;l Systematic Approach to Data Structures using C - 11.27

This technique was invented in 1959 by D.L.Shell and hence the name Shell Sort. This technique
is similar to a simple insertion sort. Instead of comparing the adjacent elements one after the other
as in insertion sort, far apart elements with equal distance are compared. Suppose, the following
elements have to be sorted:

Let the gap between the elements to be compared is 3. The subfiles generated with this gap are
shown below:

Subfile 1 a[O] a[3] a[6] a[9] a[12]


Subfile 2 a[1] a[4] a[7] a[10]
Subfile 3 a[2] a[5] a[8] a[11]
L-.,--J L-.,--J L-.,--J

3 3 3 ~ gap between the items in each subfile is 3

Input to Pass 1 with gap = 3

Output of pass I is input to pass 2 and gap is 2

I 20 I 5 I 30 I 45 I 10 I 75 I 50 I 36 I 75 I 80 I 65 I 90 I 85 I
1 I I I I I I

Output of pass2 is input to pass3 and gap is I

Output of pass 3

Figure 11.7.1. Shell sort


11.28 Q Sorting and searching

Each sub file is sorted using insertion sort as shown in fig. 11.7.1. Now, reduce the gap between
the elements to be compared by 1. Generate the subfiles and sort these files based on this
technique. Repeat the same process each time by reducing the gap. Finally, if the gap is one, it
works as simple insertion sort and final output obtained will be the sorted vector.
It is observed from the example shown in figure 11. 7.1 that, in this sorting technique,
instead of comparing adjacent elements as in insertion sort, the elements with an equal gap or
equal distance are compared. The simple insertion technique is used with an exception that the
distance between the elements to be compared is same. The first version of the algorithm/function
is shown below:
item = a[i];
j = i-gap
while (j >= 0 && item < a[j] )
{
a[j+gap] = a[j];
j = j - gap; •
}

a[j+gap] = item;

Note that in the above function, if gap has the value 1, this function is reduced to the insertion
sort technique discussed in the previous section. The above set of statements have to be executed
for each a[i] where gap s i < n. So, the next version of the function can be written as

for (i = 0; i < n; i += gap)


{
item = a[i];
j = i-gap;

while (j >= 0 && item < a[j] )


{
a[j+gap] = a[j];
J = J - gap;
}

a[j+gap] = item;
}

It has been seen earlier that an insertion sort is very efficient if the array is almostsorted
and if the size is small. Initially, make the gap between individual items to be compared aslarge
say gap = (n -1) / 2 so that the sub files are small and the insertion sort technique can be used.In
the next pass, reduce the gap by a factor of 2 and sort again using the above technique. Finally
when gap is 1, note that it works as a simple insertion sort and all the elements are arrangedin
ascending order. The complete C function for this is shown below:
~ Systematic Approach to Data Structures using C - 11.29

Example 11.7.1: C function to sort n numbers using shell sort

void shell_sort(int n, int a[])


{
int ij.gap.item;

for ( gap = (n-l )/2; gap> 0; gap /= 2)


{
for (i = 0; i < n; i += gap)
{
item = a[i];
j = i-gap;
while (j >= 0 && item < afj] )
{
afj+gap] = afj);
j = j - gap;
}
afj+gapl = item;
}

In the above function, the statements in the middle loop can be written using the for statement as
shown below:

Example 11.7.2: C function to sort n numbers using shell sort

void shell_sort(int n, int a[])


{
int iJ,gap,item;

for (gap = (n-l)/2; gap> 0; gap /= 2)


{
for ( i = 0; i < n; i += gap)
{
for ( item = a[i], j = i-gap; j >= 0 && item < afj]; j -= gap)
{
afj+gap] = a[j];
}
afj+gap] = item;
11.30 ~ Sorting and searching

The functions provided in example 11.7.1 and 11.7.2 are equivalent. In these functions there are
three nested loops: The outermost loop is controlling the gap between the elements to be
compared, reducing the gap by a factor of 2 in each pass. Once the gap is zero, all the elements
are sorted in ascending order. The middle loop is used to access each item in each sub-file. The
complete C program to sort the items using Shell Sort is shown below:
Example 11.7.3: C program to sort n numbers using shell sort

#include <stdio.h>
/* Insert the function given in example 11.7.1 or 11.7.2 */
void maint)
{
int n,i,a[20];
printf("Enter the value for n\n");
scanf("%d" ,&n);
printf("Enter n values\n");
for ( i = 0; i < n; i++)
scanf("%d ,&a[i]);
II

shell_ sort(n,a);

printf("The sorted vector is\n");


for (i = 0; i < n; i++)
printf("%d\n" ,a[i]);

11.8 Address calculation sort

The Address Calculation Sort is also called Hash Sort. In this technique, a particular kind of
hashing is used. The hashing function hashO should have the property that if xl :$; x2, then
hash(x1) :$; hash(x2). The function which exhibits this property is called order-preserving or 1101/-
decreasing hashing function. If this hashing function is used to hash an item to which some
previous items have already been hashed, then this item is placed in such a way that all the items
hashed to a particular value should be arranged in ascending or descending order. Thus all the
items in one sub-file will be less than or equal to the elements in the subsequent sub-files. When
all the items have been placed in this order into sub-files, finally concatenate the items in each
sub-file to get the sorted elements. For example, consider the items shown below.

57,45,36,91,28,79,35,68,89,20,62,43,84,55,86

Since the digits available are 0 to 9, we use an array of pointers a[10], where each location in this
array points to the first item in the sub-file whose first digit is same.
~ Systematic Approach to Data Structures using C - 11.31
Hash value for this problem can be obtained by selecting the largest number and finding at which
position the most significant digit is present. For example, for the item 45 hash value is 10
because the digit 4 is in tens position. For the item 199 hash value is 3 since the digit 1 is in
hundredth position. The hash value of a largest number can be obtained using the function shown
below:

Example 11.8.1: C function to find the hash value

int hash(iot a[], int n)


{
int big,i;

/* Find the largest of all the numbers */


big = a[O];
for ( i = 1; i < n; i++)
{
if ( a[i] > big) big = a[i];

i = logI0(big);

return pow(10,i); /* The position of largest number */

After finding the hash value, divide each item to be sorted using this hash value and insert the
item into the appropriate location. For example, if item is 45 and hash value is 10,45110 is 4. So,
insert 45 into the 4th location. If some items are already present in this location, insert it in the
appropriate position such that items in that location are in order. For this reason, we use an array
of ordered linked list. Once all the items are inserted in this way, obtain the items present in each
list in the array one by one and display. The C function to sort the items using Address
Calculation Sort(Hash Sort) is shown below:

Example 11.8.2: C function for Address Calculation Sort (Hash Sort)

void hash_sort(int a[], int n)


{
NODE b[10], temp;
int i, j, digit, hash_value;
hash_value = hash(a,n);
for (i = 0; i < 10; i++) b[i] = NULL;
fore i = 0; i < n; i++)
{
digit = a[i] / hash_value;
b[digit] = insert(a[i],b[digit]);
11.32 Q Sorting and searching

fore i = j = 0; i < 10; i++)


{
temp = b[i];
while ( temp != NULL)
{
a[j++] = temp->info;
temp = temp->link;

The C program to sort the items using Address calculation sort (hash sort) is shown below:
Example 11.8.3: C program to sort numbers using Address Calculation Sort (Hash Sort)

#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <math.h>

struct node

int info;
struct node *link;
};

typedef struct node* NODE;

1* Include Example 9.2.1.3: C Function to get a new node from the availability list *1
1* Include Example 9.3.7: C function to create an ordered linked list *1
1* Include Example 11.8.1: C function to find the hash value *1
1* Include Example 11.8.2: C function for Address Calculation Sort (Hash Sort) *1

void maint)
{
int i,n,a[40];

printf("Enter the value of n\n");


scanf("%d" ,&n);

printf("Enter the items to sort\n");


for (i = 0; i < n; i++) scanf("%d",&a[i]);
t

hash_sort(a,n);

printf("The sorted vector is\n");


for ( i = 0; i < n; i++)
printf("%d\n",a[i]);
· Q Systematic Approach to Data Structures using C -:' 11.33

11.9 Radix sort

This is the method of sorting technique used in card-sorting machines, the machines that are not
available now and are found only in museums. Here we assume that all the numbers to be sorted
°
are of equal digits. There are 10 pockets ranging from to 9. Initially all the packets are empty.
Scan the numbers one by one sequentially, separate the least significant digit and insert into the
appropriate packet. If a packet is not empty, the new item has to be inserted at the rear end of the
pocket. This technique can be explained easily by taking an example. Consider the elements
shown below that we want to sort.

57,45,36,91,28,79,35,68,89,20,62,43,84,55,86,96,78,67

Scan the first number. Here it is 57. Separating the 151 least significant digit we get 7 and we
insert 57 into the 71h pocket. Likewise, scan each item one by one, separate the 151 least significant
digit and insert the item into the appropriate pocket. After this pass is over, the items stored in all
10 pockets are shown below:

55 96 78
35 86 67 68 89
20 91 62 43 84 45 36 57 28 79
Pockets-7 0 I 2 3 4 5 6 7 8 9

Copying the items from pockets ° to 9 we get

20,91,62,43,84,45,35,55,36,86,96,57,67,28,68,78,79,89
In the second pass, empty all the pockets, scan all the numbers one by one, separate the 2nd least
significant digit and insert into the appropriate pocket. The contents of the pockets after the 2nd
pass is shown below:
68 89
28 36 45 57 67 79 86 96
20 35 43 55 62 78 84 91
Pockets-s 0 I 2 3
Copying the items from pockets
4
°
5 6 7
to 9 we get
8 9

20,28,35,36,43,45,55,57,62,67,68,78,79,84,86,89,91,96

Now all the items are arranged in ascending order.

While designing the algorithm we should choose the appropriate data structures. We have 10
pockets, which are empty initially. An item to be inserted into a pocket has to be inserted at the
end and we can insert any number of elements. For this we can use an array of linked lists. We
also know that items are inserted at the end of every pocket and while copying we are accessing
the elements which are at the beginning. So, another data structure that we can use is FIFO data
structure which is queue. While designing we can assume the following functions are available.
11.34 ~ Sorting and searching

• separate(item,j) - 111isfunction returns the jth least significant digit. For example, if item
is 345 and j is 2, the function returns 4.
• insert_rear(start,item) - This function inserts an item at the end of the list identified by
start and returns address of the first node in the list.

In every pass we perform the following operations.

1. Initialize pockets to empty and is achieved by the following statement.


Repeat for i = 0 to 9
P[i] = NULL
End for

2. Obtain the jlh least significant digit from each item to be sorted one after the other and insert
into the appropriate pocket. This can be done using the statement shown below:
Repeat for i '= 0 to n-I
digit = separate(a[i],j) II separate jib digit from a[l]
p[digit] = insert_rear(a[i],p[ digit)) II insert a[i] at the end of digit pocket

End for

3. Copy all the items from each pocket one after the other
Repeat for i = 0 to 9
temp = p[i]; II Obtain starting location ofith pocket
k=O
/* If items are in the pocket, copy them *1
While (temp != NULL)
a[k] = info(temp)
k=k+l
temp = link(temp J
End while
End for
The three statements have to be executed for each pass j where 1 ~ j ~ m where In is the
maximum number of digits in the largest item. The complete algorithm is shown below:

big = largest(a,n)
m = loglO(big) + 1

Repeat for j = 1 to m
Repeat for i = 0 to 9 II Initialize all the pockets
P[i] = NULL
End for
Repeat for i = 0 to n-I
digit = separate(a[i],j) II separate j'h digit from a[l]
p[digit) = insert reartafij.p[digitj) II insert a[i] at the end of digit pocket
End for
Q Systematic Approach to Data Structures using C - 11.35
Repeat for i = 0 to 9
temp = p[i]; II Obtain starting location of i'" pocket
k=O
I*If items are in the pocket, copy them *1
While (temp != NULL)
ark] = info(temp)
k=k+1
temp = link(temp)
End while
End for
End for

TIle statement m = log10(big) + 1 is used to obtain the number of passes necessary. After
executing the statement 111 contains the number of passes required. For example, if big is 234,
after the execution of this statement 111 will be 3 which is the number of digits in the number. TIle
above algorithm we have written by assuming the functions shown below are existing.
• separate(itemJ)
• insert_rear(start,item)
• largest(a,n)

The function to separate jth digit from the item is shown below:

Algorithm separate(itemJ)
{
return item 11oi-1 mod 10

If item is 235 and j is 3, the function returns 235 I 102 mod 19 which is 2.

The function which returns the largest of n numbers is shown below:

Algorithm largest(a,n)
{
big = a[O];
repeat for i = 1 to n-1
if ( a[i] > big) big = a[i]
end for

return big

The C function to arrange numbers in ascending order using radix sort is below:

Example 11.9.1: C function for Radix Sort


11.36 8 Sorting and searching

void radix_sort(iot a[], int n)


{
int ij,k,m,big,digit;
NODE p[10], temp;

big = largest(a,n);
rn = log10(big) + 1;

for (j = l;j <= m;j++)


{
for ( i = 0; i <= 9; i++ ) p[i] = NULL;

for (i = 0; i < n; i++)


{
digit = separate(a[i]j);
p[digit] = insert reart a[i],p[digit]);

k=O;

for ( i = 0; i <= 9; i++ )


{
temp = p[i];
while ( temp != NULL)
{
a[k++] = temp->info;
temp = temp-e-link;
}

The complete program to arrange numbers in ascending order is shown below:


Example 11.9.2: C program to arrange numbers in ascending order using Radix Sort

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <process.h>
struct node
{
int info;
struct node *Iink;
};
typedef struct node *NODE;
.!;lSystematic Approach to Data Structures using C - 11.37

/* function which returns the jib digit of the item */


int separate(int item, int j)
{
return item / (int)pow(10J-l) % 10;

/* function to return largest ofn items*/


int largest(int a[], int n)
{
int i,big;
big = a[O];
for (i = 1; i < n; i++)
{
if ( a[i] > big) big = a[i];
}
return big;

/* Include Example 9.2.1.3: C Function to get a new node from the availability list */
/* Include: Example 9.3.2: Function to insert an item at the rear end of the list */
/* Include: Example 11.9.1: C function for Radix Sort */
void maint)
{
int n,i,a[20];

printf("Enter n items\n");
scanf("%d ,&n);
II

printf("Enter the elements to sortin");


for ( i = 0; i < n; i++)
scanf("%d" ,&a[i]);

radix_sort(a,n);

printf("The sorted array is\n");


for (i = 0; i < n; i++)
printf("%d\n" ,a[i]);

11.10 Searching
Before writing the algorithm/program for searching, let us ask the question "What is searching?
What are the various searching techniques?"

Definition: More often we will be working with large amount of data. It may be necessary to
determine whether a particular item is present in the large amount of data. This process offinding
11.38 Q Sortin and searchin

a particular item 1/1 the large (1/1/011111 oj data is called searching. The two important and simple
searching techniques art' show n below:

11.10.1 Linear search (Sequential search)

Before writing the algorithm or the program it is better to know the answer for "What is linear
search?"

Definition: A linear search is a simple searching technique. In this technique we search for a
given key item in the list In linear order (sequential order) i.e., one after the other. The item to be
searched is 0 ften called key item. The linear search is also called sequential search. For example,
if key = 10 and the list is 20,10,40,25 after searching we say that key is present. Ifkey = 100
after searching we say that key is not present.
Once we know the concept of linear search, the next question is "How to search Jor an
item in a list oj elements?" ow, let us see how to search for an item. The procedure is shown
below:
Procedure: Let us take an example. Assume 10 is the item to be searched in the list of items 50,
40, 30, 60, 10. Observe from above figure that, 10 has to be compared wit a[O], a[ 1], a[2], a[3]
and a[4] as shown below:

Item = 10

50 40 30 60 10
a[O] a[l] a[2] a[3] a[4]
i (Note: i = 0, 1,2,3,4)

~A ,

1 for (i = 0; i < 5; i++)


During searching if item = a[O] {
or ifitem == a[l] if item = a[i]
or if item = a[2] {
or if item = a[3] printf("S uccessful");
or if item == a[4] exit(O);
the search is successful
}
}

But, once the value of i is greater than or equal to 5, it is an indication that item is not present and
display the message"UnsuccessJul search",
~ Systematic Approach to Data Structures using C - 11.39
In general the terminal condition in the for loop i < 5 can be replaced by i < n. The C
program for linear search is shown below:

#include <stdio.h>
#include <process.h>

void maint) TRACING! TRACING2


{
1
int i,n,key,a[20]; 1
Input 1
printf("Enter the value ofn\n"); Enter value of n Enter value of n
scanf("%d" ,&n); 5
1 5
I
printf("Enter n values\n"); Enter n values 1 Enter n values
for (i = 0; i < n; i++) scanf("%d",&a[i]); 10 20 50 40 30 1020504020
I
printf("Enter the item to be searched\n"); Enter item to search I Enter item to srch
scanf("%d" ,&key); 30 1 60
Output Output
1* Search for an element */
for ( i = 0; i< n; i++)
.1
{ 1
if ( a[i] = key) 1
{
printf("Jtem found\n"); Item found I
exit(O); I
1
1
prmtf'(t'Not found\n"); 1 Not found
1
I
Advantages of linear search
• Very simple approach
• Works well for small arrays
• Used to search when the elements are not sorted

Disadvantages of linear search


• Less efficient if the array size is large
• If the elements are already sorted, linear search is not efficient.

Note: When the elements are not sorted and size is very less, linear search is used. If the
elements are sorted, a better algorithm such as binary search can be used.
11.40 Q Sorting and searching

11.10.2 Binary search

Note: The binary search has already been discussed in section 2.6

Advantages of binary search


• Simple technique
• Very efficient searching technique

Disadvantages of binary search


• The list of elements where searching takes place should be sorted.
• It is necessary to obtain the middle element which is possible only if the elements are stored
in the array. If the elements are stored in linked list, this method can not be used.

Now, let us see the difference between binary search and linear search.

Binary search Linear search


• Works only on sorted items • Works on sorted as well as unsorted
items
• Very efficient if the items are sorted • Very efficient if the items are less and
present in the beginning of the list
• Works well with arrays and not on • Works with arrays and linked lists
linked lists • More number of comparisons are
required if the items are present in the
• Number of comparisons are less later part of the array or if elements
are more

11.10.3 Searching an ordered table

The search time for a given key can be reduced significantly if the record keys are stored in
ascending or descending order in a table. For example, assume that a table has n records but not
sorted and assume the item to be searched is not present. Now, to say that item is not present in
the table it requires n number of comparisons (see the previous section for details). On the other
hand, if the record keys are sorted, the number of comparisons are reduced significantly. This is
because, if the records are arranged in ascending order and if the key item being searched is
greater than the item in the table, we can immediately say that search is unsuccessful. In other
words, a given item is missing from the table (which is sorted in ascending order) as soon as we
encounter an item that is greater than the item being searched. Thus, the searching involves few
lookups even during sequential searching. The corresponding C program is shown below:
Note: For simplicity and efficiency of sequential processing, it is worthwhile to arrange the tables
in ascending order or descending order.
~ Systematic Approach to Data Structures using C - 11.41
Example 11.10.3: C function showing linear search on sorted table
#include <stdio.h>
int linear(int item, int n, int a[])
{
int t:,

for (i = 0; i < n; i++)


{
if ( item = a[i]) return i+ 1; /* Item found */
if ( item < a[i] ) return -1; /* Item not found */
}
return -1; /* Item not found */

void maim)
L
int i, n, item, a[20], pos;
printf("Enter the value ofn\n");
scanf("%d",&n);
printf("Enter the elements in ascending order\n");
for (i = 0; i < n; i++)
scanf("%d",&a[i]);
printf("Enter the item to be searched\n");
scanf("%d",& item);
pos = linear(item, n, a);
if (pos = -1)
printf("Item not found\n");
else
printf("ltem found at %d position\n", pos);

11.10.4 Indexed sequential search

The search efficiency for sorted tables can be improved further using indexed sequential search.
This technique- requires additional storage space for storing the index of group of items. In this
technique apart from the sorted table, an auxiliary table say t that holds the key as well as
corresponding pointer to the table is used. The basic requirement in this method is that the
elements in the auxiliary table t as well as the elements in the main table where actual search is
being carried out must be sorted on key. Assume that the auxiliary table t is l/Sth the size of the
sorted table. The auxiliary table t, the sorted table and the relationship between the two is shown
below:
11.42 Q Sorting and searching

Key Student name


\0 Name I
15 Name 2
17 Name 3
18 Name 4
,
21 Name 5
25 Name 6
27 Name 7
t 30 Name 8
kin dex pindex 31 Name 9
21
33
--
I 33
37
Name
Name
10
II
39 Name 12
47
-- 41 Name 13
65
44 Name 14
.... .....
~ 47 Name 15
49 Name 16
55 Name 17
59 Name 18
60 Name 19
65 Name 20

Figure 11.10.4 In indexed sequential file

The algorithm for indexed sequential search is simple and straight forward and is shown below:

for (i = 0; i < INDEX_SIZE; i++)


{
if (key < kindex[i] ) break;
}

low = (i = O)? 0: pindex[i-1]; /* Find the lower limit */

high = (i == INDEX_SIZE)? n-l: pindex[iJ-l; 1* Find the upper limit *1

for (i = low; i <= high; i++) /* Search for the key in master record */
{
if (a[i] = key) return i + 1; /* Key found */
}
return -1; /* Key not found */
~ Systematic Approach to Data Structures using C - 11.43
Using this method, any record can be sequentially searched but with more efficiency with few
lookups. A sequential search is performed on smaller index (left table of figure 12.4.1). Once the
correct position has been found, using the auxiliary table which holds kindex and pindex, it is
required to find the range low and high which is very important step. Once this step is over,
normal sequential search is done for this small table identified (between low and high) thus
increasing the efficiency.

Advantages: The main advantage of indexed sequential search is that the items present in the
table are examined sequentially. But, the search time for an item being searched is reduced
sharply. The technique is very simple. By using flags, deletions from the table can be done very
easily.

Disadvantages: The table that gives the index where to search for can be implemented efficiently
using linked lists (table t shown in figure 12.4.1) and the larger one using arrays. Since linked list
is used, even though insertions and deletions are performed easily, there is an overhead of extra
space for the pointers. If the table is too large to search, then secondary indexing can be used. The
secondary index, actually provide an index to the primary index which in turn points to the entries
in the table we are searching for. Even though, deleting an entry from the table is easy (by using
flags), inserting an item into the table is very difficult and requires movement of large quantity of
data. So, the complexity of the program increases during insertion.

11.10.5 Interpolation search

This technique also works if the items are arranged either in ascending order or descending order.
This technique is better than binary search when the items are uniformly distributed between a[O]
and a[n-l]. The same technique used in binary search is used here also with one exception. In
binary search, the mid value is obtained using the relation:

mid = (low + high)/2;

where as in interpolation search, mid is calculated using the formula:

mid = low + (high -low) * (( key - a[low]) / (a [high] - a[low]));

The complete C program to search for an item using interpolation search is shown below:

Example 11.10.5: C Program to search for an item(interpolation search)

#inc\ude <stdio.h>
int search(item, a, low, high)
int item; /* Element to search */
int a[]; /* Elements to be searched */
int low; /* Points to the first element */
int high; /* Points tot the last element */

int mid; /* Points to the middle element of the table */


11.44 Q Sorting and searching

if ( low> high) return -1; 1* No item found *1

mid = low + (high -low) * (( item - a[low)) I (a[high] - a[low)));

if (item = a[mid)) return mid+ 1; 1* return the middle position *1

if (item < a[mid))


return search(item, a, low, mid - 1) : 1* search left part *1
else
return search(item, a, mid + 1, high)); 1* search right part *1
}

void maint)
{
int n, i, a[20], item, pos;
printf("Enter the number of elements\n");
scanf("%d", &n);
printf("Enter %d items\n",n);
for (i = 0; i < n; i++)
{
scanf("%d" ,&a[i));
}

printf("Enter the item to be searched\n");


scanf("%d",&item);
pos = search(item, a, 0, n-l); 1* 0 -low index and n-l is the high index *1
if(pos = -1)
printf("Item not found\n");
else
printf("Item found at %d position\n", pos);
}

Exercises

1. What are the various sequential searching methods? Explain with example
2. Write a C program to implement iterative and recursive sequential searching technique
3. What sequential technique can be used to search an ordered table
4. What is the advantage of indexed sequential search over searching an ordered table without
index?
5. Write C programs to arrange the numbers in ascending or descending order using various
techniques
6. Write C programs to search for an item using linear search, binary search, interpolation search
and indexed sequential search.
QUESTION PAPERS - 12
12.1 Linear queue and its applications

Now, let us see "What is a linear queue? What arc the applications of linear arrays?"

Definition: A linear queue is a an ordinary queue (definition page 8.3)

Applications: The linear queues are widely used in waiting lines. Some applications
of queues are shown below:
+ Print Server: In a computer network where there are multiple users normally share
the printer. Even in a single user environment we request the OS to print many
files. When we give the command to print various files, those files are added to
the print queue. The file which reaches the front of the queue is printed.
+ Disk driver: In a computer network, disk driver maintains a queue of disk input
and output requests
• Scheduler: The operating system maintains a linear queue of processes in which
the various processes wait for CPU for execution.

12.2 Multiple stacks using a single array

Now, let us "Write a C program to implement multiple stacks using single array". The
multiple stacks can be implemented using a single array. This is implemented using
array of singly linked lists as shown below:

#include <stdio.h>
#include <stdlib.h>

typedef struct node


{
int info;
struct node *link;
} *NODE;

/* Function to get a node: Include: example 9.2.! .3, page 110. 9.11 */
12.2 Q Question papers

1* Function to insert a node: Include: example 9.2.2.1.2, page 9.17 *1

1* Function to delete a node: Include: example 9.3.l. page 9.22 *1

1* Function to display all the stacks *1


void display(NODE a[], int n)
{
NODE temp;
int i;

printf("Contents of multiple stacks\n");

for (i = 0; i < n; i++)


{
printf("Stack %d : ", i);

if ( a[i] = NULL) /* Check for empty list *1


{
printf("empty\n");
continue;
}

temp = a[i]; !* Holds address of the first node *1


while (temp != NULL) t= As long as no end of list */
{
printf("%d ",temp->info); /* Display the info field of node *1
temp = temp->link; !* Point to the next node */
}
printf("\n");
}
}

void maim)
{
int item, choice, n,i;
NODE a[5] = {NULL};

printf("Enter number of stacks\n");


scanf("%d",&n); .
Q Systematic Approach to Data Structures using C - 12.3

for (;;)
{
printf(" 1: Insert 2:Delete\n");
printf("3: Display 4:Exit\n");
printf("Enter the choicexn");
scanf("%d",& choice);

switch (choice)
{
case 1:
printf("Enter stack number and item: \n");
scanf("%d%d",&i, &item);
a[i] = insert_front(item, ajij);
break;

case 2:
printf("From which stack number to delete: ");
scanf("%d" ,&i);
printf("Stack %d : ",i);
a[i] = delete_front(a[iJ);
break;

case 3:
display(a, n);
break;

default:
exit(O);
}
}
}

12.3 Delete nodes whose key z "Kmin" and < Kmax

All the nodes in a list whose information value is greater than or equal to krnin and
less than kmax can be obtained by modifying the function shown in page 9.42 as
shown below:
12.4 Q Question papers

NODE delete_kmin_to_kmax(NODE first, int kmin, int kmax)


{
NODE cur, prey;

while (1)
{
if (first = NULL) return NULL;

if (kmin <= first->info && first->info <= kmax)


{
cur = first;
first = first->link;
free (cur);
continue;
}

prey = NULL;
cur = first;

while (cur != NULL)


{
if(kmin <= cur->info && cur->info <= kmax) break;

prey = cur;
cur = cur->link;
}

if( cur = NULL) return first;

prov-e-link = cur-c-link;
free (cur);

continue;
}
}
Q Systematic Approach to Data Structures using C - 12.5

12.4 Insert to the immediate left of Kth node

This function is obtained by modifying the function shown in page 9.49. Replacing
pos by pos-l, we can insert to the left of the immediate left of Klh node. The complete
function is shown below:

NODE insert_Ieft(int item, int pos, NODE first)


{
NODE temp; /* Node to be inserted */
NODE prey, cur; /* Insert temp between these two nodes */
int count; /* To find the position to insert */

temp = (NODE) malloc(sizeof(struct nodc)); /* Create a node */


temp->info = item;
temp->link = NULL;

if (first == NULL II pos-l == 1) /* Insert the node for the first time */
{
return temp;
}

if (first = NULL)
{
printf'(t'lnvalid positionin");
return first;
}

if (pos-l = 0)
{
temp-c-link = first;
return temp;
}

/* Find the appropriate position */


count = 1;
prey = NULL;
cur = first;
12.6 ~ Question papers

while (cur != NULL && count != pos-l )


{
pre v = cur;
cur = cur->link;
count++;
}

if (count = pos-l )
{
prev->link = temp;
temp->link = cur;

return first;
}

printf("Invalid position\n");
return first;
}

12.5 Concatenate two circular lists using header node

Now, let us "Implement concatenation of two circular singly linked lists List 1 and
List 2. Use header nodes to implement the list" Suppose two circular lists are created
with header nodes identified by list I and list 2. The following function concatenates
two lists:

NODE concatenate(NODE listl, NODE list2)


{
NODE curl, cur22;

!* Obtain the address of the last node of the first 11::;! ,~.
curl = listl->link;
while (curl-c-link != listl)
{
curl = curl->link;
}

/'~ Obtain the address of the last node of the second lisi":
cur2 = list2->link;
while (cur2->link != list2) cur2 = cur2->link;
Q Systematic Approach to Data Structures using C ~ 12.7

!* attach the first node of list 2 to end of hst I vs ,


curl->link = list2->link;

1* Point the last node oflist2 to header oflistl *!


cur2->link = listl;
}

12.6 Reverse a string using stack (array implementation)


Now, let us "Implement reversing a string using stack (array implementation) in C"
The complete program is shown below:
#include <stdio.h>
void strJev( char a[])
{
char s[10];
int i, top;
/* Push all characters onto stack *1
top = -1;
for (i = 0; a[i] != '\0'; H+)
{
s[++top] = a[i];
}
1* Pop from stack and store it in given array *i
i = 0;
while (top != -1)
{
a[i++] = s[top--];
}
}
void maint)
{
char a[10];
printf("Enter the string\n");
scanf("%s" ,a);
strjevfa);
printf("Reversed string = %s\n", a);
}
12.8 Q Question papers

12.7 Length of a string obtained from command line parameter

Let us "Write another program that accepts a string as a command line parameter and
prints its length." The C program is shown below:

#include <stdio.h>
#include <string.h>

void main(int argc, char *argv[])


{
if (argc = 2)
{
printf("String length of%s = %d\n",argv[I], strlen(argv[I]);
}
}

Note: Let us assume the file name corresponding to the above program is "length.e".
It is required to create an executable file and execute the program in the command
line as shown:

Output
C:\>length ComputerScience
String length of ComputerScience = 15

C:\>length InfoScience
String length of InfoScience = 11

12.8 Count the number of nodes in a list

This is similar to the display function shown 111 page 9.19 with the following
modifications: .

int count_node(NODE first)


{
NODE temp;
int count;
~ Systematic Approach to Data Structures using C - 12.9

if (first = NULL) return 0;

count = 0;
temp = first; 1* Holds address of the first node */

while ( temp != NULL ) t= As long as no end oflist */


{
count++; /* count the number ofnodes*!
temp = temp->link; /* Point to the next node *!
}

return count;
}

] 2.9 Update oj(, of student marks by 10'%

Now, let us "Write a C program to read the following information for n students in a
class: Student Name, regno, marks scored in three subjects. Pass the structure through
the function to update percentage by 10%" The percentage is obtained by dividing the
marks obtained by totalmarks and multliplying by 100 as shown below:
percentage = (float) tot_marks_obtained /300 * 100;

Since there are three subjects, we are dividing by 300. After calculating the
percentage, to update percentage of marks by 10% we use the relation:
percentage + percentage* 10/100;

The complete C program is shown below:

#include <stdio.h>
#include <string.h>

typedef struct student


{
char name[10]; !* Name of the student */
int USN; /* University serial number *!
int marks1; /* Marks in subject 1 *i
int marks2; !* Marks in subject 2 *i
int marks3; /*Marks in subject 3 *i
} STUDENT;
12.10 Q Question papers-

void update..J)ercentage(int n, STUDENT a[], float upldated_percentage[])


{
int 1;
int tot_marks _obtained;
float percentage;

for (i = 0; i < n; i++)


{
tot - marks - obtained = a[i].marksl + ajij.marks? + a[i].marks3;
.-

percentage = (float) tot_marks_obtained /300 * 100;

I*Update percentage by 10 %) *;
updated ..J)ercentage[i] = percentage + percentage * 10/ 100;
}
}

void maint)
{
int n; t= Number of students =t
int 1; t= Used to access the student record *!
STUDENT a[lO]; /* Holds the details of 10 students */
float updated ..J)erccntage[l 0];

printf("Enter the number of students\n");


scanf("%d" ,&n);

printf("Enter the details of%d studentsui'',n);

for (i = 0; i < n; i++)


{
printf("Details of %d student\n" ,i+ 1);
printf("Name = "); scanf(" %[I\\n]", a[i].name);
printf("USN = "; scanf("%d", &a[i].USN);
printf("Marksl = "); scanf("%d", &a[i].marksl);
printf("Marks2 = "); scanf("%d", &a[i].marks2);
printf("Marks3 = "); scanf("%d", &a[i].marks3);
}
.Q Systematic Approach to Data Structures using C - 12.11

!*Update percentage by 1O~/;)*1


updatejirercenagem, a, updatedjiercenagc);

printf("The updated marks of the studentsvn");


for (i = 0; i < n; i++) printf("%f\n",updated percentage[i]);

12.10 Pointers revisited

Now, let us see "What is the di fference between *a[l 0]. ('~3)[10]. (*a)( )?,.

Consider 'ka(101 : In the hierarchy of operations, the operator [] is having higher


precedence over * operator. So, *a[lO] is an array of 10 pointers each location
pointing to the specified data type ( for example, see figure). Here, each location of a
points to a string of characters of varying length.

Columns

° 2 3 4 5 6 7 8 9 10 II 12 13 14 15 16

a \0
a[O]?
a[I]?
b a I I I I \0 I
a[2]? C 0 m . r p 1 ul t T e T r T I sic I i I ern I c I e I \0 I
Memory representation

Note: Also refer to page 2.79, example 2.8.4

Consider (*a)( 101: In the declaration (*a)[lO], (*a) indicates that a is a pointer
variable. So, (*a) [10] indicates that a is a pointer to a group of contiguous 1-
dimesnional array elements as shown in figure. lIere, the value 10 indicates the
number of elements in each array.

a ?1 L-.._L....,.._c=.l____l_._:=J. _
I" array

a + I~I ......L.
__ LI ,-;:-;r_.LI __ ..L-_--t _

2nd array

a +2 1 I 1 L- ---.JL- _

~ 3ril array
.......... and so on
12.12 Q Question papers

Note: Also refer to page 2.79, example 2.8.5

Consider (*a) () : Here, (*a)( ) indicates that a is a pointer variable and can store the
address of a function. Here, a is a function pointer and the function do not have any
parameters. If we have the declaration
.'

(*a) (char *, char *)

it indicates that a is pointer variable and can store the address of a function which has
two parameters both of type char *. For details, refer to page 2.106

Now, let us see "What is the difference between int (*ptr) ( ) and int * ptr ( )7"

Consider int (*ptr) 0: Here, ptr is a pointer to a function which does not accept any
parameters and returning an integer value

Consider int ''<ptr 0: Here, ptr is the name of the function which does not accept any
parameters and the function returning an integer value.

12.11 Sum of +ve and +ve numbers using dynamic memory allocation

Now, let us "Develop a program to determine the sum or positive and negative
elements of an array using dynamic memory allocation" The complete program is
shown below:

#include <stdio.h>
#include <stdlib.h>

void maint)
{
int n', !* Number of elements to input From the keyboard *!
int *a; /* To hold starting address of 11 elements */
int i:, 1* Used as index to array *i

int psum; 1* To hold sum of positive numbers *!


int nsum; !* To hold sum of negative numbers *1

printf("Enter number of elements\n");


scanf("%d", &n);
g Systematic Approach to Data Structures using C - 12.13

!* Allocate the required number of memory locations dynamically *!


a = (int *) malloc(n*sizeof(int));

/* Read all n elements */


for (i = 0; i < n; i++) scanf("%d",a+i);

psum = nsum = 0; /* Initial stun of positive and negative numbers */

for (i = 0; i < n; i++)


{
if (*(a+i) > 0) /* find sum of +ve numbers */
psum += *(a+i);
else i* find sum of-ve numbers *!
nsum += *(a+i);
}

/* Deallocate the memory *j


free(a);

printf("Sum of +ve numbers = %d\n", psum);


printf("Sum of -ve numbers = %d\n", nsum);
}

12.12 Average ofn values stored in linked lists

Now, let us "Write a C program to find the average of a set or values stored in a
singly linked list" The complete program is shown below:

float average(NODE first)


{
int n, sum;
NODE temp;

n = sum = 0;
temp = first;
12.14 Q Question papers

while(temp != NULL)
{
sum += temp->info;
n++;

temp = temp->link;
}

return (float) sum/n;


}

12.13 Replace all occurrences of a given value by other value

Now, let us "Write a program 10 replace all occurrences of a given value by other
value". The complete function is shown below:

NODE replace(int item, int other_item, NODE first)


{
NODE cur;

cur = first;
while (cur != NULL)
{
if (item = cur->info) cur->info = other_item;

cur = cur->link;
}

return first;
}
Q Systematic Approach to Data Structures using C - 12.15

Third Semester B.E. Degree Examination, January/February 2004


Computer Science / Information Science and Engineering
Data Structures with C
Time: 3 hrs. Max. Marks: 100

Note: Answer any 5 full questions. All questions carry equal marks

1. (a) What is a structure? How does a structure differ from an array? How are structure
members assigned values and are accessed? Explain. Hence or otherwise develop a C
function to represent a complex number using structure and to add two complex numbers
ADS: Page 4.6: section 4.5, 4,4 (8 marks)
Page 4.20
_ Page 4.47
(b) Write a' c program to accept a string as a command line parameter and to print its
length, . (6 marks)
Ans:Page 12.8

(c) Explain any two C functions used in file handling (6 marks)

Ans: Page 5.9

2. (a) Define a stack. List the operations on stack and give C implementation of these
operations (10 marks)
Ans: Page 6.2, Page 6.11, Example 6.2.9 or Example 6.2.10
Page 6.57, Example 6.5.8

(b) Write an algorithm for evaluating a valid postfix expression. Trace the same on
AB+C-BA+C$- for given values A=I, B=2, C=3 (10 marks)

Ans: Page 6.65

3. (a) What is recursion? Write a recursive function for computing nth term of a fibbonocci
sequence. Hence or otherwise give the trace of stack contents for n = 4
Ans: Page 7.1, Page 7.9 and 7.10 (10 marks)

(b) What is a circular queue? give the static implementation of the same and write the
CQINSERT routine (10 marks)
Ans:Page 8.21, Page 8.23

4, (a) What is a linked list? Compare static and dynamic implementation oflinked lists in C
Ans: Page 9.2, Page 9.70 (10 marks)
12.16 Q Question papers

(b) How can an ordinary queue is represented using a singly linked list? Give algorithms
for inserting as well as deleting elements into a singly linked list
Ans: Page 9.29 (10 marks)

5. (a) What are different methods to represent a binary tree and compare them? (10 marks)
Ans: Page 10.9, section 10.3

(b) Given a binary tree implementation for the following:


i. To compute its maximum depth
ii. To print the nodes in ascending order assuming that the tree is BST
Ans: Page 10.34, section 10.5.3.3
Page 10.44. section 10.6.2 (10 marks)

6. (a) Give an algorithm for constructing as binary search tree. while constructing
the tree take care that duplicate values are not added. Trace the algorithm on
8, 13, 10, 12,6,9,5,2. (10 marks)
Ans: Page 10.30, example 10.5.1.2

(b) Write algorithms for implementing the following:


i. To concatenate two circular linked lists
ii. Delete the first occurrence of value X from a doubly linked list
Ans:Page 9.47 Similar to example 9.3.11.1
Page 9.107 (10 marks)

7. (a) Explain the shell sort procedure by using a suitable data set. (10 marks)
Ans: Page 11.26

(b) Wheat is Hashing? Explain any two techniques for resolving hash collisions.
(10 marks)

8. Write notes on: (4 x 5 = 20 marks)


a. Expression tree Ans: Page 10.45
b. Priority queues Ans:Page 8.27
c. Simple insertion sort Ans:Page 1.50
d. Dynamic memory allocation in C. Ans: Page 2.80 onwards
Q Systematic Approach to Data Structures using C - 12.17

Third Semester B.E. Degree Examination, July/August 2004


Computer Science / Information Science and Engineering
Data Structures with C
Time: 3 hrs. Max. Marks: 100

Note: Answer any 5 full questions. All questions carry equal marks

1. a) What is union? How is it different from structure? With a suitable example


show how union is declared and used in C. (6 marks)
ADs: Page 4.53 onwards

b) What do you understand by dynamic memory allocation? Explain any three


function that support dynamic allocation. (6 marks)
ADs: Page 2.81, page 2.84:Section 2.9.2

c) What are command line arguments? Write a C program to copy contents of a


file to another file. Accept file names an command line arguments.
Ans: Page 5.41, page 5.46

2. a) List applications of stacks. Using stack write an algorithm to determine if a


given string is palindrome and print suitable message as output. (10 marks)
Ans: page 6.14, page 6.48

b) Write an algorithm for converting infix expression to post-fix expression.


Trace the algorithm indicating content of stack for expression (a-b) / (c *d) + e
Ans: Page 6.23 to 6.25 . (10 marks)

3. a) What is recursion? Explain with an 'example. (8 marks)


ADs: Page7.1, 7.5

b) Write recursive function for:


i. Fibonacci series for nth number. (6 marks)
ii. Printing number in reverse order (6 marks)
Ans: Page 7.9, page 7.24:sectiom 7.10

4. a) What are different types of linked lists? Write a C function to count number of
elements present in single linked list?· (10 marks)
Ans:Page 9.3, page 12.8
12.18 ,!;l Question papers

b) Write advantages of doubly lined list over singly lined list. Write C function
that will insert a given integer value into an ordered doubly linked list.
Ans: Page 9.116,Similar to Page 9.37 (10 marks)

5. a) Explain various types of tree traversal with simple example. (6 marks)


Ans: Page 10.5

b) Write C functions for following tree traversals: Inorder, Preorder and Post
order. Ans: Page 10.5, 10.6 (6 marks)

c) Construct a binary tree for the expression A + (B - C) * (E + F) IG and draw


the diagram showing each step. (8 marks)
ns:Page 10.45

6. a) Explain binary tree sort with suitable example. Comment on its efficiency
Ans: Page 10.44, section 10.6.2 (10 marks)

b) What is interpolation search? Explain with an example. (10 marks)


Ans:Page 11.43

7. a) What is hashing? Explain any two hashing methods for resolving hash
collision. (10 marks)

b) Write an algorithm for deleting a node from binary search tree considering all
possibilities. (10 marks)
Ans: Page 10.36

8. Write short notes: (4 x 5 = 20 marks)


a) Threaded binary tree (Page 10.61)
b) Circular queue (Page 8.21)
c) Dynamic stack representation (Page 9.30)
d) Fill operation functions. (Page 5.9)
Q Systematic Approach to Data Structures using C - 12.19

Third Semester B.E. Degree Examination, Jan/Feb 2005


Computer Science / Information Science and Engineering
Data Structures with C
Time: 3 hrs. Max. Marks: 100

Note: Answer any 5 full questions. All questions carry equal marks

1. a) What is a structure? How is it different from an array? Explain the methods of


initializing the structure members with an illustrative example. (10 marks)
Ans: Page 4.6: section 4.5,4,4 (8 marks)
Page 5.15 to 4.20

b) Write a C program to read the following information for n students in a class: Student
Name, regno, marks scored in three subjects. Pass the structure through the function to
update percentage by 10%(6 marks) (6 marks)
ADS: Page 12.9

c) Distinguish between the following:


i) (*m)[5] and *m[5]
ii) int (*ptr) ( ) and int * ptr ( ) (4 marks)
ADS: Page 12.11, 12,12

2. a) Develop a C program to write data of employees into a file. Each employee is a


structure with the following members:
char name[lO], folat salary, int id, char designation[lO]
Further read the data from the file and display it on the console. (8 marks)
ADS: Page 5.37, example 5.4.2.6 (Similar to this problem)

b) What are command line arguments? Illustrate with a simple program


ADS: Page 5.41, Page 12.8 to see the example, (6 marks)

c) Develop a program to determine the sum of positive and negative elements of


an array using dynamic memory allocation (6 marks)
Ans.Page 12.12

3. a) What a stack? Indicate how stack is represented in C. (5 marks)


ADS: Page 6.2. Stack can be represented using arrays (page 6.11, page 6.13) and linked
lists (page 9.30)
12.20 ~ Question papers

b) Write an.algorithm for converting infix expression to postfix expression.


Further, trace the above algorithm clearly indicating the contents of the
stack for the following expression:
(( A - (B + C)) * D) $ (E + F) (15 marks)
ADS: Page 6.23 to 6.25

4. a) What is recursion? Comment on the efficiency of recursive routines (4 marks)


ADS:Page 7.1, 7.6

b) Write a recursive C function to find the sum of all the elements in an array
with N integer values. (6 marks)
Ans:Page 7.23

c) What is circular queue? Write the implementation of circular queue


using array. Also develop the routines to perform following operation
on the circular queue. -
i) Insertion ii) deletion iii) Display (10 marks)
ADS:Page 8.21, page 8.26

5. a) Write algorithm to implement the following on a singly linked list:


i) To find the average of a set of values
ii) To replace all the occurrences of a given value by other value from the
list . (10 marks)
Ans: Page 12.13 and 12.14

b) With an illustrative example, show how a queue can be structured as a circular


list. (10 marks)
Ans: Page 9.73, page 9.79 (both rear insert and front delete along with display)

6. a) Enlist the advantages and disadvantages of double linked list over singly linked
list. (4 marks)
Ans: Page 9.116

b) Write a program to insert a given value into an ordered doubly linked list into
its proper position (6 marks)
ADS:Page 9.37
Q Systematic Approach to Data Structures using C - 12.21

c) Brietly explain the different operations performed on a binary tree. Also


indicate the various schemes of representing a binary tree (10 marks)
Ans: Page 439:Section 10.4

7. a) Conctruct a binary tree given the following traversals.


Pre-order: A B D G C E H L F
In-order : D G B A H E L C F (8 marks)

b) What do you mean by a threaded binary tree? Discuss the impact of such a
representation on the tree traversal procedure (8 marks)
Ans:Page 482 onwards, Page 491:Section 10.9.6

c) Comment on the number of comparisons in binary tree sort algorithm.


(4 marks)
8. a) Explain the working of radix sort on a suitable data set and comment on its
efficiency. (10 marks)
Ans:Page 11.33

b) What is hashing? Explain various methods for resolving hash collisions.


(10 marks)
12.22 ~ Question papers

Third Semester B.E. Degree Examination, July/August 2005


Computer Science / Information Science and Engineering
Data Structures with C
Time: 3 hrs. Max. Marks: 100
Note: Answer any 5 full questions. All questions carry equal marks
I. a) What are bit-fields? Why are bit fields used with structures? Explain with an
example. (6 marks)
Ans: Page 4.58

b) What are the disadvantages of not freeing the memory during dynamic
allocation? (4 marks)
Ans: Page 2.100

c) Write a C program to simulate rudimentary calculator by using pointers to


functions. (10 marks)
Ans: Page 2.109

2. a) Discuss the various operations that could be used for string manipulations
Ans: Page 3.26 (8 marks)

b) Write a C program to print the reverse of a given 5 digit integer number


i) Without using arrays ii)With using arrays
Ans:Page 7.24, 7.25

3. a) Discuss the various exceptional conditions that should be handled while using
stacks. (8 marks)
Ans: Overflow, underflow. For details refer sections: 6.2.1, 6.2.2, 6.2.3 (Page
6.5, 6.8, 6.10)

b) Convert the following postfix expressions to its corresponding infix and prefix
expressions:
i) ABCDE/* - F/G++
i i) 234& & 93 / + 4 3 * 2 + 5 -
iii) abcdg/*++ (12 marks)

Hint: Scan from left to right till we get an operator and scan backwards till we get
two operands. Convert the two operands along with operator into infix or prefix
expression. Repeat the above step

4. a) Write a C program to display nth harmonic number using recursion. Also


display the number of calls made to the recursive functions (7 marks)
Q Systematic Approach to Data Structures using C-, 12.23

b) What is the output of this program if S = "VTU Belgaum"


#include <stdio.h>

void do_something(char *s) {


if (*s != NULL) {
do_something( ++s);
putchar(*( --s»;

}
void mairu)]
char s[80];
printf("Enter something in");
gets(s);
do_something(s);
(6 marks)
Ans: If input is VTU Belgaum the output is reverse of the string which is
muagleB UTV

c) Write a C program to calculate the factorial of N using recursion handling all


the exceptions. (7 marks)
Ans: Page 7.5

5. a) What do your mean by a queue? Discuss queues W.r.t its sequential


representation (6 marks)
Ans: Page 8.1, 8.2

b) Write a C program to implement circular queues (8 marks)


Ans:Page 8.26

c) What do you mean by a priority in a queue? Explain the array implementation


of the priority. (6 marks)
Ans: Page 8.27

6. a) Write a c program to add 2 polynomial containing 2 varialbes using single


linked lists. (lOmarks)
Ans: Page 9.134

b) Write a C program to check whether a given string is a palindrome using


doubly linked list (10 marks)

Ans: Hint: Have 2 pointers, the first one pointing to the first node and the second
one pointing to the last node. Compare the info fields. If not same the string is not
12.24 Q Question papers

a palindrome. If equal, update the first pointer towards right and second pointer
towards left and repeat the process. Finally, if all characters match the string is a
palindrome. Write the program for this.

7. a) Explain the following.


Binary tree, Descendant-left and right in a binary tree, Depth of a binary
tree, complete binary tree, level of a node. (2x5= 10 marks)
Ans: Page 10.4 to10.6, 10.7

b) Write the results after traversing the following tree in in order, preorder and
postorder (6 marks)

Ans: Inorder: d g b a h e i c f
Postorder:g d b hie f c a
Preorder: a b d gee h i f

c) Wrie a note on anyone of the following:


i)Address calculation sort ii) Radix sort
Ans: Page 11.30 Ans:Page 11.33

8. a) List the various searching techniques. Explain in detail the interpolation search
technique (10 marks)

b)Write short notes on two of the following:


circular queues Ans:Page 8.21
Tree searching Ans:Page 10.21
(5x2=10 marks)
Q Systematic Approach to Data Structures using C - 12.25

Third Semester B.E. Degree Examination, Dec. 07/ J an 08


Data Structures with C
Time: 3hrs Max. Marks: 100

I. a) Gi ven the following declarations: (05 marks)


int x: double d; int *p; double *q;

Which of the following expressions are not allowed?


i) p = &x; A S: allowed
ii) p = &d; ANS: not allowed
iii) q = &x; ANS: not allowed
iv) q = &d ANS: allowed
v) p = x; ANS: not allowed

b) Show what would be printed from the following block:


/* Local definitions */
int x[2][3] = {
{4,S,2},
{7, 6, 9}
};
t= statements */
fun (x ):
funtx+ I);
return 0;

void fun(int (*p)[3])


{
printf("\n %d %d", (*p)[O], (*p)[l], *p[2]); (06 marks)
return;

Ans: 4 5 7
7 6 junk value

c) Briefly explain memory allocation functions (09 marks)


Ans: PAGE 2.84, section 2.9.2
12.26 Q Question papers

2) a. Implement i) copying one string to another ii) Reversing the given string
Without using sring library functions in C (12 marks

A S: Copying one string to another: page 3.29, section 3.6.2


A !S: Reversing the string: Page 12.7

b. Write a C program to represent a complex number using structure and add two
complex numbers. (08 marks)
Ans: Page 4.47, section: 4.9,4.9.1

3) a. Define a stack and operations over stack. Implement reversing a string using stack
(array implementation) in C (12 marks)
Ans: Definition: page 6.2
reversing a string using stack: same as program given in question 2.a

b. What is recursion? Explain efficiency of recursion. Write a C recursive program to


solve tower of Hanoi problem. (08 marks)
Ans: page 7.1, page 7.26, page 7.14

4) a. Write a C program to implement multiple stacks using single array (12 marks)
Ans: 12.1

b. What is a linear queue? What are the applications of linear queue? Implement insert
and delete operations. (08 marks)
Definition: page 8.1, section 8.1
Applications:
Implementation: page 8.3, section 8.2.1.1
page 8.6, section 8.2.1.2

5. a. Given an ordered lined list whose first node is denoted by 'start' and node is
represented by 'key' as information and 'link' as link field. Write a C program to
implement deleting number of nodes (consecutive) whose 'key' values are greater than or
equal to 'KOlin' and less than Kmax. (12 marks)
Ans: Page 12.4

b. Write a C program to implement insertion to the immediate left of Kth node in the
list ( 08 marks)
Ans: Page 12.5
~ Systematic Approach to Data Structures using C - 12.27

6. :1. Write a C program to implement doubly linked list with following operations:
i) Create ii) Insert (10 marks)
ns: Page 9.100

b. Implement concatenation of two circular singly linked lists Li t 1 and List 2. Use
header nodes to implement the list (10 marks)
Ans: Page 12.6

7. a. Implement binary tree traversals in C: i) Inorder ii) preorder iii) Postorder


(10 marks)
Ans: Page 10.14

b. What are the applications of binary tree? Implement binary search tree and check for
duplicate data (10 marks)
Ans: applications of binary tree (page no 10.44)
Program: page no. 10.31

8. Write short notes on: . (20 mark)


a) Threaded binary tree (Ans: PAGE 10.61)
b) Applications of stack (Ans: PAGE 6.14)
c) Array implementation of binary trees (Ans: PAGE 10.11)
d. structures and union (Ans: PAGE 4.6, section 4.4.1
PAGE 4.53)

You might also like